コード例 #1
0
        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);
        }
コード例 #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);
        }
コード例 #3
0
        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);
            }
        }
コード例 #4
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);
        }
コード例 #5
0
ファイル: InstEmitSimdMove.cs プロジェクト: zpoo32/Ryujinx
        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);
        }
コード例 #6
0
        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);
            }
        }
コード例 #7
0
        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);
        }
コード例 #8
0
ファイル: InstEmitFlowHelper.cs プロジェクト: venhow/Ryujinx
        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);
        }
コード例 #9
0
        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);
        }
コード例 #10
0
ファイル: InstEmitFlowHelper.cs プロジェクト: venhow/Ryujinx
 public static void EmitCondBranch(ArmEmitterContext context, Operand target, Condition cond)
 {
     if (cond != Condition.Al)
     {
         context.BranchIfTrue(target, GetCondTrue(context, cond));
     }
     else
     {
         context.Branch(target);
     }
 }
コード例 #11
0
        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);
        }
コード例 #12
0
ファイル: InstEmitFlow.cs プロジェクト: turbedi/Ryujinx
        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);
            }
        }
コード例 #13
0
        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));
            }
        }
コード例 #14
0
        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);
            }
        }
コード例 #15
0
ファイル: InstEmitFlow32.cs プロジェクト: vsear/Ryujinx
        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));
            }
        }
コード例 #16
0
        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);
            }
        }
コード例 #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
ファイル: InstEmitCcmp.cs プロジェクト: derparb/h
        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);
        }
コード例 #19
0
ファイル: InstEmitSimdMemory32.cs プロジェクト: derparb/h
        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);
        }
コード例 #20
0
        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);
        }
コード例 #21
0
ファイル: InstEmitMemoryEx32.cs プロジェクト: Xpl0itR/Ryujinx
        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);
                }
            }
        }
コード例 #22
0
        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);
            }
        }
コード例 #23
0
        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);
            }
        }
コード例 #24
0
        public static void B(ArmEmitterContext context)
        {
            IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;

            context.Branch(context.GetLabel((ulong)op.Immediate));
        }
コード例 #25
0
        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);
            }
        }
コード例 #26
0
ファイル: InstEmitMemory32.cs プロジェクト: zpoo32/Ryujinx
        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);
                }
            }
        }
コード例 #27
0
        public static void B(ArmEmitterContext context)
        {
            OpCodeBImmAl op = (OpCodeBImmAl)context.CurrOp;

            context.Branch(context.GetLabel((ulong)op.Immediate));
        }