Пример #1
0
        private static void HandleLoadArgumentSystemVAbi(
            CompilerContext cctx,
            IntrusiveList <Node> nodes,
            Node node,
            Operand[] preservedArgs,
            Operation operation)
        {
            Operand source = operation.GetSource(0);

            Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");

            int index = source.AsInt32();

            int intCount = 0;
            int vecCount = 0;

            for (int cIndex = 0; cIndex < index; cIndex++)
            {
                OperandType argType = cctx.FuncArgTypes[cIndex];

                if (argType.IsInteger())
                {
                    intCount++;
                }
                else if (argType == OperandType.V128)
                {
                    intCount += 2;
                }
                else
                {
                    vecCount++;
                }
            }

            bool passOnReg;

            if (source.Type.IsInteger())
            {
                passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
            }
            else if (source.Type == OperandType.V128)
            {
                passOnReg = intCount + 1 < CallingConvention.GetIntArgumentsOnRegsCount();
            }
            else
            {
                passOnReg = vecCount < CallingConvention.GetVecArgumentsOnRegsCount();
            }

            if (passOnReg)
            {
                Operand dest = operation.Destination;

                if (preservedArgs[index] == null)
                {
                    if (dest.Type == OperandType.V128)
                    {
                        // V128 is a struct, we pass each half on a GPR if possible.
                        Operand pArg = Local(OperandType.V128);

                        Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
                        Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);

                        Operation copyL = new Operation(Instruction.VectorCreateScalar, pArg, argLReg);
                        Operation copyH = new Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));

                        cctx.Cfg.Entry.Operations.AddFirst(copyH);
                        cctx.Cfg.Entry.Operations.AddFirst(copyL);

                        preservedArgs[index] = pArg;
                    }
                    else
                    {
                        Operand pArg = Local(dest.Type);

                        Operand argReg = dest.Type.IsInteger()
                            ? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
                            : Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);

                        Operation copyOp = new Operation(Instruction.Copy, pArg, argReg);

                        cctx.Cfg.Entry.Operations.AddFirst(copyOp);

                        preservedArgs[index] = pArg;
                    }
                }

                Operation argCopyOp = new Operation(Instruction.Copy, dest, preservedArgs[index]);

                nodes.AddBefore(node, argCopyOp);

                Delete(nodes, node, operation);
            }
            else
            {
                // TODO: Pass on stack.
            }
        }
Пример #2
0
            public void Sequence(List <Operation> sequence)
            {
                Dictionary <Register, Register> locations = new Dictionary <Register, Register>();
                Dictionary <Register, Register> sources   = new Dictionary <Register, Register>();

                Dictionary <Register, OperandType> types = new Dictionary <Register, OperandType>();

                Queue <Register> pendingQueue = new Queue <Register>();
                Queue <Register> readyQueue   = new Queue <Register>();

                foreach (Copy copy in _copies)
                {
                    locations[copy.Source] = copy.Source;
                    sources[copy.Dest]     = copy.Source;
                    types[copy.Dest]       = copy.Type;

                    pendingQueue.Enqueue(copy.Dest);
                }

                foreach (Copy copy in _copies)
                {
                    // If the destination is not used anywhere, we can assign it immediately.
                    if (!locations.ContainsKey(copy.Dest))
                    {
                        readyQueue.Enqueue(copy.Dest);
                    }
                }

                while (pendingQueue.TryDequeue(out Register current))
                {
                    Register copyDest;
                    Register origSource;
                    Register copySource;

                    while (readyQueue.TryDequeue(out copyDest))
                    {
                        origSource = sources[copyDest];
                        copySource = locations[origSource];

                        OperandType type = types[copyDest];

                        EmitCopy(sequence, GetRegister(copyDest, type), GetRegister(copySource, type));

                        locations[origSource] = copyDest;

                        if (origSource == copySource && sources.ContainsKey(origSource))
                        {
                            readyQueue.Enqueue(origSource);
                        }
                    }

                    copyDest   = current;
                    origSource = sources[copyDest];
                    copySource = locations[origSource];

                    if (copyDest != copySource)
                    {
                        OperandType type = types[copyDest];

                        type = type.IsInteger() ? OperandType.I64 : OperandType.V128;

                        EmitXorSwap(sequence, GetRegister(copyDest, type), GetRegister(copySource, type));

                        locations[origSource] = copyDest;

                        Register swapOther = copySource;

                        if (copyDest != locations[sources[copySource]])
                        {
                            // Find the other swap destination register.
                            // To do that, we search all the pending registers, and pick
                            // the one where the copy source register is equal to the
                            // current destination register being processed (copyDest).
                            foreach (Register pending in pendingQueue)
                            {
                                // Is this a copy of pending <- copyDest?
                                if (copyDest == locations[sources[pending]])
                                {
                                    swapOther = pending;

                                    break;
                                }
                            }
                        }

                        // The value that was previously at "copyDest" now lives on
                        // "copySource" thanks to the swap, now we need to update the
                        // location for the next copy that is supposed to copy the value
                        // that used to live on "copyDest".
                        locations[sources[swapOther]] = copySource;
                    }
                }
            }