private static void EmitCmtstOp(ArmEmitterContext context, bool scalar) { OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; Operand res = context.VectorZero(); int elems = !scalar?op.GetBytesCount() >> op.Size : 1; ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size)); for (int index = 0; index < elems; index++) { Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size); Operand test = context.BitwiseAnd(ne, me); Operand isTrue = context.ICompareNotEqual(test, Const(0L)); Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L)); res = EmitVectorInsert(context, res, mask, index, op.Size); } context.Copy(GetVec(op.Rd), res); }
public static void Smlaw_(ArmEmitterContext context) { OpCode32AluMla op = (OpCode32AluMla)context.CurrOp; Operand n = GetIntA32(context, op.Rn); Operand m = GetIntA32(context, op.Rm); Operand a = GetIntA32(context, op.Ra); if (op.MHigh) { m = context.SignExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16))); } else { m = context.SignExtend16(OperandType.I64, m); } Operand res = context.Multiply(context.SignExtend32(OperandType.I64, n), m); Operand toAdd = context.ShiftLeft(context.SignExtend32(OperandType.I64, a), Const(16)); res = context.Add(res, toAdd); res = context.ShiftRightSI(res, Const(16)); Operand q = context.ICompareNotEqual(res, context.SignExtend32(OperandType.I64, res)); res = context.ConvertI64ToI32(res); UpdateQFlag(context, q); EmitGenericAluStoreA32(context, op.Rd, false, res); }
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 EmitStoreExclusive( ArmEmitterContext context, Operand address, Operand value, bool exclusive, int size, int rs, bool a32) { if (size < 3) { value = context.ConvertI64ToI32(value); } if (exclusive) { void SetRs(Operand value) { if (a32) { SetIntA32(context, rs, value); } else { SetIntOrZR(context, rs, value); } } Operand arg0 = context.LoadArgument(OperandType.I64, 0); Operand exAddrPtr = context.Add(arg0, Const((long)NativeContext.GetExclusiveAddressOffset())); Operand exAddr = context.Load(address.Type, exAddrPtr); // STEP 1: Check if we have exclusive access to this memory region. If not, fail and skip store. Operand maskedAddress = context.BitwiseAnd(address, Const(address.Type, GetExclusiveAddressMask())); Operand exFailed = context.ICompareNotEqual(exAddr, maskedAddress); Operand lblExit = Label(); SetRs(exFailed); context.BranchIfTrue(lblExit, exFailed); // STEP 2: We have exclusive access, make sure that the address is valid. Operand isUnalignedAddr = InstEmitMemoryHelper.EmitAddressCheck(context, address, size); Operand lblFastPath = Label(); context.BranchIfFalse(lblFastPath, isUnalignedAddr); // The call is not expected to return (it should throw). context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address); // STEP 3: We have exclusive access and the address is valid, attempt the store using CAS. context.MarkLabel(lblFastPath); Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, null, write: true); Operand exValuePtr = context.Add(arg0, Const((long)NativeContext.GetExclusiveValueOffset())); Operand exValue = size switch { 0 => context.Load8(exValuePtr), 1 => context.Load16(exValuePtr), 2 => context.Load(OperandType.I32, exValuePtr), 3 => context.Load(OperandType.I64, exValuePtr), _ => context.Load(OperandType.V128, exValuePtr) }; Operand currValue = size switch { 0 => context.CompareAndSwap8(physAddr, exValue, value), 1 => context.CompareAndSwap16(physAddr, exValue, value), _ => context.CompareAndSwap(physAddr, exValue, value) }; // STEP 4: Check if we succeeded by comparing expected and in-memory values. Operand storeFailed; if (size == 4) { Operand currValueLow = context.VectorExtract(OperandType.I64, currValue, 0); Operand currValueHigh = context.VectorExtract(OperandType.I64, currValue, 1); Operand exValueLow = context.VectorExtract(OperandType.I64, exValue, 0); Operand exValueHigh = context.VectorExtract(OperandType.I64, exValue, 1); storeFailed = context.BitwiseOr( context.ICompareNotEqual(currValueLow, exValueLow), context.ICompareNotEqual(currValueHigh, exValueHigh)); } else { storeFailed = context.ICompareNotEqual(currValue, exValue); } SetRs(storeFailed); context.MarkLabel(lblExit); } else { InstEmitMemoryHelper.EmitWriteIntAligned(context, address, value, size); } }
public static void EmitStoreExclusive( ArmEmitterContext context, Operand address, Operand value, bool exclusive, int size, int rs, bool a32) { if (size < 3) { value = context.ConvertI64ToI32(value); } if (exclusive) { // We overwrite one of the register (Rs), // keep a copy of the values to ensure we are working with the correct values. address = context.Copy(address); value = context.Copy(value); void SetRs(Operand value) { if (a32) { SetIntA32(context, rs, value); } else { SetIntOrZR(context, rs, value); } } Operand arg0 = context.LoadArgument(OperandType.I64, 0); Operand exAddrPtr = context.Add(arg0, Const((long)NativeContext.GetExclusiveAddressOffset())); Operand exAddr = context.Load(address.Type, exAddrPtr); // STEP 1: Check if we have exclusive access to this memory region. If not, fail and skip store. Operand maskedAddress = context.BitwiseAnd(address, Const(address.Type, GetExclusiveAddressMask())); Operand exFailed = context.ICompareNotEqual(exAddr, maskedAddress); Operand lblExit = Label(); SetRs(Const(1)); context.BranchIfTrue(lblExit, exFailed); // STEP 2: We have exclusive access and the address is valid, attempt the store using CAS. Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, null, write: true, size); Operand exValuePtr = context.Add(arg0, Const((long)NativeContext.GetExclusiveValueOffset())); Operand exValue = size switch { 0 => context.Load8(exValuePtr), 1 => context.Load16(exValuePtr), 2 => context.Load(OperandType.I32, exValuePtr), 3 => context.Load(OperandType.I64, exValuePtr), _ => context.Load(OperandType.V128, exValuePtr) }; Operand currValue = size switch { 0 => context.CompareAndSwap8(physAddr, exValue, value), 1 => context.CompareAndSwap16(physAddr, exValue, value), _ => context.CompareAndSwap(physAddr, exValue, value) }; // STEP 3: Check if we succeeded by comparing expected and in-memory values. Operand storeFailed; if (size == 4) { Operand currValueLow = context.VectorExtract(OperandType.I64, currValue, 0); Operand currValueHigh = context.VectorExtract(OperandType.I64, currValue, 1); Operand exValueLow = context.VectorExtract(OperandType.I64, exValue, 0); Operand exValueHigh = context.VectorExtract(OperandType.I64, exValue, 1); storeFailed = context.BitwiseOr( context.ICompareNotEqual(currValueLow, exValueLow), context.ICompareNotEqual(currValueHigh, exValueHigh)); } else { storeFailed = context.ICompareNotEqual(currValue, exValue); } SetRs(storeFailed); context.MarkLabel(lblExit); } else { InstEmitMemoryHelper.EmitWriteIntAligned(context, address, value, size); } }