private static void EmitSat(ArmEmitterContext context, int intMin, int intMax) { OpCode32Sat op = (OpCode32Sat)context.CurrOp; Operand n = GetIntA32(context, op.Rn); int shift = DecodeImmShift(op.ShiftType, op.Imm5); switch (op.ShiftType) { case ShiftType.Lsl: if (shift == 32) { n = Const(0); } else { n = context.ShiftLeft(n, Const(shift)); } break; case ShiftType.Asr: if (shift == 32) { n = context.ShiftRightSI(n, Const(31)); } else { n = context.ShiftRightSI(n, Const(shift)); } break; } Operand lblCheckLtIntMin = Label(); Operand lblNoSat = Label(); Operand lblEnd = Label(); context.BranchIfFalse(lblCheckLtIntMin, context.ICompareGreater(n, Const(intMax))); SetFlag(context, PState.QFlag, Const(1)); SetIntA32(context, op.Rd, Const(intMax)); context.Branch(lblEnd); context.MarkLabel(lblCheckLtIntMin); context.BranchIfFalse(lblNoSat, context.ICompareLess(n, Const(intMin))); SetFlag(context, PState.QFlag, Const(1)); SetIntA32(context, op.Rd, Const(intMin)); context.Branch(lblEnd); context.MarkLabel(lblNoSat); SetIntA32(context, op.Rd, n); context.MarkLabel(lblEnd); }
private static void EmitDiv(ArmEmitterContext context, bool unsigned) { OpCodeAluBinary op = (OpCodeAluBinary)context.CurrOp; // If Rm == 0, Rd = 0 (division by zero). Operand n = GetIntOrZR(context, op.Rn); Operand m = GetIntOrZR(context, op.Rm); Operand divisorIsZero = context.ICompareEqual(m, Const(m.Type, 0)); Operand lblBadDiv = Label(); Operand lblEnd = Label(); context.BranchIfTrue(lblBadDiv, divisorIsZero); if (!unsigned) { // If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow). bool is32Bits = op.RegisterSize == RegisterSize.Int32; Operand intMin = is32Bits ? Const(int.MinValue) : Const(long.MinValue); Operand minus1 = is32Bits ? Const(-1) : Const(-1L); Operand nIsIntMin = context.ICompareEqual(n, intMin); Operand mIsMinus1 = context.ICompareEqual(m, minus1); Operand lblGoodDiv = Label(); context.BranchIfFalse(lblGoodDiv, context.BitwiseAnd(nIsIntMin, mIsMinus1)); SetAluDOrZR(context, intMin); context.Branch(lblEnd); context.MarkLabel(lblGoodDiv); } Operand d = unsigned ? context.DivideUI(n, m) : context.Divide(n, m); SetAluDOrZR(context, d); context.Branch(lblEnd); context.MarkLabel(lblBadDiv); SetAluDOrZR(context, Const(op.GetOperandType(), 0)); context.MarkLabel(lblEnd); }
private static void EmitSat16(ArmEmitterContext context, int intMin, int intMax) { OpCode32Sat16 op = (OpCode32Sat16)context.CurrOp; void SetD(int part, Operand value) { if (part == 0) { SetIntA32(context, op.Rd, context.ZeroExtend16(OperandType.I32, value)); } else { SetIntA32(context, op.Rd, context.BitwiseOr(GetIntA32(context, op.Rd), context.ShiftLeft(value, Const(16)))); } } Operand n = GetIntA32(context, op.Rn); Operand nLow = context.SignExtend16(OperandType.I32, n); Operand nHigh = context.ShiftRightSI(n, Const(16)); for (int part = 0; part < 2; part++) { Operand nPart = part == 0 ? nLow : nHigh; Operand lblCheckLtIntMin = Label(); Operand lblNoSat = Label(); Operand lblEnd = Label(); context.BranchIfFalse(lblCheckLtIntMin, context.ICompareGreater(nPart, Const(intMax))); SetFlag(context, PState.QFlag, Const(1)); SetD(part, Const(intMax)); context.Branch(lblEnd); context.MarkLabel(lblCheckLtIntMin); context.BranchIfFalse(lblNoSat, context.ICompareLess(nPart, Const(intMin))); SetFlag(context, PState.QFlag, Const(1)); SetD(part, Const(intMin)); context.Branch(lblEnd); context.MarkLabel(lblNoSat); SetD(part, nPart); context.MarkLabel(lblEnd); } }
public static void EmitDiv(ArmEmitterContext context, bool unsigned) { Operand n = GetAluN(context); Operand m = GetAluM(context); Operand zero = Const(m.Type, 0); Operand divisorIsZero = context.ICompareEqual(m, zero); Operand lblBadDiv = Label(); Operand lblEnd = Label(); context.BranchIfTrue(lblBadDiv, divisorIsZero); if (!unsigned) { // ARM64 behaviour: If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow). // TODO: tests to ensure A32 works the same Operand intMin = Const(int.MinValue); Operand minus1 = Const(-1); Operand nIsIntMin = context.ICompareEqual(n, intMin); Operand mIsMinus1 = context.ICompareEqual(m, minus1); Operand lblGoodDiv = Label(); context.BranchIfFalse(lblGoodDiv, context.BitwiseAnd(nIsIntMin, mIsMinus1)); EmitAluStore(context, intMin); context.Branch(lblEnd); context.MarkLabel(lblGoodDiv); } Operand res = unsigned ? context.DivideUI(n, m) : context.Divide(n, m); EmitAluStore(context, res); context.Branch(lblEnd); context.MarkLabel(lblBadDiv); EmitAluStore(context, zero); context.MarkLabel(lblEnd); }
public static void Fcsel_S(ArmEmitterContext context) { OpCodeSimdFcond op = (OpCodeSimdFcond)context.CurrOp; Operand lblTrue = Label(); Operand lblEnd = Label(); Operand isTrue = InstEmitFlowHelper.GetCondTrue(context, op.Cond); context.BranchIfTrue(lblTrue, isTrue); OperandType type = op.Size == 0 ? OperandType.FP32 : OperandType.FP64; Operand me = context.VectorExtract(type, GetVec(op.Rm), 0); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), me, 0)); context.Branch(lblEnd); context.MarkLabel(lblTrue); Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), ne, 0)); context.MarkLabel(lblEnd); }
private static void EmitReadInt(ArmEmitterContext context, Operand address, int rt, int size) { Operand lblSlowPath = Label(); Operand lblEnd = Label(); Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size); Operand value = default; switch (size) { case 0: value = context.Load8(physAddr); break; case 1: value = context.Load16(physAddr); break; case 2: value = context.Load(OperandType.I32, physAddr); break; case 3: value = context.Load(OperandType.I64, physAddr); break; } SetInt(context, rt, value); if (!context.Memory.Type.IsHostMapped()) { context.Branch(lblEnd); context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); EmitReadIntFallback(context, address, rt, size); context.MarkLabel(lblEnd); } }
private static void EmitReadInt(ArmEmitterContext context, Operand address, int rt, int size) { Operand lblSlowPath = Label(); Operand lblEnd = Label(); Operand isUnalignedAddr = EmitAddressCheck(context, address, size); context.BranchIfTrue(lblSlowPath, isUnalignedAddr); Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false); Operand value = null; switch (size) { case 0: value = context.Load8(physAddr); break; case 1: value = context.Load16(physAddr); break; case 2: value = context.Load(OperandType.I32, physAddr); break; case 3: value = context.Load(OperandType.I64, physAddr); break; } SetInt(context, rt, value); context.Branch(lblEnd); context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); EmitReadIntFallback(context, address, rt, size); context.MarkLabel(lblEnd); }
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 void EmitReadVector( ArmEmitterContext context, Operand address, Operand vector, int rt, int elem, int size) { Operand isUnalignedAddr = EmitAddressCheck(context, address, size); Operand lblFastPath = Label(); Operand lblSlowPath = Label(); Operand lblEnd = Label(); context.BranchIfFalse(lblFastPath, isUnalignedAddr); context.MarkLabel(lblSlowPath); EmitReadVectorFallback(context, address, vector, rt, elem, size); context.Branch(lblEnd); context.MarkLabel(lblFastPath); Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath); Operand value = null; switch (size) { case 0: value = context.VectorInsert8(vector, context.Load8(physAddr), elem); break; case 1: value = context.VectorInsert16(vector, context.Load16(physAddr), elem); break; case 2: value = context.VectorInsert(vector, context.Load(OperandType.I32, physAddr), elem); break; case 3: value = context.VectorInsert(vector, context.Load(OperandType.I64, physAddr), elem); break; case 4: value = context.Load(OperandType.V128, physAddr); break; } context.Copy(GetVec(rt), value); context.MarkLabel(lblEnd); }
public static void EmitCondBranch(ArmEmitterContext context, Operand target, Condition cond) { if (cond != Condition.Al) { context.BranchIfTrue(target, GetCondTrue(context, cond)); } else { context.Branch(target); } }
private static void EmitWriteVector( ArmEmitterContext context, Operand address, int rt, int elem, int size) { Operand isUnalignedAddr = EmitAddressCheck(context, address, size); Operand lblFastPath = Label(); Operand lblSlowPath = Label(); Operand lblEnd = Label(); context.BranchIfFalse(lblFastPath, isUnalignedAddr); context.MarkLabel(lblSlowPath); EmitWriteVectorFallback(context, address, rt, elem, size); context.Branch(lblEnd); context.MarkLabel(lblFastPath); Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath); Operand value = GetVec(rt); switch (size) { case 0: context.Store8(physAddr, context.VectorExtract8(value, elem)); break; case 1: context.Store16(physAddr, context.VectorExtract16(value, elem)); break; case 2: context.Store(physAddr, context.VectorExtract(OperandType.FP32, value, elem)); break; case 3: context.Store(physAddr, context.VectorExtract(OperandType.FP64, value, elem)); break; case 4: context.Store(physAddr, value); break; } context.MarkLabel(lblEnd); }
public static void B(ArmEmitterContext context) { OpCodeBImmAl op = (OpCodeBImmAl)context.CurrOp; if (context.CurrBlock.Branch != null) { context.Branch(context.GetLabel((ulong)op.Immediate)); } else { EmitTailContinue(context, Const(op.Immediate), context.CurrBlock.TailCall); } }
public static void B(ArmEmitterContext context) { OpCodeBImmAl op = (OpCodeBImmAl)context.CurrOp; if (context.CurrBlock.Branch != null) { context.Branch(context.GetLabel((ulong)op.Immediate)); } else { context.Return(Const(op.Immediate)); } }
public static void EmitCall(ArmEmitterContext context, ulong immediate) { bool isRecursive = immediate == context.EntryAddress; if (isRecursive) { context.Branch(context.GetLabel(immediate)); } else { EmitTableBranch(context, Const(immediate), isJump: false); } }
public static void B(ArmEmitterContext context) { IOpCode32BImm op = (IOpCode32BImm)context.CurrOp; if (context.CurrBlock.Branch != null) { context.Branch(context.GetLabel((ulong)op.Immediate)); } else { context.StoreToContext(); context.Return(Const(op.Immediate)); } }
public static void EmitCall(ArmEmitterContext context, ulong immediate) { bool isRecursive = immediate == context.EntryAddress; if (isRecursive) { context.Branch(context.GetLabel(immediate)); } else { Operand address = !context.HasTtc ? Const(immediate) : Const(immediate, new Symbol(SymbolType.DynFunc, context.GetOffset(immediate))); EmitTableBranch(context, address, isJump: false); } }
private static void EmitFccmpOrFccmpe(ArmEmitterContext context, bool signalNaNs) { OpCodeSimdFcond op = (OpCodeSimdFcond)context.CurrOp; Operand lblTrue = Label(); Operand lblEnd = Label(); context.BranchIfTrue(lblTrue, InstEmitFlowHelper.GetCondTrue(context, op.Cond)); EmitSetNzcv(context, op.Nzcv); context.Branch(lblEnd); context.MarkLabel(lblTrue); EmitFcmpOrFcmpe(context, signalNaNs); context.MarkLabel(lblEnd); }
private static void EmitCcmp(ArmEmitterContext context, bool isNegated) { OpCodeCcmp op = (OpCodeCcmp)context.CurrOp; Operand lblTrue = Label(); Operand lblEnd = Label(); EmitCondBranch(context, lblTrue, op.Cond); SetFlag(context, PState.VFlag, Const((op.Nzcv >> 0) & 1)); SetFlag(context, PState.CFlag, Const((op.Nzcv >> 1) & 1)); SetFlag(context, PState.ZFlag, Const((op.Nzcv >> 2) & 1)); SetFlag(context, PState.NFlag, Const((op.Nzcv >> 3) & 1)); context.Branch(lblEnd); context.MarkLabel(lblTrue); Operand n = GetAluN(context); Operand m = GetAluM(context); if (isNegated) { Operand d = context.Add(n, m); EmitNZFlagsCheck(context, d); EmitAddsCCheck(context, n, d); EmitAddsVCheck(context, n, m, d); } else { Operand d = context.Subtract(n, m); EmitNZFlagsCheck(context, d); EmitSubsCCheck(context, n, m); EmitSubsVCheck(context, n, m, d); } context.MarkLabel(lblEnd); }
private static void EmitDVectorStore(ArmEmitterContext context, Operand address, int vecD) { int vecQ = vecD >> 1; int vecSElem = (vecD & 1) << 1; Operand lblBigEndian = Label(); Operand lblEnd = Label(); context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); EmitStoreSimd(context, address, vecQ, vecSElem, WordSizeLog2); EmitStoreSimd(context, context.Add(address, Const(4)), vecQ, vecSElem | 1, WordSizeLog2); context.Branch(lblEnd); context.MarkLabel(lblBigEndian); EmitStoreSimd(context, address, vecQ, vecSElem | 1, WordSizeLog2); EmitStoreSimd(context, context.Add(address, Const(4)), vecQ, vecSElem, WordSizeLog2); context.MarkLabel(lblEnd); }
private static void EmitWriteInt(ArmEmitterContext context, Operand address, int rt, int size) { Operand isUnalignedAddr = EmitAddressCheck(context, address, size); Operand lblFastPath = Label(); Operand lblSlowPath = Label(); Operand lblEnd = Label(); context.BranchIfFalse(lblFastPath, isUnalignedAddr); context.MarkLabel(lblSlowPath); EmitWriteIntFallback(context, address, rt, size); context.Branch(lblEnd); context.MarkLabel(lblFastPath); Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath); Operand value = GetInt(context, rt); if (size < 3 && value.Type == OperandType.I64) { value = context.ConvertI64ToI32(value); } switch (size) { case 0: context.Store8(physAddr, value); break; case 1: context.Store16(physAddr, value); break; case 2: context.Store(physAddr, value); break; case 3: context.Store(physAddr, value); break; } context.MarkLabel(lblEnd); }
private static void EmitExLoadOrStore(ArmEmitterContext context, int size, AccessType accType) { IOpCode32MemEx op = (IOpCode32MemEx)context.CurrOp; Operand address = context.Copy(GetIntA32(context, op.Rn)); var exclusive = (accType & AccessType.Exclusive) != 0; var ordered = (accType & AccessType.Ordered) != 0; if ((accType & AccessType.Load) != 0) { if (ordered) { EmitBarrier(context); } if (size == DWordSizeLog2) { // Keep loads atomic - make the call to get the whole region and then decompose it into parts // for the registers. Operand value = EmitLoadExclusive(context, address, exclusive, size); Operand valueLow = context.ConvertI64ToI32(value); valueLow = context.ZeroExtend32(OperandType.I64, valueLow); Operand valueHigh = context.ShiftRightUI(value, Const(32)); Operand lblBigEndian = Label(); Operand lblEnd = Label(); context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); SetIntA32(context, op.Rt, valueLow); SetIntA32(context, op.Rt | 1, valueHigh); context.Branch(lblEnd); context.MarkLabel(lblBigEndian); SetIntA32(context, op.Rt | 1, valueLow); SetIntA32(context, op.Rt, valueHigh); context.MarkLabel(lblEnd); } else { SetIntA32(context, op.Rt, EmitLoadExclusive(context, address, exclusive, size)); } } else { if (size == DWordSizeLog2) { // Split the result into 2 words (based on endianness) Operand lo = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt)); Operand hi = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt | 1)); Operand lblBigEndian = Label(); Operand lblEnd = Label(); context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); Operand leResult = context.BitwiseOr(lo, context.ShiftLeft(hi, Const(32))); EmitStoreExclusive(context, address, leResult, exclusive, size, op.Rd, a32: true); context.Branch(lblEnd); context.MarkLabel(lblBigEndian); Operand beResult = context.BitwiseOr(hi, context.ShiftLeft(lo, Const(32))); EmitStoreExclusive(context, address, beResult, exclusive, size, op.Rd, a32: true); context.MarkLabel(lblEnd); } else { Operand value = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt)); EmitStoreExclusive(context, address, value, exclusive, size, op.Rd, a32: true); } if (ordered) { EmitBarrier(context); } } }
private static void EmitFcmpOrFcmpe(ArmEmitterContext context, bool signalNaNs) { OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; const int cmpOrdered = 7; bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false; if (Optimizations.FastFP && Optimizations.UseSse2) { Operand n = GetVec(op.Rn); Operand m = cmpWithZero ? context.VectorZero() : GetVec(op.Rm); Operand lblNaN = Label(); Operand lblEnd = Label(); if (op.Size == 0) { Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpss, n, m, Const(cmpOrdered)); Operand isOrdered = context.VectorExtract16(ordMask, 0); context.BranchIfFalse(lblNaN, isOrdered); Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, n, m); Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, n, m); Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, n, m); SetFlag(context, PState.VFlag, Const(0)); SetFlag(context, PState.CFlag, cf); SetFlag(context, PState.ZFlag, zf); SetFlag(context, PState.NFlag, nf); } else /* if (op.Size == 1) */ { Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, m, Const(cmpOrdered)); Operand isOrdered = context.VectorExtract16(ordMask, 0); context.BranchIfFalse(lblNaN, isOrdered); Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, n, m); Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, n, m); Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, n, m); SetFlag(context, PState.VFlag, Const(0)); SetFlag(context, PState.CFlag, cf); SetFlag(context, PState.ZFlag, zf); SetFlag(context, PState.NFlag, nf); } context.Branch(lblEnd); context.MarkLabel(lblNaN); SetFlag(context, PState.VFlag, Const(1)); SetFlag(context, PState.CFlag, Const(1)); SetFlag(context, PState.ZFlag, Const(0)); SetFlag(context, PState.NFlag, Const(0)); context.MarkLabel(lblEnd); } else { OperandType type = op.Size != 0 ? OperandType.FP64 : OperandType.FP32; Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0); Operand me; if (cmpWithZero) { me = op.Size == 0 ? ConstF(0f) : ConstF(0d); } else { me = context.VectorExtract(type, GetVec(op.Rm), 0); } Delegate dlg = op.Size != 0 ? (Delegate) new _S32_F64_F64_Bool(SoftFloat64.FPCompare) : (Delegate) new _S32_F32_F32_Bool(SoftFloat32.FPCompare); Operand nzcv = context.Call(dlg, ne, me, Const(signalNaNs)); EmitSetNzcv(context, nzcv); } }
private static void EmitVcmpOrVcmpe(ArmEmitterContext context, bool signalNaNs) { OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; bool cmpWithZero = (op.Opc & 2) != 0; int sizeF = op.Size & 1; if (Optimizations.FastFP && (signalNaNs ? Optimizations.UseAvx : Optimizations.UseSse2)) { CmpCondition cmpOrdered = signalNaNs ? CmpCondition.OrderedS : CmpCondition.OrderedQ; bool doubleSize = sizeF != 0; int shift = doubleSize ? 1 : 2; Operand m = GetVecA32(op.Vm >> shift); Operand n = GetVecA32(op.Vd >> shift); n = EmitSwapScalar(context, n, op.Vd, doubleSize); m = cmpWithZero ? context.VectorZero() : EmitSwapScalar(context, m, op.Vm, doubleSize); Operand lblNaN = Label(); Operand lblEnd = Label(); if (!doubleSize) { Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpss, n, m, Const((int)cmpOrdered)); Operand isOrdered = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, ordMask); context.BranchIfFalse(lblNaN, isOrdered); Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, n, m); Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, n, m); Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, n, m); SetFpFlag(context, FPState.VFlag, Const(0)); SetFpFlag(context, FPState.CFlag, cf); SetFpFlag(context, FPState.ZFlag, zf); SetFpFlag(context, FPState.NFlag, nf); } else { Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, m, Const((int)cmpOrdered)); Operand isOrdered = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, ordMask); context.BranchIfFalse(lblNaN, isOrdered); Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, n, m); Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, n, m); Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, n, m); SetFpFlag(context, FPState.VFlag, Const(0)); SetFpFlag(context, FPState.CFlag, cf); SetFpFlag(context, FPState.ZFlag, zf); SetFpFlag(context, FPState.NFlag, nf); } context.Branch(lblEnd); context.MarkLabel(lblNaN); SetFpFlag(context, FPState.VFlag, Const(1)); SetFpFlag(context, FPState.CFlag, Const(1)); SetFpFlag(context, FPState.ZFlag, Const(0)); SetFpFlag(context, FPState.NFlag, Const(0)); context.MarkLabel(lblEnd); } else { OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32; Operand ne = ExtractScalar(context, type, op.Vd); Operand me; if (cmpWithZero) { me = sizeF == 0 ? ConstF(0f) : ConstF(0d); } else { me = ExtractScalar(context, type, op.Vm); } MethodInfo info = sizeF != 0 ? typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)) : typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)); Operand nzcv = context.Call(info, ne, me, Const(signalNaNs)); EmitSetFpscrNzcv(context, nzcv); } }
public static void B(ArmEmitterContext context) { IOpCode32BImm op = (IOpCode32BImm)context.CurrOp; context.Branch(context.GetLabel((ulong)op.Immediate)); }
private static void EmitFcmpOrFcmpe(ArmEmitterContext context, bool signalNaNs) { OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false; if (Optimizations.FastFP && (signalNaNs ? Optimizations.UseAvx : Optimizations.UseSse2)) { Operand n = GetVec(op.Rn); Operand m = cmpWithZero ? context.VectorZero() : GetVec(op.Rm); CmpCondition cmpOrdered = signalNaNs ? CmpCondition.OrderedS : CmpCondition.OrderedQ; Operand lblNaN = Label(); Operand lblEnd = Label(); if (op.Size == 0) { Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpss, n, m, Const((int)cmpOrdered)); Operand isOrdered = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, ordMask); context.BranchIfFalse(lblNaN, isOrdered); Operand nCopy = context.Copy(n); Operand mCopy = cmpWithZero ? context.VectorZero() : context.Copy(m); Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, nCopy, mCopy); Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, nCopy, mCopy); Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, nCopy, mCopy); SetFlag(context, PState.VFlag, Const(0)); SetFlag(context, PState.CFlag, cf); SetFlag(context, PState.ZFlag, zf); SetFlag(context, PState.NFlag, nf); } else /* if (op.Size == 1) */ { Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, m, Const((int)cmpOrdered)); Operand isOrdered = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, ordMask); context.BranchIfFalse(lblNaN, isOrdered); Operand nCopy = context.Copy(n); Operand mCopy = cmpWithZero ? context.VectorZero() : context.Copy(m); Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, nCopy, mCopy); Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, nCopy, mCopy); Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, nCopy, mCopy); SetFlag(context, PState.VFlag, Const(0)); SetFlag(context, PState.CFlag, cf); SetFlag(context, PState.ZFlag, zf); SetFlag(context, PState.NFlag, nf); } context.Branch(lblEnd); context.MarkLabel(lblNaN); SetFlag(context, PState.VFlag, Const(1)); SetFlag(context, PState.CFlag, Const(1)); SetFlag(context, PState.ZFlag, Const(0)); SetFlag(context, PState.NFlag, Const(0)); context.MarkLabel(lblEnd); } else { OperandType type = op.Size != 0 ? OperandType.FP64 : OperandType.FP32; Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0); Operand me; if (cmpWithZero) { me = op.Size == 0 ? ConstF(0f) : ConstF(0d); } else { me = context.VectorExtract(type, GetVec(op.Rm), 0); } Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs)); EmitSetNzcv(context, nzcv); } }
private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType) { OpCode32Mem op = (OpCode32Mem)context.CurrOp; Operand n = context.Copy(GetIntA32(context, op.Rn)); Operand temp = null; if (op.Index || op.WBack) { temp = op.Add ? context.Add(n, Const(op.Immediate)) : context.Subtract(n, Const(op.Immediate)); } if (op.WBack) { SetIntA32(context, op.Rn, temp); } Operand address; if (op.Index) { address = temp; } else { address = n; } if ((accType & AccessType.Load) != 0) { void Load(int rt, int offs, int loadSize) { Operand addr = context.Add(address, Const(offs)); if ((accType & AccessType.Signed) != 0) { EmitLoadSx32(context, addr, rt, loadSize); } else { EmitLoadZx(context, addr, rt, loadSize); } } if (size == DWordSizeLog2) { Operand lblBigEndian = Label(); Operand lblEnd = Label(); context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); Load(op.Rt, 0, WordSizeLog2); Load(op.Rt | 1, 4, WordSizeLog2); context.Branch(lblEnd); context.MarkLabel(lblBigEndian); Load(op.Rt | 1, 0, WordSizeLog2); Load(op.Rt, 4, WordSizeLog2); context.MarkLabel(lblEnd); } else { Load(op.Rt, 0, size); } } else { void Store(int rt, int offs, int storeSize) { Operand addr = context.Add(address, Const(offs)); EmitStore(context, addr, rt, storeSize); } if (size == DWordSizeLog2) { Operand lblBigEndian = Label(); Operand lblEnd = Label(); context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); Store(op.Rt, 0, WordSizeLog2); Store(op.Rt | 1, 4, WordSizeLog2); context.Branch(lblEnd); context.MarkLabel(lblBigEndian); Store(op.Rt | 1, 0, WordSizeLog2); Store(op.Rt, 4, WordSizeLog2); context.MarkLabel(lblEnd); } else { Store(op.Rt, 0, size); } } }
public static void B(ArmEmitterContext context) { OpCodeBImmAl op = (OpCodeBImmAl)context.CurrOp; context.Branch(context.GetLabel((ulong)op.Immediate)); }