Beispiel #1
0
        public EmitterContext()
        {
            _irLabels = new Dictionary <Operand, BasicBlock>();
            _irBlocks = new IntrusiveList <BasicBlock>();

            _needsNewBlock = true;
        }
Beispiel #2
0
        private static Node HandleNegate(IntrusiveList <Node> nodes, Node node, Operation operation)
        {
            // There's no SSE FP negate instruction, so we need to transform that into
            // a XOR of the value to be negated with a mask with the highest bit set.
            // This also produces -0 for a negation of the value 0.
            Operand dest   = operation.Destination;
            Operand source = operation.GetSource(0);

            Debug.Assert(dest.Type == OperandType.FP32 ||
                         dest.Type == OperandType.FP64, $"Invalid destination type \"{dest.Type}\".");

            Node currentNode = node;

            Operand res = Local(dest.Type);

            node = nodes.AddAfter(node, new Operation(Instruction.VectorOne, res));

            if (dest.Type == OperandType.FP32)
            {
                node = nodes.AddAfter(node, new IntrinsicOperation(Intrinsic.X86Pslld, res, res, Const(31)));
            }
            else /* if (dest.Type == OperandType.FP64) */
            {
                node = nodes.AddAfter(node, new IntrinsicOperation(Intrinsic.X86Psllq, res, res, Const(63)));
            }

            node = nodes.AddAfter(node, new IntrinsicOperation(Intrinsic.X86Xorps, res, res, source));

            node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, res));

            Delete(nodes, currentNode, operation);

            return(node);
        }
Beispiel #3
0
        private static void HandleReturnSystemVAbi(IntrusiveList <Node> nodes, Node node, Operation operation)
        {
            if (operation.SourcesCount == 0)
            {
                return;
            }

            Operand source = operation.GetSource(0);

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

                nodes.AddBefore(node, new Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
                nodes.AddBefore(node, new Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
            }
            else
            {
                Operand retReg = source.Type.IsInteger()
                    ? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
                    : Xmm(CallingConvention.GetVecReturnRegister(), source.Type);

                Operation retCopyOp = new Operation(Instruction.Copy, retReg, source);

                nodes.AddBefore(node, retCopyOp);
            }
        }
Beispiel #4
0
        public ControlFlowGraph(BasicBlock entry, IntrusiveList <BasicBlock> blocks)
        {
            Entry  = entry;
            Blocks = blocks;

            Update(removeUnreachableBlocks: true);
        }
Beispiel #5
0
        public ControlFlowGraph(BasicBlock entry, IntrusiveList <BasicBlock> blocks, int localsCount)
        {
            Entry       = entry;
            Blocks      = blocks;
            LocalsCount = localsCount;

            Update(removeUnreachableBlocks: true);
        }
Beispiel #6
0
        public ControlFlowGraph(BasicBlock entry, IntrusiveList <BasicBlock> blocks, int localsCount)
        {
            Entry       = entry;
            Blocks      = blocks;
            LocalsCount = localsCount;

            Update();
        }
Beispiel #7
0
        public EmitterContext()
        {
            _irLabels = new Dictionary <Operand, BasicBlock>();
            _irBlocks = new IntrusiveList <BasicBlock>();

            _needsNewBlock = true;
            _nextBlockFreq = BasicBlockFrequency.Default;
        }
Beispiel #8
0
        private static void HandleReturnWindowsAbi(
            CompilerContext cctx,
            IntrusiveList <Node> nodes,
            Node node,
            Operand[] preservedArgs,
            Operation operation)
        {
            if (operation.SourcesCount == 0)
            {
                return;
            }

            Operand source = operation.GetSource(0);

            Operand retReg;

            if (source.Type.IsInteger())
            {
                retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
            }
            else if (source.Type == OperandType.V128)
            {
                if (preservedArgs[0] == null)
                {
                    Operand preservedArg = Local(OperandType.I64);

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

                    Operation copyOp = new Operation(Instruction.Copy, preservedArg, arg0);

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

                    preservedArgs[0] = preservedArg;
                }

                retReg = preservedArgs[0];
            }
            else
            {
                retReg = Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
            }

            if (source.Type == OperandType.V128)
            {
                Operation retStoreOp = new Operation(Instruction.Store, null, retReg, source);

                nodes.AddBefore(node, retStoreOp);
            }
            else
            {
                Operation retCopyOp = new Operation(Instruction.Copy, retReg, source);

                nodes.AddBefore(node, retCopyOp);
            }

            operation.SetSources(System.Array.Empty <Operand>());
        }
Beispiel #9
0
        private static Operand AddCopy(IntrusiveList <Node> nodes, Node node, Operand source)
        {
            Operand temp = Local(source.Type);

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

            nodes.AddBefore(node, copyOp);

            return(temp);
        }
Beispiel #10
0
        private static Node HandleConvertToFPUI(IntrusiveList <Node> nodes, Node node, Operation operation)
        {
            // Unsigned integer to FP conversions are not supported on X86.
            // We need to turn them into signed integer to FP conversions, and
            // adjust the final result.
            Operand dest   = operation.Destination;
            Operand source = operation.GetSource(0);

            Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");

            Node currentNode = node;

            if (source.Type == OperandType.I32)
            {
                // For 32-bits integers, we can just zero-extend to 64-bits,
                // and then use the 64-bits signed conversion instructions.
                Operand zex = Local(OperandType.I64);

                node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend32, zex, source));
                node = nodes.AddAfter(node, new Operation(Instruction.ConvertToFP, dest, zex));
            }
            else /* if (source.Type == OperandType.I64) */
            {
                // For 64-bits integers, we need to do the following:
                // - Ensure that the integer has the most significant bit clear.
                // -- This can be done by shifting the value right by 1, that is, dividing by 2.
                // -- The least significant bit is lost in this case though.
                // - We can then convert the shifted value with a signed integer instruction.
                // - The result still needs to be corrected after that.
                // -- First, we need to multiply the result by 2, as we divided it by 2 before.
                // --- This can be done efficiently by adding the result to itself.
                // -- Then, we need to add the least significant bit that was shifted out.
                // --- We can convert the least significant bit to float, and add it to the result.
                Operand lsb  = Local(OperandType.I64);
                Operand half = Local(OperandType.I64);

                Operand lsbF = Local(dest.Type);

                node = nodes.AddAfter(node, new Operation(Instruction.Copy, lsb, source));
                node = nodes.AddAfter(node, new Operation(Instruction.Copy, half, source));

                node = nodes.AddAfter(node, new Operation(Instruction.BitwiseAnd, lsb, lsb, Const(1L)));
                node = nodes.AddAfter(node, new Operation(Instruction.ShiftRightUI, half, half, Const(1)));

                node = nodes.AddAfter(node, new Operation(Instruction.ConvertToFP, lsbF, lsb));
                node = nodes.AddAfter(node, new Operation(Instruction.ConvertToFP, dest, half));

                node = nodes.AddAfter(node, new Operation(Instruction.Add, dest, dest, dest));
                node = nodes.AddAfter(node, new Operation(Instruction.Add, dest, dest, lsbF));
            }

            Delete(nodes, currentNode, operation);

            return(node);
        }
Beispiel #11
0
        private static void Delete(IntrusiveList <Node> nodes, Node node, Operation operation)
        {
            operation.Destination = null;

            for (int index = 0; index < operation.SourcesCount; index++)
            {
                operation.SetSource(index, null);
            }

            nodes.Remove(node);
        }
Beispiel #12
0
        private static Operand AddXmmCopy(IntrusiveList <Node> nodes, Node node, Operand source)
        {
            Operand temp = Local(source.Type);

            Operand intConst = AddCopy(nodes, node, GetIntConst(source));

            Operation copyOp = new Operation(Instruction.VectorCreateScalar, temp, intConst);

            nodes.AddBefore(node, copyOp);

            return(temp);
        }
Beispiel #13
0
        private void RemoveUnreachableBlocks(IntrusiveList <BasicBlock> blocks)
        {
            HashSet <BasicBlock> visited = new HashSet <BasicBlock>();

            Queue <BasicBlock> workQueue = new Queue <BasicBlock>();

            visited.Add(Entry);

            workQueue.Enqueue(Entry);

            while (workQueue.TryDequeue(out BasicBlock block))
            {
                Debug.Assert(block.Index != -1, "Invalid block index.");

                if (block.Next != null && visited.Add(block.Next))
                {
                    workQueue.Enqueue(block.Next);
                }

                if (block.Branch != null && visited.Add(block.Branch))
                {
                    workQueue.Enqueue(block.Branch);
                }
            }

            if (visited.Count < blocks.Count)
            {
                // Remove unreachable blocks and renumber.
                int index = 0;

                for (BasicBlock block = blocks.First; block != null;)
                {
                    BasicBlock nextBlock = block.ListNext;

                    if (!visited.Contains(block))
                    {
                        block.Next   = null;
                        block.Branch = null;

                        blocks.Remove(block);
                    }
                    else
                    {
                        block.Index = index++;
                    }

                    block = nextBlock;
                }
            }
        }
Beispiel #14
0
        private void RemoveUnreachableBlocks(IntrusiveList <BasicBlock> blocks)
        {
            var visited   = new HashSet <BasicBlock>();
            var workQueue = new Queue <BasicBlock>();

            visited.Add(Entry);
            workQueue.Enqueue(Entry);

            while (workQueue.TryDequeue(out BasicBlock block))
            {
                Debug.Assert(block.Index != -1, "Invalid block index.");

                for (int i = 0; i < block.SuccessorsCount; i++)
                {
                    BasicBlock succ = block.GetSuccessor(i);

                    if (visited.Add(succ))
                    {
                        workQueue.Enqueue(succ);
                    }
                }
            }

            if (visited.Count < blocks.Count)
            {
                // Remove unreachable blocks and renumber.
                int index = 0;

                for (BasicBlock block = blocks.First; block != null;)
                {
                    BasicBlock nextBlock = block.ListNext;

                    if (!visited.Contains(block))
                    {
                        while (block.SuccessorsCount > 0)
                        {
                            block.RemoveSuccessor(index: block.SuccessorsCount - 1);
                        }

                        blocks.Remove(block);
                    }
                    else
                    {
                        block.Index = index++;
                    }

                    block = nextBlock;
                }
            }
        }
Beispiel #15
0
        private static Node HandleVectorInsert8(IntrusiveList <Node> nodes, Node node, Operation operation)
        {
            // Handle vector insertion, when SSE 4.1 is not supported.
            Operand dest = operation.Destination;
            Operand src1 = operation.GetSource(0); // Vector
            Operand src2 = operation.GetSource(1); // Value
            Operand src3 = operation.GetSource(2); // Index

            Debug.Assert(src3.Kind == OperandKind.Constant);

            byte index = src3.AsByte();

            Debug.Assert(index < 16);

            Node currentNode = node;

            Operand temp1 = Local(OperandType.I32);
            Operand temp2 = Local(OperandType.I32);

            node = nodes.AddAfter(node, new Operation(Instruction.Copy, temp2, src2));

            Operation vextOp = new Operation(Instruction.VectorExtract16, temp1, src1, Const(index >> 1));

            node = nodes.AddAfter(node, vextOp);

            if ((index & 1) != 0)
            {
                node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend8, temp1, temp1));
                node = nodes.AddAfter(node, new Operation(Instruction.ShiftLeft, temp2, temp2, Const(8)));
                node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
            }
            else
            {
                node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend8, temp2, temp2));
                node = nodes.AddAfter(node, new Operation(Instruction.BitwiseAnd, temp1, temp1, Const(0xff00)));
                node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
            }

            Operation vinsOp = new Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1));

            node = nodes.AddAfter(node, vinsOp);

            Delete(nodes, currentNode, operation);

            return(node);
        }
Beispiel #16
0
        public ControlFlowGraph(BasicBlock entry, IntrusiveList<BasicBlock> blocks)
        {
            Entry = entry;
            Blocks = blocks;

            RemoveUnreachableBlocks(blocks);

            var visited = new HashSet<BasicBlock>();
            var blockStack = new Stack<BasicBlock>();

            PostOrderBlocks = new BasicBlock[blocks.Count];
            PostOrderMap = new int[blocks.Count];

            visited.Add(entry);
            blockStack.Push(entry);

            int index = 0;

            while (blockStack.TryPop(out BasicBlock block))
            {
                bool visitedNew = false;

                for (int i = 0; i < block.SuccessorCount; i++)
                {
                    BasicBlock succ = block.GetSuccessor(i);

                    if (visited.Add(succ))
                    {
                        blockStack.Push(block);
                        blockStack.Push(succ);

                        visitedNew = true;

                        break;
                    }
                }

                if (!visitedNew)
                {
                    PostOrderMap[block.Index] = index;

                    PostOrderBlocks[index++] = block;
                }
            }
        }
Beispiel #17
0
        public ControlFlowGraph(BasicBlock entry, IntrusiveList <BasicBlock> blocks)
        {
            Entry  = entry;
            Blocks = blocks;

            RemoveUnreachableBlocks(blocks);

            HashSet <BasicBlock> visited = new HashSet <BasicBlock>();

            Stack <BasicBlock> blockStack = new Stack <BasicBlock>();

            PostOrderBlocks = new BasicBlock[blocks.Count];

            PostOrderMap = new int[blocks.Count];

            visited.Add(entry);

            blockStack.Push(entry);

            int index = 0;

            while (blockStack.TryPop(out BasicBlock block))
            {
                if (block.Next != null && visited.Add(block.Next))
                {
                    blockStack.Push(block);
                    blockStack.Push(block.Next);
                }
                else if (block.Branch != null && visited.Add(block.Branch))
                {
                    blockStack.Push(block);
                    blockStack.Push(block.Branch);
                }
                else
                {
                    PostOrderMap[block.Index] = index;

                    PostOrderBlocks[index++] = block;
                }
            }
        }
Beispiel #18
0
        private static Node HandleSameDestSrc1Copy(IntrusiveList <Node> nodes, Node node, Operation operation)
        {
            if (operation.Destination == null || operation.SourcesCount == 0)
            {
                return(node);
            }

            Instruction inst = operation.Instruction;

            Operand dest = operation.Destination;
            Operand src1 = operation.GetSource(0);

            // The multiply instruction (that maps to IMUL) is somewhat special, it has
            // a three operand form where the second source is a immediate value.
            bool threeOperandForm = inst == Instruction.Multiply && operation.GetSource(1).Kind == OperandKind.Constant;

            if (IsSameOperandDestSrc1(operation) && src1.Kind == OperandKind.LocalVariable && !threeOperandForm)
            {
                bool useNewLocal = false;

                for (int srcIndex = 1; srcIndex < operation.SourcesCount; srcIndex++)
                {
                    if (operation.GetSource(srcIndex) == dest)
                    {
                        useNewLocal = true;

                        break;
                    }
                }

                if (useNewLocal)
                {
                    // Dest is being used as some source already, we need to use a new
                    // local to store the temporary value, otherwise the value on dest
                    // local would be overwritten.
                    Operand temp = Local(dest.Type);

                    nodes.AddBefore(node, new Operation(Instruction.Copy, temp, src1));

                    operation.SetSource(0, temp);

                    node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, temp));

                    operation.Destination = temp;
                }
                else
                {
                    nodes.AddBefore(node, new Operation(Instruction.Copy, dest, src1));

                    operation.SetSource(0, dest);
                }
            }
            else if (inst == Instruction.ConditionalSelect)
            {
                Operand src2 = operation.GetSource(1);
                Operand src3 = operation.GetSource(2);

                if (src1 == dest || src2 == dest)
                {
                    Operand temp = Local(dest.Type);

                    nodes.AddBefore(node, new Operation(Instruction.Copy, temp, src3));

                    operation.SetSource(2, temp);

                    node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, temp));

                    operation.Destination = temp;
                }
                else
                {
                    nodes.AddBefore(node, new Operation(Instruction.Copy, dest, src3));

                    operation.SetSource(2, dest);
                }
            }

            return(node);
        }
Beispiel #19
0
        private static void HandleConstantCopy(IntrusiveList <Node> nodes, Node node, Operation operation)
        {
            if (operation.SourcesCount == 0 || IsIntrinsic(operation.Instruction))
            {
                return;
            }

            Instruction inst = operation.Instruction;

            Operand src1 = operation.GetSource(0);
            Operand src2;

            if (src1.Kind == OperandKind.Constant)
            {
                if (!src1.Type.IsInteger())
                {
                    // Handle non-integer types (FP32, FP64 and V128).
                    // For instructions without an immediate operand, we do the following:
                    // - Insert a copy with the constant value (as integer) to a GPR.
                    // - Insert a copy from the GPR to a XMM register.
                    // - Replace the constant use with the XMM register.
                    src1 = AddXmmCopy(nodes, node, src1);

                    operation.SetSource(0, src1);
                }
                else if (!HasConstSrc1(inst))
                {
                    // Handle integer types.
                    // Most ALU instructions accepts a 32-bits immediate on the second operand.
                    // We need to ensure the following:
                    // - If the constant is on operand 1, we need to move it.
                    // -- But first, we try to swap operand 1 and 2 if the instruction is commutative.
                    // -- Doing so may allow us to encode the constant as operand 2 and avoid a copy.
                    // - If the constant is on operand 2, we check if the instruction supports it,
                    // if not, we also add a copy. 64-bits constants are usually not supported.
                    if (IsCommutative(inst))
                    {
                        src2 = operation.GetSource(1);

                        Operand temp = src1;

                        src1 = src2;
                        src2 = temp;

                        operation.SetSource(0, src1);
                        operation.SetSource(1, src2);
                    }

                    if (src1.Kind == OperandKind.Constant)
                    {
                        src1 = AddCopy(nodes, node, src1);

                        operation.SetSource(0, src1);
                    }
                }
            }

            if (operation.SourcesCount < 2)
            {
                return;
            }

            src2 = operation.GetSource(1);

            if (src2.Kind == OperandKind.Constant)
            {
                if (!src2.Type.IsInteger())
                {
                    src2 = AddXmmCopy(nodes, node, src2);

                    operation.SetSource(1, src2);
                }
                else if (!HasConstSrc2(inst) || CodeGenCommon.IsLongConst(src2))
                {
                    src2 = AddCopy(nodes, node, src2);

                    operation.SetSource(1, src2);
                }
            }
        }
Beispiel #20
0
        private static Node HandleFixedRegisterCopy(IntrusiveList <Node> nodes, Node node, Operation operation)
        {
            Operand dest = operation.Destination;

            switch (operation.Instruction)
            {
            case Instruction.CompareAndSwap128:
            {
                // Handle the many restrictions of the compare and exchange (16 bytes) instruction:
                // - The expected value should be in RDX:RAX.
                // - The new value to be written should be in RCX:RBX.
                // - The value at the memory location is loaded to RDX:RAX.
                void SplitOperand(Operand source, Operand lr, Operand hr)
                {
                    nodes.AddBefore(node, new Operation(Instruction.VectorExtract, lr, source, Const(0)));
                    nodes.AddBefore(node, new Operation(Instruction.VectorExtract, hr, source, Const(1)));
                }

                Operand rax = Gpr(X86Register.Rax, OperandType.I64);
                Operand rbx = Gpr(X86Register.Rbx, OperandType.I64);
                Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
                Operand rdx = Gpr(X86Register.Rdx, OperandType.I64);

                SplitOperand(operation.GetSource(1), rax, rdx);
                SplitOperand(operation.GetSource(2), rbx, rcx);

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

                operation.SetDestinations(new Operand[] { rdx, rax });

                operation.SetSources(new Operand[] { operation.GetSource(0), rdx, rax, rcx, rbx });

                break;
            }

            case Instruction.CpuId:
            {
                // Handle the many restrictions of the CPU Id instruction:
                // - EAX controls the information returned by this instruction.
                // - When EAX is 1, feature information is returned.
                // - The information is written to registers EAX, EBX, ECX and EDX.
                Debug.Assert(dest.Type == OperandType.I64);

                Operand eax = Gpr(X86Register.Rax, OperandType.I32);
                Operand ebx = Gpr(X86Register.Rbx, OperandType.I32);
                Operand ecx = Gpr(X86Register.Rcx, OperandType.I32);
                Operand edx = Gpr(X86Register.Rdx, OperandType.I32);

                // Value 0x01 = Version, family and feature information.
                nodes.AddBefore(node, new Operation(Instruction.Copy, eax, Const(1)));

                // Copy results to the destination register.
                // The values are split into 2 32-bits registers, we merge them
                // into a single 64-bits register.
                Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);

                node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend32, dest, edx));
                node = nodes.AddAfter(node, new Operation(Instruction.ShiftLeft, dest, dest, Const(32)));
                node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr, dest, dest, rcx));

                operation.SetDestinations(new Operand[] { eax, ebx, ecx, edx });

                operation.SetSources(new Operand[] { eax });

                break;
            }

            case Instruction.Divide:
            case Instruction.DivideUI:
            {
                // Handle the many restrictions of the division instructions:
                // - The dividend is always in RDX:RAX.
                // - The result is always in RAX.
                // - Additionally it also writes the remainder in RDX.
                if (dest.Type.IsInteger())
                {
                    Operand src1 = operation.GetSource(0);

                    Operand rax = Gpr(X86Register.Rax, src1.Type);
                    Operand rdx = Gpr(X86Register.Rdx, src1.Type);

                    nodes.AddBefore(node, new Operation(Instruction.Copy, rax, src1));
                    nodes.AddBefore(node, new Operation(Instruction.Clobber, rdx));

                    node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rax));

                    operation.SetDestinations(new Operand[] { rdx, rax });

                    operation.SetSources(new Operand[] { rdx, rax, operation.GetSource(1) });

                    operation.Destination = rax;
                }

                break;
            }

            case Instruction.Extended:
            {
                IntrinsicOperation intrinOp = (IntrinsicOperation)operation;

                // BLENDVPD, BLENDVPS, PBLENDVB last operand is always implied to be XMM0 when VEX is not supported.
                if ((intrinOp.Intrinsic == Intrinsic.X86Blendvpd ||
                     intrinOp.Intrinsic == Intrinsic.X86Blendvps ||
                     intrinOp.Intrinsic == Intrinsic.X86Pblendvb) &&
                    !HardwareCapabilities.SupportsVexEncoding)
                {
                    Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128);

                    nodes.AddBefore(node, new Operation(Instruction.Copy, xmm0, operation.GetSource(2)));

                    operation.SetSource(2, xmm0);
                }

                break;
            }

            case Instruction.Multiply64HighSI:
            case Instruction.Multiply64HighUI:
            {
                // Handle the many restrictions of the i64 * i64 = i128 multiply instructions:
                // - The multiplicand is always in RAX.
                // - The lower 64-bits of the result is always in RAX.
                // - The higher 64-bits of the result is always in RDX.
                Operand src1 = operation.GetSource(0);

                Operand rax = Gpr(X86Register.Rax, src1.Type);
                Operand rdx = Gpr(X86Register.Rdx, src1.Type);

                nodes.AddBefore(node, new Operation(Instruction.Copy, rax, src1));

                operation.SetSource(0, rax);

                node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rdx));

                operation.SetDestinations(new Operand[] { rdx, rax });

                break;
            }

            case Instruction.RotateRight:
            case Instruction.ShiftLeft:
            case Instruction.ShiftRightSI:
            case Instruction.ShiftRightUI:
            {
                // The shift register is always implied to be CL (low 8-bits of RCX or ECX).
                if (operation.GetSource(1).Kind == OperandKind.LocalVariable)
                {
                    Operand rcx = Gpr(X86Register.Rcx, OperandType.I32);

                    nodes.AddBefore(node, new Operation(Instruction.Copy, rcx, operation.GetSource(1)));

                    operation.SetSource(1, rcx);
                }

                break;
            }
            }

            return(node);
        }
Beispiel #21
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.
            }
        }
Beispiel #22
0
        private static void HandleLoadArgumentWindowsAbi(
            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 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]);

                nodes.AddBefore(node, argCopyOp);

                Delete(nodes, node, operation);
            }
            else
            {
                // TODO: Pass on stack.
            }
        }
Beispiel #23
0
        private static Node HandleCallSystemVAbi(IntrusiveList <Node> nodes, Node node, Operation operation)
        {
            Operand dest = operation.Destination;

            List <Operand> sources = new List <Operand>
            {
                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, 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, 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);
        }
Beispiel #24
0
        private static Node HandleCallWindowsAbi(IntrusiveList <Node> nodes, StackAllocator stackAlloc, Node node, Operation operation)
        {
            Operand dest = operation.Destination;

            // 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, 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, 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, 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);
        }