private Operand Add(Intrinsic intrin, Operand dest, params Operand[] sources) { NewNextBlockIfNeeded(); IntrinsicOperation operation = new IntrinsicOperation(intrin, dest, sources); _irBlock.Operations.AddLast(operation); return(dest); }
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); }