private static void EmitRrxC(ILEmitterCtx context, bool setCarry) { // Rotate right by 1 with carry. if (setCarry) { context.Emit(OpCodes.Dup); context.EmitLdc_I4(1); context.Emit(OpCodes.And); context.EmitSttmp(); } context.EmitLsr(1); context.EmitLdflg((int)PState.CBit); context.EmitLsl(31); context.Emit(OpCodes.Or); if (setCarry) { context.EmitLdtmp(); context.EmitStflg((int)PState.CBit); } }
private static void EmitAsrC(ILEmitterCtx context, bool setCarry, int shift) { if ((uint)shift >= 32) { context.EmitAsr(31); if (setCarry) { context.Emit(OpCodes.Dup); context.EmitLdc_I4(1); context.Emit(OpCodes.And); context.EmitStflg((int)PState.CBit); } } else { if (setCarry) { context.Emit(OpCodes.Dup); context.EmitLsr(shift - 1); context.EmitLdc_I4(1); context.Emit(OpCodes.And); context.EmitStflg((int)PState.CBit); } context.EmitAsr(shift); } }
public static void EmitDataLoadOper2(ILEmitterCtx context) { switch (context.CurrOp) { case IOpCodeAluImm64 op: context.EmitLdc_I(op.Imm); break; case IOpCodeAluRs64 op: context.EmitLdintzr(op.Rm); switch (op.ShiftType) { case ShiftType.Lsl: context.EmitLsl(op.Shift); break; case ShiftType.Lsr: context.EmitLsr(op.Shift); break; case ShiftType.Asr: context.EmitAsr(op.Shift); break; case ShiftType.Ror: context.EmitRor(op.Shift); break; } break; case IOpCodeAluRx64 op: context.EmitLdintzr(op.Rm); context.EmitCast(op.IntType); context.EmitLsl(op.Shift); break; } }
public static void Bfm(ILEmitterCtx context) { OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; if (op.Pos < op.Shift) { //BFI. context.EmitLdintzr(op.Rn); int shift = op.GetBitsCount() - op.Shift; int width = op.Pos + 1; long mask = (long)(ulong.MaxValue >> (64 - width)); context.EmitLdc_I(mask); context.Emit(OpCodes.And); context.EmitLsl(shift); context.EmitLdintzr(op.Rd); context.EmitLdc_I(~(mask << shift)); context.Emit(OpCodes.And); context.Emit(OpCodes.Or); context.EmitStintzr(op.Rd); } else { //BFXIL. context.EmitLdintzr(op.Rn); context.EmitLsr(op.Shift); int width = op.Pos - op.Shift + 1; long mask = (long)(ulong.MaxValue >> (64 - width)); context.EmitLdc_I(mask); context.Emit(OpCodes.And); context.EmitLdintzr(op.Rd); context.EmitLdc_I(~mask); context.Emit(OpCodes.And); context.Emit(OpCodes.Or); context.EmitStintzr(op.Rd); } }
public static void EmitAluLoadOper2(ILEmitterCtx context, bool setCarry = true) { switch (context.CurrOp) { // ARM32. case OpCode32AluImm op: context.EmitLdc_I4(op.Imm); if (op.SetFlags && op.IsRotated) { context.EmitLdc_I4((int)((uint)op.Imm >> 31)); context.EmitStflg((int)PState.CBit); } break; case OpCode32AluRsImm op: EmitLoadRmShiftedByImmediate(context, op, setCarry); break; case OpCodeT16AluImm8 op: context.EmitLdc_I4(op.Imm); break; // ARM64. case IOpCodeAluImm64 op: context.EmitLdc_I(op.Imm); break; case IOpCodeAluRs64 op: context.EmitLdintzr(op.Rm); switch (op.ShiftType) { case ShiftType.Lsl: context.EmitLsl(op.Shift); break; case ShiftType.Lsr: context.EmitLsr(op.Shift); break; case ShiftType.Asr: context.EmitAsr(op.Shift); break; case ShiftType.Ror: context.EmitRor(op.Shift); break; } break; case IOpCodeAluRx64 op: context.EmitLdintzr(op.Rm); context.EmitCast(op.IntType); context.EmitLsl(op.Shift); break; default: throw new InvalidOperationException(); } }
private static void EmitRorC(ILEmitterCtx context, bool setCarry, int shift) { shift &= 0x1f; context.EmitRor(shift); if (setCarry) { context.Emit(OpCodes.Dup); context.EmitLsr(31); context.EmitStflg((int)PState.CBit); } }
private static void EmitLsrC(ILEmitterCtx context, bool setCarry, int shift) { if ((uint)shift > 32) { EmitShiftByMoreThan32(context, setCarry); } else if (shift == 32) { if (setCarry) { context.EmitLsr(31); context.EmitStflg((int)PState.CBit); } else { context.Emit(OpCodes.Pop); } context.EmitLdc_I4(0); } else { context.Emit(OpCodes.Dup); context.EmitLsr(shift - 1); context.EmitLdc_I4(1); context.Emit(OpCodes.And); context.EmitStflg((int)PState.CBit); context.EmitLsr(shift); } }
private static void EmitBfiz(ILEmitterCtx context, bool signed) { OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; int width = op.Pos + 1; context.EmitLdintzr(op.Rn); context.EmitLsl(op.GetBitsCount() - width); if (signed) { context.EmitAsr(op.Shift - width); } else { context.EmitLsr(op.Shift - width); } context.EmitStintzr(op.Rd); }
private static void EmitPtPointerLoad(ILEmitterCtx context, ILLabel lblFallbackPath) { context.EmitLdc_I8(context.Memory.PageTable.ToInt64()); context.Emit(OpCodes.Conv_I); int bit = MemoryManager.PageBits; do { context.EmitLdint(_tempIntAddress); if (context.CurrOp.RegisterSize == RegisterSize.Int32) { context.Emit(OpCodes.Conv_U8); } context.EmitLsr(bit); bit += context.Memory.PtLevelBits; if (bit < context.Memory.AddressSpaceBits) { context.EmitLdc_I8(context.Memory.PtLevelMask); context.Emit(OpCodes.And); } context.EmitLdc_I8(IntPtr.Size); context.Emit(OpCodes.Mul); context.Emit(OpCodes.Conv_I); context.Emit(OpCodes.Add); context.Emit(OpCodes.Ldind_I); }while (bit < context.Memory.AddressSpaceBits); if (!context.Memory.HasWriteWatchSupport) { context.Emit(OpCodes.Conv_U8); context.EmitStint(_tempIntPtAddr); context.EmitLdint(_tempIntPtAddr); context.EmitLdc_I8(MemoryManager.PteFlagsMask); context.Emit(OpCodes.And); context.Emit(OpCodes.Brtrue, lblFallbackPath); context.EmitLdint(_tempIntPtAddr); context.Emit(OpCodes.Conv_I); } context.EmitLdint(_tempIntAddress); context.EmitLdc_I(MemoryManager.PageMask); context.Emit(OpCodes.And); context.Emit(OpCodes.Conv_I); context.Emit(OpCodes.Add); }
private static void EmitLoadOrStore(ILEmitterCtx context, int size, AccessType accType) { OpCode32Mem op = (OpCode32Mem)context.CurrOp; if (op.Index || op.WBack) { EmitLoadFromRegister(context, op.Rn); context.EmitLdc_I4(op.Imm); context.Emit(op.Add ? OpCodes.Add : OpCodes.Sub); context.EmitSttmp(); } if (op.Index) { context.EmitLdtmp(); } else { EmitLoadFromRegister(context, op.Rn); } if ((accType & AccessType.Load) != 0) { if ((accType & AccessType.Signed) != 0) { EmitReadSx32Call(context, size); } else { EmitReadZxCall(context, size); } if (op.WBack) { context.EmitLdtmp(); EmitStoreToRegister(context, op.Rn); } if (size == DWordSizeLog2) { context.Emit(OpCodes.Dup); context.EmitLdflg((int)PState.EBit); ILLabel lblBigEndian = new ILLabel(); ILLabel lblEnd = new ILLabel(); context.Emit(OpCodes.Brtrue_S, lblBigEndian); //Little endian mode. context.Emit(OpCodes.Conv_U4); EmitStoreToRegister(context, op.Rt); context.EmitLsr(32); context.Emit(OpCodes.Conv_U4); EmitStoreToRegister(context, op.Rt | 1); context.Emit(OpCodes.Br_S, lblEnd); //Big endian mode. context.MarkLabel(lblBigEndian); context.EmitLsr(32); context.Emit(OpCodes.Conv_U4); EmitStoreToRegister(context, op.Rt); context.Emit(OpCodes.Conv_U4); EmitStoreToRegister(context, op.Rt | 1); context.MarkLabel(lblEnd); } else { EmitStoreToRegister(context, op.Rt); } } else { if (op.WBack) { context.EmitLdtmp(); EmitStoreToRegister(context, op.Rn); } EmitLoadFromRegister(context, op.Rt); if (size == DWordSizeLog2) { context.Emit(OpCodes.Conv_U8); context.EmitLdflg((int)PState.EBit); ILLabel lblBigEndian = new ILLabel(); ILLabel lblEnd = new ILLabel(); context.Emit(OpCodes.Brtrue_S, lblBigEndian); //Little endian mode. EmitLoadFromRegister(context, op.Rt | 1); context.Emit(OpCodes.Conv_U8); context.EmitLsl(32); context.Emit(OpCodes.Or); context.Emit(OpCodes.Br_S, lblEnd); //Big endian mode. context.MarkLabel(lblBigEndian); context.EmitLsl(32); EmitLoadFromRegister(context, op.Rt | 1); context.Emit(OpCodes.Conv_U8); context.Emit(OpCodes.Or); context.MarkLabel(lblEnd); } EmitWriteCall(context, size); } }
private static void EmitLoad(ILEmitterCtx context, AccessType accType, bool pair) { OpCodeMemEx64 op = (OpCodeMemEx64)context.CurrOp; bool ordered = (accType & AccessType.Ordered) != 0; bool exclusive = (accType & AccessType.Exclusive) != 0; if (ordered) { EmitBarrier(context); } context.EmitLdint(op.Rn); context.EmitSttmp(); if (exclusive) { context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdtmp(); context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.SetExclusiveAddress)); } void WriteExclusiveValue(string propName) { if (op.Size < 3) { context.Emit(OpCodes.Conv_U8); } context.EmitSttmp2(); context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdtmp2(); context.EmitCallPrivatePropSet(typeof(CpuThreadState), propName); context.EmitLdtmp2(); if (op.Size < 3) { context.Emit(OpCodes.Conv_U4); } } if (pair) { //Exclusive loads should be atomic. For pairwise loads, we need to //read all the data at once. For a 32-bits pairwise load, we do a //simple 64-bits load, for a 128-bits load, we need to call a special //method to read 128-bits atomically. if (op.Size == 2) { context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); EmitReadZxCall(context, 3); context.Emit(OpCodes.Dup); //Mask low half. context.Emit(OpCodes.Conv_U4); if (exclusive) { WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow)); } context.EmitStintzr(op.Rt); //Shift high half. context.EmitLsr(32); context.Emit(OpCodes.Conv_U4); if (exclusive) { WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueHigh)); } context.EmitStintzr(op.Rt2); } else if (op.Size == 3) { context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicReadInt128)); context.Emit(OpCodes.Dup); //Load low part of the vector. context.EmitLdc_I4(0); context.EmitLdc_I4(3); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractIntZx)); if (exclusive) { WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow)); } context.EmitStintzr(op.Rt); //Load high part of the vector. context.EmitLdc_I4(1); context.EmitLdc_I4(3); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractIntZx)); if (exclusive) { WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueHigh)); } context.EmitStintzr(op.Rt2); } else { throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes."); } } else { //8, 16, 32 or 64-bits (non-pairwise) load. context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); EmitReadZxCall(context, op.Size); if (exclusive) { WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow)); } context.EmitStintzr(op.Rt); } }