Пример #1
0
        private Operand Add(Intrinsic intrin, Operand dest, params Operand[] sources)
        {
            NewNextBlockIfNeeded();

            IntrinsicOperation operation = new IntrinsicOperation(intrin, dest, sources);

            _irBlock.Operations.AddLast(operation);

            return(dest);
        }
Пример #2
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);
        }