Ejemplo n.º 1
0
        private static void HandleLoadArgumentSystemVAbi(
            CompilerContext cctx,
            LLNode 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]);

                node.List.AddBefore(node, argCopyOp);

                Delete(node, operation);
            }
            else
            {
                // TODO: Pass on stack.
            }
        }
Ejemplo n.º 2
0
        private static void HandleLoadArgumentWindowsAbi(
            CompilerContext cctx,
            LLNode node,
            Operand[] preservedArgs,
            Operation operation)
        {
            Operand source = operation.GetSource(0);

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

            int retArgs = cctx.FuncReturnType == OperandType.V128 ? 1 : 0;

            int index = source.AsInt32() + retArgs;

            if (index < CallingConvention.GetArgumentsOnRegsCount())
            {
                Operand dest = operation.Destination;

                if (preservedArgs[index] == null)
                {
                    Operand argReg, pArg;

                    if (dest.Type.IsInteger())
                    {
                        argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);

                        pArg = Local(dest.Type);
                    }
                    else if (dest.Type == OperandType.V128)
                    {
                        argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), OperandType.I64);

                        pArg = Local(OperandType.I64);
                    }
                    else
                    {
                        argReg = Xmm(CallingConvention.GetVecArgumentRegister(index), dest.Type);

                        pArg = Local(dest.Type);
                    }

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

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

                    preservedArgs[index] = pArg;
                }

                Operation argCopyOp = new Operation(dest.Type == OperandType.V128
                    ? Instruction.Load
                    : Instruction.Copy, dest, preservedArgs[index]);

                node.List.AddBefore(node, argCopyOp);

                Delete(node, operation);
            }
            else
            {
                // TODO: Pass on stack.
            }
        }
Ejemplo n.º 3
0
        private static LLNode HandleCallWindowsAbi(StackAllocator stackAlloc, LLNode node, Operation operation)
        {
            Operand dest = operation.Destination;

            LinkedList <Node> nodes = node.List;

            // Handle struct arguments.
            int retArgs = 0;

            int stackAllocOffset = 0;

            int AllocateOnStack(int size)
            {
                // We assume that the stack allocator is initially empty (TotalSize = 0).
                // Taking that into account, we can reuse the space allocated for other
                // calls by keeping track of our own allocated size (stackAllocOffset).
                // If the space allocated is not big enough, then we just expand it.
                int offset = stackAllocOffset;

                if (stackAllocOffset + size > stackAlloc.TotalSize)
                {
                    stackAlloc.Allocate((stackAllocOffset + size) - stackAlloc.TotalSize);
                }

                stackAllocOffset += size;

                return(offset);
            }

            Operand arg0Reg = null;

            if (dest != null && dest.Type == OperandType.V128)
            {
                int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());

                arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);

                Operation allocOp = new Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));

                nodes.AddBefore(node, allocOp);

                retArgs = 1;
            }

            int argsCount = operation.SourcesCount - 1;

            int maxArgs = CallingConvention.GetArgumentsOnRegsCount() - retArgs;

            if (argsCount > maxArgs)
            {
                argsCount = maxArgs;
            }

            Operand[] sources = new Operand[1 + retArgs + argsCount];

            sources[0] = operation.GetSource(0);

            if (arg0Reg != null)
            {
                sources[1] = arg0Reg;
            }

            for (int index = 1; index < operation.SourcesCount; index++)
            {
                Operand source = operation.GetSource(index);

                if (source.Type == OperandType.V128)
                {
                    Operand stackAddr = Local(OperandType.I64);

                    int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());

                    nodes.AddBefore(node, new Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));

                    Operation storeOp = new Operation(Instruction.Store, null, stackAddr, source);

                    HandleConstantCopy(nodes.AddBefore(node, storeOp), storeOp);

                    operation.SetSource(index, stackAddr);
                }
            }

            // Handle arguments passed on registers.
            for (int index = 0; index < argsCount; index++)
            {
                Operand source = operation.GetSource(index + 1);

                Operand argReg;

                int argIndex = index + retArgs;

                if (source.Type.IsInteger())
                {
                    argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
                }
                else
                {
                    argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
                }

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

                HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp);

                sources[1 + retArgs + index] = argReg;
            }

            // The remaining arguments (those that are not passed on registers)
            // should be passed on the stack, we write them to the stack with "SpillArg".
            for (int index = argsCount; index < operation.SourcesCount - 1; index++)
            {
                Operand source = operation.GetSource(index + 1);

                Operand offset = new Operand((index + retArgs) * 8);

                Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);

                HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp);
            }

            if (dest != null)
            {
                if (dest.Type == OperandType.V128)
                {
                    Operand retValueAddr = Local(OperandType.I64);

                    nodes.AddBefore(node, new Operation(Instruction.Copy, retValueAddr, arg0Reg));

                    Operation loadOp = new Operation(Instruction.Load, dest, retValueAddr);

                    node = nodes.AddAfter(node, loadOp);

                    operation.Destination = null;
                }
                else
                {
                    Operand retReg = dest.Type.IsInteger()
                        ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
                        : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);

                    Operation copyOp = new Operation(Instruction.Copy, dest, retReg);

                    node = nodes.AddAfter(node, copyOp);

                    operation.Destination = retReg;
                }
            }

            operation.SetSources(sources);

            return(node);
        }
Ejemplo n.º 4
0
        private static LLNode HandleCallSystemVAbi(LLNode node, Operation operation)
        {
            Operand dest = operation.Destination;

            LinkedList <Node> nodes = node.List;

            List <Operand> sources = new List <Operand>();

            sources.Add(operation.GetSource(0));

            int argsCount = operation.SourcesCount - 1;

            int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
            int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();

            int intCount = 0;
            int vecCount = 0;

            int stackOffset = 0;

            for (int index = 0; index < argsCount; index++)
            {
                Operand source = operation.GetSource(index + 1);

                bool passOnReg;

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

                if (source.Type == OperandType.V128 && passOnReg)
                {
                    // V128 is a struct, we pass each half on a GPR if possible.
                    Operand argReg  = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
                    Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);

                    nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg, source, Const(0)));
                    nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg2, source, Const(1)));

                    continue;
                }

                if (passOnReg)
                {
                    Operand argReg = source.Type.IsInteger()
                        ? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
                        : Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);

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

                    HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp);

                    sources.Add(argReg);
                }
                else
                {
                    Operand offset = new Operand(stackOffset);

                    Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);

                    HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp);

                    stackOffset += source.Type.GetSizeInBytes();
                }
            }

            if (dest != null)
            {
                if (dest.Type == OperandType.V128)
                {
                    Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
                    Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);

                    node = nodes.AddAfter(node, new Operation(Instruction.VectorCreateScalar, dest, retLReg));
                    node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));

                    operation.Destination = null;
                }
                else
                {
                    Operand retReg = dest.Type.IsInteger()
                        ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
                        : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);

                    Operation copyOp = new Operation(Instruction.Copy, dest, retReg);

                    node = nodes.AddAfter(node, copyOp);

                    operation.Destination = retReg;
                }
            }

            operation.SetSources(sources.ToArray());

            return(node);
        }
Ejemplo n.º 5
0
        public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs)
        {
            maxCallArgs = -1;

            CallConvName callConv = CallingConvention.GetCurrentCallConv();

            Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()];

            foreach (BasicBlock block in cctx.Cfg.Blocks)
            {
                LLNode nextNode;

                for (LLNode node = block.Operations.First; node != null; node = nextNode)
                {
                    nextNode = node.Next;

                    if (!(node.Value is Operation operation))
                    {
                        continue;
                    }

                    HandleConstantCopy(node, operation);

                    HandleSameDestSrc1Copy(node, operation);

                    HandleFixedRegisterCopy(node, operation);

                    switch (operation.Instruction)
                    {
                    case Instruction.Call:
                        // Get the maximum number of arguments used on a call.
                        // On windows, when a struct is returned from the call,
                        // we also need to pass the pointer where the struct
                        // should be written on the first argument.
                        int argsCount = operation.SourcesCount - 1;

                        if (operation.Destination != null && operation.Destination.Type == OperandType.V128)
                        {
                            argsCount++;
                        }

                        if (maxCallArgs < argsCount)
                        {
                            maxCallArgs = argsCount;
                        }

                        // Copy values to registers expected by the function
                        // being called, as mandated by the ABI.
                        if (callConv == CallConvName.Windows)
                        {
                            node = HandleCallWindowsAbi(stackAlloc, node, operation);
                        }
                        else     /* if (callConv == CallConvName.SystemV) */
                        {
                            node = HandleCallSystemVAbi(node, operation);
                        }
                        break;

                    case Instruction.ConvertToFPUI:
                        HandleConvertToFPUI(node, operation);
                        break;

                    case Instruction.LoadArgument:
                        if (callConv == CallConvName.Windows)
                        {
                            HandleLoadArgumentWindowsAbi(cctx, node, preservedArgs, operation);
                        }
                        else     /* if (callConv == CallConvName.SystemV) */
                        {
                            HandleLoadArgumentSystemVAbi(cctx, node, preservedArgs, operation);
                        }
                        break;

                    case Instruction.Negate:
                        if (!operation.GetSource(0).Type.IsInteger())
                        {
                            node = HandleNegate(node, operation);
                        }
                        break;

                    case Instruction.Return:
                        if (callConv == CallConvName.Windows)
                        {
                            HandleReturnWindowsAbi(cctx, node, preservedArgs, operation);
                        }
                        else     /* if (callConv == CallConvName.SystemV) */
                        {
                            HandleReturnSystemVAbi(node, operation);
                        }
                        break;

                    case Instruction.VectorInsert8:
                        if (!HardwareCapabilities.SupportsSse41)
                        {
                            node = HandleVectorInsert8(node, operation);
                        }
                        break;
                    }
                }
            }
        }