public static void EmitGenericAluStoreA32(ArmEmitterContext context, int rd, bool setFlags, Operand value) { Debug.Assert(value.Type == OperandType.I32); if (rd == RegisterAlias.Aarch32Pc && setFlags) { if (setFlags) { // TODO: Load SPSR etc. Operand isThumb = GetFlag(PState.TFlag); Operand lblThumb = Label(); context.BranchIfTrue(lblThumb, isThumb); // Make this count as a call, the translator will ignore the low bit for the address. context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseOr(context.BitwiseAnd(value, Const(~3)), Const(1)))); context.MarkLabel(lblThumb); context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseOr(value, Const(1)))); } else { EmitAluWritePc(context, value); } } else { SetIntA32(context, rd, value); } }
private static Operand EmitReverseBits8Op(ArmEmitterContext context, Operand op) { Debug.Assert(op.Type == OperandType.I64); Operand val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xaaul)), Const(1)), context.ShiftLeft(context.BitwiseAnd(op, Const(0x55ul)), Const(1))); val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xccul)), Const(2)), context.ShiftLeft(context.BitwiseAnd(val, Const(0x33ul)), Const(2))); return(context.BitwiseOr(context.ShiftRightUI(val, Const(4)), context.ShiftLeft(context.BitwiseAnd(val, Const(0x0ful)), Const(4)))); }
private static void EmitGetNzcv(ArmEmitterContext context) { OpCodeSystem op = (OpCodeSystem)context.CurrOp; Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)); Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)); Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)); Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); SetIntOrZR(context, op.Rt, nzcvSh); }
public static void Vrev(ArmEmitterContext context) { OpCode32Simd op = (OpCode32Simd)context.CurrOp; EmitVectorUnaryOpZx32(context, (op1) => { switch (op.Opc) { case 0: switch (op.Size) // Swap bytes. { default: return(op1); case 1: return(InstEmitAluHelper.EmitReverseBytes16_32Op(context, op1)); case 2: case 3: return(context.ByteSwap(op1)); } case 1: switch (op.Size) { default: return(op1); case 2: return(context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff0000)), Const(16)), context.ShiftLeft(context.BitwiseAnd(op1, Const(0x0000ffff)), Const(16)))); case 3: return(context.BitwiseOr( context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff000000000000ul)), Const(48)), context.ShiftLeft(context.BitwiseAnd(op1, Const(0x000000000000fffful)), Const(48))), context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0x0000ffff00000000ul)), Const(16)), context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000ffff0000ul)), Const(16))))); } case 2: // Swap upper and lower halves. return(context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffffffff00000000ul)), Const(32)), context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000fffffffful)), Const(32)))); } return(op1); }); }
private static void EmitGetFpscr(ArmEmitterContext context) { OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; Operand vSh = context.ShiftLeft(GetFpFlag(FPState.VFlag), Const((int)FPState.VFlag)); Operand cSh = context.ShiftLeft(GetFpFlag(FPState.CFlag), Const((int)FPState.CFlag)); Operand zSh = context.ShiftLeft(GetFpFlag(FPState.ZFlag), Const((int)FPState.ZFlag)); Operand nSh = context.ShiftLeft(GetFpFlag(FPState.NFlag), Const((int)FPState.NFlag)); Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); Operand fpscr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); SetIntA32(context, op.Rt, context.BitwiseOr(nzcvSh, fpscr)); }
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 Orr_Vi(ArmEmitterContext context) { if (Optimizations.UseSse2) { OpCodeSimdImm op = (OpCodeSimdImm)context.CurrOp; int eSize = 8 << op.Size; Operand d = GetVec(op.Rd); Operand imm = eSize switch { 16 => X86GetAllElements(context, (short)op.Immediate), 32 => X86GetAllElements(context, (int)op.Immediate), _ => throw new InvalidOperationException($"Invalid element size {eSize}.") }; Operand res = context.AddIntrinsic(Intrinsic.X86Por, d, imm); if (op.RegisterSize == RegisterSize.Simd64) { res = context.VectorZeroUpper64(res); } context.Copy(GetVec(op.Rd), res); } else { EmitVectorImmBinaryOp(context, (op1, op2) => context.BitwiseOr(op1, op2)); } }
public static void EmitTailContinue(ArmEmitterContext context, Operand address, bool allowRejit = false) { // Left option here as it may be useful if we need to return to managed rather than tail call in future. // (eg. for debug) bool useTailContinue = true; if (useTailContinue) { if (context.HighCq) { // If we're doing a tail continue in HighCq, reserve a space in the jump table to avoid calling back // to the translator. This will always try to get a HighCq version of our continue target as well. EmitJumpTableBranch(context, address, true); } else { if (allowRejit) { address = context.BitwiseOr(address, Const(CallFlag)); } Operand fallbackAddr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), address); EmitNativeCall(context, fallbackAddr, true); } } else { context.Return(address); } }
public static void Extr(ArmEmitterContext context) { OpCodeAluRs op = (OpCodeAluRs)context.CurrOp; Operand res = GetIntOrZR(context, op.Rm); if (op.Shift != 0) { if (op.Rn == op.Rm) { res = context.RotateRight(res, Const(op.Shift)); } else { res = context.ShiftRightUI(res, Const(op.Shift)); Operand n = GetIntOrZR(context, op.Rn); int invShift = op.GetBitsCount() - op.Shift; res = context.BitwiseOr(res, context.ShiftLeft(n, Const(invShift))); } } SetAluDOrZR(context, res); }
private static void EmitBranchFallback(ArmEmitterContext context, Operand address, bool isJump) { address = context.BitwiseOr(address, Const(address.Type, (long)CallFlag)); // Set call flag. Operand fallbackAddr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), address); EmitNativeCall(context, fallbackAddr, isJump); }
public static Operand EmitReverseBits32Op(ArmEmitterContext context, Operand op) { Debug.Assert(op.Type == OperandType.I32); Operand val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xaaaaaaaau)), Const(1)), context.ShiftLeft(context.BitwiseAnd(op, Const(0x55555555u)), Const(1))); val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xccccccccu)), Const(2)), context.ShiftLeft(context.BitwiseAnd(val, Const(0x33333333u)), Const(2))); val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xf0f0f0f0u)), Const(4)), context.ShiftLeft(context.BitwiseAnd(val, Const(0x0f0f0f0fu)), Const(4))); val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xff00ff00u)), Const(8)), context.ShiftLeft(context.BitwiseAnd(val, Const(0x00ff00ffu)), Const(8))); return(context.BitwiseOr(context.ShiftRightUI(val, Const(16)), context.ShiftLeft(val, Const(16)))); }
public static void Sli_V(ArmEmitterContext context) { OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; Operand res = context.VectorZero(); int elems = op.GetBytesCount() >> op.Size; int shift = GetImmShl(op); ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0; for (int index = 0; index < elems; index++) { Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); Operand neShifted = context.ShiftLeft(ne, Const(shift)); Operand de = EmitVectorExtractZx(context, op.Rd, index, op.Size); Operand deMasked = context.BitwiseAnd(de, Const(mask)); Operand e = context.BitwiseOr(neShifted, deMasked); res = EmitVectorInsert(context, res, e, index, op.Size); } context.Copy(GetVec(op.Rd), res); }
public static Operand EmitAsrC(ArmEmitterContext context, Operand m, bool setCarry, Operand shift, Operand shiftIsZero) { Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32 && shiftIsZero.Type == OperandType.I32); Operand l32Result; Operand ge32Result; Operand less32 = context.ICompareLess(shift, Const(32)); ge32Result = context.ShiftRightSI(m, Const(31)); if (setCarry) { EmitIfHelper(context, context.BitwiseOr(less32, shiftIsZero), () => { SetCarryMLsb(context, ge32Result); }, false); } l32Result = context.ShiftRightSI(m, shift); if (setCarry) { EmitIfHelper(context, context.BitwiseAnd(less32, context.BitwiseNot(shiftIsZero)), () => { Operand cOut = context.ShiftRightUI(m, context.Subtract(shift, Const(1))); cOut = context.BitwiseAnd(cOut, Const(1)); SetFlag(context, PState.CFlag, cOut); }); } return(context.ConditionalSelect(less32, l32Result, ge32Result)); }
public static void Vmov_GD(ArmEmitterContext context) { OpCode32SimdMovGpDouble op = (OpCode32SimdMovGpDouble)context.CurrOp; Operand vec = GetVecA32(op.Vm >> 1); if (op.Op == 1) { // To general purpose. Operand value = context.VectorExtract(OperandType.I64, vec, op.Vm & 1); SetIntA32(context, op.Rt, context.ConvertI64ToI32(value)); SetIntA32(context, op.Rt2, context.ConvertI64ToI32(context.ShiftRightUI(value, Const(32)))); } else { // From general purpose. Operand lowValue = GetIntA32(context, op.Rt); Operand highValue = GetIntA32(context, op.Rt2); Operand value = context.BitwiseOr( context.ZeroExtend32(OperandType.I64, lowValue), context.ShiftLeft(context.ZeroExtend32(OperandType.I64, highValue), Const(32))); context.Copy(vec, context.VectorInsert(vec, value, op.Vm & 1)); } }
public static Operand EmitReverseBytes16_64Op(ArmEmitterContext context, Operand op) { Debug.Assert(op.Type == OperandType.I64); return(context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xff00ff00ff00ff00ul)), Const(8)), context.ShiftLeft(context.BitwiseAnd(op, Const(0x00ff00ff00ff00fful)), Const(8)))); }
public static void Orn_V(ArmEmitterContext context) { if (Optimizations.UseSse2) { OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; Operand n = GetVec(op.Rn); Operand m = GetVec(op.Rm); Operand mask = X86GetAllElements(context, -1L); Operand res = context.AddIntrinsic(Intrinsic.X86Pandn, m, mask); res = context.AddIntrinsic(Intrinsic.X86Por, res, n); if (op.RegisterSize == RegisterSize.Simd64) { res = context.VectorZeroUpper64(res); } context.Copy(GetVec(op.Rd), res); } else { EmitVectorBinaryOpZx(context, (op1, op2) => { return(context.BitwiseOr(op1, context.BitwiseNot(op2))); }); } }
public static void EmitBxWritePc(ArmEmitterContext context, Operand pc) { Operand mode = context.BitwiseAnd(pc, Const(1)); SetFlag(context, PState.TFlag, mode); Operand lblArmMode = Label(); context.BranchIfTrue(lblArmMode, mode); // Make this count as a call, the translator will ignore the low bit for the address. context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseOr(pc, Const((int)InstEmitFlowHelper.CallFlag)))); context.MarkLabel(lblArmMode); context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseOr(context.BitwiseAnd(pc, Const(~3)), Const((int)InstEmitFlowHelper.CallFlag)))); }
public static void EmitDynamicTableCall(ArmEmitterContext context, Operand tableAddress, Operand address, bool isJump) { // Loop over elements of the dynamic table. Unrolled loop. Operand endLabel = Label(); Operand fallbackLabel = Label(); void EmitTableEntry(Operand entrySkipLabel) { // Try to take this entry in the table if its guest address equals 0. Operand gotResult = context.CompareAndSwap(tableAddress, Const(0L), address); // Is the address ours? (either taken via CompareAndSwap (0), or what was already here) context.BranchIfFalse(entrySkipLabel, context.BitwiseOr( context.ICompareEqual(gotResult, address), context.ICompareEqual(gotResult, Const(0L))) ); // It's ours, so what function is it pointing to? Operand targetFunctionPtr = context.Add(tableAddress, Const(8L)); Operand targetFunction = context.Load(OperandType.I64, targetFunctionPtr); // Call the function. // We pass in the entry address as the guest address, as the entry may need to be updated by the // indirect call stub. EmitNativeCallWithGuestAddress(context, targetFunction, tableAddress, isJump); context.Branch(endLabel); } // Currently this uses a size of 1, as higher values inflate code size for no real benefit. for (int i = 0; i < JumpTable.DynamicTableElems; i++) { if (i == JumpTable.DynamicTableElems - 1) { // If this is the last entry, avoid emitting the additional label and add. EmitTableEntry(fallbackLabel); } else { Operand nextLabel = Label(); EmitTableEntry(nextLabel); context.MarkLabel(nextLabel); // Move to the next table entry. tableAddress = context.Add(tableAddress, Const((long)JumpTable.JumpTableStride)); } } context.MarkLabel(fallbackLabel); EmitBranchFallback(context, address, isJump); context.MarkLabel(endLabel); }
private static Operand EmitReverseBytes32_64Op(ArmEmitterContext context, Operand op) { Debug.Assert(op.Type == OperandType.I64); Operand val = EmitReverseBytes16_64Op(context, op); return(context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xffff0000ffff0000ul)), Const(16)), context.ShiftLeft(context.BitwiseAnd(val, Const(0x0000ffff0000fffful)), Const(16)))); }
public static void Orn(ArmEmitterContext context) { Operand n = GetAluN(context); Operand m = GetAluM(context); Operand d = context.BitwiseOr(n, context.BitwiseNot(m)); SetAluD(context, d); }
private static void EmitExtend16(ArmEmitterContext context, bool signed) { IOpCode32AluUx op = (IOpCode32AluUx)context.CurrOp; Operand m = GetAluM(context); Operand res; if (op.RotateBits == 0) { res = m; } else { Operand rotate = Const(op.RotateBits); res = context.RotateRight(m, rotate); } Operand low16, high16; if (signed) { low16 = context.SignExtend8(OperandType.I32, res); high16 = context.SignExtend8(OperandType.I32, context.ShiftRightUI(res, Const(16))); } else { low16 = context.ZeroExtend8(OperandType.I32, res); high16 = context.ZeroExtend8(OperandType.I32, context.ShiftRightUI(res, Const(16))); } if (op.Add) { Operand n = GetAluN(context); Operand lowAdd, highAdd; if (signed) { lowAdd = context.SignExtend16(OperandType.I32, n); highAdd = context.SignExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16))); } else { lowAdd = context.ZeroExtend16(OperandType.I32, n); highAdd = context.ZeroExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16))); } low16 = context.Add(low16, lowAdd); high16 = context.Add(high16, highAdd); } res = context.BitwiseOr( context.ZeroExtend16(OperandType.I32, low16), context.ShiftLeft(context.ZeroExtend16(OperandType.I32, high16), Const(16))); EmitAluStore(context, res); }
private static void EmitSri(ArmEmitterContext context, bool scalar) { OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; int shift = GetImmShr(op); int eSize = 8 << op.Size; ulong mask = (ulong.MaxValue << (eSize - shift)) & (ulong.MaxValue >> (64 - eSize)); if (Optimizations.UseSse2 && op.Size > 0) { Operand d = GetVec(op.Rd); Operand n = GetVec(op.Rn); Intrinsic srlInst = X86PsrlInstruction[op.Size]; Operand nShifted = context.AddIntrinsic(srlInst, n, Const(shift)); Operand dMask = X86GetAllElements(context, (long)mask * _masks_SliSri[op.Size]); Operand dMasked = context.AddIntrinsic(Intrinsic.X86Pand, d, dMask); Operand res = context.AddIntrinsic(Intrinsic.X86Por, nShifted, dMasked); if ((op.RegisterSize == RegisterSize.Simd64) || scalar) { res = context.VectorZeroUpper64(res); } context.Copy(d, res); } else { Operand res = context.VectorZero(); int elems = !scalar?op.GetBytesCount() >> op.Size : 1; for (int index = 0; index < elems; index++) { Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); Operand neShifted = shift != 64 ? context.ShiftRightUI(ne, Const(shift)) : Const(0UL); Operand de = EmitVectorExtractZx(context, op.Rd, index, op.Size); Operand deMasked = context.BitwiseAnd(de, Const(mask)); Operand e = context.BitwiseOr(neShifted, deMasked); res = EmitVectorInsert(context, res, e, index, op.Size); } context.Copy(GetVec(op.Rd), res); } }
public static void EmitAdcsCCheck(ArmEmitterContext context, Operand n, Operand d) { // C = (Rd == Rn && CIn) || Rd < Rn Operand cIn = GetFlag(PState.CFlag); Operand cOut = context.BitwiseAnd(context.ICompareEqual(d, n), cIn); cOut = context.BitwiseOr(cOut, context.ICompareLessUI(d, n)); SetFlag(context, PState.CFlag, cOut); }
public static void EmitBxWritePc(ArmEmitterContext context, Operand pc, int sourceRegister = 0) { bool isReturn = sourceRegister == RegisterAlias.Aarch32Lr || IsA32Return(context); Operand mode = context.BitwiseAnd(pc, Const(1)); SetFlag(context, PState.TFlag, mode); Operand addr = context.ConditionalSelect(mode, context.BitwiseOr(pc, Const((int)InstEmitFlowHelper.CallFlag)), context.BitwiseAnd(pc, Const(~3))); InstEmitFlowHelper.EmitVirtualJump(context, addr, isReturn); }
public static void EmitSbcsCCheck(ArmEmitterContext context, Operand n, Operand m) { // C = (Rn == Rm && CIn) || Rn > Rm Operand cIn = GetFlag(PState.CFlag); Operand cOut = context.BitwiseAnd(context.ICompareEqual(n, m), cIn); cOut = context.BitwiseOr(cOut, context.ICompareGreaterUI(n, m)); SetFlag(context, PState.CFlag, cOut); }
public static void Vorr_I(ArmEmitterContext context) { if (Optimizations.UseSse2) { EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Por, n, m)); } else { EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseOr(op1, op2)); } }
public static void Movt(ArmEmitterContext context) { OpCode32AluImm16 op = (OpCode32AluImm16)context.CurrOp; Operand d = GetIntA32(context, op.Rd); Operand imm = Const(op.Immediate << 16); // Immeditate value as top halfword. Operand res = context.BitwiseAnd(d, Const(0x0000ffff)); res = context.BitwiseOr(res, imm); EmitAluStore(context, res); }
private static Operand EmitShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size, bool unsigned) { if (shiftLsB.Type == OperandType.I64) { shiftLsB = context.ConvertI64ToI32(shiftLsB); } shiftLsB = context.SignExtend8(OperandType.I32, shiftLsB); Debug.Assert((uint)size < 4u); Operand negShiftLsB = context.Negate(shiftLsB); Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0)); Operand shl = context.ShiftLeft(op, shiftLsB); Operand shr = unsigned ? context.ShiftRightUI(op, negShiftLsB) : context.ShiftRightSI(op, negShiftLsB); Operand res = context.ConditionalSelect(isPositive, shl, shr); if (unsigned) { Operand isOutOfRange = context.BitwiseOr( context.ICompareGreaterOrEqual(shiftLsB, Const(8 << size)), context.ICompareGreaterOrEqual(negShiftLsB, Const(8 << size))); return(context.ConditionalSelect(isOutOfRange, Const(op.Type, 0), res)); } else { Operand isOutOfRange0 = context.ICompareGreaterOrEqual(shiftLsB, Const(8 << size)); Operand isOutOfRangeN = context.ICompareGreaterOrEqual(negShiftLsB, Const(8 << size)); // Also zero if shift is too negative, but value was positive. isOutOfRange0 = context.BitwiseOr(isOutOfRange0, context.BitwiseAnd(isOutOfRangeN, context.ICompareGreaterOrEqual(op, Const(op.Type, 0)))); Operand min = (op.Type == OperandType.I64) ? Const(-1L) : Const(-1); return(context.ConditionalSelect(isOutOfRange0, Const(op.Type, 0), context.ConditionalSelect(isOutOfRangeN, min, res))); } }
public static void Pkh(ArmEmitterContext context) { OpCode32AluRsImm op = (OpCode32AluRsImm)context.CurrOp; Operand n = GetAluN(context); Operand m = GetAluM(context); Operand res; bool tbform = op.ShiftType == ShiftType.Asr; if (tbform) { res = context.BitwiseOr(context.BitwiseAnd(n, Const(0xFFFF0000)), context.BitwiseAnd(m, Const(0xFFFF))); } else { res = context.BitwiseOr(context.BitwiseAnd(m, Const(0xFFFF0000)), context.BitwiseAnd(n, Const(0xFFFF))); } EmitAluStore(context, res); }
public static void Bfm(ArmEmitterContext context) { OpCodeBfm op = (OpCodeBfm)context.CurrOp; Operand d = GetIntOrZR(context, op.Rd); Operand n = GetIntOrZR(context, op.Rn); Operand res; if (op.Pos < op.Shift) { // BFI. int shift = op.GetBitsCount() - op.Shift; int width = op.Pos + 1; long mask = (long)(ulong.MaxValue >> (64 - width)); res = context.ShiftLeft(context.BitwiseAnd(n, Const(n.Type, mask)), Const(shift)); res = context.BitwiseOr(res, context.BitwiseAnd(d, Const(d.Type, ~(mask << shift)))); } else { // BFXIL. int shift = op.Shift; int width = op.Pos - shift + 1; long mask = (long)(ulong.MaxValue >> (64 - width)); res = context.BitwiseAnd(context.ShiftRightUI(n, Const(shift)), Const(n.Type, mask)); res = context.BitwiseOr(res, context.BitwiseAnd(d, Const(d.Type, ~mask))); } SetIntOrZR(context, op.Rd, res); }