diff --git a/lib/Target/X86/InstSelectSimple.cpp b/lib/Target/X86/InstSelectSimple.cpp index 4a04b2910fc..4988a0dc4c6 100644 --- a/lib/Target/X86/InstSelectSimple.cpp +++ b/lib/Target/X86/InstSelectSimple.cpp @@ -1502,6 +1502,8 @@ void ISel::LowerUnknownIntrinsicFunctionCalls(Function &F) { case Intrinsic::frameaddress: case Intrinsic::memcpy: case Intrinsic::memset: + case Intrinsic::readport: + case Intrinsic::writeport: // We directly implement these intrinsics break; default: @@ -1663,6 +1665,65 @@ void ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) { return; } + case Intrinsic::readport: + // + // First, determine that the size of the operand falls within the + // acceptable range for this architecture. + // + assert (((CI.getOperand(1)->getType()->getPrimitiveSize()) == 2) && + "llvm.readport operand size is not a 16 bit value!"); + + // + // Now, move the I/O port address into the DX register and use the IN + // instruction to get the input data. + // + BuildMI(BB, X86::MOV16rr, 1, X86::DX).addReg(getReg(CI.getOperand(1))); + switch (CI.getCalledFunction()->getReturnType()->getPrimitiveSize()) { + case 1: + BuildMI(BB, X86::IN8, 1); + break; + case 2: + BuildMI(BB, X86::IN16, 1); + break; + case 4: + BuildMI(BB, X86::IN32, 1); + break; + default: + assert (0 && "Cannot do input on this data type"); + } + return; + + case Intrinsic::writeport: + // + // First, determine that the size of the operand falls within the + // acceptable range for this architecture. + // + assert (((CI.getOperand(1)->getType()->getPrimitiveSize()) == 2) && + "llvm.readport operand size is not a 16 bit value!"); + + // + // Now, move the I/O port address into the DX register and the value to + // write into the AL/AX/EAX register. + // + BuildMI(BB, X86::MOV16rr, 1, X86::DX).addReg(getReg(CI.getOperand(1))); + switch (CI.getOperand(2)->getType()->getPrimitiveSize()) { + case 1: + BuildMI(BB, X86::MOV8rr, 1, X86::AL).addReg(getReg(CI.getOperand(2))); + BuildMI(BB, X86::OUT8, 1); + break; + case 2: + BuildMI(BB, X86::MOV16rr, 1, X86::AX).addReg(getReg(CI.getOperand(2))); + BuildMI(BB, X86::OUT16, 1); + break; + case 4: + BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(getReg(CI.getOperand(2))); + BuildMI(BB, X86::OUT32, 1); + break; + default: + assert (0 && "Cannot do input on this data type"); + } + return; + default: assert(0 && "Error: unknown intrinsics should have been lowered!"); } } diff --git a/lib/Target/X86/Printer.cpp b/lib/Target/X86/Printer.cpp index 73971bbe7f6..e2f06846d95 100644 --- a/lib/Target/X86/Printer.cpp +++ b/lib/Target/X86/Printer.cpp @@ -105,7 +105,8 @@ namespace { } void printImplUsesBefore(const TargetInstrDescriptor &Desc); - void printImplUsesAfter(const TargetInstrDescriptor &Desc); + bool printImplUsesAfter(const TargetInstrDescriptor &Desc, const bool LC); + bool printImplDefsAfter(const TargetInstrDescriptor &Desc, const bool LC); void printMachineInstruction(const MachineInstr *MI); void printOp(const MachineOperand &MO, bool elideOffsetKeyword = false); @@ -546,14 +547,65 @@ void Printer::printImplUsesBefore(const TargetInstrDescriptor &Desc) { /// printImplUsesAfter - Emit the implicit-use registers for the instruction /// described by DESC, if its PrintImplUsesAfter flag is set. /// -void Printer::printImplUsesAfter(const TargetInstrDescriptor &Desc) { +/// Inputs: +/// Comma - List of registers will need a leading comma. +/// Desc - Description of the Instruction. +/// +/// Return value: +/// true - Emitted one or more registers. +/// false - Emitted no registers. +/// +bool Printer::printImplUsesAfter(const TargetInstrDescriptor &Desc, + const bool Comma = true) { const MRegisterInfo &RI = *TM.getRegisterInfo(); if (Desc.TSFlags & X86II::PrintImplUsesAfter) { - for (const unsigned *p = Desc.ImplicitUses; *p; ++p) { + bool emitted = false; + const unsigned *p = Desc.ImplicitUses; + if (*p) { + O << (Comma ? ", %" : "%") << RI.get (*p).Name; + emitted = true; + ++p; + } + while (*p) { // Bug Workaround: See note in Printer::doInitialization about %. O << ", %" << RI.get(*p).Name; + ++p; } + return emitted; } + return false; +} + +/// printImplDefsAfter - Emit the implicit-definition registers for the +/// instruction described by DESC, if its PrintImplDefsAfter flag is set. +/// +/// Inputs: +/// Comma - List of registers will need a leading comma. +/// Desc - Description of the Instruction +/// +/// Return value: +/// true - Emitted one or more registers. +/// false - Emitted no registers. +/// +bool Printer::printImplDefsAfter(const TargetInstrDescriptor &Desc, + const bool Comma = true) { + const MRegisterInfo &RI = *TM.getRegisterInfo(); + if (Desc.TSFlags & X86II::PrintImplDefsAfter) { + bool emitted = false; + const unsigned *p = Desc.ImplicitDefs; + if (*p) { + O << (Comma ? ", %" : "%") << RI.get (*p).Name; + emitted = true; + ++p; + } + while (*p) { + // Bug Workaround: See note in Printer::doInitialization about %. + O << ", %" << RI.get(*p).Name; + ++p; + } + return emitted; + } + return false; } /// printMachineInstruction -- Print out a single X86 LLVM instruction @@ -575,33 +627,36 @@ void Printer::printMachineInstruction(const MachineInstr *MI) { printOp(MI->getOperand(0)); O << " = phi "; for (unsigned i = 1, e = MI->getNumOperands(); i != e; i+=2) { - if (i != 1) O << ", "; - O << "["; - printOp(MI->getOperand(i)); - O << ", "; - printOp(MI->getOperand(i+1)); - O << "]"; + if (i != 1) O << ", "; + O << "["; + printOp(MI->getOperand(i)); + O << ", "; + printOp(MI->getOperand(i+1)); + O << "]"; } } else { unsigned i = 0; if (MI->getNumOperands() && MI->getOperand(0).isDef()) { - printOp(MI->getOperand(0)); - O << " = "; - ++i; + printOp(MI->getOperand(0)); + O << " = "; + ++i; } O << TII.getName(MI->getOpcode()); for (unsigned e = MI->getNumOperands(); i != e; ++i) { - O << " "; - if (MI->getOperand(i).isDef()) O << "*"; - printOp(MI->getOperand(i)); - if (MI->getOperand(i).isDef()) O << "*"; + O << " "; + if (MI->getOperand(i).isDef()) O << "*"; + printOp(MI->getOperand(i)); + if (MI->getOperand(i).isDef()) O << "*"; } } O << "\n"; return; case X86II::RawFrm: + { + bool LeadingComma = false; + // The accepted forms of Raw instructions are: // 1. nop - No operand required // 2. jmp foo - PC relative displacement operand @@ -617,9 +672,13 @@ void Printer::printMachineInstruction(const MachineInstr *MI) { if (MI->getNumOperands() == 1) { printOp(MI->getOperand(0), true); // Don't print "OFFSET"... + LeadingComma = true; } + LeadingComma = printImplDefsAfter(Desc, LeadingComma) || LeadingComma; + printImplUsesAfter(Desc, LeadingComma); O << "\n"; return; + } case X86II::AddRegFrm: { // There are currently two forms of acceptable AddRegFrm instructions. diff --git a/lib/Target/X86/X86.td b/lib/Target/X86/X86.td index 5584dd0d195..3cb54b6dc95 100644 --- a/lib/Target/X86/X86.td +++ b/lib/Target/X86/X86.td @@ -33,12 +33,26 @@ def X86InstrInfo : InstrInfo { // Define how we want to layout our TargetSpecific information field... This // should be kept up-to-date with the fields in the X86InstrInfo.h file. - let TSFlagsFields = ["FormBits" , "hasOpSizePrefix" , "Prefix", "MemTypeBits", - "ImmTypeBits", "FPFormBits", "printImplicitUsesAfter", - "printImplicitUsesBefore", "Opcode"]; - let TSFlagsShifts = [0, 5, 6, 10, 13, - 15, 18, 19, - 20]; + let TSFlagsFields = ["FormBits", + "hasOpSizePrefix", + "Prefix", + "MemTypeBits", + "ImmTypeBits", + "FPFormBits", + "printImplicitUsesAfter", + "printImplicitUsesBefore", + "printImplicitDefsAfter", + "Opcode"]; + let TSFlagsShifts = [0, + 5, + 6, + 10, + 13, + 15, + 18, + 19, + 20, + 21]; } def X86 : Target { diff --git a/lib/Target/X86/X86AsmPrinter.cpp b/lib/Target/X86/X86AsmPrinter.cpp index 73971bbe7f6..e2f06846d95 100644 --- a/lib/Target/X86/X86AsmPrinter.cpp +++ b/lib/Target/X86/X86AsmPrinter.cpp @@ -105,7 +105,8 @@ namespace { } void printImplUsesBefore(const TargetInstrDescriptor &Desc); - void printImplUsesAfter(const TargetInstrDescriptor &Desc); + bool printImplUsesAfter(const TargetInstrDescriptor &Desc, const bool LC); + bool printImplDefsAfter(const TargetInstrDescriptor &Desc, const bool LC); void printMachineInstruction(const MachineInstr *MI); void printOp(const MachineOperand &MO, bool elideOffsetKeyword = false); @@ -546,14 +547,65 @@ void Printer::printImplUsesBefore(const TargetInstrDescriptor &Desc) { /// printImplUsesAfter - Emit the implicit-use registers for the instruction /// described by DESC, if its PrintImplUsesAfter flag is set. /// -void Printer::printImplUsesAfter(const TargetInstrDescriptor &Desc) { +/// Inputs: +/// Comma - List of registers will need a leading comma. +/// Desc - Description of the Instruction. +/// +/// Return value: +/// true - Emitted one or more registers. +/// false - Emitted no registers. +/// +bool Printer::printImplUsesAfter(const TargetInstrDescriptor &Desc, + const bool Comma = true) { const MRegisterInfo &RI = *TM.getRegisterInfo(); if (Desc.TSFlags & X86II::PrintImplUsesAfter) { - for (const unsigned *p = Desc.ImplicitUses; *p; ++p) { + bool emitted = false; + const unsigned *p = Desc.ImplicitUses; + if (*p) { + O << (Comma ? ", %" : "%") << RI.get (*p).Name; + emitted = true; + ++p; + } + while (*p) { // Bug Workaround: See note in Printer::doInitialization about %. O << ", %" << RI.get(*p).Name; + ++p; } + return emitted; } + return false; +} + +/// printImplDefsAfter - Emit the implicit-definition registers for the +/// instruction described by DESC, if its PrintImplDefsAfter flag is set. +/// +/// Inputs: +/// Comma - List of registers will need a leading comma. +/// Desc - Description of the Instruction +/// +/// Return value: +/// true - Emitted one or more registers. +/// false - Emitted no registers. +/// +bool Printer::printImplDefsAfter(const TargetInstrDescriptor &Desc, + const bool Comma = true) { + const MRegisterInfo &RI = *TM.getRegisterInfo(); + if (Desc.TSFlags & X86II::PrintImplDefsAfter) { + bool emitted = false; + const unsigned *p = Desc.ImplicitDefs; + if (*p) { + O << (Comma ? ", %" : "%") << RI.get (*p).Name; + emitted = true; + ++p; + } + while (*p) { + // Bug Workaround: See note in Printer::doInitialization about %. + O << ", %" << RI.get(*p).Name; + ++p; + } + return emitted; + } + return false; } /// printMachineInstruction -- Print out a single X86 LLVM instruction @@ -575,33 +627,36 @@ void Printer::printMachineInstruction(const MachineInstr *MI) { printOp(MI->getOperand(0)); O << " = phi "; for (unsigned i = 1, e = MI->getNumOperands(); i != e; i+=2) { - if (i != 1) O << ", "; - O << "["; - printOp(MI->getOperand(i)); - O << ", "; - printOp(MI->getOperand(i+1)); - O << "]"; + if (i != 1) O << ", "; + O << "["; + printOp(MI->getOperand(i)); + O << ", "; + printOp(MI->getOperand(i+1)); + O << "]"; } } else { unsigned i = 0; if (MI->getNumOperands() && MI->getOperand(0).isDef()) { - printOp(MI->getOperand(0)); - O << " = "; - ++i; + printOp(MI->getOperand(0)); + O << " = "; + ++i; } O << TII.getName(MI->getOpcode()); for (unsigned e = MI->getNumOperands(); i != e; ++i) { - O << " "; - if (MI->getOperand(i).isDef()) O << "*"; - printOp(MI->getOperand(i)); - if (MI->getOperand(i).isDef()) O << "*"; + O << " "; + if (MI->getOperand(i).isDef()) O << "*"; + printOp(MI->getOperand(i)); + if (MI->getOperand(i).isDef()) O << "*"; } } O << "\n"; return; case X86II::RawFrm: + { + bool LeadingComma = false; + // The accepted forms of Raw instructions are: // 1. nop - No operand required // 2. jmp foo - PC relative displacement operand @@ -617,9 +672,13 @@ void Printer::printMachineInstruction(const MachineInstr *MI) { if (MI->getNumOperands() == 1) { printOp(MI->getOperand(0), true); // Don't print "OFFSET"... + LeadingComma = true; } + LeadingComma = printImplDefsAfter(Desc, LeadingComma) || LeadingComma; + printImplUsesAfter(Desc, LeadingComma); O << "\n"; return; + } case X86II::AddRegFrm: { // There are currently two forms of acceptable AddRegFrm instructions. diff --git a/lib/Target/X86/X86ISelSimple.cpp b/lib/Target/X86/X86ISelSimple.cpp index 4a04b2910fc..4988a0dc4c6 100644 --- a/lib/Target/X86/X86ISelSimple.cpp +++ b/lib/Target/X86/X86ISelSimple.cpp @@ -1502,6 +1502,8 @@ void ISel::LowerUnknownIntrinsicFunctionCalls(Function &F) { case Intrinsic::frameaddress: case Intrinsic::memcpy: case Intrinsic::memset: + case Intrinsic::readport: + case Intrinsic::writeport: // We directly implement these intrinsics break; default: @@ -1663,6 +1665,65 @@ void ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) { return; } + case Intrinsic::readport: + // + // First, determine that the size of the operand falls within the + // acceptable range for this architecture. + // + assert (((CI.getOperand(1)->getType()->getPrimitiveSize()) == 2) && + "llvm.readport operand size is not a 16 bit value!"); + + // + // Now, move the I/O port address into the DX register and use the IN + // instruction to get the input data. + // + BuildMI(BB, X86::MOV16rr, 1, X86::DX).addReg(getReg(CI.getOperand(1))); + switch (CI.getCalledFunction()->getReturnType()->getPrimitiveSize()) { + case 1: + BuildMI(BB, X86::IN8, 1); + break; + case 2: + BuildMI(BB, X86::IN16, 1); + break; + case 4: + BuildMI(BB, X86::IN32, 1); + break; + default: + assert (0 && "Cannot do input on this data type"); + } + return; + + case Intrinsic::writeport: + // + // First, determine that the size of the operand falls within the + // acceptable range for this architecture. + // + assert (((CI.getOperand(1)->getType()->getPrimitiveSize()) == 2) && + "llvm.readport operand size is not a 16 bit value!"); + + // + // Now, move the I/O port address into the DX register and the value to + // write into the AL/AX/EAX register. + // + BuildMI(BB, X86::MOV16rr, 1, X86::DX).addReg(getReg(CI.getOperand(1))); + switch (CI.getOperand(2)->getType()->getPrimitiveSize()) { + case 1: + BuildMI(BB, X86::MOV8rr, 1, X86::AL).addReg(getReg(CI.getOperand(2))); + BuildMI(BB, X86::OUT8, 1); + break; + case 2: + BuildMI(BB, X86::MOV16rr, 1, X86::AX).addReg(getReg(CI.getOperand(2))); + BuildMI(BB, X86::OUT16, 1); + break; + case 4: + BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(getReg(CI.getOperand(2))); + BuildMI(BB, X86::OUT32, 1); + break; + default: + assert (0 && "Cannot do input on this data type"); + } + return; + default: assert(0 && "Error: unknown intrinsics should have been lowered!"); } } diff --git a/lib/Target/X86/X86InstrInfo.h b/lib/Target/X86/X86InstrInfo.h index 55700623550..90e8d524efc 100644 --- a/lib/Target/X86/X86InstrInfo.h +++ b/lib/Target/X86/X86InstrInfo.h @@ -121,7 +121,7 @@ namespace X86II { Mem128 = 6 << MemShift, //===------------------------------------------------------------------===// - // This tow-bit field describes the size of an immediate operand. Zero is + // This two-bit field describes the size of an immediate operand. Zero is // unused so that we can tell if we forgot to set a value. ImmShift = 13, ImmMask = 7 << ImmShift, @@ -169,9 +169,13 @@ namespace X86II { // before the normal operands. PrintImplUsesBefore = 1 << 19, - OpcodeShift = 20, + // PrintImplDefsAfter - Print out implicit defs in the assembly output + // after the normal operands. + PrintImplDefsAfter = 1 << 20, + + OpcodeShift = 21, OpcodeMask = 0xFF << OpcodeShift, - // Bits 25 -> 31 are unused + // Bits 26 -> 31 are unused }; } diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index d44e0c61eee..1ddaaabd826 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -82,10 +82,20 @@ class X86Inst opcod, Format f, MemType m, ImmType i> : Instr ImmType ImmT = i; bits<2> ImmTypeBits = ImmT.Value; + // // Attributes specific to X86 instructions... + // bit hasOpSizePrefix = 0; // Does this inst have a 0x66 prefix? - bit printImplicitUsesBefore = 0; // Should we print implicit uses before this inst? - bit printImplicitUsesAfter = 0; // Should we print implicit uses after this inst? + + // Flag whether implicit register usage is printed before/after the + // instruction + bit printImplicitUsesBefore = 0; + bit printImplicitUsesAfter = 0; + + // Flag whether implicit register definitions are printed before/after the + // instruction + bit printImplicitDefsBefore = 0; + bit printImplicitDefsAfter = 0; bits<4> Prefix = 0; // Which prefix byte does this inst have? FPFormat FPForm; // What flavor of FP instruction is this? @@ -141,6 +151,8 @@ class Im32i8 o, Format f> : X86Inst; // Helper for shift instructions class UsesCL { list Uses = [CL]; bit printImplicitUsesAfter = 1; } +class PrintImpUsesAfter {bit printImplicitUsesAfter = 1;} +class PrintImpDefsAfter {bit printImplicitDefsAfter = 1;} //===----------------------------------------------------------------------===// // Instruction list... @@ -233,6 +245,17 @@ def REP_STOSW : I<"rep stosw", 0xAB, RawFrm>, REP, OpSize, def REP_STOSD : I<"rep stosd", 0xAB, RawFrm>, REP, Imp<[EAX,ECX,EDI], [ECX,EDI]>; +//===----------------------------------------------------------------------===// +// Input/Output Instructions... +// +def IN8 : I<"in", 0xEC, RawFrm>, Imp<[DX],[AL]>, PrintImpUsesAfter, PrintImpDefsAfter; // in AL = I/O address DX +def IN16 : I<"in", 0xED, RawFrm>, Imp<[DX],[AX]>, PrintImpUsesAfter, PrintImpDefsAfter; // in AX = I/O address DX +def IN32 : I<"in", 0xED, RawFrm>, Imp<[DX],[EAX]>, PrintImpUsesAfter, PrintImpDefsAfter; // in EAX = I/O address DX + +def OUT8 : I<"out", 0xEE, RawFrm>, Imp<[DX, AL], []>, PrintImpUsesAfter; +def OUT16 : I<"out", 0xEF, RawFrm>, Imp<[DX, AX], []>, PrintImpUsesAfter; +def OUT32 : I<"out", 0xEF, RawFrm>, Imp<[DX, EAX], []>, PrintImpUsesAfter; + //===----------------------------------------------------------------------===// // Move Instructions... //