private static void EmitHsub8(ArmEmitterContext context, bool unsigned) { OpCode32AluReg op = (OpCode32AluReg)context.CurrOp; Operand m = GetIntA32(context, op.Rm); Operand n = GetIntA32(context, op.Rn); Operand left, right, carry, res; // This relies on the equality x-y == (x^y) - (((x^y)&y) << 1). // Note that x^y always contains the LSB of the result. // Since we want to calculate (x+y)/2, we can instead calculate ((x^y)>>1) - ((x^y)&y). carry = context.BitwiseExclusiveOr(m, n); left = context.ShiftRightUI(carry, Const(1)); right = context.BitwiseAnd(carry, m); // We must now perform a partitioned subtraction. // We can do this because minuend contains 7 bit fields. // We use the extra bit in minuend as a bit to borrow from; we set this bit. // We invert this bit at the end as this tells us if that bit was borrowed from. res = context.BitwiseOr(left, Const(0x80808080)); res = context.Subtract(res, right); res = context.BitwiseExclusiveOr(res, Const(0x80808080)); if (!unsigned) { // We then sign extend the result into this bit. carry = context.BitwiseAnd(carry, Const(0x80808080)); res = context.BitwiseExclusiveOr(res, carry); } SetIntA32(context, op.Rd, res); }
public static void Bsl_V(ArmEmitterContext context) { if (Optimizations.UseSse2) { OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; Operand d = GetVec(op.Rd); Operand n = GetVec(op.Rn); Operand m = GetVec(op.Rm); Operand res = context.AddIntrinsic(Intrinsic.X86Pxor, n, m); res = context.AddIntrinsic(Intrinsic.X86Pand, res, d); res = context.AddIntrinsic(Intrinsic.X86Pxor, res, m); if (op.RegisterSize == RegisterSize.Simd64) { res = context.VectorZeroUpper64(res); } context.Copy(GetVec(op.Rd), res); } else { EmitVectorTernaryOpZx(context, (op1, op2, op3) => { return(context.BitwiseExclusiveOr( context.BitwiseAnd(op1, context.BitwiseExclusiveOr(op2, op3)), op3)); }); } }
private static void EmitHadd8(ArmEmitterContext context, bool unsigned) { OpCode32AluReg op = (OpCode32AluReg)context.CurrOp; Operand m = GetIntA32(context, op.Rm); Operand n = GetIntA32(context, op.Rn); Operand xor, res, carry; // This relies on the equality x+y == ((x&y) << 1) + (x^y). // Note that x^y always contains the LSB of the result. // Since we want to calculate (x+y)/2, we can instead calculate (x&y) + ((x^y)>>1). // We mask by 0x7F to remove the LSB so that it doesn't leak into the field below. res = context.BitwiseAnd(m, n); carry = context.BitwiseExclusiveOr(m, n); xor = context.ShiftRightUI(carry, Const(1)); xor = context.BitwiseAnd(xor, Const(0x7F7F7F7Fu)); res = context.Add(res, xor); if (!unsigned) { // Propagates the sign bit from (x^y)>>1 upwards by one. carry = context.BitwiseAnd(carry, Const(0x80808080u)); res = context.BitwiseExclusiveOr(res, carry); } SetIntA32(context, op.Rd, res); }
private static void EmitBifBit(ArmEmitterContext context, bool notRm) { OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp; if (Optimizations.UseSse2) { EmitVectorTernaryOpSimd32(context, (d, n, m) => { Operand res = context.AddIntrinsic(Intrinsic.X86Pxor, n, d); res = context.AddIntrinsic((notRm) ? Intrinsic.X86Pandn : Intrinsic.X86Pand, m, res); return(context.AddIntrinsic(Intrinsic.X86Pxor, d, res)); }); } else { EmitVectorTernaryOpZx32(context, (d, n, m) => { if (notRm) { m = context.BitwiseNot(m); } return(context.BitwiseExclusiveOr( context.BitwiseAnd(m, context.BitwiseExclusiveOr(d, n)), d)); }); } }
private static void EmitBifBit(ArmEmitterContext context, bool notRm) { OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; if (Optimizations.UseSse2) { Operand d = GetVec(op.Rd); Operand n = GetVec(op.Rn); Operand m = GetVec(op.Rm); Operand res = context.AddIntrinsic(Intrinsic.X86Pxor, n, d); if (notRm) { res = context.AddIntrinsic(Intrinsic.X86Pandn, m, res); } else { res = context.AddIntrinsic(Intrinsic.X86Pand, m, res); } res = context.AddIntrinsic(Intrinsic.X86Pxor, d, res); if (op.RegisterSize == RegisterSize.Simd64) { res = context.VectorZeroUpper64(res); } context.Copy(GetVec(op.Rd), res); } else { Operand res = context.VectorZero(); int elems = op.RegisterSize == RegisterSize.Simd128 ? 2 : 1; for (int index = 0; index < elems; index++) { Operand d = EmitVectorExtractZx(context, op.Rd, index, 3); Operand n = EmitVectorExtractZx(context, op.Rn, index, 3); Operand m = EmitVectorExtractZx(context, op.Rm, index, 3); if (notRm) { m = context.BitwiseNot(m); } Operand e = context.BitwiseExclusiveOr(d, n); e = context.BitwiseAnd(e, m); e = context.BitwiseExclusiveOr(e, d); res = EmitVectorInsert(context, res, e, index, 3); } context.Copy(GetVec(op.Rd), res); } }
public static void Vbsl(ArmEmitterContext context) { EmitVectorTernaryOpZx32(context, (op1, op2, op3) => { return(context.BitwiseExclusiveOr( context.BitwiseAnd(op1, context.BitwiseExclusiveOr(op2, op3)), op3)); }); }
public static void EmitSubsVCheck(ArmEmitterContext context, Operand n, Operand m, Operand d) { // V = (Rd ^ Rn) & (Rn ^ Rm) < 0 Operand vOut = context.BitwiseExclusiveOr(d, n); vOut = context.BitwiseAnd(vOut, context.BitwiseExclusiveOr(n, m)); vOut = context.ICompareLess(vOut, Const(vOut.Type, 0)); SetFlag(context, PState.VFlag, vOut); }
private static void EmitBifBit(ArmEmitterContext context, bool notRm) { OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp; EmitVectorTernaryOpZx32(context, (d, n, m) => { if (notRm) { m = context.BitwiseNot(m); } return(context.BitwiseExclusiveOr( context.BitwiseAnd(m, context.BitwiseExclusiveOr(d, n)), d)); }); }
private static void EmitSbc(ArmEmitterContext context, bool setFlags) { Operand n = GetAluN(context); Operand m = GetAluM(context); Operand d = context.Subtract(n, m); Operand borrow = context.BitwiseExclusiveOr(GetFlag(PState.CFlag), Const(1)); if (context.CurrOp.RegisterSize == RegisterSize.Int64) { borrow = context.ZeroExtend32(OperandType.I64, borrow); } d = context.Subtract(d, borrow); if (setFlags) { EmitNZFlagsCheck(context, d); EmitSbcsCCheck(context, n, m); EmitSubsVCheck(context, n, m, d); } SetAluDOrZR(context, d); }
public static void Eon(ArmEmitterContext context) { Operand n = GetAluN(context); Operand m = GetAluM(context); Operand d = context.BitwiseExclusiveOr(n, context.BitwiseNot(m)); SetAluD(context, d); }
public static void Teq(ArmEmitterContext context) { Operand n = GetAluN(context); Operand m = GetAluM(context); Operand res = context.BitwiseExclusiveOr(n, m); EmitNZFlagsCheck(context, res); }
public static void Veor_I(ArmEmitterContext context) { if (Optimizations.UseSse2) { EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Pxor, n, m)); } else { EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseExclusiveOr(op1, op2)); } }
public static void Vbsl(ArmEmitterContext context) { if (Optimizations.UseSse2) { EmitVectorTernaryOpSimd32(context, (d, n, m) => { Operand res = context.AddIntrinsic(Intrinsic.X86Pxor, n, m); res = context.AddIntrinsic(Intrinsic.X86Pand, res, d); return(context.AddIntrinsic(Intrinsic.X86Pxor, res, m)); }); } else { EmitVectorTernaryOpZx32(context, (op1, op2, op3) => { return(context.BitwiseExclusiveOr( context.BitwiseAnd(op1, context.BitwiseExclusiveOr(op2, op3)), op3)); }); } }
public static void Eor(ArmEmitterContext context) { IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; Operand n = GetAluN(context); Operand m = GetAluM(context); Operand res = context.BitwiseExclusiveOr(n, m); if (op.SetFlags) { EmitNZFlagsCheck(context, res); } EmitAluStore(context, res); }
public static void Uhadd8(ArmEmitterContext context) { OpCode32AluReg op = (OpCode32AluReg)context.CurrOp; Operand m = GetIntA32(context, op.Rm); Operand n = GetIntA32(context, op.Rn); Operand xor, res; res = context.BitwiseAnd(m, n); xor = context.BitwiseExclusiveOr(m, n); xor = context.ShiftRightUI(xor, Const(1)); xor = context.BitwiseAnd(xor, Const(0x7F7F7F7Fu)); res = context.Add(res, xor); SetIntA32(context, op.Rd, res); }
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 Operand EmitPolynomialMultiply(ArmEmitterContext context, Operand op1, Operand op2, int eSize) { Debug.Assert(eSize <= 32); Operand result = eSize == 32 ? Const(0L) : Const(0); if (eSize == 32) { op1 = context.ZeroExtend32(OperandType.I64, op1); op2 = context.ZeroExtend32(OperandType.I64, op2); } for (int i = 0; i < eSize; i++) { Operand mask = context.BitwiseAnd(op1, Const(op1.Type, 1L << i)); result = context.BitwiseExclusiveOr(result, context.Multiply(op2, mask)); } return(result); }
public static void Sbc(ArmEmitterContext context) { IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; Operand n = GetAluN(context); Operand m = GetAluM(context, setCarry: false); Operand res = context.Subtract(n, m); Operand borrow = context.BitwiseExclusiveOr(GetFlag(PState.CFlag), Const(1)); res = context.Subtract(res, borrow); if (op.SetFlags) { EmitNZFlagsCheck(context, res); EmitSbcsCCheck(context, n, m); EmitSubsVCheck(context, n, m, res); } EmitAluStore(context, res); }
private static void EmitSse41ConvertInt32(ArmEmitterContext context, FPRoundingMode roundMode, bool signed) { // A port of the similar round function in InstEmitSimdCvt. OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp; bool doubleSize = (op.Size & 1) != 0; int shift = doubleSize ? 1 : 2; Operand n = GetVecA32(op.Vm >> shift); n = EmitSwapScalar(context, n, op.Vm, doubleSize); if (!doubleSize) { Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode))); Operand zero = context.VectorZero(); Operand nCmp; Operand nIntOrLong2 = default; if (!signed) { nCmp = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); } int fpMaxVal = 0x4F000000; // 2.14748365E9f (2147483648) Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); Operand nIntOrLong = context.AddIntrinsicInt(Intrinsic.X86Cvtss2si, nRes); if (!signed) { nRes = context.AddIntrinsic(Intrinsic.X86Subss, nRes, fpMaxValMask); nCmp = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); nIntOrLong2 = context.AddIntrinsicInt(Intrinsic.X86Cvtss2si, nRes); } nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); Operand nInt = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, nRes); Operand dRes; if (signed) { dRes = context.BitwiseExclusiveOr(nIntOrLong, nInt); } else { dRes = context.BitwiseExclusiveOr(nIntOrLong2, nInt); dRes = context.Add(dRes, nIntOrLong); } InsertScalar(context, op.Vd, dRes); } else { Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode))); Operand zero = context.VectorZero(); Operand nCmp; Operand nIntOrLong2 = default; if (!signed) { nCmp = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); } long fpMaxVal = 0x41E0000000000000L; // 2147483648.0000000d (2147483648) Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); Operand nIntOrLong = context.AddIntrinsicInt(Intrinsic.X86Cvtsd2si, nRes); if (!signed) { nRes = context.AddIntrinsic(Intrinsic.X86Subsd, nRes, fpMaxValMask); nCmp = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); nIntOrLong2 = context.AddIntrinsicInt(Intrinsic.X86Cvtsd2si, nRes); } nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); Operand nLong = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, nRes); nLong = context.ConvertI64ToI32(nLong); Operand dRes; if (signed) { dRes = context.BitwiseExclusiveOr(nIntOrLong, nLong); } else { dRes = context.BitwiseExclusiveOr(nIntOrLong2, nLong); dRes = context.Add(dRes, nIntOrLong); } InsertScalar(context, op.Vd, dRes); } }
public static Operand GetCondTrue(ArmEmitterContext context, Condition condition) { Operand cmpResult = context.TryGetComparisonResult(condition); if (cmpResult != null) { return(cmpResult); } Operand value = Const(1); Operand Inverse(Operand val) { return(context.BitwiseExclusiveOr(val, Const(1))); } switch (condition) { case Condition.Eq: value = GetFlag(PState.ZFlag); break; case Condition.Ne: value = Inverse(GetFlag(PState.ZFlag)); break; case Condition.GeUn: value = GetFlag(PState.CFlag); break; case Condition.LtUn: value = Inverse(GetFlag(PState.CFlag)); break; case Condition.Mi: value = GetFlag(PState.NFlag); break; case Condition.Pl: value = Inverse(GetFlag(PState.NFlag)); break; case Condition.Vs: value = GetFlag(PState.VFlag); break; case Condition.Vc: value = Inverse(GetFlag(PState.VFlag)); break; case Condition.GtUn: { Operand c = GetFlag(PState.CFlag); Operand z = GetFlag(PState.ZFlag); value = context.BitwiseAnd(c, Inverse(z)); break; } case Condition.LeUn: { Operand c = GetFlag(PState.CFlag); Operand z = GetFlag(PState.ZFlag); value = context.BitwiseOr(Inverse(c), z); break; } case Condition.Ge: { Operand n = GetFlag(PState.NFlag); Operand v = GetFlag(PState.VFlag); value = context.ICompareEqual(n, v); break; } case Condition.Lt: { Operand n = GetFlag(PState.NFlag); Operand v = GetFlag(PState.VFlag); value = context.ICompareNotEqual(n, v); break; } case Condition.Gt: { Operand n = GetFlag(PState.NFlag); Operand z = GetFlag(PState.ZFlag); Operand v = GetFlag(PState.VFlag); value = context.BitwiseAnd(Inverse(z), context.ICompareEqual(n, v)); break; } case Condition.Le: { Operand n = GetFlag(PState.NFlag); Operand z = GetFlag(PState.ZFlag); Operand v = GetFlag(PState.VFlag); value = context.BitwiseOr(z, context.ICompareNotEqual(n, v)); break; } } return(value); }
public static void Vmvn_I(ArmEmitterContext context) { EmitVectorImmUnaryOp32(context, (op1) => context.BitwiseExclusiveOr(op1, op1)); }
public static void Eor(ArmEmitterContext context) { SetAluD(context, context.BitwiseExclusiveOr(GetAluN(context), GetAluM(context))); }