| // -*- mode: c++ -*- |
| |
| // Copyright (c) 2012-2013, 2015-2018 ARM Limited |
| // All rights reserved |
| // |
| // The license below extends only to copyright in the software and shall |
| // not be construed as granting a license to any other intellectual |
| // property including but not limited to intellectual property relating |
| // to a hardware implementation of the functionality of the software |
| // licensed hereunder. You may use the software subject to the license |
| // terms below provided that you ensure that this notice is replicated |
| // unmodified and in its entirety in all distributions of the software, |
| // modified or unmodified, in source code or in binary form. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer; |
| // redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution; |
| // neither the name of the copyright holders nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| // |
| // Authors: Giacomo Gabrielli |
| // Mbou Eyole |
| |
| let {{ |
| |
| header_output = "" |
| exec_output = "" |
| decoders = { 'Generic' : {} } |
| |
| # FP types (FP operations always work with unsigned representations) |
| floatTypes = ("uint16_t", "uint32_t", "uint64_t") |
| smallFloatTypes = ("uint32_t",) |
| |
| def threeEqualRegInstX(name, Name, opClass, types, rCount, op, |
| readDest=False, pairwise=False, scalar=False, |
| byElem=False, decoder='Generic'): |
| assert (not pairwise) or ((not byElem) and (not scalar)) |
| global header_output, exec_output, decoders |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect srcReg1, destReg; |
| ''' |
| if byElem: |
| # 2nd register operand has to be read fully |
| eWalkCode += ''' |
| FullRegVect srcReg2; |
| ''' |
| else: |
| eWalkCode += ''' |
| RegVect srcReg2; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if byElem: |
| # 2nd operand has to be read fully |
| for reg in range(rCount, 4): |
| eWalkCode += ''' |
| srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = gtoh(destReg.elements[i]);' |
| if pairwise: |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = gtoh(2 * i < eCount ? |
| srcReg1.elements[2 * i] : |
| srcReg2.elements[2 * i - eCount]); |
| Element srcElem2 = gtoh(2 * i < eCount ? |
| srcReg1.elements[2 * i + 1] : |
| srcReg2.elements[2 * i + 1 - eCount]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htog(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| else: |
| scalarCheck = ''' |
| if (i != 0) { |
| destReg.elements[i] = 0; |
| continue; |
| } |
| ''' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| %(scalarCheck)s |
| Element srcElem1 = gtoh(srcReg1.elements[i]); |
| Element srcElem2 = gtoh(srcReg2.elements[%(src2Index)s]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htog(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode, |
| "scalarCheck" : scalarCheck if scalar else "", |
| "src2Index" : "imm" if byElem else "i" } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| if rCount < 4: # zero upper half |
| for reg in range(rCount, 4): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX2RegImmOp" if byElem else "DataX2RegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| if byElem: |
| header_output += NeonX2RegImmOpDeclare.subst(iop) |
| else: |
| header_output += NeonX2RegOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def threeUnequalRegInstX(name, Name, opClass, types, op, |
| bigSrc1, bigSrc2, bigDest, readDest, scalar=False, |
| byElem=False, hi=False): |
| assert not (scalar and hi) |
| global header_output, exec_output |
| src1Cnt = src2Cnt = destCnt = 2 |
| src1Prefix = src2Prefix = destPrefix = '' |
| if bigSrc1: |
| src1Cnt = 4 |
| src1Prefix = 'Big' |
| if bigSrc2: |
| src2Cnt = 4 |
| src2Prefix = 'Big' |
| if bigDest: |
| destCnt = 4 |
| destPrefix = 'Big' |
| if byElem: |
| src2Prefix = 'Full' |
| eWalkCode = simd64EnabledCheckCode + ''' |
| %sRegVect srcReg1; |
| %sRegVect srcReg2; |
| %sRegVect destReg; |
| ''' % (src1Prefix, src2Prefix, destPrefix) |
| srcReg1 = 0 |
| if hi and not bigSrc1: # long/widening operations |
| srcReg1 = 2 |
| for reg in range(src1Cnt): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(srcReg1)d_uw); |
| ''' % { "reg" : reg, "srcReg1" : srcReg1 } |
| srcReg1 += 1 |
| srcReg2 = 0 |
| if (not byElem) and (hi and not bigSrc2): # long/widening operations |
| srcReg2 = 2 |
| for reg in range(src2Cnt): |
| eWalkCode += ''' |
| srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(srcReg2)d_uw); |
| ''' % { "reg" : reg, "srcReg2" : srcReg2 } |
| srcReg2 += 1 |
| if byElem: |
| # 2nd operand has to be read fully |
| for reg in range(src2Cnt, 4): |
| eWalkCode += ''' |
| srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| for reg in range(destCnt): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = gtoh(destReg.elements[i]);' |
| scalarCheck = ''' |
| if (i != 0) { |
| destReg.elements[i] = 0; |
| continue; |
| } |
| ''' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| %(scalarCheck)s |
| %(src1Prefix)sElement srcElem1 = gtoh(srcReg1.elements[i]); |
| %(src1Prefix)sElement srcElem2 = gtoh(srcReg2.elements[%(src2Index)s]); |
| %(destPrefix)sElement destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htog(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode, |
| "src1Prefix" : src1Prefix, "src2Prefix" : src2Prefix, |
| "destPrefix" : destPrefix, |
| "scalarCheck" : scalarCheck if scalar else "", |
| "src2Index" : "imm" if byElem else "i" } |
| destReg = 0 |
| if hi and not bigDest: |
| # narrowing operations |
| destReg = 2 |
| for reg in range(destCnt): |
| eWalkCode += ''' |
| AA64FpDestP%(destReg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg, "destReg": destReg } |
| destReg += 1 |
| if destCnt < 4: |
| if hi: # Explicitly merge with lower half |
| for reg in range(0, destCnt): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = AA64FpDestP%(reg)d_uw;''' % { "reg" : reg } |
| else: # zero upper half |
| for reg in range(destCnt, 4): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0;''' % { "reg" : reg } |
| |
| iop = InstObjParams(name, Name, |
| "DataX2RegImmOp" if byElem else "DataX2RegOp", |
| { "code": eWalkCode, |
| "r_count": 2, |
| "op_class": opClass }, []) |
| if byElem: |
| header_output += NeonX2RegImmOpDeclare.subst(iop) |
| else: |
| header_output += NeonX2RegOpDeclare.subst(iop) |
| exec_output += NeonXUnequalRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def threeRegNarrowInstX(name, Name, opClass, types, op, readDest=False, |
| scalar=False, byElem=False, hi=False): |
| assert not byElem |
| threeUnequalRegInstX(name, Name, opClass, types, op, |
| True, True, False, readDest, scalar, byElem, hi) |
| |
| def threeRegLongInstX(name, Name, opClass, types, op, readDest=False, |
| scalar=False, byElem=False, hi=False): |
| threeUnequalRegInstX(name, Name, opClass, types, op, |
| False, False, True, readDest, scalar, byElem, hi) |
| |
| def threeRegWideInstX(name, Name, opClass, types, op, readDest=False, |
| scalar=False, byElem=False, hi=False): |
| assert not byElem |
| threeUnequalRegInstX(name, Name, opClass, types, op, |
| True, False, True, readDest, scalar, byElem, hi) |
| |
| def twoEqualRegInstX(name, Name, opClass, types, rCount, op, |
| readDest=False, scalar=False, byElem=False, |
| hasImm=False, isDup=False): |
| global header_output, exec_output |
| assert (not isDup) or byElem |
| if byElem: |
| hasImm = True |
| if isDup: |
| eWalkCode = simd64EnabledCheckCode + ''' |
| FullRegVect srcReg1; |
| RegVect destReg; |
| ''' |
| else: |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect srcReg1, destReg; |
| ''' |
| for reg in range(4 if isDup else rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = gtoh(destReg.elements[i]);' |
| scalarCheck = ''' |
| if (i != 0) { |
| destReg.elements[i] = 0; |
| continue; |
| } |
| ''' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| %(scalarCheck)s |
| unsigned j = i; |
| Element srcElem1 = gtoh(srcReg1.elements[%(src1Index)s]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[j] = htog(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode, |
| "scalarCheck" : scalarCheck if scalar else "", |
| "src1Index" : "imm" if byElem else "i" } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| if rCount < 4: # zero upper half |
| for reg in range(rCount, 4): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX1RegImmOp" if hasImm else "DataX1RegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| if hasImm: |
| header_output += NeonX1RegImmOpDeclare.subst(iop) |
| else: |
| header_output += NeonX1RegOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def twoRegLongInstX(name, Name, opClass, types, op, readDest=False, |
| hi=False, hasImm=False): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect srcReg1; |
| BigRegVect destReg; |
| ''' |
| destReg = 0 if not hi else 2 |
| for reg in range(2): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(destReg)d_uw); |
| ''' % { "reg" : reg, "destReg": destReg } |
| destReg += 1 |
| destReg = 0 if not hi else 2 |
| if readDest: |
| for reg in range(4): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| destReg += 1 |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destReg = gtoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = gtoh(srcReg1.elements[i]); |
| BigElement destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htog(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(4): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX1RegImmOp" if hasImm else "DataX1RegOp", |
| { "code": eWalkCode, |
| "r_count": 2, |
| "op_class": opClass }, []) |
| if hasImm: |
| header_output += NeonX1RegImmOpDeclare.subst(iop) |
| else: |
| header_output += NeonX1RegOpDeclare.subst(iop) |
| exec_output += NeonXUnequalRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def twoRegNarrowInstX(name, Name, opClass, types, op, readDest=False, |
| scalar=False, hi=False, hasImm=False): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| BigRegVect srcReg1; |
| RegVect destReg; |
| ''' |
| for reg in range(4): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| for reg in range(2): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| else: |
| eWalkCode += ''' |
| destReg.elements[0] = 0; |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = gtoh(destReg.elements[i]);' |
| scalarCheck = ''' |
| if (i != 0) { |
| destReg.elements[i] = 0; |
| continue; |
| } |
| ''' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| %(scalarCheck)s |
| BigElement srcElem1 = gtoh(srcReg1.elements[i]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htog(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode, |
| "scalarCheck" : scalarCheck if scalar else "" } |
| destReg = 0 if not hi else 2 |
| for reg in range(2): |
| eWalkCode += ''' |
| AA64FpDestP%(destReg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg, "destReg": destReg } |
| destReg += 1 |
| if hi: |
| for reg in range(0, 2): # Explicitly merge with the lower half |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = AA64FpDestP%(reg)d_uw;''' % { "reg" : reg } |
| else: |
| for reg in range(2, 4): # zero upper half |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| |
| iop = InstObjParams(name, Name, |
| "DataX1RegImmOp" if hasImm else "DataX1RegOp", |
| { "code": eWalkCode, |
| "r_count": 2, |
| "op_class": opClass }, []) |
| if hasImm: |
| header_output += NeonX1RegImmOpDeclare.subst(iop) |
| else: |
| header_output += NeonX1RegOpDeclare.subst(iop) |
| exec_output += NeonXUnequalRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def threeRegScrambleInstX(name, Name, opClass, types, rCount, op): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect srcReg1, srcReg2, destReg; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| eWalkCode += op |
| for reg in range(rCount): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| if rCount < 4: |
| for reg in range(rCount, 4): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX2RegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX2RegOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def insFromVecElemInstX(name, Name, opClass, types, rCount): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| FullRegVect srcReg1; |
| RegVect destReg; |
| ''' |
| for reg in range(4): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| eWalkCode += ''' |
| Element srcElem1 = gtoh(srcReg1.elements[imm2]); |
| Element destElem = srcElem1; |
| destReg.elements[imm1] = htog(destElem); |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX1Reg2ImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX1Reg2ImmOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def twoRegPairwiseScInstX(name, Name, opClass, types, rCount, op): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect srcReg1, destReg; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| eWalkCode += ''' |
| Element srcElem1 = gtoh(srcReg1.elements[0]); |
| Element srcElem2 = gtoh(srcReg1.elements[1]); |
| Element destElem; |
| %(op)s |
| destReg.elements[0] = htog(destElem); |
| ''' % { "op" : op } |
| destCnt = rCount / 2 |
| for reg in range(destCnt): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| for reg in range(destCnt, 4): # zero upper half |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX1RegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX1RegOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def twoRegAcrossInstX(name, Name, opClass, types, rCount, op, |
| doubleDest=False, long=False): |
| global header_output, exec_output |
| destPrefix = "Big" if long else "" |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect srcReg1; |
| %sRegVect destReg; |
| ''' % destPrefix |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| eWalkCode += ''' |
| destReg.regs[0] = 0; |
| %(destPrefix)sElement destElem = 0; |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = gtoh(srcReg1.elements[i]); |
| if (i == 0) { |
| destElem = srcElem1; |
| } else { |
| %(op)s |
| } |
| } |
| destReg.elements[0] = htog(destElem); |
| ''' % { "op" : op, "destPrefix" : destPrefix } |
| destCnt = 2 if doubleDest else 1 |
| for reg in range(destCnt): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| for reg in range(destCnt, 4): # zero upper half |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX1RegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX1RegOpDeclare.subst(iop) |
| if long: |
| exec_output += NeonXUnequalRegOpExecute.subst(iop) |
| else: |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def twoRegCondenseInstX(name, Name, opClass, types, rCount, op, |
| readDest=False): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect srcRegs; |
| BigRegVect destReg; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcRegs.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = gtoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount / 2; i++) { |
| Element srcElem1 = gtoh(srcRegs.elements[2 * i]); |
| Element srcElem2 = gtoh(srcRegs.elements[2 * i + 1]); |
| BigElement destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htog(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| if rCount < 4: # zero upper half |
| for reg in range(rCount, 4): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX1RegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX1RegOpDeclare.subst(iop) |
| exec_output += NeonXUnequalRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def oneRegImmInstX(name, Name, opClass, types, rCount, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect destReg; |
| ''' |
| if readDest: |
| for reg in range(rCount): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = gtoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htog(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| if rCount < 4: # zero upper half |
| for reg in range(rCount, 4): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataXImmOnlyOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX1RegImmOnlyOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def dupGprInstX(name, Name, opClass, types, rCount, gprSpec): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect destReg; |
| for (unsigned i = 0; i < eCount; i++) { |
| destReg.elements[i] = htog((Element) %sOp1); |
| } |
| ''' % gprSpec |
| for reg in range(rCount): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| if rCount < 4: # zero upper half |
| for reg in range(rCount, 4): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX1RegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX1RegOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def extInstX(name, Name, opClass, types, rCount, op): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect srcReg1, srcReg2, destReg; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| eWalkCode += op |
| for reg in range(rCount): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| if rCount < 4: # zero upper half |
| for reg in range(rCount, 4): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX2RegImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX2RegImmOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def insFromGprInstX(name, Name, opClass, types, rCount, gprSpec): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| RegVect destReg; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| eWalkCode += ''' |
| destReg.elements[imm] = htog((Element) %sOp1); |
| ''' % gprSpec |
| for reg in range(rCount): |
| eWalkCode += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX1RegImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX1RegImmOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def insToGprInstX(name, Name, opClass, types, rCount, gprSpec, |
| signExt=False): |
| global header_output, exec_output |
| eWalkCode = simd64EnabledCheckCode + ''' |
| FullRegVect srcReg; |
| ''' |
| for reg in range(4): |
| eWalkCode += ''' |
| srcReg.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if signExt: |
| eWalkCode += ''' |
| %sDest = sext<sizeof(Element) * 8>(srcReg.elements[imm]); |
| ''' % gprSpec |
| else: |
| eWalkCode += ''' |
| %sDest = srcReg.elements[imm]; |
| ''' % gprSpec |
| iop = InstObjParams(name, Name, |
| "DataX1RegImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX1RegImmOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| def tbxTblInstX(name, Name, opClass, types, length, isTbl, rCount): |
| global header_output, decoder_output, exec_output |
| code = simd64EnabledCheckCode + ''' |
| union |
| { |
| uint8_t bytes[64]; |
| uint32_t regs[16]; |
| } table; |
| |
| union |
| { |
| uint8_t bytes[%(rCount)d * 4]; |
| uint32_t regs[%(rCount)d]; |
| } destReg, srcReg2; |
| |
| const unsigned length = %(length)d; |
| const bool isTbl = %(isTbl)s; |
| ''' % { "rCount" : rCount, "length" : length, "isTbl" : isTbl } |
| for reg in range(rCount): |
| code += ''' |
| srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); |
| destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| for reg in range(16): |
| if reg < length * 4: |
| code += ''' |
| table.regs[%(reg)d] = htog(AA64FpOp1P%(p)dV%(v)dS_uw); |
| ''' % { "reg" : reg, "p" : reg % 4, "v" : reg / 4 } |
| else: |
| code += ''' |
| table.regs[%(reg)d] = 0; |
| ''' % { "reg" : reg } |
| code += ''' |
| for (unsigned i = 0; i < sizeof(destReg); i++) { |
| uint8_t index = srcReg2.bytes[i]; |
| if (index < 16 * length) { |
| destReg.bytes[i] = table.bytes[index]; |
| } else { |
| if (isTbl) |
| destReg.bytes[i] = 0; |
| // else destReg.bytes[i] unchanged |
| } |
| } |
| ''' |
| for reg in range(rCount): |
| code += ''' |
| AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| if rCount < 4: # zero upper half |
| for reg in range(rCount, 4): |
| code += ''' |
| AA64FpDestP%(reg)d_uw = 0; |
| ''' % { "reg" : reg } |
| iop = InstObjParams(name, Name, |
| "DataX2RegOp", |
| { "code": code, |
| "r_count": rCount, |
| "op_class": opClass }, []) |
| header_output += NeonX2RegOpDeclare.subst(iop) |
| exec_output += NeonXEqualRegOpExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonXExecDeclare.subst(substDict) |
| |
| # ABS |
| absCode = ''' |
| if (srcElem1 < 0) { |
| destElem = -srcElem1; |
| } else { |
| destElem = srcElem1; |
| } |
| ''' |
| twoEqualRegInstX("abs", "AbsDX", "SimdAluOp", signedTypes, 2, absCode) |
| twoEqualRegInstX("abs", "AbsQX", "SimdAluOp", signedTypes, 4, absCode) |
| # ADD |
| addCode = "destElem = srcElem1 + srcElem2;" |
| threeEqualRegInstX("add", "AddDX", "SimdAddOp", unsignedTypes, 2, addCode) |
| threeEqualRegInstX("add", "AddQX", "SimdAddOp", unsignedTypes, 4, addCode) |
| # ADDHN, ADDHN2 |
| addhnCode = ''' |
| destElem = ((BigElement)srcElem1 + (BigElement)srcElem2) >> |
| (sizeof(Element) * 8); |
| ''' |
| threeRegNarrowInstX("addhn", "AddhnX", "SimdAddOp", smallUnsignedTypes, |
| addhnCode) |
| threeRegNarrowInstX("addhn2", "Addhn2X", "SimdAddOp", smallUnsignedTypes, |
| addhnCode, hi=True) |
| # ADDP (scalar) |
| twoRegPairwiseScInstX("addp", "AddpScQX", "SimdAddOp", ("uint64_t",), 4, |
| addCode) |
| # ADDP (vector) |
| threeEqualRegInstX("addp", "AddpDX", "SimdAddOp", smallUnsignedTypes, 2, |
| addCode, pairwise=True) |
| threeEqualRegInstX("addp", "AddpQX", "SimdAddOp", unsignedTypes, 4, |
| addCode, pairwise=True) |
| # ADDV |
| # Note: SimdAddOp can be a bit optimistic here |
| addAcrossCode = "destElem += srcElem1;" |
| twoRegAcrossInstX("addv", "AddvDX", "SimdAddOp", ("uint8_t", "uint16_t"), |
| 2, addAcrossCode) |
| twoRegAcrossInstX("addv", "AddvQX", "SimdAddOp", smallUnsignedTypes, 4, |
| addAcrossCode) |
| # AND |
| andCode = "destElem = srcElem1 & srcElem2;" |
| threeEqualRegInstX("and", "AndDX", "SimdAluOp", ("uint64_t",), 2, andCode) |
| threeEqualRegInstX("and", "AndQX", "SimdAluOp", ("uint64_t",), 4, andCode) |
| # BIC (immediate) |
| bicImmCode = "destElem &= ~imm;" |
| oneRegImmInstX("bic", "BicImmDX", "SimdAluOp", ("uint64_t",), 2, |
| bicImmCode, True) |
| oneRegImmInstX("bic", "BicImmQX", "SimdAluOp", ("uint64_t",), 4, |
| bicImmCode, True) |
| # BIC (register) |
| bicCode = "destElem = srcElem1 & ~srcElem2;" |
| threeEqualRegInstX("bic", "BicDX", "SimdAluOp", ("uint64_t",), 2, bicCode) |
| threeEqualRegInstX("bic", "BicQX", "SimdAluOp", ("uint64_t",), 4, bicCode) |
| # BIF |
| bifCode = "destElem = (destElem & srcElem2) | (srcElem1 & ~srcElem2);" |
| threeEqualRegInstX("bif", "BifDX", "SimdAluOp", ("uint64_t",), 2, bifCode, |
| True) |
| threeEqualRegInstX("bif", "BifQX", "SimdAluOp", ("uint64_t",), 4, bifCode, |
| True) |
| # BIT |
| bitCode = "destElem = (srcElem1 & srcElem2) | (destElem & ~srcElem2);" |
| threeEqualRegInstX("bit", "BitDX", "SimdAluOp", ("uint64_t",), 2, bitCode, |
| True) |
| threeEqualRegInstX("bit", "BitQX", "SimdAluOp", ("uint64_t",), 4, bitCode, |
| True) |
| # BSL |
| bslCode = "destElem = (srcElem1 & destElem) | (srcElem2 & ~destElem);" |
| threeEqualRegInstX("bsl", "BslDX", "SimdAluOp", ("uint64_t",), 2, bslCode, |
| True) |
| threeEqualRegInstX("bsl", "BslQX", "SimdAluOp", ("uint64_t",), 4, bslCode, |
| True) |
| # CLS |
| clsCode = ''' |
| unsigned count = 0; |
| if (srcElem1 < 0) { |
| srcElem1 <<= 1; |
| while (srcElem1 < 0 && count < sizeof(Element) * 8 - 1) { |
| count++; |
| srcElem1 <<= 1; |
| } |
| } else { |
| srcElem1 <<= 1; |
| while (srcElem1 >= 0 && count < sizeof(Element) * 8 - 1) { |
| count++; |
| srcElem1 <<= 1; |
| } |
| } |
| destElem = count; |
| ''' |
| twoEqualRegInstX("cls", "ClsDX", "SimdAluOp", smallSignedTypes, 2, clsCode) |
| twoEqualRegInstX("cls", "ClsQX", "SimdAluOp", smallSignedTypes, 4, clsCode) |
| # CLZ |
| clzCode = ''' |
| unsigned count = 0; |
| while (srcElem1 >= 0 && count < sizeof(Element) * 8) { |
| count++; |
| srcElem1 <<= 1; |
| } |
| destElem = count; |
| ''' |
| twoEqualRegInstX("clz", "ClzDX", "SimdAluOp", smallSignedTypes, 2, clzCode) |
| twoEqualRegInstX("clz", "ClzQX", "SimdAluOp", smallSignedTypes, 4, clzCode) |
| # CMEQ (register) |
| cmeqCode = "destElem = (srcElem1 == srcElem2) ? (Element)(-1) : 0;" |
| threeEqualRegInstX("cmeq", "CmeqDX", "SimdCmpOp", unsignedTypes, 2, |
| cmeqCode) |
| threeEqualRegInstX("cmeq", "CmeqQX", "SimdCmpOp", unsignedTypes, 4, |
| cmeqCode) |
| # CMEQ (zero) |
| cmeqZeroCode = "destElem = (srcElem1 == 0) ? (Element)(-1) : 0;" |
| twoEqualRegInstX("cmeq", "CmeqZeroDX", "SimdCmpOp", signedTypes, 2, |
| cmeqZeroCode) |
| twoEqualRegInstX("cmeq", "CmeqZeroQX", "SimdCmpOp", signedTypes, 4, |
| cmeqZeroCode) |
| # CMGE (register) |
| cmgeCode = "destElem = (srcElem1 >= srcElem2) ? (Element)(-1) : 0;" |
| threeEqualRegInstX("cmge", "CmgeDX", "SimdCmpOp", signedTypes, 2, cmgeCode) |
| threeEqualRegInstX("cmge", "CmgeQX", "SimdCmpOp", signedTypes, 4, cmgeCode) |
| # CMGE (zero) |
| cmgeZeroCode = "destElem = (srcElem1 >= 0) ? (Element)(-1) : 0;" |
| twoEqualRegInstX("cmge", "CmgeZeroDX", "SimdCmpOp", signedTypes, 2, |
| cmgeZeroCode) |
| twoEqualRegInstX("cmge", "CmgeZeroQX", "SimdCmpOp", signedTypes, 4, |
| cmgeZeroCode) |
| # CMGT (register) |
| cmgtCode = "destElem = (srcElem1 > srcElem2) ? (Element)(-1) : 0;" |
| threeEqualRegInstX("cmgt", "CmgtDX", "SimdCmpOp", signedTypes, 2, cmgtCode) |
| threeEqualRegInstX("cmgt", "CmgtQX", "SimdCmpOp", signedTypes, 4, cmgtCode) |
| # CMGT (zero) |
| cmgtZeroCode = "destElem = (srcElem1 > 0) ? (Element)(-1) : 0;" |
| twoEqualRegInstX("cmgt", "CmgtZeroDX", "SimdCmpOp", signedTypes, 2, |
| cmgtZeroCode) |
| twoEqualRegInstX("cmgt", "CmgtZeroQX", "SimdCmpOp", signedTypes, 4, |
| cmgtZeroCode) |
| # CMHI (register) |
| threeEqualRegInstX("cmhi", "CmhiDX", "SimdCmpOp", unsignedTypes, 2, |
| cmgtCode) |
| threeEqualRegInstX("cmhi", "CmhiQX", "SimdCmpOp", unsignedTypes, 4, |
| cmgtCode) |
| # CMHS (register) |
| threeEqualRegInstX("cmhs", "CmhsDX", "SimdCmpOp", unsignedTypes, 2, |
| cmgeCode) |
| threeEqualRegInstX("cmhs", "CmhsQX", "SimdCmpOp", unsignedTypes, 4, |
| cmgeCode) |
| # CMLE (zero) |
| cmleZeroCode = "destElem = (srcElem1 <= 0) ? (Element)(-1) : 0;" |
| twoEqualRegInstX("cmle", "CmleZeroDX", "SimdCmpOp", signedTypes, 2, |
| cmleZeroCode) |
| twoEqualRegInstX("cmle", "CmleZeroQX", "SimdCmpOp", signedTypes, 4, |
| cmleZeroCode) |
| # CMLT (zero) |
| cmltZeroCode = "destElem = (srcElem1 < 0) ? (Element)(-1) : 0;" |
| twoEqualRegInstX("cmlt", "CmltZeroDX", "SimdCmpOp", signedTypes, 2, |
| cmltZeroCode) |
| twoEqualRegInstX("cmlt", "CmltZeroQX", "SimdCmpOp", signedTypes, 4, |
| cmltZeroCode) |
| # CMTST (register) |
| tstCode = "destElem = (srcElem1 & srcElem2) ? (Element)(-1) : 0;" |
| threeEqualRegInstX("cmtst", "CmtstDX", "SimdAluOp", unsignedTypes, 2, |
| tstCode) |
| threeEqualRegInstX("cmtst", "CmtstQX", "SimdAluOp", unsignedTypes, 4, |
| tstCode) |
| # CNT |
| cntCode = ''' |
| unsigned count = 0; |
| while (srcElem1 && count < sizeof(Element) * 8) { |
| count += srcElem1 & 0x1; |
| srcElem1 >>= 1; |
| } |
| destElem = count; |
| ''' |
| twoEqualRegInstX("cnt", "CntDX", "SimdAluOp", ("uint8_t",), 2, cntCode) |
| twoEqualRegInstX("cnt", "CntQX", "SimdAluOp", ("uint8_t",), 4, cntCode) |
| # DUP (element) |
| dupCode = "destElem = srcElem1;" |
| twoEqualRegInstX("dup", "DupElemDX", "SimdMiscOp", smallUnsignedTypes, 2, |
| dupCode, isDup=True, byElem=True) |
| twoEqualRegInstX("dup", "DupElemQX", "SimdMiscOp", unsignedTypes, 4, |
| dupCode, isDup=True, byElem=True) |
| twoEqualRegInstX("dup", "DupElemScX", "SimdMiscOp", unsignedTypes, 4, |
| dupCode, isDup=True, byElem=True, scalar=True) |
| # DUP (general register) |
| dupGprInstX("dup", "DupGprWDX", "SimdMiscOp", smallUnsignedTypes, 2, 'W') |
| dupGprInstX("dup", "DupGprWQX", "SimdMiscOp", smallUnsignedTypes, 4, 'W') |
| dupGprInstX("dup", "DupGprXQX", "SimdMiscOp", ("uint64_t",), 4, 'X') |
| # EOR |
| eorCode = "destElem = srcElem1 ^ srcElem2;" |
| threeEqualRegInstX("eor", "EorDX", "SimdAluOp", ("uint64_t",), 2, eorCode) |
| threeEqualRegInstX("eor", "EorQX", "SimdAluOp", ("uint64_t",), 4, eorCode) |
| # EXT |
| extCode = ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| unsigned index = i + imm; |
| if (index < eCount) { |
| destReg.elements[i] = srcReg1.elements[index]; |
| } else { |
| index -= eCount; |
| if (index >= eCount) { |
| fault = std::make_shared<UndefinedInstruction>( |
| machInst, false, mnemonic); |
| } else { |
| destReg.elements[i] = srcReg2.elements[index]; |
| } |
| } |
| } |
| ''' |
| extInstX("Ext", "ExtDX", "SimdMiscOp", ("uint8_t",), 2, extCode) |
| extInstX("Ext", "ExtQX", "SimdMiscOp", ("uint8_t",), 4, extCode) |
| # FABD |
| fpOp = ''' |
| FPSCR fpscr = (FPSCR) FpscrExc; |
| destElem = %s; |
| FpscrExc = fpscr; |
| ''' |
| fabdCode = fpOp % "fplibAbs<Element>(fplibSub(srcElem1, srcElem2, fpscr))" |
| threeEqualRegInstX("fabd", "FabdDX", "SimdFloatAddOp", smallFloatTypes, 2, |
| fabdCode) |
| threeEqualRegInstX("fabd", "FabdQX", "SimdFloatAddOp", floatTypes, 4, |
| fabdCode) |
| threeEqualRegInstX("fabd", "FabdScX", "SimdFloatAddOp", floatTypes, 4, |
| fabdCode, scalar=True) |
| # FABS |
| fabsCode = fpOp % "fplibAbs<Element>(srcElem1)" |
| twoEqualRegInstX("Abs", "FabsDX", "SimdFloatAluOp", smallFloatTypes, 2, |
| fabsCode) |
| twoEqualRegInstX("Abs", "FabsQX", "SimdFloatAluOp", floatTypes, 4, |
| fabsCode) |
| # FACGE |
| fpCmpAbsOp = fpOp % ("fplibCompare%s<Element>(fplibAbs<Element>(srcElem1)," |
| " fplibAbs<Element>(srcElem2), fpscr) ? -1 : 0") |
| facgeCode = fpCmpAbsOp % "GE" |
| threeEqualRegInstX("facge", "FacgeDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, facgeCode) |
| threeEqualRegInstX("facge", "FacgeQX", "SimdFloatCmpOp", floatTypes, 4, |
| facgeCode) |
| threeEqualRegInstX("facge", "FacgeScX", "SimdFloatCmpOp", floatTypes, 4, |
| facgeCode, scalar=True) |
| # FACGT |
| facgtCode = fpCmpAbsOp % "GT" |
| threeEqualRegInstX("facgt", "FacgtDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, facgtCode) |
| threeEqualRegInstX("facgt", "FacgtQX", "SimdFloatCmpOp", floatTypes, 4, |
| facgtCode) |
| threeEqualRegInstX("facgt", "FacgtScX", "SimdFloatCmpOp", floatTypes, 4, |
| facgtCode, scalar=True) |
| # FADD |
| fpBinOp = fpOp % "fplib%s<Element>(srcElem1, srcElem2, fpscr)" |
| faddCode = fpBinOp % "Add" |
| threeEqualRegInstX("fadd", "FaddDX", "SimdFloatAddOp", smallFloatTypes, 2, |
| faddCode) |
| threeEqualRegInstX("fadd", "FaddQX", "SimdFloatAddOp", floatTypes, 4, |
| faddCode) |
| # FADDP (scalar) |
| twoRegPairwiseScInstX("faddp", "FaddpScDX", "SimdFloatAddOp", |
| ("uint32_t",), 2, faddCode) |
| twoRegPairwiseScInstX("faddp", "FaddpScQX", "SimdFloatAddOp", |
| ("uint64_t",), 4, faddCode) |
| # FADDP (vector) |
| threeEqualRegInstX("faddp", "FaddpDX", "SimdFloatAddOp", smallFloatTypes, |
| 2, faddCode, pairwise=True) |
| threeEqualRegInstX("faddp", "FaddpQX", "SimdFloatAddOp", floatTypes, 4, |
| faddCode, pairwise=True) |
| # FCMEQ (register) |
| fpCmpOp = fpOp % ("fplibCompare%s<Element>(srcElem1, srcElem2, fpscr) ?" |
| " -1 : 0") |
| fcmeqCode = fpCmpOp % "EQ" |
| threeEqualRegInstX("fcmeq", "FcmeqDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fcmeqCode) |
| threeEqualRegInstX("fcmeq", "FcmeqQX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmeqCode) |
| threeEqualRegInstX("fcmeq", "FcmeqScX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmeqCode, scalar=True) |
| # FCMEQ (zero) |
| fpCmpZeroOp = fpOp % "fplibCompare%s<Element>(srcElem1, 0, fpscr) ? -1 : 0" |
| fcmeqZeroCode = fpCmpZeroOp % "EQ" |
| twoEqualRegInstX("fcmeq", "FcmeqZeroDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fcmeqZeroCode) |
| twoEqualRegInstX("fcmeq", "FcmeqZeroQX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmeqZeroCode) |
| twoEqualRegInstX("fcmeq", "FcmeqZeroScX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmeqZeroCode, scalar=True) |
| # FCMGE (register) |
| fcmgeCode = fpCmpOp % "GE" |
| threeEqualRegInstX("fcmge", "FcmgeDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fcmgeCode) |
| threeEqualRegInstX("fcmge", "FcmgeQX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmgeCode) |
| threeEqualRegInstX("fcmge", "FcmgeScX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmgeCode, scalar=True) |
| # FCMGE (zero) |
| fcmgeZeroCode = fpCmpZeroOp % "GE" |
| twoEqualRegInstX("fcmge", "FcmgeZeroDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fcmgeZeroCode) |
| twoEqualRegInstX("fcmge", "FcmgeZeroQX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmgeZeroCode) |
| twoEqualRegInstX("fcmge", "FcmgeZeroScX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmgeZeroCode, scalar=True) |
| # FCMGT (register) |
| fcmgtCode = fpCmpOp % "GT" |
| threeEqualRegInstX("fcmgt", "FcmgtDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fcmgtCode) |
| threeEqualRegInstX("fcmgt", "FcmgtQX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmgtCode) |
| threeEqualRegInstX("fcmgt", "FcmgtScX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmgtCode, scalar=True) |
| # FCMGT (zero) |
| fcmgtZeroCode = fpCmpZeroOp % "GT" |
| twoEqualRegInstX("fcmgt", "FcmgtZeroDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fcmgtZeroCode) |
| twoEqualRegInstX("fcmgt", "FcmgtZeroQX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmgtZeroCode) |
| twoEqualRegInstX("fcmgt", "FcmgtZeroScX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmgtZeroCode, scalar=True) |
| # FCMLE (zero) |
| fpCmpRevZeroOp = fpOp % ("fplibCompare%s<Element>(0, srcElem1, fpscr) ?" |
| " -1 : 0") |
| fcmleZeroCode = fpCmpRevZeroOp % "GE" |
| twoEqualRegInstX("fcmle", "FcmleZeroDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fcmleZeroCode) |
| twoEqualRegInstX("fcmle", "FcmleZeroQX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmleZeroCode) |
| twoEqualRegInstX("fcmle", "FcmleZeroScX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmleZeroCode, scalar=True) |
| # FCMLT (zero) |
| fcmltZeroCode = fpCmpRevZeroOp % "GT" |
| twoEqualRegInstX("fcmlt", "FcmltZeroDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fcmltZeroCode) |
| twoEqualRegInstX("fcmlt", "FcmltZeroQX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmltZeroCode) |
| twoEqualRegInstX("fcmlt", "FcmltZeroScX", "SimdFloatCmpOp", floatTypes, 4, |
| fcmltZeroCode, scalar=True) |
| # FCVTAS |
| fcvtCode = fpOp % ("fplibFPToFixed<Element, Element>(" |
| "srcElem1, %s, %s, %s, fpscr)") |
| fcvtasCode = fcvtCode % ("0", "false", "FPRounding_TIEAWAY") |
| twoEqualRegInstX("fcvtas", "FcvtasDX", "SimdCvtOp", smallFloatTypes, 2, |
| fcvtasCode) |
| twoEqualRegInstX("fcvtas", "FcvtasQX", "SimdCvtOp", floatTypes, 4, |
| fcvtasCode) |
| twoEqualRegInstX("fcvtas", "FcvtasScX", "SimdCvtOp", floatTypes, 4, |
| fcvtasCode, scalar=True) |
| # FCVTAU |
| fcvtauCode = fcvtCode % ("0", "true", "FPRounding_TIEAWAY") |
| twoEqualRegInstX("fcvtau", "FcvtauDX", "SimdCvtOp", smallFloatTypes, 2, |
| fcvtauCode) |
| twoEqualRegInstX("fcvtau", "FcvtauQX", "SimdCvtOp", floatTypes, 4, |
| fcvtauCode) |
| twoEqualRegInstX("fcvtau", "FcvtauScX", "SimdCvtOp", floatTypes, 4, |
| fcvtauCode, scalar=True) |
| # FCVTL, FCVTL2 |
| fcvtlCode = fpOp % ("fplibConvert<Element, BigElement>(" |
| "srcElem1, FPCRRounding(fpscr), fpscr)") |
| twoRegLongInstX("fcvtl", "FcvtlX", "SimdCvtOp", ("uint16_t", "uint32_t"), |
| fcvtlCode) |
| twoRegLongInstX("fcvtl", "Fcvtl2X", "SimdCvtOp", ("uint16_t", "uint32_t"), |
| fcvtlCode, hi=True) |
| # FCVTMS |
| fcvtmsCode = fcvtCode % ("0", "false", "FPRounding_NEGINF") |
| twoEqualRegInstX("fcvtms", "FcvtmsDX", "SimdCvtOp", smallFloatTypes, 2, |
| fcvtmsCode) |
| twoEqualRegInstX("fcvtms", "FcvtmsQX", "SimdCvtOp", floatTypes, 4, |
| fcvtmsCode) |
| twoEqualRegInstX("fcvtms", "FcvtmsScX", "SimdCvtOp", floatTypes, 4, |
| fcvtmsCode, scalar=True) |
| # FCVTMU |
| fcvtmuCode = fcvtCode % ("0", "true", "FPRounding_NEGINF") |
| twoEqualRegInstX("fcvtmu", "FcvtmuDX", "SimdCvtOp", smallFloatTypes, 2, |
| fcvtmuCode) |
| twoEqualRegInstX("fcvtmu", "FcvtmuQX", "SimdCvtOp", floatTypes, 4, |
| fcvtmuCode) |
| twoEqualRegInstX("fcvtmu", "FcvtmuScX", "SimdCvtOp", floatTypes, 4, |
| fcvtmuCode, scalar=True) |
| # FCVTN, FCVTN2 |
| fcvtnCode = fpOp % ("fplibConvert<BigElement, Element>(" |
| "srcElem1, FPCRRounding(fpscr), fpscr)") |
| twoRegNarrowInstX("fcvtn", "FcvtnX", "SimdCvtOp", |
| ("uint16_t", "uint32_t"), fcvtnCode) |
| twoRegNarrowInstX("fcvtn", "Fcvtn2X", "SimdCvtOp", |
| ("uint16_t", "uint32_t"), fcvtnCode, hi=True) |
| # FCVTNS |
| fcvtnsCode = fcvtCode % ("0", "false", "FPRounding_TIEEVEN") |
| twoEqualRegInstX("fcvtns", "FcvtnsDX", "SimdCvtOp", smallFloatTypes, 2, |
| fcvtnsCode) |
| twoEqualRegInstX("fcvtns", "FcvtnsQX", "SimdCvtOp", floatTypes, 4, |
| fcvtnsCode) |
| twoEqualRegInstX("fcvtns", "FcvtnsScX", "SimdCvtOp", floatTypes, 4, |
| fcvtnsCode, scalar=True) |
| # FCVTNU |
| fcvtnuCode = fcvtCode % ("0", "true", "FPRounding_TIEEVEN") |
| twoEqualRegInstX("fcvtnu", "FcvtnuDX", "SimdCvtOp", smallFloatTypes, 2, |
| fcvtnuCode) |
| twoEqualRegInstX("fcvtnu", "FcvtnuQX", "SimdCvtOp", floatTypes, 4, |
| fcvtnuCode) |
| twoEqualRegInstX("fcvtnu", "FcvtnuScX", "SimdCvtOp", floatTypes, 4, |
| fcvtnuCode, scalar=True) |
| # FCVTPS |
| fcvtpsCode = fcvtCode % ("0", "false", "FPRounding_POSINF") |
| twoEqualRegInstX("fcvtps", "FcvtpsDX", "SimdCvtOp", smallFloatTypes, 2, |
| fcvtpsCode) |
| twoEqualRegInstX("fcvtps", "FcvtpsQX", "SimdCvtOp", floatTypes, 4, |
| fcvtpsCode) |
| twoEqualRegInstX("fcvtps", "FcvtpsScX", "SimdCvtOp", floatTypes, 4, |
| fcvtpsCode, scalar=True) |
| # FCVTPU |
| fcvtpuCode = fcvtCode % ("0", "true", "FPRounding_POSINF") |
| twoEqualRegInstX("fcvtpu", "FcvtpuDX", "SimdCvtOp", smallFloatTypes, 2, |
| fcvtpuCode) |
| twoEqualRegInstX("fcvtpu", "FcvtpuQX", "SimdCvtOp", floatTypes, 4, |
| fcvtpuCode) |
| twoEqualRegInstX("fcvtpu", "FcvtpuScX", "SimdCvtOp", floatTypes, 4, |
| fcvtpuCode, scalar=True) |
| # FCVTXN, FCVTXN2 |
| fcvtxnCode = fpOp % ("fplibConvert<BigElement, Element>(" |
| "srcElem1, FPRounding_ODD, fpscr)") |
| twoRegNarrowInstX("fcvtxn", "FcvtxnX", "SimdCvtOp", smallFloatTypes, |
| fcvtxnCode) |
| twoRegNarrowInstX("fcvtxn", "Fcvtxn2X", "SimdCvtOp", smallFloatTypes, |
| fcvtxnCode, hi=True) |
| twoRegNarrowInstX("fcvtxn", "FcvtxnScX", "SimdCvtOp", smallFloatTypes, |
| fcvtxnCode, scalar=True) |
| # FCVTZS (fixed-point) |
| fcvtzsCode = fcvtCode % ("imm", "false", "FPRounding_ZERO") |
| twoEqualRegInstX("fcvtzs", "FcvtzsFixedDX", "SimdCvtOp", smallFloatTypes, |
| 2, fcvtzsCode, hasImm=True) |
| twoEqualRegInstX("fcvtzs", "FcvtzsFixedQX", "SimdCvtOp", floatTypes, 4, |
| fcvtzsCode, hasImm=True) |
| twoEqualRegInstX("fcvtzs", "FcvtzsFixedScX", "SimdCvtOp", floatTypes, 4, |
| fcvtzsCode, hasImm=True, scalar=True) |
| # FCVTZS (integer) |
| fcvtzsIntCode = fcvtCode % ("0", "false", "FPRounding_ZERO") |
| twoEqualRegInstX("fcvtzs", "FcvtzsIntDX", "SimdCvtOp", smallFloatTypes, |
| 2, fcvtzsIntCode) |
| twoEqualRegInstX("fcvtzs", "FcvtzsIntQX", "SimdCvtOp", floatTypes, 4, |
| fcvtzsIntCode) |
| twoEqualRegInstX("fcvtzs", "FcvtzsIntScX", "SimdCvtOp", floatTypes, 4, |
| fcvtzsIntCode, scalar=True) |
| # FCVTZU (fixed-point) |
| fcvtzuCode = fcvtCode % ("imm", "true", "FPRounding_ZERO") |
| twoEqualRegInstX("fcvtzu", "FcvtzuFixedDX", "SimdCvtOp", smallFloatTypes, |
| 2, fcvtzuCode, hasImm=True) |
| twoEqualRegInstX("fcvtzu", "FcvtzuFixedQX", "SimdCvtOp", floatTypes, 4, |
| fcvtzuCode, hasImm=True) |
| twoEqualRegInstX("fcvtzu", "FcvtzuFixedScX", "SimdCvtOp", floatTypes, 4, |
| fcvtzuCode, hasImm=True, scalar=True) |
| # FCVTZU (integer) |
| fcvtzuIntCode = fcvtCode % ("0", "true", "FPRounding_ZERO") |
| twoEqualRegInstX("fcvtzu", "FcvtzuIntDX", "SimdCvtOp", smallFloatTypes, 2, |
| fcvtzuIntCode) |
| twoEqualRegInstX("fcvtzu", "FcvtzuIntQX", "SimdCvtOp", floatTypes, 4, |
| fcvtzuIntCode) |
| twoEqualRegInstX("fcvtzu", "FcvtzuIntScX", "SimdCvtOp", floatTypes, 4, |
| fcvtzuIntCode, scalar=True) |
| # FDIV |
| fdivCode = fpBinOp % "Div" |
| threeEqualRegInstX("fdiv", "FdivDX", "SimdFloatDivOp", smallFloatTypes, 2, |
| fdivCode) |
| threeEqualRegInstX("fdiv", "FdivQX", "SimdFloatDivOp", floatTypes, 4, |
| fdivCode) |
| # FMAX |
| fmaxCode = fpBinOp % "Max" |
| threeEqualRegInstX("fmax", "FmaxDX", "SimdFloatCmpOp", smallFloatTypes, 2, |
| fmaxCode) |
| threeEqualRegInstX("fmax", "FmaxQX", "SimdFloatCmpOp", floatTypes, 4, |
| fmaxCode) |
| # FMAXNM |
| fmaxnmCode = fpBinOp % "MaxNum" |
| threeEqualRegInstX("fmaxnm", "FmaxnmDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fmaxnmCode) |
| threeEqualRegInstX("fmaxnm", "FmaxnmQX", "SimdFloatCmpOp", floatTypes, 4, |
| fmaxnmCode) |
| # FMAXNMP (scalar) |
| twoRegPairwiseScInstX("fmaxnmp", "FmaxnmpScDX", "SimdFloatCmpOp", |
| ("uint32_t",), 2, fmaxnmCode) |
| twoRegPairwiseScInstX("fmaxnmp", "FmaxnmpScQX", "SimdFloatCmpOp", |
| ("uint64_t",), 4, fmaxnmCode) |
| # FMAXNMP (vector) |
| threeEqualRegInstX("fmaxnmp", "FmaxnmpDX", "SimdFloatCmpOp", |
| smallFloatTypes, 2, fmaxnmCode, pairwise=True) |
| threeEqualRegInstX("fmaxnmp", "FmaxnmpQX", "SimdFloatCmpOp", floatTypes, 4, |
| fmaxnmCode, pairwise=True) |
| # FMAXNMV |
| # Note: SimdFloatCmpOp can be a bit optimistic here |
| fpAcrossOp = fpOp % "fplib%s<Element>(destElem, srcElem1, fpscr)" |
| fmaxnmAcrossCode = fpAcrossOp % "MaxNum" |
| twoRegAcrossInstX("fmaxnmv", "FmaxnmvQX", "SimdFloatCmpOp", ("uint32_t",), |
| 4, fmaxnmAcrossCode) |
| # FMAXP (scalar) |
| twoRegPairwiseScInstX("fmaxp", "FmaxpScDX", "SimdFloatCmpOp", |
| ("uint32_t",), 2, fmaxCode) |
| twoRegPairwiseScInstX("fmaxp", "FmaxpScQX", "SimdFloatCmpOp", |
| ("uint64_t",), 4, fmaxCode) |
| # FMAXP (vector) |
| threeEqualRegInstX("fmaxp", "FmaxpDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fmaxCode, pairwise=True) |
| threeEqualRegInstX("fmaxp", "FmaxpQX", "SimdFloatCmpOp", floatTypes, 4, |
| fmaxCode, pairwise=True) |
| # FMAXV |
| # Note: SimdFloatCmpOp can be a bit optimistic here |
| fmaxAcrossCode = fpAcrossOp % "Max" |
| twoRegAcrossInstX("fmaxv", "FmaxvQX", "SimdFloatCmpOp", ("uint32_t",), 4, |
| fmaxAcrossCode) |
| # FMIN |
| fminCode = fpBinOp % "Min" |
| threeEqualRegInstX("fmin", "FminDX", "SimdFloatCmpOp", smallFloatTypes, 2, |
| fminCode) |
| threeEqualRegInstX("fmin", "FminQX", "SimdFloatCmpOp", floatTypes, 4, |
| fminCode) |
| # FMINNM |
| fminnmCode = fpBinOp % "MinNum" |
| threeEqualRegInstX("fminnm", "FminnmDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fminnmCode) |
| threeEqualRegInstX("fminnm", "FminnmQX", "SimdFloatCmpOp", floatTypes, 4, |
| fminnmCode) |
| # FMINNMP (scalar) |
| twoRegPairwiseScInstX("fminnmp", "FminnmpScDX", "SimdFloatCmpOp", |
| ("uint32_t",), 2, fminnmCode) |
| twoRegPairwiseScInstX("fminnmp", "FminnmpScQX", "SimdFloatCmpOp", |
| ("uint64_t",), 4, fminnmCode) |
| # FMINNMP (vector) |
| threeEqualRegInstX("fminnmp", "FminnmpDX", "SimdFloatCmpOp", |
| smallFloatTypes, 2, fminnmCode, pairwise=True) |
| threeEqualRegInstX("fminnmp", "FminnmpQX", "SimdFloatCmpOp", floatTypes, 4, |
| fminnmCode, pairwise=True) |
| # FMINNMV |
| # Note: SimdFloatCmpOp can be a bit optimistic here |
| fminnmAcrossCode = fpAcrossOp % "MinNum" |
| twoRegAcrossInstX("fminnmv", "FminnmvQX", "SimdFloatCmpOp", ("uint32_t",), |
| 4, fminnmAcrossCode) |
| # FMINP (scalar) |
| twoRegPairwiseScInstX("fminp", "FminpScDX", "SimdFloatCmpOp", |
| ("uint32_t",), 2, fminCode) |
| twoRegPairwiseScInstX("fminp", "FminpScQX", "SimdFloatCmpOp", |
| ("uint64_t",), 4, fminCode) |
| # FMINP (vector) |
| threeEqualRegInstX("fminp", "FminpDX", "SimdFloatCmpOp", smallFloatTypes, |
| 2, fminCode, pairwise=True) |
| threeEqualRegInstX("fminp", "FminpQX", "SimdFloatCmpOp", floatTypes, 4, |
| fminCode, pairwise=True) |
| # FMINV |
| # Note: SimdFloatCmpOp can be a bit optimistic here |
| fminAcrossCode = fpAcrossOp % "Min" |
| twoRegAcrossInstX("fminv", "FminvQX", "SimdFloatCmpOp", ("uint32_t",), 4, |
| fminAcrossCode) |
| # FMLA (by element) |
| fmlaCode = fpOp % ("fplibMulAdd<Element>(" |
| "destElem, srcElem1, srcElem2, fpscr)") |
| threeEqualRegInstX("fmla", "FmlaElemDX", "SimdFloatMultAccOp", |
| smallFloatTypes, 2, fmlaCode, True, byElem=True) |
| threeEqualRegInstX("fmla", "FmlaElemQX", "SimdFloatMultAccOp", floatTypes, |
| 4, fmlaCode, True, byElem=True) |
| threeEqualRegInstX("fmla", "FmlaElemScX", "SimdFloatMultAccOp", floatTypes, |
| 4, fmlaCode, True, byElem=True, scalar=True) |
| # FMLA (vector) |
| threeEqualRegInstX("fmla", "FmlaDX", "SimdFloatMultAccOp", smallFloatTypes, |
| 2, fmlaCode, True) |
| threeEqualRegInstX("fmla", "FmlaQX", "SimdFloatMultAccOp", floatTypes, 4, |
| fmlaCode, True) |
| # FMLS (by element) |
| fmlsCode = fpOp % ("fplibMulAdd<Element>(destElem," |
| " fplibNeg<Element>(srcElem1), srcElem2, fpscr)") |
| threeEqualRegInstX("fmls", "FmlsElemDX", "SimdFloatMultAccOp", |
| smallFloatTypes, 2, fmlsCode, True, byElem=True) |
| threeEqualRegInstX("fmls", "FmlsElemQX", "SimdFloatMultAccOp", floatTypes, |
| 4, fmlsCode, True, byElem=True) |
| threeEqualRegInstX("fmls", "FmlsElemScX", "SimdFloatMultAccOp", floatTypes, |
| 4, fmlsCode, True, byElem=True, scalar=True) |
| # FMLS (vector) |
| threeEqualRegInstX("fmls", "FmlsDX", "SimdFloatMultAccOp", smallFloatTypes, |
| 2, fmlsCode, True) |
| threeEqualRegInstX("fmls", "FmlsQX", "SimdFloatMultAccOp", floatTypes, 4, |
| fmlsCode, True) |
| # FMOV |
| fmovCode = 'destElem = imm;' |
| oneRegImmInstX("fmov", "FmovDX", "SimdMiscOp", smallFloatTypes, 2, |
| fmovCode) |
| oneRegImmInstX("fmov", "FmovQX", "SimdMiscOp", floatTypes, 4, fmovCode) |
| # FMUL (by element) |
| fmulCode = fpBinOp % "Mul" |
| threeEqualRegInstX("fmul", "FmulElemDX", "SimdFloatMultOp", |
| smallFloatTypes, 2, fmulCode, byElem=True) |
| threeEqualRegInstX("fmul", "FmulElemQX", "SimdFloatMultOp", floatTypes, 4, |
| fmulCode, byElem=True) |
| threeEqualRegInstX("fmul", "FmulElemScX", "SimdFloatMultOp", floatTypes, 4, |
| fmulCode, byElem=True, scalar=True) |
| # FMUL (vector) |
| threeEqualRegInstX("fmul", "FmulDX", "SimdFloatMultOp", smallFloatTypes, 2, |
| fmulCode) |
| threeEqualRegInstX("fmul", "FmulQX", "SimdFloatMultOp", floatTypes, 4, |
| fmulCode) |
| # FMULX |
| fmulxCode = fpBinOp % "MulX" |
| threeEqualRegInstX("fmulx", "FmulxDX", "SimdFloatMultOp", smallFloatTypes, |
| 2, fmulxCode) |
| threeEqualRegInstX("fmulx", "FmulxQX", "SimdFloatMultOp", floatTypes, 4, |
| fmulxCode) |
| threeEqualRegInstX("fmulx", "FmulxScX", "SimdFloatMultOp", floatTypes, 4, |
| fmulxCode, scalar=True) |
| # FMULX (by element) |
| threeEqualRegInstX("fmulx", "FmulxElemDX", "SimdFloatMultOp", |
| smallFloatTypes, 2, fmulxCode, byElem=True) |
| threeEqualRegInstX("fmulx", "FmulxElemQX", "SimdFloatMultOp", floatTypes, |
| 4, fmulxCode, byElem=True) |
| threeEqualRegInstX("fmulx", "FmulxElemScX", "SimdFloatMultOp", floatTypes, |
| 4, fmulxCode, byElem=True, scalar=True) |
| # FNEG |
| fnegCode = fpOp % "fplibNeg<Element>(srcElem1)" |
| twoEqualRegInstX("Neg", "FnegDX", "SimdFloatAluOp", smallFloatTypes, 2, |
| fnegCode) |
| twoEqualRegInstX("Neg", "FnegQX", "SimdFloatAluOp", floatTypes, 4, |
| fnegCode) |
| # FRECPE |
| frecpeCode = fpOp % "fplibRecipEstimate<Element>(srcElem1, fpscr)" |
| twoEqualRegInstX("frecpe", "FrecpeDX", "SimdFloatMultAccOp", |
| smallFloatTypes, 2, frecpeCode) |
| twoEqualRegInstX("frecpe", "FrecpeQX", "SimdFloatMultAccOp", floatTypes, 4, |
| frecpeCode) |
| twoEqualRegInstX("frecpe", "FrecpeScX", "SimdFloatMultAccOp", floatTypes, |
| 4, frecpeCode, scalar=True) |
| # FRECPS |
| frecpsCode = fpBinOp % "RecipStepFused" |
| threeEqualRegInstX("frecps", "FrecpsDX", "SimdFloatMultAccOp", |
| smallFloatTypes, 2, frecpsCode) |
| threeEqualRegInstX("frecps", "FrecpsQX", "SimdFloatMultAccOp", floatTypes, |
| 4, frecpsCode) |
| threeEqualRegInstX("frecps", "FrecpsScX", "SimdFloatMultAccOp", floatTypes, |
| 4, frecpsCode, scalar=True) |
| # FRECPX |
| frecpxCode = fpOp % "fplibRecpX<Element>(srcElem1, fpscr)" |
| twoEqualRegInstX("frecpx", "FrecpxX", "SimdFloatMultAccOp", floatTypes, 4, |
| frecpxCode, scalar=True) |
| # FRINTA |
| frintCode = fpOp % "fplibRoundInt<Element>(srcElem1, %s, %s, fpscr)" |
| frintaCode = frintCode % ("FPRounding_TIEAWAY", "false") |
| twoEqualRegInstX("frinta", "FrintaDX", "SimdCvtOp", smallFloatTypes, 2, |
| frintaCode) |
| twoEqualRegInstX("frinta", "FrintaQX", "SimdCvtOp", floatTypes, 4, |
| frintaCode) |
| # FRINTI |
| frintiCode = frintCode % ("FPCRRounding(fpscr)", "false") |
| twoEqualRegInstX("frinti", "FrintiDX", "SimdCvtOp", smallFloatTypes, 2, |
| frintiCode) |
| twoEqualRegInstX("frinti", "FrintiQX", "SimdCvtOp", floatTypes, 4, |
| frintiCode) |
| # FRINTM |
| frintmCode = frintCode % ("FPRounding_NEGINF", "false") |
| twoEqualRegInstX("frintm", "FrintmDX", "SimdCvtOp", smallFloatTypes, 2, |
| frintmCode) |
| twoEqualRegInstX("frintm", "FrintmQX", "SimdCvtOp", floatTypes, 4, |
| frintmCode) |
| # FRINTN |
| frintnCode = frintCode % ("FPRounding_TIEEVEN", "false") |
| twoEqualRegInstX("frintn", "FrintnDX", "SimdCvtOp", smallFloatTypes, 2, |
| frintnCode) |
| twoEqualRegInstX("frintn", "FrintnQX", "SimdCvtOp", floatTypes, 4, |
| frintnCode) |
| # FRINTP |
| frintpCode = frintCode % ("FPRounding_POSINF", "false") |
| twoEqualRegInstX("frintp", "FrintpDX", "SimdCvtOp", smallFloatTypes, 2, |
| frintpCode) |
| twoEqualRegInstX("frintp", "FrintpQX", "SimdCvtOp", floatTypes, 4, |
| frintpCode) |
| # FRINTX |
| frintxCode = frintCode % ("FPCRRounding(fpscr)", "true") |
| twoEqualRegInstX("frintx", "FrintxDX", "SimdCvtOp", smallFloatTypes, 2, |
| frintxCode) |
| twoEqualRegInstX("frintx", "FrintxQX", "SimdCvtOp", floatTypes, 4, |
| frintxCode) |
| # FRINTZ |
| frintzCode = frintCode % ("FPRounding_ZERO", "false") |
| twoEqualRegInstX("frintz", "FrintzDX", "SimdCvtOp", smallFloatTypes, 2, |
| frintzCode) |
| twoEqualRegInstX("frintz", "FrintzQX", "SimdCvtOp", floatTypes, 4, |
| frintzCode) |
| # FRSQRTE |
| frsqrteCode = fpOp % "fplibRSqrtEstimate<Element>(srcElem1, fpscr)" |
| twoEqualRegInstX("frsqrte", "FrsqrteDX", "SimdFloatSqrtOp", |
| smallFloatTypes, 2, frsqrteCode) |
| twoEqualRegInstX("frsqrte", "FrsqrteQX", "SimdFloatSqrtOp", floatTypes, 4, |
| frsqrteCode) |
| twoEqualRegInstX("frsqrte", "FrsqrteScX", "SimdFloatSqrtOp", floatTypes, 4, |
| frsqrteCode, scalar=True) |
| # FRSQRTS |
| frsqrtsCode = fpBinOp % "RSqrtStepFused" |
| threeEqualRegInstX("frsqrts", "FrsqrtsDX", "SimdFloatMiscOp", |
| smallFloatTypes, 2, frsqrtsCode) |
| threeEqualRegInstX("frsqrts", "FrsqrtsQX", "SimdFloatMiscOp", floatTypes, |
| 4, frsqrtsCode) |
| threeEqualRegInstX("frsqrts", "FrsqrtsScX", "SimdFloatMiscOp", floatTypes, |
| 4, frsqrtsCode, scalar=True) |
| # FSQRT |
| fsqrtCode = fpOp % "fplibSqrt<Element>(srcElem1, fpscr)" |
| twoEqualRegInstX("fsqrt", "FsqrtDX", "SimdFloatSqrtOp", smallFloatTypes, 2, |
| fsqrtCode) |
| twoEqualRegInstX("fsqrt", "FsqrtQX", "SimdFloatSqrtOp", floatTypes, 4, |
| fsqrtCode) |
| # FSUB |
| fsubCode = fpBinOp % "Sub" |
| threeEqualRegInstX("fsub", "FsubDX", "SimdFloatAddOp", smallFloatTypes, 2, |
| fsubCode) |
| threeEqualRegInstX("fsub", "FsubQX", "SimdFloatAddOp", floatTypes, 4, |
| fsubCode) |
| # INS (element) |
| insFromVecElemInstX("ins", "InsElemX", "SimdMiscOp", unsignedTypes, 4) |
| # INS (general register) |
| insFromGprInstX("ins", "InsGprWX", "SimdMiscOp", smallUnsignedTypes, 4, |
| 'W') |
| insFromGprInstX("ins", "InsGprXX", "SimdMiscOp", unsignedTypes, 4, 'X') |
| # MLA (by element) |
| mlaCode = "destElem += srcElem1 * srcElem2;" |
| threeEqualRegInstX("mla", "MlaElemDX", "SimdMultAccOp", |
| ("uint16_t", "uint32_t"), 2, mlaCode, True, byElem=True) |
| threeEqualRegInstX("mla", "MlaElemQX", "SimdMultAccOp", |
| ("uint16_t", "uint32_t"), 4, mlaCode, True, byElem=True) |
| # MLA (vector) |
| threeEqualRegInstX("mla", "MlaDX", "SimdMultAccOp", smallUnsignedTypes, 2, |
| mlaCode, True) |
| threeEqualRegInstX("mla", "MlaQX", "SimdMultAccOp", smallUnsignedTypes, 4, |
| mlaCode, True) |
| # MLS (by element) |
| mlsCode = "destElem -= srcElem1 * srcElem2;" |
| threeEqualRegInstX("mls", "MlsElemDX", "SimdMultAccOp", |
| ("uint16_t", "uint32_t"), 2, mlsCode, True, byElem=True) |
| threeEqualRegInstX("mls", "MlsElemQX", "SimdMultAccOp", |
| ("uint16_t", "uint32_t"), 4, mlsCode, True, byElem=True) |
| # MLS (vector) |
| threeEqualRegInstX("mls", "MlsDX", "SimdMultAccOp", smallUnsignedTypes, 2, |
| mlsCode, True) |
| threeEqualRegInstX("mls", "MlsQX", "SimdMultAccOp", smallUnsignedTypes, 4, |
| mlsCode, True) |
| # MOV (element) -> alias to INS (element) |
| # MOV (from general) -> alias to INS (general register) |
| # MOV (scalar) -> alias to DUP (element) |
| # MOV (to general) -> alias to UMOV |
| # MOV (vector) -> alias to ORR (register) |
| # MOVI |
| movImmCode = "destElem = imm;" |
| oneRegImmInstX("movi", "MoviDX", "SimdMiscOp", ("uint64_t",), 2, |
| movImmCode) |
| oneRegImmInstX("movi", "MoviQX", "SimdMiscOp", ("uint64_t",), 4, |
| movImmCode) |
| # MUL (by element) |
| mulCode = "destElem = srcElem1 * srcElem2;" |
| threeEqualRegInstX("mul", "MulElemDX", "SimdMultOp", |
| ("uint16_t", "uint32_t"), 2, mulCode, byElem=True) |
| threeEqualRegInstX("mul", "MulElemQX", "SimdMultOp", |
| ("uint16_t", "uint32_t"), 4, mulCode, byElem=True) |
| # MUL (vector) |
| threeEqualRegInstX("mul", "MulDX", "SimdMultOp", smallUnsignedTypes, 2, |
| mulCode) |
| threeEqualRegInstX("mul", "MulQX", "SimdMultOp", smallUnsignedTypes, 4, |
| mulCode) |
| # MVN |
| mvnCode = "destElem = ~srcElem1;" |
| twoEqualRegInstX("mvn", "MvnDX", "SimdAluOp", ("uint64_t",), 2, mvnCode) |
| twoEqualRegInstX("mvn", "MvnQX", "SimdAluOp", ("uint64_t",), 4, mvnCode) |
| # MVNI |
| mvniCode = "destElem = ~imm;" |
| oneRegImmInstX("mvni", "MvniDX", "SimdAluOp", ("uint64_t",), 2, mvniCode) |
| oneRegImmInstX("mvni", "MvniQX", "SimdAluOp", ("uint64_t",), 4, mvniCode) |
| # NEG |
| negCode = "destElem = -srcElem1;" |
| twoEqualRegInstX("neg", "NegDX", "SimdAluOp", signedTypes, 2, negCode) |
| twoEqualRegInstX("neg", "NegQX", "SimdAluOp", signedTypes, 4, negCode) |
| # NOT -> alias to MVN |
| # ORN |
| ornCode = "destElem = srcElem1 | ~srcElem2;" |
| threeEqualRegInstX("orn", "OrnDX", "SimdAluOp", ("uint64_t",), 2, ornCode) |
| threeEqualRegInstX("orn", "OrnQX", "SimdAluOp", ("uint64_t",), 4, ornCode) |
| # ORR (immediate) |
| orrImmCode = "destElem |= imm;" |
| oneRegImmInstX("orr", "OrrImmDX", "SimdAluOp", ("uint64_t",), 2, |
| orrImmCode, True) |
| oneRegImmInstX("orr", "OrrImmQX", "SimdAluOp", ("uint64_t",), 4, |
| orrImmCode, True) |
| # ORR (register) |
| orrCode = "destElem = srcElem1 | srcElem2;" |
| threeEqualRegInstX("orr", "OrrDX", "SimdAluOp", ("uint64_t",), 2, orrCode) |
| threeEqualRegInstX("orr", "OrrQX", "SimdAluOp", ("uint64_t",), 4, orrCode) |
| # PMUL |
| pmulCode = ''' |
| destElem = 0; |
| for (unsigned j = 0; j < sizeof(Element) * 8; j++) { |
| if (bits(srcElem2, j)) |
| destElem ^= srcElem1 << j; |
| } |
| ''' |
| threeEqualRegInstX("pmul", "PmulDX", "SimdMultOp", ("uint8_t",), 2, |
| pmulCode) |
| threeEqualRegInstX("pmul", "PmulQX", "SimdMultOp", ("uint8_t",), 4, |
| pmulCode) |
| # PMULL, PMULL2 |
| # Note: 64-bit PMULL is not available (Crypto. Extension) |
| pmullCode = ''' |
| destElem = 0; |
| for (unsigned j = 0; j < sizeof(Element) * 8; j++) { |
| if (bits(srcElem2, j)) |
| destElem ^= (BigElement)srcElem1 << j; |
| } |
| ''' |
| threeRegLongInstX("pmull", "PmullX", "SimdMultOp", ("uint8_t",), pmullCode) |
| threeRegLongInstX("pmull", "Pmull2X", "SimdMultOp", ("uint8_t",), |
| pmullCode, hi=True) |
| # RADDHN, RADDHN2 |
| raddhnCode = ''' |
| destElem = ((BigElement)srcElem1 + (BigElement)srcElem2 + |
| ((BigElement)1 << (sizeof(Element) * 8 - 1))) >> |
| (sizeof(Element) * 8); |
| ''' |
| threeRegNarrowInstX("raddhn", "RaddhnX", "SimdAddOp", smallUnsignedTypes, |
| raddhnCode) |
| threeRegNarrowInstX("raddhn2", "Raddhn2X", "SimdAddOp", smallUnsignedTypes, |
| raddhnCode, hi=True) |
| # RBIT |
| rbitCode = ''' |
| destElem = 0; |
| Element temp = srcElem1; |
| for (int i = 0; i < 8 * sizeof(Element); i++) { |
| destElem = destElem | ((temp & 0x1) << |
| (8 * sizeof(Element) - 1 - i)); |
| temp >>= 1; |
| } |
| ''' |
| twoEqualRegInstX("rbit", "RbitDX", "SimdAluOp", ("uint8_t",), 2, rbitCode) |
| twoEqualRegInstX("rbit", "RbitQX", "SimdAluOp", ("uint8_t",), 4, rbitCode) |
| # REV16 |
| rev16Code = ''' |
| destElem = srcElem1; |
| unsigned groupSize = ((1 << 1) / sizeof(Element)); |
| unsigned reverseMask = (groupSize - 1); |
| j = i ^ reverseMask; |
| ''' |
| twoEqualRegInstX("rev16", "Rev16DX", "SimdAluOp", ("uint8_t",), 2, |
| rev16Code) |
| twoEqualRegInstX("rev16", "Rev16QX", "SimdAluOp", ("uint8_t",), 4, |
| rev16Code) |
| # REV32 |
| rev32Code = ''' |
| destElem = srcElem1; |
| unsigned groupSize = ((1 << 2) / sizeof(Element)); |
| unsigned reverseMask = (groupSize - 1); |
| j = i ^ reverseMask; |
| ''' |
| twoEqualRegInstX("rev32", "Rev32DX", "SimdAluOp", ("uint8_t", "uint16_t"), |
| 2, rev32Code) |
| twoEqualRegInstX("rev32", "Rev32QX", "SimdAluOp", ("uint8_t", "uint16_t"), |
| 4, rev32Code) |
| # REV64 |
| rev64Code = ''' |
| destElem = srcElem1; |
| unsigned groupSize = ((1 << 3) / sizeof(Element)); |
| unsigned reverseMask = (groupSize - 1); |
| j = i ^ reverseMask; |
| ''' |
| twoEqualRegInstX("rev64", "Rev64DX", "SimdAluOp", smallUnsignedTypes, 2, |
| rev64Code) |
| twoEqualRegInstX("rev64", "Rev64QX", "SimdAluOp", smallUnsignedTypes, 4, |
| rev64Code) |
| # RSHRN, RSHRN2 |
| rshrnCode = ''' |
| if (imm > sizeof(srcElem1) * 8) { |
| destElem = 0; |
| } else if (imm) { |
| Element rBit = bits(srcElem1, imm - 1); |
| destElem = ((srcElem1 >> (imm - 1)) >> 1) + rBit; |
| } else { |
| destElem = srcElem1; |
| } |
| ''' |
| twoRegNarrowInstX("rshrn", "RshrnX", "SimdShiftOp", smallUnsignedTypes, |
| rshrnCode, hasImm=True) |
| twoRegNarrowInstX("rshrn2", "Rshrn2X", "SimdShiftOp", smallUnsignedTypes, |
| rshrnCode, hasImm=True, hi=True) |
| # RSUBHN, RSUBHN2 |
| rsubhnCode = ''' |
| destElem = ((BigElement)srcElem1 - (BigElement)srcElem2 + |
| ((BigElement)1 << (sizeof(Element) * 8 - 1))) >> |
| (sizeof(Element) * 8); |
| ''' |
| threeRegNarrowInstX("rsubhn", "RsubhnX", "SimdAddOp", smallTypes, |
| rsubhnCode) |
| threeRegNarrowInstX("rsubhn2", "Rsubhn2X", "SimdAddOp", smallTypes, |
| rsubhnCode, hi=True) |
| # SABA |
| abaCode = ''' |
| destElem += (srcElem1 > srcElem2) ? (srcElem1 - srcElem2) : |
| (srcElem2 - srcElem1); |
| ''' |
| threeEqualRegInstX("saba", "SabaDX", "SimdAddAccOp", smallSignedTypes, 2, |
| abaCode, True) |
| threeEqualRegInstX("saba", "SabaQX", "SimdAddAccOp", smallSignedTypes, 4, |
| abaCode, True) |
| # SABAL, SABAL2 |
| abalCode = ''' |
| destElem += (srcElem1 > srcElem2) ? |
| ((BigElement)srcElem1 - (BigElement)srcElem2) : |
| ((BigElement)srcElem2 - (BigElement)srcElem1); |
| ''' |
| threeRegLongInstX("sabal", "SabalX", "SimdAddAccOp", smallSignedTypes, |
| abalCode, True) |
| threeRegLongInstX("sabal2", "Sabal2X", "SimdAddAccOp", smallSignedTypes, |
| abalCode, True, hi=True) |
| # SABD |
| abdCode = ''' |
| destElem = (srcElem1 > srcElem2) ? (srcElem1 - srcElem2) : |
| (srcElem2 - srcElem1); |
| ''' |
| threeEqualRegInstX("sabd", "SabdDX", "SimdAddOp", smallSignedTypes, 2, |
| abdCode) |
| threeEqualRegInstX("sabd", "SabdQX", "SimdAddOp", smallSignedTypes, 4, |
| abdCode) |
| # SABDL, SABDL2 |
| abdlCode = ''' |
| destElem = (srcElem1 > srcElem2) ? |
| ((BigElement)srcElem1 - (BigElement)srcElem2) : |
| ((BigElement)srcElem2 - (BigElement)srcElem1); |
| ''' |
| threeRegLongInstX("sabdl", "SabdlX", "SimdAddAccOp", smallSignedTypes, |
| abdlCode, True) |
| threeRegLongInstX("sabdl2", "Sabdl2X", "SimdAddAccOp", smallSignedTypes, |
| abdlCode, True, hi=True) |
| # SADALP |
| adalpCode = "destElem += (BigElement)srcElem1 + (BigElement)srcElem2;" |
| twoRegCondenseInstX("sadalp", "SadalpDX", "SimdAddOp", smallSignedTypes, 2, |
| adalpCode, True) |
| twoRegCondenseInstX("sadalp", "SadalpQX", "SimdAddOp", smallSignedTypes, 4, |
| adalpCode, True) |
| # SADDL, SADDL2 |
| addlwCode = "destElem = (BigElement)srcElem1 + (BigElement)srcElem2;" |
| threeRegLongInstX("saddl", "SaddlX", "SimdAddAccOp", smallSignedTypes, |
| addlwCode) |
| threeRegLongInstX("saddl2", "Saddl2X", "SimdAddAccOp", smallSignedTypes, |
| addlwCode, hi=True) |
| # SADDLP |
| twoRegCondenseInstX("saddlp", "SaddlpDX", "SimdAddOp", smallSignedTypes, 2, |
| addlwCode) |
| twoRegCondenseInstX("saddlp", "SaddlpQX", "SimdAddOp", smallSignedTypes, 4, |
| addlwCode) |
| # SADDLV |
| # Note: SimdAddOp can be a bit optimistic here |
| addAcrossLongCode = "destElem += (BigElement)srcElem1;" |
| twoRegAcrossInstX("saddlv", "SaddlvDX", "SimdAddOp", ("int8_t", "int16_t"), |
| 2, addAcrossLongCode, long=True) |
| twoRegAcrossInstX("saddlv", "SaddlvQX", "SimdAddOp", ("int8_t", "int16_t"), |
| 4, addAcrossLongCode, long=True) |
| twoRegAcrossInstX("saddlv", "SaddlvBQX", "SimdAddOp", ("int32_t",), 4, |
| addAcrossLongCode, doubleDest=True, long=True) |
| # SADDW, SADDW2 |
| threeRegWideInstX("saddw", "SaddwX", "SimdAddAccOp", smallSignedTypes, |
| addlwCode) |
| threeRegWideInstX("saddw2", "Saddw2X", "SimdAddAccOp", smallSignedTypes, |
| addlwCode, hi=True) |
| # SCVTF (fixed-point) |
| scvtfFixedCode = fpOp % ("fplibFixedToFP<Element>((int%d_t) srcElem1, imm," |
| " false, FPCRRounding(fpscr), fpscr)") |
| twoEqualRegInstX("scvtf", "ScvtfFixedDX", "SimdCvtOp", smallFloatTypes, 2, |
| scvtfFixedCode % 32, hasImm=True) |
| twoEqualRegInstX("scvtf", "ScvtfFixedSQX", "SimdCvtOp", smallFloatTypes, 4, |
| scvtfFixedCode % 32, hasImm=True) |
| twoEqualRegInstX("scvtf", "ScvtfFixedDQX", "SimdCvtOp", ("uint64_t",), 4, |
| scvtfFixedCode % 64, hasImm=True) |
| twoEqualRegInstX("scvtf", "ScvtfFixedScSX", "SimdCvtOp", smallFloatTypes, |
| 4, scvtfFixedCode % 32, hasImm=True, scalar=True) |
| twoEqualRegInstX("scvtf", "ScvtfFixedScDX", "SimdCvtOp", ("uint64_t",), 4, |
| scvtfFixedCode % 64, hasImm=True, scalar=True) |
| # SCVTF (integer) |
| scvtfIntCode = fpOp % ("fplibFixedToFP<Element>((int%d_t) srcElem1, 0," |
| " false, FPCRRounding(fpscr), fpscr)") |
| twoEqualRegInstX("scvtf", "ScvtfIntDX", "SimdCvtOp", smallFloatTypes, 2, |
| scvtfIntCode % 32) |
| twoEqualRegInstX("scvtf", "ScvtfIntSQX", "SimdCvtOp", smallFloatTypes, 4, |
| scvtfIntCode % 32) |
| twoEqualRegInstX("scvtf", "ScvtfIntDQX", "SimdCvtOp", ("uint64_t",), 4, |
| scvtfIntCode % 64) |
| twoEqualRegInstX("scvtf", "ScvtfIntScSX", "SimdCvtOp", smallFloatTypes, 4, |
| scvtfIntCode % 32, scalar=True) |
| twoEqualRegInstX("scvtf", "ScvtfIntScDX", "SimdCvtOp", ("uint64_t",), 4, |
| scvtfIntCode % 64, scalar=True) |
| # SHADD |
| haddCode = ''' |
| Element carryBit = |
| (((unsigned)srcElem1 & 0x1) + |
| ((unsigned)srcElem2 & 0x1)) >> 1; |
| // Use division instead of a shift to ensure the sign extension works |
| // right. The compiler will figure out if it can be a shift. Mask the |
| // inputs so they get truncated correctly. |
| destElem = (((srcElem1 & ~(Element)1) / 2) + |
| ((srcElem2 & ~(Element)1) / 2)) + carryBit; |
| ''' |
| threeEqualRegInstX("shadd", "ShaddDX", "SimdAddOp", smallSignedTypes, 2, |
| haddCode) |
| threeEqualRegInstX("shadd", "ShaddQX", "SimdAddOp", smallSignedTypes, 4, |
| haddCode) |
| # SHL |
| shlCode = ''' |
| if (imm >= sizeof(Element) * 8) |
| destElem = (srcElem1 << (sizeof(Element) * 8 - 1)) << 1; |
| else |
| destElem = srcElem1 << imm; |
| ''' |
| twoEqualRegInstX("shl", "ShlDX", "SimdShiftOp", unsignedTypes, 2, shlCode, |
| hasImm=True) |
| twoEqualRegInstX("shl", "ShlQX", "SimdShiftOp", unsignedTypes, 4, shlCode, |
| hasImm=True) |
| # SHLL, SHLL2 |
| shllCode = "destElem = ((BigElement)srcElem1) << (sizeof(Element) * 8);" |
| twoRegLongInstX("shll", "ShllX", "SimdShiftOp", smallTypes, shllCode) |
| twoRegLongInstX("shll", "Shll2X", "SimdShiftOp", smallTypes, shllCode, |
| hi=True) |
| # SHRN, SHRN2 |
| shrnCode = ''' |
| if (imm >= sizeof(srcElem1) * 8) { |
| destElem = 0; |
| } else { |
| destElem = srcElem1 >> imm; |
| } |
| ''' |
| twoRegNarrowInstX("shrn", "ShrnX", "SimdShiftOp", smallUnsignedTypes, |
| shrnCode, hasImm=True) |
| twoRegNarrowInstX("shrn2", "Shrn2X", "SimdShiftOp", smallUnsignedTypes, |
| shrnCode, hasImm=True, hi=True) |
| # SHSUB |
| hsubCode = ''' |
| Element borrowBit = |
| (((srcElem1 & 0x1) - (srcElem2 & 0x1)) >> 1) & 0x1; |
| // Use division instead of a shift to ensure the sign extension works |
| // right. The compiler will figure out if it can be a shift. Mask the |
| // inputs so they get truncated correctly. |
| destElem = (((srcElem1 & ~(Element)1) / 2) - |
| ((srcElem2 & ~(Element)1) / 2)) - borrowBit; |
| ''' |
| threeEqualRegInstX("shsub", "ShsubDX", "SimdAddOp", smallSignedTypes, 2, |
| hsubCode) |
| threeEqualRegInstX("shsub", "ShsubQX", "SimdAddOp", smallSignedTypes, 4, |
| hsubCode) |
| # SLI |
| sliCode = ''' |
| if (imm >= sizeof(Element) * 8) |
| destElem = destElem; |
| else |
| destElem = (srcElem1 << imm) | (destElem & mask(imm)); |
| ''' |
| twoEqualRegInstX("sli", "SliDX", "SimdShiftOp", unsignedTypes, 2, sliCode, |
| True, hasImm=True) |
| twoEqualRegInstX("sli", "SliQX", "SimdShiftOp", unsignedTypes, 4, sliCode, |
| True, hasImm=True) |
| # SMAX |
| maxCode = "destElem = (srcElem1 > srcElem2) ? srcElem1 : srcElem2;" |
| threeEqualRegInstX("smax", "SmaxDX", "SimdCmpOp", smallSignedTypes, 2, |
| maxCode) |
| threeEqualRegInstX("smax", "SmaxQX", "SimdCmpOp", smallSignedTypes, 4, |
| maxCode) |
| # SMAXP |
| threeEqualRegInstX("smaxp", "SmaxpDX", "SimdCmpOp", smallSignedTypes, 2, |
| maxCode, pairwise=True) |
| threeEqualRegInstX("smaxp", "SmaxpQX", "SimdCmpOp", smallSignedTypes, 4, |
| maxCode, pairwise=True) |
| # SMAXV |
| maxAcrossCode = ''' |
| if (i == 0 || srcElem1 > destElem) |
| destElem = srcElem1; |
| ''' |
| twoRegAcrossInstX("smaxv", "SmaxvDX", "SimdCmpOp", ("int8_t", "int16_t"), |
| 2, maxAcrossCode) |
| twoRegAcrossInstX("smaxv", "SmaxvQX", "SimdCmpOp", smallSignedTypes, 4, |
| maxAcrossCode) |
| # SMIN |
| minCode = "destElem = (srcElem1 < srcElem2) ? srcElem1 : srcElem2;" |
| threeEqualRegInstX("smin", "SminDX", "SimdCmpOp", smallSignedTypes, 2, |
| minCode) |
| threeEqualRegInstX("smin", "SminQX", "SimdCmpOp", smallSignedTypes, 4, |
| minCode) |
| # SMINP |
| threeEqualRegInstX("sminp", "SminpDX", "SimdCmpOp", smallSignedTypes, 2, |
| minCode, pairwise=True) |
| threeEqualRegInstX("sminp", "SminpQX", "SimdCmpOp", smallSignedTypes, 4, |
| minCode, pairwise=True) |
| # SMINV |
| minAcrossCode = ''' |
| if (i == 0 || srcElem1 < destElem) |
| destElem = srcElem1; |
| ''' |
| twoRegAcrossInstX("sminv", "SminvDX", "SimdCmpOp", ("int8_t", "int16_t"), |
| 2, minAcrossCode) |
| twoRegAcrossInstX("sminv", "SminvQX", "SimdCmpOp", smallSignedTypes, 4, |
| minAcrossCode) |
| |
| split('exec') |
| |
| # SMLAL, SMLAL2 (by element) |
| mlalCode = "destElem += (BigElement)srcElem1 * (BigElement)srcElem2;" |
| threeRegLongInstX("smlal", "SmlalElemX", "SimdMultAccOp", |
| ("int16_t", "int32_t"), mlalCode, True, byElem=True) |
| threeRegLongInstX("smlal", "SmlalElem2X", "SimdMultAccOp", |
| ("int16_t", "int32_t"), mlalCode, True, byElem=True, |
| hi=True) |
| # SMLAL, SMLAL2 (vector) |
| threeRegLongInstX("smlal", "SmlalX", "SimdMultAccOp", smallSignedTypes, |
| mlalCode, True) |
| threeRegLongInstX("smlal", "Smlal2X", "SimdMultAccOp", smallSignedTypes, |
| mlalCode, True, hi=True) |
| # SMLSL, SMLSL2 (by element) |
| mlslCode = "destElem -= (BigElement)srcElem1 * (BigElement)srcElem2;" |
| threeRegLongInstX("smlsl", "SmlslElemX", "SimdMultAccOp", smallSignedTypes, |
| mlslCode, True, byElem=True) |
| threeRegLongInstX("smlsl", "SmlslElem2X", "SimdMultAccOp", |
| smallSignedTypes, mlslCode, True, byElem=True, hi=True) |
| # SMLSL, SMLSL2 (vector) |
| threeRegLongInstX("smlsl", "SmlslX", "SimdMultAccOp", smallSignedTypes, |
| mlslCode, True) |
| threeRegLongInstX("smlsl", "Smlsl2X", "SimdMultAccOp", smallSignedTypes, |
| mlslCode, True, hi=True) |
| # SMOV |
| insToGprInstX("smov", "SmovWX", "SimdMiscOp", ("int8_t", "int16_t"), 4, |
| 'W', True) |
| insToGprInstX("smov", "SmovXX", "SimdMiscOp", smallSignedTypes, 4, 'X', |
| True) |
| # SMULL, SMULL2 (by element) |
| mullCode = "destElem = (BigElement)srcElem1 * (BigElement)srcElem2;" |
| threeRegLongInstX("smull", "SmullElemX", "SimdMultOp", smallSignedTypes, |
| mullCode, byElem=True) |
| threeRegLongInstX("smull", "SmullElem2X", "SimdMultOp", smallSignedTypes, |
| mullCode, byElem=True, hi=True) |
| # SMULL, SMULL2 (vector) |
| threeRegLongInstX("smull", "SmullX", "SimdMultOp", smallSignedTypes, |
| mullCode) |
| threeRegLongInstX("smull", "Smull2X", "SimdMultOp", smallSignedTypes, |
| mullCode, hi=True) |
| # SQABS |
| sqabsCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (srcElem1 == (Element)(std::numeric_limits<Element>::min())) { |
| fpscr.qc = 1; |
| destElem = ~srcElem1; |
| } else if (srcElem1 < 0) { |
| destElem = -srcElem1; |
| } else { |
| destElem = srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoEqualRegInstX("sqabs", "SqabsDX", "SimdAluOp", smallSignedTypes, 2, |
| sqabsCode) |
| twoEqualRegInstX("sqabs", "SqabsQX", "SimdAluOp", signedTypes, 4, |
| sqabsCode) |
| twoEqualRegInstX("sqabs", "SqabsScX", "SimdAluOp", signedTypes, 4, |
| sqabsCode, scalar=True) |
| # SQADD |
| sqaddCode = ''' |
| destElem = srcElem1 + srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| bool negDest = (destElem < 0); |
| bool negSrc1 = (srcElem1 < 0); |
| bool negSrc2 = (srcElem2 < 0); |
| if ((negDest != negSrc1) && (negSrc1 == negSrc2)) { |
| destElem = std::numeric_limits<Element>::min(); |
| if (negDest) |
| destElem -= 1; |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInstX("sqadd", "SqaddDX", "SimdAddOp", smallSignedTypes, 2, |
| sqaddCode) |
| threeEqualRegInstX("sqadd", "SqaddQX", "SimdAddOp", signedTypes, 4, |
| sqaddCode) |
| threeEqualRegInstX("sqadd", "SqaddScX", "SimdAddOp", signedTypes, 4, |
| sqaddCode, scalar=True) |
| # SQDMLAL, SQDMLAL2 (by element) |
| qdmlalCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| BigElement midElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2); |
| Element maxNeg = std::numeric_limits<Element>::min(); |
| Element halfNeg = maxNeg / 2; |
| if ((srcElem1 == maxNeg && srcElem2 == maxNeg) || |
| (srcElem1 == halfNeg && srcElem2 == maxNeg) || |
| (srcElem1 == maxNeg && srcElem2 == halfNeg)) { |
| midElem = ~((BigElement)maxNeg << (sizeof(Element) * 8)); |
| fpscr.qc = 1; |
| } |
| bool negPreDest = ltz(destElem); |
| destElem += midElem; |
| bool negDest = ltz(destElem); |
| bool negMid = ltz(midElem); |
| if (negPreDest == negMid && negMid != negDest) { |
| destElem = mask(sizeof(BigElement) * 8 - 1); |
| if (negPreDest) |
| destElem = ~destElem; |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeRegLongInstX("sqdmlal", "SqdmlalElemX", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlalCode, True, byElem=True) |
| threeRegLongInstX("sqdmlal", "SqdmlalElem2X", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlalCode, True, byElem=True, |
| hi=True) |
| threeRegLongInstX("sqdmlal", "SqdmlalElemScX", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlalCode, True, byElem=True, |
| scalar=True) |
| # SQDMLAL, SQDMLAL2 (vector) |
| threeRegLongInstX("sqdmlal", "SqdmlalX", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlalCode, True) |
| threeRegLongInstX("sqdmlal", "Sqdmlal2X", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlalCode, True, hi=True) |
| threeRegLongInstX("sqdmlal", "SqdmlalScX", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlalCode, True, scalar=True) |
| # SQDMLSL, SQDMLSL2 (by element) |
| qdmlslCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| BigElement midElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2); |
| Element maxNeg = std::numeric_limits<Element>::min(); |
| Element halfNeg = maxNeg / 2; |
| if ((srcElem1 == maxNeg && srcElem2 == maxNeg) || |
| (srcElem1 == halfNeg && srcElem2 == maxNeg) || |
| (srcElem1 == maxNeg && srcElem2 == halfNeg)) { |
| midElem = ~((BigElement)maxNeg << (sizeof(Element) * 8)); |
| fpscr.qc = 1; |
| } |
| bool negPreDest = ltz(destElem); |
| destElem -= midElem; |
| bool negDest = ltz(destElem); |
| bool posMid = ltz((BigElement)-midElem); |
| if (negPreDest == posMid && posMid != negDest) { |
| destElem = mask(sizeof(BigElement) * 8 - 1); |
| if (negPreDest) |
| destElem = ~destElem; |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeRegLongInstX("sqdmlsl", "SqdmlslElemX", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlslCode, True, byElem=True) |
| threeRegLongInstX("sqdmlsl", "SqdmlslElem2X", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlslCode, True, byElem=True, |
| hi=True) |
| threeRegLongInstX("sqdmlsl", "SqdmlslElemScX", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlslCode, True, byElem=True, |
| scalar=True) |
| # SQDMLSL, SQDMLSL2 (vector) |
| threeRegLongInstX("sqdmlsl", "SqdmlslX", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlslCode, True) |
| threeRegLongInstX("sqdmlsl", "Sqdmlsl2X", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlslCode, True, hi=True) |
| threeRegLongInstX("sqdmlsl", "SqdmlslScX", "SimdMultAccOp", |
| ("int16_t", "int32_t"), qdmlslCode, True, scalar=True) |
| # SQDMULH (by element) |
| sqdmulhCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| destElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2) >> |
| (sizeof(Element) * 8); |
| if (srcElem1 == srcElem2 && |
| srcElem1 == (Element)((Element)1 << |
| (sizeof(Element) * 8 - 1))) { |
| destElem = ~srcElem1; |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInstX("sqdmulh", "SqdmulhElemDX", "SimdMultOp", |
| ("int16_t", "int32_t"), 2, sqdmulhCode, byElem=True) |
| threeEqualRegInstX("sqdmulh", "SqdmulhElemQX", "SimdMultOp", |
| ("int16_t", "int32_t"), 4, sqdmulhCode, byElem=True) |
| threeEqualRegInstX("sqdmulh", "SqdmulhElemScX", "SimdMultOp", |
| ("int16_t", "int32_t"), 4, sqdmulhCode, byElem=True, |
| scalar=True) |
| # SQDMULH (vector) |
| threeEqualRegInstX("sqdmulh", "SqdmulhDX", "SimdMultOp", |
| ("int16_t", "int32_t"), 2, sqdmulhCode) |
| threeEqualRegInstX("sqdmulh", "SqdmulhQX", "SimdMultOp", |
| ("int16_t", "int32_t"), 4, sqdmulhCode) |
| threeEqualRegInstX("sqdmulh", "SqdmulhScX", "SimdMultOp", |
| ("int16_t", "int32_t"), 4, sqdmulhCode, scalar=True) |
| # SQDMULL, SQDMULL2 (by element) |
| qdmullCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| destElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2); |
| if (srcElem1 == srcElem2 && |
| srcElem1 == (Element)((Element)1 << |
| (Element)(sizeof(Element) * 8 - 1))) { |
| destElem = ~((BigElement)srcElem1 << (sizeof(Element) * 8)); |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeRegLongInstX("sqdmull", "SqdmullElemX", "SimdMultOp", |
| ("int16_t", "int32_t"), qdmullCode, True, byElem=True) |
| threeRegLongInstX("sqdmull", "SqdmullElem2X", "SimdMultOp", |
| ("int16_t", "int32_t"), qdmullCode, True, byElem=True, |
| hi=True) |
| threeRegLongInstX("sqdmull", "SqdmullElemScX", "SimdMultOp", |
| ("int16_t", "int32_t"), qdmullCode, True, byElem=True, |
| scalar=True) |
| # SQDMULL, SQDMULL2 (vector) |
| threeRegLongInstX("sqdmull", "SqdmullX", "SimdMultOp", |
| ("int16_t", "int32_t"), qdmullCode, True) |
| threeRegLongInstX("sqdmull", "Sqdmull2X", "SimdMultOp", |
| ("int16_t", "int32_t"), qdmullCode, True, hi=True) |
| threeRegLongInstX("sqdmull", "SqdmullScX", "SimdMultOp", |
| ("int16_t", "int32_t"), qdmullCode, True, scalar=True) |
| # SQNEG |
| sqnegCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (srcElem1 == (Element)(std::numeric_limits<Element>::min())) { |
| fpscr.qc = 1; |
| destElem = ~srcElem1; |
| } else { |
| destElem = -srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoEqualRegInstX("sqneg", "SqnegDX", "SimdAluOp", smallSignedTypes, 2, |
| sqnegCode) |
| twoEqualRegInstX("sqneg", "SqnegQX", "SimdAluOp", signedTypes, 4, |
| sqnegCode) |
| twoEqualRegInstX("sqneg", "SqnegScX", "SimdAluOp", signedTypes, 4, |
| sqnegCode, scalar=True) |
| # SQRDMULH (by element) |
| sqrdmulhCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| destElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2 + |
| ((int64_t)1 << (sizeof(Element) * 8 - 1))) >> |
| (sizeof(Element) * 8); |
| Element maxNeg = std::numeric_limits<Element>::min(); |
| Element halfNeg = maxNeg / 2; |
| if ((srcElem1 == maxNeg && srcElem2 == maxNeg) || |
| (srcElem1 == halfNeg && srcElem2 == maxNeg) || |
| (srcElem1 == maxNeg && srcElem2 == halfNeg)) { |
| if (destElem < 0) { |
| destElem = mask(sizeof(Element) * 8 - 1); |
| } else { |
| destElem = std::numeric_limits<Element>::min(); |
| } |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInstX("sqrdmulh", "SqrdmulhElemDX", "SimdMultOp", |
| ("int16_t", "int32_t"), 2, sqrdmulhCode, byElem=True) |
| threeEqualRegInstX("sqrdmulh", "SqrdmulhElemQX", "SimdMultOp", |
| ("int16_t", "int32_t"), 4, sqrdmulhCode, byElem=True) |
| threeEqualRegInstX("sqrdmulh", "SqrdmulhElemScX", "SimdMultOp", |
| ("int16_t", "int32_t"), 4, sqrdmulhCode, byElem=True, |
| scalar=True) |
| # SQRDMULH (vector) |
| threeEqualRegInstX("sqrdmulh", "SqrdmulhDX", "SimdMultOp", |
| ("int16_t", "int32_t"), 2, sqrdmulhCode) |
| threeEqualRegInstX("sqrdmulh", "SqrdmulhQX", "SimdMultOp", |
| ("int16_t", "int32_t"), 4, sqrdmulhCode) |
| threeEqualRegInstX("sqrdmulh", "SqrdmulhScX", "SimdMultOp", |
| ("int16_t", "int32_t"), 4, sqrdmulhCode, scalar=True) |
| # SQRSHL |
| sqrshlCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| Element rBit = 0; |
| if (shiftAmt <= sizeof(Element) * 8) |
| rBit = bits(srcElem1, shiftAmt - 1); |
| if (shiftAmt > sizeof(Element) * 8 && srcElem1 < 0) |
| rBit = 1; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| // Make sure the right shift sign extended when it should. |
| if (srcElem1 < 0 && destElem >= 0) { |
| destElem |= -((Element)1 << (sizeof(Element) * 8 - |
| 1 - shiftAmt)); |
| } |
| destElem += rBit; |
| } else if (shiftAmt > 0) { |
| bool sat = false; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| if (srcElem1 != 0) |
| sat = true; |
| else |
| destElem = 0; |
| } else { |
| if (bits((uint64_t) srcElem1, sizeof(Element) * 8 - 1, |
| sizeof(Element) * 8 - 1 - shiftAmt) != |
| ((srcElem1 < 0) ? mask(shiftAmt + 1) : 0)) { |
| sat = true; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } |
| if (sat) { |
| fpscr.qc = 1; |
| destElem = mask(sizeof(Element) * 8 - 1); |
| if (srcElem1 < 0) |
| destElem = ~destElem; |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInstX("sqrshl", "SqrshlDX", "SimdCmpOp", smallSignedTypes, 2, |
| sqrshlCode) |
| threeEqualRegInstX("sqrshl", "SqrshlQX", "SimdCmpOp", signedTypes, 4, |
| sqrshlCode) |
| threeEqualRegInstX("sqrshl", "SqrshlScX", "SimdCmpOp", signedTypes, 4, |
| sqrshlCode, scalar=True) |
| # SQRSHRN, SQRSHRN2 |
| sqrshrnCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (imm > sizeof(srcElem1) * 8) { |
| if (srcElem1 != 0 && srcElem1 != -1) |
| fpscr.qc = 1; |
| destElem = 0; |
| } else if (imm) { |
| BigElement mid = (srcElem1 >> (imm - 1)); |
| uint64_t rBit = mid & 0x1; |
| mid >>= 1; |
| mid |= -(mid & ((BigElement)1 << |
| (sizeof(BigElement) * 8 - 1 - imm))); |
| mid += rBit; |
| if (mid != (Element)mid) { |
| destElem = mask(sizeof(Element) * 8 - 1); |
| if (srcElem1 < 0) |
| destElem = ~destElem; |
| fpscr.qc = 1; |
| } else { |
| destElem = mid; |
| } |
| } else { |
| if (srcElem1 != (Element)srcElem1) { |
| destElem = mask(sizeof(Element) * 8 - 1); |
| if (srcElem1 < 0) |
| destElem = ~destElem; |
| fpscr.qc = 1; |
| } else { |
| destElem = srcElem1; |
| } |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoRegNarrowInstX("sqrshrn", "SqrshrnX", "SimdShiftOp", smallSignedTypes, |
| sqrshrnCode, hasImm=True) |
| twoRegNarrowInstX("sqrshrn2", "Sqrshrn2X", "SimdShiftOp", smallSignedTypes, |
| sqrshrnCode, hasImm=True, hi=True) |
| twoRegNarrowInstX("sqrshrn", "SqrshrnScX", "SimdShiftOp", smallSignedTypes, |
| sqrshrnCode, hasImm=True, scalar=True) |
| # SQRSHRUN, SQRSHRUN2 |
| sqrshrunCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (imm > sizeof(srcElem1) * 8) { |
| if (srcElem1 != 0) |
| fpscr.qc = 1; |
| destElem = 0; |
| } else if (imm) { |
| BigElement mid = (srcElem1 >> (imm - 1)); |
| uint64_t rBit = mid & 0x1; |
| mid >>= 1; |
| mid |= -(mid & ((BigElement)1 << |
| (sizeof(BigElement) * 8 - 1 - imm))); |
| mid += rBit; |
| if (bits(mid, sizeof(BigElement) * 8 - 1, |
| sizeof(Element) * 8) != 0) { |
| if (srcElem1 < 0) { |
| destElem = 0; |
| } else { |
| destElem = mask(sizeof(Element) * 8); |
| } |
| fpscr.qc = 1; |
| } else { |
| destElem = mid; |
| } |
| } else { |
| if (srcElem1 < 0) { |
| fpscr.qc = 1; |
| destElem = 0; |
| } else { |
| destElem = srcElem1; |
| } |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoRegNarrowInstX("sqrshrun", "SqrshrunX", "SimdShiftOp", smallSignedTypes, |
| sqrshrunCode, hasImm=True) |
| twoRegNarrowInstX("sqrshrun", "Sqrshrun2X", "SimdShiftOp", |
| smallSignedTypes, sqrshrunCode, hasImm=True, hi=True) |
| twoRegNarrowInstX("sqrshrun", "SqrshrunScX", "SimdShiftOp", |
| smallSignedTypes, sqrshrunCode, hasImm=True, scalar=True) |
| # SQSHL (immediate) |
| sqshlImmCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (imm >= sizeof(Element) * 8) { |
| if (srcElem1 != 0) { |
| destElem = std::numeric_limits<Element>::min(); |
| if (srcElem1 > 0) |
| destElem = ~destElem; |
| fpscr.qc = 1; |
| } else { |
| destElem = 0; |
| } |
| } else if (imm) { |
| destElem = (srcElem1 << imm); |
| uint64_t topBits = bits((uint64_t)srcElem1, |
| sizeof(Element) * 8 - 1, |
| sizeof(Element) * 8 - 1 - imm); |
| if (topBits != 0 && topBits != mask(imm + 1)) { |
| destElem = std::numeric_limits<Element>::min(); |
| if (srcElem1 > 0) |
| destElem = ~destElem; |
| fpscr.qc = 1; |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoEqualRegInstX("sqshl", "SqshlImmDX", "SimdAluOp", smallSignedTypes, 2, |
| sqshlImmCode, hasImm=True) |
| twoEqualRegInstX("sqshl", "SqshlImmQX", "SimdAluOp", signedTypes, 4, |
| sqshlImmCode, hasImm=True) |
| twoEqualRegInstX("sqshl", "SqshlImmScX", "SimdAluOp", signedTypes, 4, |
| sqshlImmCode, hasImm=True, scalar=True) |
| # SQSHL (register) |
| sqshlCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| // Make sure the right shift sign extended when it should. |
| if (srcElem1 < 0 && destElem >= 0) { |
| destElem |= -((Element)1 << (sizeof(Element) * 8 - |
| 1 - shiftAmt)); |
| } |
| } else if (shiftAmt > 0) { |
| bool sat = false; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| if (srcElem1 != 0) |
| sat = true; |
| else |
| destElem = 0; |
| } else { |
| if (bits((uint64_t) srcElem1, sizeof(Element) * 8 - 1, |
| sizeof(Element) * 8 - 1 - shiftAmt) != |
| ((srcElem1 < 0) ? mask(shiftAmt + 1) : 0)) { |
| sat = true; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } |
| if (sat) { |
| fpscr.qc = 1; |
| destElem = mask(sizeof(Element) * 8 - 1); |
| if (srcElem1 < 0) |
| destElem = ~destElem; |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInstX("sqshl", "SqshlDX", "SimdAluOp", smallSignedTypes, 2, |
| sqshlCode) |
| threeEqualRegInstX("sqshl", "SqshlQX", "SimdAluOp", signedTypes, 4, |
| sqshlCode) |
| threeEqualRegInstX("sqshl", "SqshlScX", "SimdAluOp", signedTypes, 4, |
| sqshlCode, scalar=True) |
| # SQSHLU |
| sqshluCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (imm >= sizeof(Element) * 8) { |
| if (srcElem1 < 0) { |
| destElem = 0; |
| fpscr.qc = 1; |
| } else if (srcElem1 > 0) { |
| destElem = mask(sizeof(Element) * 8); |
| fpscr.qc = 1; |
| } else { |
| destElem = 0; |
| } |
| } else if (imm) { |
| destElem = (srcElem1 << imm); |
| uint64_t topBits = bits((uint64_t)srcElem1, |
| sizeof(Element) * 8 - 1, |
| sizeof(Element) * 8 - imm); |
| if (srcElem1 < 0) { |
| destElem = 0; |
| fpscr.qc = 1; |
| } else if (topBits != 0) { |
| destElem = mask(sizeof(Element) * 8); |
| fpscr.qc = 1; |
| } |
| } else { |
| if (srcElem1 < 0) { |
| fpscr.qc = 1; |
| destElem = 0; |
| } else { |
| destElem = srcElem1; |
| } |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoEqualRegInstX("sqshlu", "SqshluDX", "SimdAluOp", smallSignedTypes, 2, |
| sqshluCode, hasImm=True) |
| twoEqualRegInstX("sqshlu", "SqshluQX", "SimdAluOp", signedTypes, 4, |
| sqshluCode, hasImm=True) |
| twoEqualRegInstX("sqshlu", "SqshluScX", "SimdAluOp", signedTypes, 4, |
| sqshluCode, hasImm=True, scalar=True) |
| # SQSHRN, SQSHRN2 |
| sqshrnCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (imm > sizeof(srcElem1) * 8) { |
| if (srcElem1 != 0 && srcElem1 != -1) |
| fpscr.qc = 1; |
| destElem = 0; |
| } else if (imm) { |
| BigElement mid = ((srcElem1 >> (imm - 1)) >> 1); |
| mid |= -(mid & ((BigElement)1 << |
| (sizeof(BigElement) * 8 - 1 - imm))); |
| if (mid != (Element)mid) { |
| destElem = mask(sizeof(Element) * 8 - 1); |
| if (srcElem1 < 0) |
| destElem = ~destElem; |
| fpscr.qc = 1; |
| } else { |
| destElem = mid; |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoRegNarrowInstX("sqshrn", "SqshrnX", "SimdShiftOp", smallSignedTypes, |
| sqshrnCode, hasImm=True) |
| twoRegNarrowInstX("sqshrn2", "Sqshrn2X", "SimdShiftOp", smallSignedTypes, |
| sqshrnCode, hasImm=True, hi=True) |
| twoRegNarrowInstX("sqshrn", "SqshrnScX", "SimdShiftOp", smallSignedTypes, |
| sqshrnCode, hasImm=True, scalar=True) |
| # SQSHRUN, SQSHRUN2 |
| sqshrunCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (imm > sizeof(srcElem1) * 8) { |
| if (srcElem1 != 0) |
| fpscr.qc = 1; |
| destElem = 0; |
| } else if (imm) { |
| BigElement mid = ((srcElem1 >> (imm - 1)) >> 1); |
| if (bits(mid, sizeof(BigElement) * 8 - 1, |
| sizeof(Element) * 8) != 0) { |
| if (srcElem1 < 0) { |
| destElem = 0; |
| } else { |
| destElem = mask(sizeof(Element) * 8); |
| } |
| fpscr.qc = 1; |
| } else { |
| destElem = mid; |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoRegNarrowInstX("sqshrun", "SqshrunX", "SimdShiftOp", smallSignedTypes, |
| sqshrunCode, hasImm=True) |
| twoRegNarrowInstX("sqshrun", "Sqshrun2X", "SimdShiftOp", smallSignedTypes, |
| sqshrunCode, hasImm=True, hi=True) |
| twoRegNarrowInstX("sqshrun", "SqshrunScX", "SimdShiftOp", smallSignedTypes, |
| sqshrunCode, hasImm=True, scalar=True) |
| # SQSUB |
| sqsubCode = ''' |
| destElem = srcElem1 - srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| bool negDest = (destElem < 0); |
| bool negSrc1 = (srcElem1 < 0); |
| bool posSrc2 = (srcElem2 >= 0); |
| if ((negDest != negSrc1) && (negSrc1 == posSrc2)) { |
| destElem = std::numeric_limits<Element>::min(); |
| if (negDest) |
| destElem -= 1; |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInstX("sqsub", "SqsubDX", "SimdAddOp", smallSignedTypes, 2, |
| sqsubCode) |
| threeEqualRegInstX("sqsub", "SqsubQX", "SimdAddOp", signedTypes, 4, |
| sqsubCode) |
| threeEqualRegInstX("sqsub", "SqsubScX", "SimdAddOp", signedTypes, 4, |
| sqsubCode, scalar=True) |
| # SQXTN, SQXTN2 |
| sqxtnCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| destElem = srcElem1; |
| if ((BigElement)destElem != srcElem1) { |
| fpscr.qc = 1; |
| destElem = mask(sizeof(Element) * 8 - 1); |
| if (srcElem1 < 0) |
| destElem = ~destElem; |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoRegNarrowInstX("sqxtn", "SqxtnX", "SimdMiscOp", smallSignedTypes, |
| sqxtnCode) |
| twoRegNarrowInstX("sqxtn", "Sqxtn2X", "SimdMiscOp", smallSignedTypes, |
| sqxtnCode, hi=True) |
| twoRegNarrowInstX("sqxtn", "SqxtnScX", "SimdMiscOp", smallSignedTypes, |
| sqxtnCode, scalar=True) |
| # SQXTUN, SQXTUN2 |
| sqxtunCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| destElem = srcElem1; |
| if (srcElem1 < 0 || |
| ((BigElement)destElem & mask(sizeof(Element) * 8)) != srcElem1) { |
| fpscr.qc = 1; |
| destElem = mask(sizeof(Element) * 8); |
| if (srcElem1 < 0) |
| destElem = ~destElem; |
| } |
| FpscrQc = fpscr; |
| ''' |
| twoRegNarrowInstX("sqxtun", "SqxtunX", "SimdMiscOp", smallSignedTypes, |
| sqxtunCode) |
| twoRegNarrowInstX("sqxtun", "Sqxtun2X", "SimdMiscOp", smallSignedTypes, |
| sqxtunCode, hi=True) |
| twoRegNarrowInstX("sqxtun", "SqxtunScX", "SimdMiscOp", smallSignedTypes, |
| sqxtunCode, scalar=True) |
| # SRHADD |
| rhaddCode = ''' |
| Element carryBit = |
| (((unsigned)srcElem1 & 0x1) + |
| ((unsigned)srcElem2 & 0x1) + 1) >> 1; |
| // Use division instead of a shift to ensure the sign extension works |
| // right. The compiler will figure out if it can be a shift. Mask the |
| // inputs so they get truncated correctly. |
| destElem = (((srcElem1 & ~(Element)1) / 2) + |
| ((srcElem2 & ~(Element)1) / 2)) + carryBit; |
| ''' |
| threeEqualRegInstX("srhadd", "SrhaddDX", "SimdAddOp", smallSignedTypes, 2, |
| rhaddCode) |
| threeEqualRegInstX("srhadd", "SrhaddQX", "SimdAddOp", smallSignedTypes, 4, |
| rhaddCode) |
| # SRI |
| sriCode = ''' |
| if (imm >= sizeof(Element) * 8) |
| destElem = destElem; |
| else |
| destElem = (srcElem1 >> imm) | |
| (destElem & ~mask(sizeof(Element) * 8 - imm)); |
| ''' |
| twoEqualRegInstX("sri", "SriDX", "SimdShiftOp", unsignedTypes, 2, sriCode, |
| True, hasImm=True) |
| twoEqualRegInstX("sri", "SriQX", "SimdShiftOp", unsignedTypes, 4, sriCode, |
| True, hasImm=True) |
| # SRSHL |
| rshlCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| Element rBit = 0; |
| if (shiftAmt <= sizeof(Element) * 8) |
| rBit = bits(srcElem1, shiftAmt - 1); |
| if (shiftAmt > sizeof(Element) * 8 && ltz(srcElem1)) |
| rBit = 1; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| // Make sure the right shift sign extended when it should. |
| if (ltz(srcElem1) && !ltz(destElem)) { |
| destElem |= -((Element)1 << (sizeof(Element) * 8 - |
| 1 - shiftAmt)); |
| } |
| destElem += rBit; |
| } else if (shiftAmt > 0) { |
| if (shiftAmt >= sizeof(Element) * 8) { |
| destElem = 0; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| ''' |
| threeEqualRegInstX("srshl", "SrshlDX", "SimdShiftOp", signedTypes, 2, |
| rshlCode) |
| threeEqualRegInstX("srshl", "SrshlQX", "SimdShiftOp", signedTypes, 4, |
| rshlCode) |
| # SRSHR |
| rshrCode = ''' |
| if (imm > sizeof(srcElem1) * 8) { |
| destElem = 0; |
| } else if (imm) { |
| Element rBit = bits(srcElem1, imm - 1); |
| destElem = ((srcElem1 >> (imm - 1)) >> 1) + rBit; |
| } else { |
| destElem = srcElem1; |
| } |
| ''' |
| twoEqualRegInstX("srshr", "SrshrDX", "SimdShiftOp", signedTypes, 2, |
| rshrCode, hasImm=True) |
| twoEqualRegInstX("srshr", "SrshrQX", "SimdShiftOp", signedTypes, 4, |
| rshrCode, hasImm=True) |
| # SRSRA |
| rsraCode = ''' |
| if (imm > sizeof(srcElem1) * 8) { |
| destElem += 0; |
| } else if (imm) { |
| Element rBit = bits(srcElem1, imm - 1); |
| destElem += ((srcElem1 >> (imm - 1)) >> 1) + rBit; |
| } else { |
| destElem += srcElem1; |
| } |
| ''' |
| twoEqualRegInstX("srsra", "SrsraDX", "SimdShiftOp", signedTypes, 2, |
| rsraCode, True, hasImm=True) |
| twoEqualRegInstX("srsra", "SrsraQX", "SimdShiftOp", signedTypes, 4, |
| rsraCode, True, hasImm=True) |
| # SSHL |
| shlCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| // Make sure the right shift sign extended when it should. |
| if (ltz(srcElem1) && !ltz(destElem)) { |
| destElem |= -((Element)1 << (sizeof(Element) * 8 - |
| 1 - shiftAmt)); |
| } |
| } else { |
| if (shiftAmt >= sizeof(Element) * 8) { |
| destElem = 0; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } |
| ''' |
| threeEqualRegInstX("sshl", "SshlDX", "SimdShiftOp", signedTypes, 2, |
| shlCode) |
| threeEqualRegInstX("sshl", "SshlQX", "SimdShiftOp", signedTypes, 4, |
| shlCode) |
| # SSHLL, SSHLL2 |
| shllCode = ''' |
| if (imm >= sizeof(destElem) * 8) { |
| destElem = 0; |
| } else { |
| destElem = (BigElement)srcElem1 << imm; |
| } |
| ''' |
| twoRegLongInstX("sshll", "SshllX", "SimdShiftOp", smallSignedTypes, |
| shllCode, hasImm=True) |
| twoRegLongInstX("sshll", "Sshll2X", "SimdShiftOp", smallSignedTypes, |
| shllCode, hasImm=True, hi=True) |
| # SSHR |
| shrCode = ''' |
| if (imm >= sizeof(srcElem1) * 8) { |
|