Beispiel #1
0
        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);
        }
Beispiel #2
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);
        }
Beispiel #3
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);
        }
Beispiel #4
0
        public static void Cmeq_V(ArmEmitterContext context)
        {
            if (Optimizations.UseSse41)
            {
                OpCodeSimd op = (OpCodeSimd)context.CurrOp;

                Operand n = GetVec(op.Rn);
                Operand m;

                if (op is OpCodeSimdReg binOp)
                {
                    m = GetVec(binOp.Rm);
                }
                else
                {
                    m = context.VectorZero();
                }

                Intrinsic cmpInst = X86PcmpeqInstruction[op.Size];

                Operand res = context.AddIntrinsic(cmpInst, n, m);

                if (op.RegisterSize == RegisterSize.Simd64)
                {
                    res = context.VectorZeroUpper64(res);
                }

                context.Copy(GetVec(op.Rd), res);
            }
            else
            {
                EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: false);
            }
        }
Beispiel #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);
            }
        }
Beispiel #6
0
 public static void Vtst(ArmEmitterContext context)
 {
     EmitVectorBinaryOpZx32(context, (op1, op2) =>
     {
         Operand isZero = context.ICompareEqual(context.BitwiseAnd(op1, op2), Const(0));
         return(context.ConditionalSelect(isZero, Const(0), Const(-1)));
     });
 }
        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 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);
        }
Beispiel #9
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));
            }
        }
Beispiel #10
0
        public static Operand GetMShiftedByReg(ArmEmitterContext context, IOpCode32AluRsReg op, bool setCarry)
        {
            Operand m           = GetIntA32(context, op.Rm);
            Operand s           = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs));
            Operand shiftIsZero = context.ICompareEqual(s, Const(0));

            Operand zeroResult  = m;
            Operand shiftResult = m;

            setCarry &= ShouldSetFlags(context);

            switch (op.ShiftType)
            {
            case ShiftType.Lsl: shiftResult = EmitLslC(context, m, setCarry, s, shiftIsZero); break;

            case ShiftType.Lsr: shiftResult = EmitLsrC(context, m, setCarry, s, shiftIsZero); break;

            case ShiftType.Asr: shiftResult = EmitAsrC(context, m, setCarry, s, shiftIsZero); break;

            case ShiftType.Ror: shiftResult = EmitRorC(context, m, setCarry, s, shiftIsZero); break;
            }

            return(context.ConditionalSelect(shiftIsZero, zeroResult, shiftResult));
        }
Beispiel #11
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);
            }
        }
Beispiel #12
0
        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);
        }
Beispiel #13
0
 public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
 {
     SetFlag(context, PState.NFlag, context.ICompareLess(d, Const(d.Type, 0)));
     SetFlag(context, PState.ZFlag, context.ICompareEqual(d, Const(d.Type, 0)));
 }
Beispiel #14
0
 public static void Cmeq_S(ArmEmitterContext context)
 {
     EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: true);
 }