示例#1
0
        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 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);
        }
示例#3
0
        private static void EmitAluStore(ArmEmitterContext context, Operand value)
        {
            IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;

            if (op.Rd == RegisterAlias.Aarch32Pc)
            {
                if (op.SetFlags)
                {
                    // TODO: Load SPSR etc.
                    Operand isThumb = GetFlag(PState.TFlag);

                    Operand lblThumb = Label();

                    context.BranchIfTrue(lblThumb, isThumb);

                    context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(value, Const(~3))));

                    context.MarkLabel(lblThumb);

                    context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(value, Const(~1))));
                }
                else
                {
                    EmitAluWritePc(context, value);
                }
            }
            else
            {
                SetIntA32(context, op.Rd, value);
            }
        }
示例#4
0
        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);
        }
示例#5
0
        private static void EmitNativeCall(ArmEmitterContext context, Operand nativeContextPtr, Operand funcAddr, bool isJump = false)
        {
            context.StoreToContext();

            if (isJump)
            {
                context.Tailcall(funcAddr, nativeContextPtr);
            }
            else
            {
                OpCode op = context.CurrOp;

                Operand returnAddress = context.Call(funcAddr, OperandType.I64, nativeContextPtr);

                context.LoadFromContext();

                // Note: The return value of a translated function is always an Int64 with the
                // address execution has returned to. We expect this address to be immediately after the
                // current instruction, if it isn't we keep returning until we reach the dispatcher.
                Operand nextAddr = Const((long)op.Address + op.OpCodeSizeInBytes);

                // Try to continue within this block.
                // If the return address isn't to our next instruction, we need to return so the JIT can figure out what to do.
                Operand lblContinue = context.GetLabel(nextAddr.Value);

                // We need to clear out the call flag for the return address before comparing it.
                context.BranchIfTrue(lblContinue, context.ICompareEqual(context.BitwiseAnd(returnAddress, Const(~CallFlag)), nextAddr));

                context.Return(returnAddress);
            }
        }
示例#6
0
        private static void EmitBranch(ArmEmitterContext context, Operand value, bool onNotZero)
        {
            OpCodeBImm op = (OpCodeBImm)context.CurrOp;

            if (context.CurrBlock.Branch != null)
            {
                Operand lblTarget = context.GetLabel((ulong)op.Immediate);

                if (onNotZero)
                {
                    context.BranchIfTrue(lblTarget, value);
                }
                else
                {
                    context.BranchIfFalse(lblTarget, value);
                }

                if (context.CurrBlock.Next == null)
                {
                    context.Return(Const(op.Address + 4));
                }
            }
            else
            {
                Operand lblTaken = Label();

                if (onNotZero)
                {
                    context.BranchIfTrue(lblTaken, value);
                }
                else
                {
                    context.BranchIfFalse(lblTaken, value);
                }

                context.Return(Const(op.Address + 4));

                context.MarkLabel(lblTaken);

                context.Return(Const(op.Immediate));
            }
        }
示例#7
0
 public static void EmitCondBranch(ArmEmitterContext context, Operand target, Condition cond)
 {
     if (cond != Condition.Al)
     {
         context.BranchIfTrue(target, GetCondTrue(context, cond));
     }
     else
     {
         context.Branch(target);
     }
 }
示例#8
0
        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);
        }
示例#9
0
        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);
        }
示例#10
0
        private static void EmitBranch(ArmEmitterContext context, Operand value, bool onNotZero)
        {
            OpCodeBImm op = (OpCodeBImm)context.CurrOp;

            Operand lblTarget = context.GetLabel((ulong)op.Immediate);

            if (onNotZero)
            {
                context.BranchIfTrue(lblTarget, value);
            }
            else
            {
                context.BranchIfFalse(lblTarget, value);
            }
        }
示例#11
0
        private static void EmitCb(ArmEmitterContext context, bool onNotZero)
        {
            OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;

            Operand value     = GetIntA32(context, op.Rn);
            Operand lblTarget = context.GetLabel((ulong)op.Immediate);

            if (onNotZero)
            {
                context.BranchIfTrue(lblTarget, value);
            }
            else
            {
                context.BranchIfFalse(lblTarget, value);
            }
        }
示例#12
0
        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);

            context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(pc, Const(~1))));

            context.MarkLabel(lblArmMode);

            context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(pc, Const(~3))));
        }
示例#13
0
        private static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblFallbackPath)
        {
            Operand pte = Const(context.Memory.PageTable.ToInt64());

            int bit = MemoryManager.PageBits;

            do
            {
                Operand addrPart = context.ShiftRightUI(address, Const(bit));

                bit += context.Memory.PtLevelBits;

                if (bit < context.Memory.AddressSpaceBits)
                {
                    addrPart = context.BitwiseAnd(addrPart, Const(addrPart.Type, context.Memory.PtLevelMask));
                }

                Operand pteOffset = context.ShiftLeft(addrPart, Const(3));

                if (pteOffset.Type == OperandType.I32)
                {
                    pteOffset = context.ZeroExtend32(OperandType.I64, pteOffset);
                }

                Operand pteAddress = context.Add(pte, pteOffset);

                pte = context.Load(OperandType.I64, pteAddress);
            }while (bit < context.Memory.AddressSpaceBits);

            if (!context.Memory.HasWriteWatchSupport)
            {
                Operand hasFlagSet = context.BitwiseAnd(pte, Const((long)MemoryManager.PteFlagsMask));

                context.BranchIfTrue(lblFallbackPath, hasFlagSet);
            }

            Operand pageOffset = context.BitwiseAnd(address, Const(address.Type, MemoryManager.PageMask));

            if (pageOffset.Type == OperandType.I32)
            {
                pageOffset = context.ZeroExtend32(OperandType.I64, pageOffset);
            }

            Operand physAddr = context.Add(pte, pageOffset);

            return(physAddr);
        }
示例#14
0
        private static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath)
        {
            int ptLevelBits = context.Memory.AddressSpaceBits - 12; // 12 = Number of page bits.
            int ptLevelSize = 1 << ptLevelBits;
            int ptLevelMask = ptLevelSize - 1;

            Operand pte = Ptc.State == PtcState.Disabled
                ? Const(context.Memory.PageTablePointer.ToInt64())
                : Const(context.Memory.PageTablePointer.ToInt64(), true, Ptc.PageTablePointerIndex);

            int bit = PageBits;

            do
            {
                Operand addrPart = context.ShiftRightUI(address, Const(bit));

                bit += ptLevelBits;

                if (bit < context.Memory.AddressSpaceBits)
                {
                    addrPart = context.BitwiseAnd(addrPart, Const(addrPart.Type, ptLevelMask));
                }

                Operand pteOffset = context.ShiftLeft(addrPart, Const(3));

                if (pteOffset.Type == OperandType.I32)
                {
                    pteOffset = context.ZeroExtend32(OperandType.I64, pteOffset);
                }

                Operand pteAddress = context.Add(pte, pteOffset);

                pte = context.Load(OperandType.I64, pteAddress);
            }while (bit < context.Memory.AddressSpaceBits);

            context.BranchIfTrue(lblSlowPath, context.ICompareLess(pte, Const(0L)));

            Operand pageOffset = context.BitwiseAnd(address, Const(address.Type, PageMask));

            if (pageOffset.Type == OperandType.I32)
            {
                pageOffset = context.ZeroExtend32(OperandType.I64, pageOffset);
            }

            return(context.Add(pte, pageOffset));
        }
示例#15
0
        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))));
        }
示例#16
0
        public static void EmitIfHelper(ArmEmitterContext context, Operand boolValue, Action action, bool expected = true)
        {
            Debug.Assert(boolValue.Type == OperandType.I32);

            Operand endLabel = Label();

            if (expected)
            {
                context.BranchIfFalse(endLabel, boolValue);
            }
            else
            {
                context.BranchIfTrue(endLabel, boolValue);
            }

            action();

            context.MarkLabel(endLabel);
        }
示例#17
0
        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);
        }
示例#18
0
        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);
        }
示例#19
0
        private static void EmitContinueOrReturnCheck(ArmEmitterContext context, Operand retVal)
        {
            // Note: The return value of the called method will be placed
            // at the Stack, the return value is always a Int64 with the
            // return address of the function. We check if the address is
            // correct, if it isn't we keep returning until we reach the dispatcher.
            ulong nextAddr = GetNextOpAddress(context.CurrOp);

            if (context.CurrBlock.Next != null)
            {
                Operand lblContinue = Label();

                context.BranchIfTrue(lblContinue, context.ICompareEqual(retVal, Const(nextAddr)));

                context.Return(Const(nextAddr));

                context.MarkLabel(lblContinue);
            }
            else
            {
                context.Return(Const(nextAddr));
            }
        }
示例#20
0
        private static void EmitContinueOrReturnCheck(ArmEmitterContext context, Operand returnAddress)
        {
            // Note: The return value of a translated function is always an Int64 with the
            // address execution has returned to. We expect this address to be immediately after the
            // current instruction, if it isn't we keep returning until we reach the dispatcher.
            Operand nextAddr = Const(GetNextOpAddress(context.CurrOp));

            // Try to continue within this block.
            // If the return address isn't to our next instruction, we need to return so the JIT can figure out what to do.
            Operand lblContinue = Label();

            // We need to clear out the call flag for the return address before comparing it.
            context.BranchIfTrue(lblContinue, context.ICompareEqual(context.BitwiseAnd(returnAddress, Const(~CallFlag)), nextAddr));

            context.Return(returnAddress);

            context.MarkLabel(lblContinue);

            if (context.CurrBlock.Next == null)
            {
                // No code following this instruction, try and find the next block and jump to it.
                EmitTailContinue(context, nextAddr);
            }
        }
示例#21
0
        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);
            }
        }
示例#22
0
        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);
            }
        }
示例#23
0
        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);
                }
            }
        }
示例#24
0
        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);
                }
            }
        }