public static void Imnmx(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool isSignedInt = op.RawOpCode.Extract(48); Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); Operand resMin = isSignedInt ? context.IMinimumS32(srcA, srcB) : context.IMinimumU32(srcA, srcB); Operand resMax = isSignedInt ? context.IMaximumS32(srcA, srcB) : context.IMaximumU32(srcA, srcB); Operand pred = GetPredicate39(context); Operand dest = GetDest(context); context.Copy(dest, context.ConditionalSelect(pred, resMin, resMax)); SetZnFlags(context, dest, op.SetCondCode); // TODO: X flags. }
public static void Iscadd(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool negateA = false, negateB = false; if (!(op is OpCodeAluImm32)) { negateB = op.RawOpCode.Extract(48); negateA = op.RawOpCode.Extract(49); } int shift = op is OpCodeAluImm32 ? op.RawOpCode.Extract(53, 5) : op.RawOpCode.Extract(39, 5); Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); srcA = context.ShiftLeft(srcA, Const(shift)); srcA = context.INegate(srcA, negateA); srcB = context.INegate(srcB, negateB); Operand res = context.IAdd(srcA, srcB); SetIaddFlags(context, res, srcA, srcB, op.SetCondCode, false); context.Copy(GetDest(context), res); }
public static void Shl(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool isMasked = op.RawOpCode.Extract(39); Operand srcB = GetSrcB(context); if (isMasked) { srcB = context.BitwiseAnd(srcB, Const(0x1f)); } Operand res = context.ShiftLeft(GetSrcA(context), srcB); if (!isMasked) { // Clamped shift value. Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32)); res = context.ConditionalSelect(isLessThan32, res, Const(0)); } // TODO: X, CC context.Copy(GetDest(context), res); }
public static void I2F(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; FPType dstType = (FPType)op.RawOpCode.Extract(8, 2); IntegerType srcType = (IntegerType)op.RawOpCode.Extract(10, 2); bool isSmallInt = srcType <= IntegerType.U16; bool isSignedInt = op.RawOpCode.Extract(13); bool negateB = op.RawOpCode.Extract(45); bool absoluteB = op.RawOpCode.Extract(49); Operand srcB = context.IAbsNeg(GetSrcB(context), absoluteB, negateB); if (isSmallInt) { int size = srcType == IntegerType.U16 ? 16 : 8; srcB = isSignedInt ? context.BitfieldExtractS32(srcB, Const(op.ByteSelection * 8), Const(size)) : context.BitfieldExtractU32(srcB, Const(op.ByteSelection * 8), Const(size)); } srcB = isSignedInt ? context.IConvertS32ToFP(srcB) : context.IConvertU32ToFP(srcB); WriteFP(context, dstType, srcB); // TODO: CC. }
public static void Iadd(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool negateA = false, negateB = false; if (!(op is OpCodeAluImm32)) { negateB = op.RawOpCode.Extract(48); negateA = op.RawOpCode.Extract(49); } Operand srcA = context.INegate(GetSrcA(context), negateA); Operand srcB = context.INegate(GetSrcB(context), negateB); Operand res = context.IAdd(srcA, srcB); bool isSubtraction = negateA || negateB; if (op.Extended) { //Add carry, or subtract borrow. res = context.IAdd(res, isSubtraction ? context.BitwiseNot(GetCF(context)) : context.BitwiseAnd(GetCF(context), Const(1))); } SetIaddFlags(context, res, srcA, srcB, op.SetCondCode, op.Extended, isSubtraction); context.Copy(GetDest(context), res); }
public static void R2p(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool isCC = op.RawOpCode.Extract(40); int shift = op.RawOpCode.Extract(41, 2) * 8; Operand value = GetSrcA(context); Operand mask = GetSrcB(context); Operand Test(Operand value, int bit) { return(context.ICompareNotEqual(context.BitwiseAnd(value, Const(1 << bit)), Const(0))); } if (isCC) { // TODO: Support Register to condition code flags copy. context.Config.PrintLog("R2P.CC not implemented."); } else { for (int bit = 0; bit < 7; bit++) { Operand pred = Register(bit, RegisterType.Predicate); Operand res = context.ConditionalSelect(Test(mask, bit), Test(value, bit + shift), pred); context.Copy(pred, res); } } }
public static void Iadd(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool negateA = false, negateB = false; if (!(op is OpCodeAluImm32)) { negateB = op.RawOpCode.Extract(48); negateA = op.RawOpCode.Extract(49); } else { // TODO: Other IADD32I variant without the negate. negateA = op.RawOpCode.Extract(56); } Operand srcA = context.INegate(GetSrcA(context), negateA); Operand srcB = context.INegate(GetSrcB(context), negateB); Operand res = context.IAdd(srcA, srcB); if (op.Extended) { res = context.IAdd(res, context.BitwiseAnd(GetCF(), Const(1))); } SetIaddFlags(context, res, srcA, srcB, op.SetCondCode, op.Extended); context.Copy(GetDest(context), res); }
public static void Bfe(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool isReverse = op.RawOpCode.Extract(40); bool isSigned = op.RawOpCode.Extract(48); Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); if (isReverse) { srcA = context.BitfieldReverse(srcA); } Operand position = context.BitwiseAnd(srcB, Const(0xff)); Operand size = context.BitfieldExtractU32(srcB, Const(8), Const(8)); Operand res = isSigned ? context.BitfieldExtractS32(srcA, position, size) : context.BitfieldExtractU32(srcA, position, size); context.Copy(GetDest(context), res); // TODO: CC, X, corner cases }
public static void S2r(EmitterContext context) { // TODO: Better impl. OpCodeAlu op = (OpCodeAlu)context.CurrOp; SystemRegister sysReg = (SystemRegister)op.RawOpCode.Extract(20, 8); Operand src; switch (sysReg) { case SystemRegister.LaneId: src = Attribute(AttributeConsts.LaneId); break; // TODO: Use value from Y direction GPU register. case SystemRegister.YDirection: src = ConstF(1); break; case SystemRegister.ThreadId: { Operand tidX = Attribute(AttributeConsts.ThreadIdX); Operand tidY = Attribute(AttributeConsts.ThreadIdY); Operand tidZ = Attribute(AttributeConsts.ThreadIdZ); tidY = context.ShiftLeft(tidY, Const(16)); tidZ = context.ShiftLeft(tidZ, Const(26)); src = context.BitwiseOr(tidX, context.BitwiseOr(tidY, tidZ)); break; } case SystemRegister.ThreadIdX: src = Attribute(AttributeConsts.ThreadIdX); break; case SystemRegister.ThreadIdY: src = Attribute(AttributeConsts.ThreadIdY); break; case SystemRegister.ThreadIdZ: src = Attribute(AttributeConsts.ThreadIdZ); break; case SystemRegister.CtaIdX: src = Attribute(AttributeConsts.CtaIdX); break; case SystemRegister.CtaIdY: src = Attribute(AttributeConsts.CtaIdY); break; case SystemRegister.CtaIdZ: src = Attribute(AttributeConsts.CtaIdZ); break; case SystemRegister.EqMask: src = Attribute(AttributeConsts.EqMask); break; case SystemRegister.LtMask: src = Attribute(AttributeConsts.LtMask); break; case SystemRegister.LeMask: src = Attribute(AttributeConsts.LeMask); break; case SystemRegister.GtMask: src = Attribute(AttributeConsts.GtMask); break; case SystemRegister.GeMask: src = Attribute(AttributeConsts.GeMask); break; default: src = Const(0); break; } context.Copy(GetDest(context), src); }
public static void Clz(ArmEmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; Operand n = GetIntOrZR(context, op.Rn); Operand d = context.CountLeadingZeros(n); SetAluDOrZR(context, d); }
public static void I2I(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; IntegerType dstType = (IntegerType)op.RawOpCode.Extract(8, 2); IntegerType srcType = (IntegerType)op.RawOpCode.Extract(10, 2); if (srcType == IntegerType.U64 || dstType == IntegerType.U64) { context.Config.PrintLog("Invalid I2I encoding."); return; } bool srcIsSmallInt = srcType <= IntegerType.U16; bool dstIsSignedInt = op.RawOpCode.Extract(12); bool srcIsSignedInt = op.RawOpCode.Extract(13); bool negateB = op.RawOpCode.Extract(45); bool absoluteB = op.RawOpCode.Extract(49); Operand srcB = GetSrcB(context); if (srcIsSmallInt) { int size = srcType == IntegerType.U16 ? 16 : 8; srcB = srcIsSignedInt ? context.BitfieldExtractS32(srcB, Const(op.ByteSelection * 8), Const(size)) : context.BitfieldExtractU32(srcB, Const(op.ByteSelection * 8), Const(size)); } srcB = context.IAbsNeg(srcB, absoluteB, negateB); if (op.Saturate) { if (dstIsSignedInt) { dstType |= IntegerType.S8; } int min = (int)GetIntMin(dstType); int max = (int)GetIntMax(dstType); srcB = dstIsSignedInt ? context.IClampS32(srcB, Const(min), Const(max)) : context.IClampU32(srcB, Const(min), Const(max)); } context.Copy(GetDest(context), srcB); // TODO: CC. }
public static void Popc(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool invert = op.RawOpCode.Extract(40); Operand srcB = context.BitwiseNot(GetSrcB(context), invert); Operand res = context.BitCount(srcB); context.Copy(GetDest(context), res); }
public static void Sel(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; Operand pred = GetPredicate39(context); Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); Operand res = context.ConditionalSelect(pred, srcA, srcB); context.Copy(GetDest(context), res); }
public static void Fswzadd(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; int mask = op.RawOpCode.Extract(28, 8); Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); Operand dest = GetDest(context); context.Copy(dest, context.FPSwizzleAdd(srcA, srcB, mask)); SetFPZnFlags(context, dest, op.SetCondCode); }
public static void Shr(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool isMasked = op.RawOpCode.Extract(39); bool isReverse = op.RawOpCode.Extract(40); bool isSigned = op.RawOpCode.Extract(48); Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); if (isReverse) { srcA = context.BitfieldReverse(srcA); } if (isMasked) { srcB = context.BitwiseAnd(srcB, Const(0x1f)); } Operand res = isSigned ? context.ShiftRightS32(srcA, srcB) : context.ShiftRightU32(srcA, srcB); if (!isMasked) { // Clamped shift value. Operand resShiftBy32; if (isSigned) { resShiftBy32 = context.ShiftRightS32(srcA, Const(31)); } else { resShiftBy32 = Const(0); } Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32)); res = context.ConditionalSelect(isLessThan32, res, resShiftBy32); } // TODO: X, CC context.Copy(GetDest(context), res); }
public static void Bfi(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); Operand srcC = GetSrcC(context); Operand position = context.BitwiseAnd(srcB, Const(0xff)); Operand size = context.BitfieldExtractU32(srcB, Const(8), Const(8)); Operand res = context.BitfieldInsert(srcC, srcA, position, size); context.Copy(GetDest(context), res); }
public static void Rro(EmitterContext context) { // This is the range reduction operator, // we translate it as a simple move, as it // should be always followed by a matching // MUFU instruction. OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool negateB = op.RawOpCode.Extract(45); bool absoluteB = op.RawOpCode.Extract(49); Operand srcB = GetSrcB(context); srcB = context.FPAbsNeg(srcB, absoluteB, negateB); context.Copy(GetDest(context), srcB); }
public static void Rev32(ArmEmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; Operand n = GetIntOrZR(context, op.Rn); if (op.RegisterSize == RegisterSize.Int32) { SetAluDOrZR(context, context.ByteSwap(n)); } else { Operand d = context.Call(new _U64_U64(SoftFallback.ReverseBytes32_64), n); SetAluDOrZR(context, d); } }
public static void Lea_Hi(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool isReg = op is OpCodeAluReg; bool negateA; int shift; if (isReg) { negateA = op.RawOpCode.Extract(37); shift = op.RawOpCode.Extract(28, 5); } else { negateA = op.RawOpCode.Extract(56); shift = op.RawOpCode.Extract(51, 5); } Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); Operand srcC = GetSrcC(context); Operand aLow = context.ShiftLeft(srcA, Const(shift)); Operand aHigh = shift == 0 ? Const(0) : context.ShiftRightU32(srcA, Const(32 - shift)); aHigh = context.BitwiseOr(aHigh, context.ShiftLeft(srcC, Const(shift))); if (negateA) { // Perform 64-bit negation by doing bitwise not of the value, // then adding 1 and carrying over from low to high. aLow = context.BitwiseNot(aLow); aHigh = context.BitwiseNot(aHigh); aLow = AddWithCarry(context, aLow, Const(1), out Operand aLowCOut); aHigh = context.IAdd(aHigh, aLowCOut); } Operand res = context.IAdd(aHigh, srcB); context.Copy(GetDest(context), res); // TODO: CC, X }
public static void Imad(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool signedA = context.CurrOp.RawOpCode.Extract(48); bool signedB = context.CurrOp.RawOpCode.Extract(53); bool high = context.CurrOp.RawOpCode.Extract(54); Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); Operand srcC = GetSrcC(context); Operand res; if (high) { if (signedA && signedB) { res = context.MultiplyHighS32(srcA, srcB); } else { res = context.MultiplyHighU32(srcA, srcB); if (signedA) { res = context.IAdd(res, context.IMultiply(srcB, context.ShiftRightS32(srcA, Const(31)))); } else if (signedB) { res = context.IAdd(res, context.IMultiply(srcA, context.ShiftRightS32(srcB, Const(31)))); } } } else { res = context.IMultiply(srcA, srcB); } res = context.IAdd(res, srcC); // TODO: CC, X, SAT, and more? context.Copy(GetDest(context), res); }
public static void Rev32(ArmEmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; Operand n = GetIntOrZR(context, op.Rn); Operand d; if (op.RegisterSize == RegisterSize.Int32) { d = context.ByteSwap(n); } else { d = EmitReverseBytes32_64Op(context, n); } SetAluDOrZR(context, d); }
public static void Rev16(ArmEmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; Operand n = GetIntOrZR(context, op.Rn); Operand d; if (op.RegisterSize == RegisterSize.Int32) { d = context.Call(new _U32_U32(SoftFallback.ReverseBytes16_32), n); } else { d = context.Call(new _U64_U64(SoftFallback.ReverseBytes16_64), n); } SetAluDOrZR(context, d); }
public static void Cls(ArmEmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; Operand n = GetIntOrZR(context, op.Rn); Operand nHigh = context.ShiftRightUI(n, Const(1)); bool is32Bits = op.RegisterSize == RegisterSize.Int32; Operand mask = is32Bits ? Const(int.MaxValue) : Const(long.MaxValue); Operand nLow = context.BitwiseAnd(n, mask); Operand res = context.CountLeadingZeros(context.BitwiseExclusiveOr(nHigh, nLow)); res = context.Subtract(res, Const(res.Type, 1)); SetAluDOrZR(context, res); }
public static void Lea(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool negateA = op.RawOpCode.Extract(45); int shift = op.RawOpCode.Extract(39, 5); Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); srcA = context.ShiftLeft(srcA, Const(shift)); srcA = context.INegate(srcA, negateA); Operand res = context.IAdd(srcA, srcB); context.Copy(GetDest(context), res); // TODO: CC, X }
public static void Flo(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool invert = op.RawOpCode.Extract(40); bool countZeros = op.RawOpCode.Extract(41); bool isSigned = op.RawOpCode.Extract(48); Operand srcB = context.BitwiseNot(GetSrcB(context), invert); Operand res = isSigned ? context.FindFirstSetS32(srcB) : context.FindFirstSetU32(srcB); if (countZeros) { res = context.BitwiseExclusiveOr(res, Const(31)); } context.Copy(GetDest(context), res); }
public static void Rev64(ArmEmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; SetAluDOrZR(context, context.ByteSwap(GetIntOrZR(context, op.Rn))); }
public static void Mov(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; context.Copy(GetDest(context), GetSrcB(context)); }
public static void Iadd3(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; IntegerHalfPart partC = (IntegerHalfPart)op.RawOpCode.Extract(31, 2); IntegerHalfPart partB = (IntegerHalfPart)op.RawOpCode.Extract(33, 2); IntegerHalfPart partA = (IntegerHalfPart)op.RawOpCode.Extract(35, 2); IntegerShift mode = (IntegerShift)op.RawOpCode.Extract(37, 2); bool negateC = op.RawOpCode.Extract(49); bool negateB = op.RawOpCode.Extract(50); bool negateA = op.RawOpCode.Extract(51); Operand Extend(Operand src, IntegerHalfPart part) { if (!(op is OpCodeAluReg) || part == IntegerHalfPart.B32) { return(src); } if (part == IntegerHalfPart.H0) { return(context.BitwiseAnd(src, Const(0xffff))); } else if (part == IntegerHalfPart.H1) { return(context.ShiftRightU32(src, Const(16))); } else { // TODO: Warning. } return(src); } Operand srcA = context.INegate(Extend(GetSrcA(context), partA), negateA); Operand srcB = context.INegate(Extend(GetSrcB(context), partB), negateB); Operand srcC = context.INegate(Extend(GetSrcC(context), partC), negateC); Operand res = context.IAdd(srcA, srcB); if (op is OpCodeAluReg && mode != IntegerShift.NoShift) { if (mode == IntegerShift.ShiftLeft) { res = context.ShiftLeft(res, Const(16)); } else if (mode == IntegerShift.ShiftRight) { res = context.ShiftRightU32(res, Const(16)); } else { // TODO: Warning. } } res = context.IAdd(res, srcC); context.Copy(GetDest(context), res); // TODO: CC, X, corner cases }
public static void Xmad(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; bool signedA = context.CurrOp.RawOpCode.Extract(48); bool signedB = context.CurrOp.RawOpCode.Extract(49); bool highA = context.CurrOp.RawOpCode.Extract(53); bool isReg = (op is OpCodeAluReg) && !(op is OpCodeAluRegCbuf); bool isImm = (op is OpCodeAluImm); XmadCMode mode = isReg || isImm ? (XmadCMode)context.CurrOp.RawOpCode.Extract(50, 3) : (XmadCMode)context.CurrOp.RawOpCode.Extract(50, 2); bool highB = false; if (isReg) { highB = context.CurrOp.RawOpCode.Extract(35); } else if (!isImm) { highB = context.CurrOp.RawOpCode.Extract(52); } Operand srcA = GetSrcA(context); Operand srcB = GetSrcB(context); Operand srcC = GetSrcC(context); // XMAD immediates are 16-bits unsigned integers. if (srcB.Type == OperandType.Constant) { srcB = Const(srcB.Value & 0xffff); } Operand Extend16To32(Operand src, bool high, bool signed) { if (signed && high) { return(context.ShiftRightS32(src, Const(16))); } else if (signed) { return(context.BitfieldExtractS32(src, Const(0), Const(16))); } else if (high) { return(context.ShiftRightU32(src, Const(16))); } else { return(context.BitwiseAnd(src, Const(0xffff))); } } srcA = Extend16To32(srcA, highA, signedA); srcB = Extend16To32(srcB, highB, signedB); bool productShiftLeft = false; bool merge = false; if (op is OpCodeAluCbuf) { productShiftLeft = context.CurrOp.RawOpCode.Extract(55); merge = context.CurrOp.RawOpCode.Extract(56); } else if (!(op is OpCodeAluRegCbuf)) { productShiftLeft = context.CurrOp.RawOpCode.Extract(36); merge = context.CurrOp.RawOpCode.Extract(37); } bool extended; if ((op is OpCodeAluReg) || (op is OpCodeAluImm)) { extended = context.CurrOp.RawOpCode.Extract(38); } else { extended = context.CurrOp.RawOpCode.Extract(54); } Operand res = context.IMultiply(srcA, srcB); if (productShiftLeft) { res = context.ShiftLeft(res, Const(16)); } switch (mode) { case XmadCMode.Cfull: break; case XmadCMode.Clo: srcC = Extend16To32(srcC, high: false, signed: false); break; case XmadCMode.Chi: srcC = Extend16To32(srcC, high: true, signed: false); break; case XmadCMode.Cbcc: { srcC = context.IAdd(srcC, context.ShiftLeft(GetSrcB(context), Const(16))); break; } case XmadCMode.Csfu: { Operand signAdjustA = context.ShiftLeft(context.ShiftRightU32(srcA, Const(31)), Const(16)); Operand signAdjustB = context.ShiftLeft(context.ShiftRightU32(srcB, Const(31)), Const(16)); srcC = context.ISubtract(srcC, context.IAdd(signAdjustA, signAdjustB)); break; } default: /* TODO: Warning */ break; } Operand product = res; if (extended) { // Add with carry. res = context.IAdd(res, context.BitwiseAnd(GetCF(), Const(1))); } else { // Add (no carry in). res = context.IAdd(res, srcC); } SetIaddFlags(context, res, product, srcC, op.SetCondCode, extended); if (merge) { res = context.BitwiseAnd(res, Const(0xffff)); res = context.BitwiseOr(res, context.ShiftLeft(GetSrcB(context), Const(16))); } context.Copy(GetDest(context), res); }