|  | //===-- X86IntelAsmPrinter.cpp - Convert X86 LLVM code to Intel assembly --===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file was developed by the LLVM research group and is distributed under | 
|  | // the University of Illinois Open Source License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file contains a printer that converts from our internal representation | 
|  | // of machine-dependent LLVM code to Intel format assembly language. | 
|  | // This printer is the output mechanism used by `llc'. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "X86IntelAsmPrinter.h" | 
|  | #include "X86.h" | 
|  | #include "llvm/Constants.h" | 
|  | #include "llvm/Module.h" | 
|  | #include "llvm/Assembly/Writer.h" | 
|  | #include "llvm/Support/Mangler.h" | 
|  | #include "llvm/Target/TargetOptions.h" | 
|  | using namespace llvm; | 
|  |  | 
|  | X86IntelAsmPrinter::X86IntelAsmPrinter(std::ostream &O, X86TargetMachine &TM) | 
|  | : X86SharedAsmPrinter(O, TM) { | 
|  | } | 
|  |  | 
|  | /// runOnMachineFunction - This uses the printMachineInstruction() | 
|  | /// method to print assembly for each instruction. | 
|  | /// | 
|  | bool X86IntelAsmPrinter::runOnMachineFunction(MachineFunction &MF) { | 
|  | SetupMachineFunction(MF); | 
|  | O << "\n\n"; | 
|  |  | 
|  | // Print out constants referenced by the function | 
|  | EmitConstantPool(MF.getConstantPool()); | 
|  |  | 
|  | // Print out labels for the function. | 
|  | SwitchToTextSection(".code", MF.getFunction()); | 
|  | EmitAlignment(4); | 
|  | if (MF.getFunction()->getLinkage() == GlobalValue::ExternalLinkage) | 
|  | O << "\tpublic " << CurrentFnName << "\n"; | 
|  | O << CurrentFnName << "\tproc near\n"; | 
|  |  | 
|  | // Print out code for the function. | 
|  | for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); | 
|  | I != E; ++I) { | 
|  | // Print a label for the basic block if there are any predecessors. | 
|  | if (I->pred_begin() != I->pred_end()) { | 
|  | printBasicBlockLabel(I, true); | 
|  | O << '\n'; | 
|  | } | 
|  | for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); | 
|  | II != E; ++II) { | 
|  | // Print the assembly for the instruction. | 
|  | O << "\t"; | 
|  | printMachineInstruction(II); | 
|  | } | 
|  | } | 
|  |  | 
|  | O << CurrentFnName << "\tendp\n"; | 
|  |  | 
|  | // We didn't modify anything. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void X86IntelAsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op) { | 
|  | unsigned char value = MI->getOperand(Op).getImmedValue(); | 
|  | assert(value <= 7 && "Invalid ssecc argument!"); | 
|  | switch (value) { | 
|  | case 0: O << "eq"; break; | 
|  | case 1: O << "lt"; break; | 
|  | case 2: O << "le"; break; | 
|  | case 3: O << "unord"; break; | 
|  | case 4: O << "neq"; break; | 
|  | case 5: O << "nlt"; break; | 
|  | case 6: O << "nle"; break; | 
|  | case 7: O << "ord"; break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void X86IntelAsmPrinter::printOp(const MachineOperand &MO, | 
|  | const char *Modifier) { | 
|  | const MRegisterInfo &RI = *TM.getRegisterInfo(); | 
|  | switch (MO.getType()) { | 
|  | case MachineOperand::MO_Register: | 
|  | if (MRegisterInfo::isPhysicalRegister(MO.getReg())) { | 
|  | unsigned Reg = MO.getReg(); | 
|  | if (Modifier && strncmp(Modifier, "trunc", strlen("trunc")) == 0) { | 
|  | MVT::ValueType VT = (strcmp(Modifier,"trunc16") == 0) | 
|  | ? MVT::i16 : MVT::i8; | 
|  | Reg = getX86SubSuperRegister(Reg, VT); | 
|  | } | 
|  | O << RI.get(Reg).Name; | 
|  | } else | 
|  | O << "reg" << MO.getReg(); | 
|  | return; | 
|  |  | 
|  | case MachineOperand::MO_Immediate: | 
|  | O << (int)MO.getImmedValue(); | 
|  | return; | 
|  | case MachineOperand::MO_MachineBasicBlock: | 
|  | printBasicBlockLabel(MO.getMachineBasicBlock()); | 
|  | return; | 
|  | case MachineOperand::MO_ConstantPoolIndex: { | 
|  | bool isMemOp  = Modifier && !strcmp(Modifier, "mem"); | 
|  | if (!isMemOp) O << "OFFSET "; | 
|  | O << "[" << PrivateGlobalPrefix << "CPI" << getFunctionNumber() << "_" | 
|  | << MO.getConstantPoolIndex(); | 
|  | int Offset = MO.getOffset(); | 
|  | if (Offset > 0) | 
|  | O << " + " << Offset; | 
|  | else if (Offset < 0) | 
|  | O << Offset; | 
|  | O << "]"; | 
|  | return; | 
|  | } | 
|  | case MachineOperand::MO_GlobalAddress: { | 
|  | bool isCallOp = Modifier && !strcmp(Modifier, "call"); | 
|  | bool isMemOp  = Modifier && !strcmp(Modifier, "mem"); | 
|  | if (!isMemOp && !isCallOp) O << "OFFSET "; | 
|  | O << Mang->getValueName(MO.getGlobal()); | 
|  | int Offset = MO.getOffset(); | 
|  | if (Offset > 0) | 
|  | O << " + " << Offset; | 
|  | else if (Offset < 0) | 
|  | O << Offset; | 
|  | return; | 
|  | } | 
|  | case MachineOperand::MO_ExternalSymbol: { | 
|  | bool isCallOp = Modifier && !strcmp(Modifier, "call"); | 
|  | if (!isCallOp) O << "OFFSET "; | 
|  | O << GlobalPrefix << MO.getSymbolName(); | 
|  | return; | 
|  | } | 
|  | default: | 
|  | O << "<unknown operand type>"; return; | 
|  | } | 
|  | } | 
|  |  | 
|  | void X86IntelAsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op){ | 
|  | assert(isMem(MI, Op) && "Invalid memory reference!"); | 
|  |  | 
|  | const MachineOperand &BaseReg  = MI->getOperand(Op); | 
|  | int ScaleVal                   = MI->getOperand(Op+1).getImmedValue(); | 
|  | const MachineOperand &IndexReg = MI->getOperand(Op+2); | 
|  | const MachineOperand &DispSpec = MI->getOperand(Op+3); | 
|  |  | 
|  | if (BaseReg.isFrameIndex()) { | 
|  | O << "[frame slot #" << BaseReg.getFrameIndex(); | 
|  | if (DispSpec.getImmedValue()) | 
|  | O << " + " << DispSpec.getImmedValue(); | 
|  | O << "]"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | O << "["; | 
|  | bool NeedPlus = false; | 
|  | if (BaseReg.getReg()) { | 
|  | printOp(BaseReg, "mem"); | 
|  | NeedPlus = true; | 
|  | } | 
|  |  | 
|  | if (IndexReg.getReg()) { | 
|  | if (NeedPlus) O << " + "; | 
|  | if (ScaleVal != 1) | 
|  | O << ScaleVal << "*"; | 
|  | printOp(IndexReg); | 
|  | NeedPlus = true; | 
|  | } | 
|  |  | 
|  | if (DispSpec.isGlobalAddress() || DispSpec.isConstantPoolIndex()) { | 
|  | if (NeedPlus) | 
|  | O << " + "; | 
|  | printOp(DispSpec, "mem"); | 
|  | } else { | 
|  | int DispVal = DispSpec.getImmedValue(); | 
|  | if (DispVal || (!BaseReg.getReg() && !IndexReg.getReg())) { | 
|  | if (NeedPlus) | 
|  | if (DispVal > 0) | 
|  | O << " + "; | 
|  | else { | 
|  | O << " - "; | 
|  | DispVal = -DispVal; | 
|  | } | 
|  | O << DispVal; | 
|  | } | 
|  | } | 
|  | O << "]"; | 
|  | } | 
|  |  | 
|  | void X86IntelAsmPrinter::printPICLabel(const MachineInstr *MI, unsigned Op) { | 
|  | O << "\"L" << getFunctionNumber() << "$pb\"\n"; | 
|  | O << "\"L" << getFunctionNumber() << "$pb\":"; | 
|  | } | 
|  |  | 
|  | bool X86IntelAsmPrinter::printAsmMRegister(const MachineOperand &MO, | 
|  | const char Mode) { | 
|  | const MRegisterInfo &RI = *TM.getRegisterInfo(); | 
|  | unsigned Reg = MO.getReg(); | 
|  | switch (Mode) { | 
|  | default: return true;  // Unknown mode. | 
|  | case 'b': // Print QImode register | 
|  | Reg = getX86SubSuperRegister(Reg, MVT::i8); | 
|  | break; | 
|  | case 'h': // Print QImode high register | 
|  | Reg = getX86SubSuperRegister(Reg, MVT::i8, true); | 
|  | break; | 
|  | case 'w': // Print HImode register | 
|  | Reg = getX86SubSuperRegister(Reg, MVT::i16); | 
|  | break; | 
|  | case 'k': // Print SImode register | 
|  | Reg = getX86SubSuperRegister(Reg, MVT::i32); | 
|  | break; | 
|  | } | 
|  |  | 
|  | O << '%' << RI.get(Reg).Name; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// PrintAsmOperand - Print out an operand for an inline asm expression. | 
|  | /// | 
|  | bool X86IntelAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | 
|  | unsigned AsmVariant, | 
|  | const char *ExtraCode) { | 
|  | // Does this asm operand have a single letter operand modifier? | 
|  | if (ExtraCode && ExtraCode[0]) { | 
|  | if (ExtraCode[1] != 0) return true; // Unknown modifier. | 
|  |  | 
|  | switch (ExtraCode[0]) { | 
|  | default: return true;  // Unknown modifier. | 
|  | case 'b': // Print QImode register | 
|  | case 'h': // Print QImode high register | 
|  | case 'w': // Print HImode register | 
|  | case 'k': // Print SImode register | 
|  | return printAsmMRegister(MI->getOperand(OpNo), ExtraCode[0]); | 
|  | } | 
|  | } | 
|  |  | 
|  | printOperand(MI, OpNo); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool X86IntelAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, | 
|  | unsigned OpNo, | 
|  | unsigned AsmVariant, | 
|  | const char *ExtraCode) { | 
|  | if (ExtraCode && ExtraCode[0]) | 
|  | return true; // Unknown modifier. | 
|  | printMemReference(MI, OpNo); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// printMachineInstruction -- Print out a single X86 LLVM instruction | 
|  | /// MI in Intel syntax to the current output stream. | 
|  | /// | 
|  | void X86IntelAsmPrinter::printMachineInstruction(const MachineInstr *MI) { | 
|  | ++EmittedInsts; | 
|  |  | 
|  | // See if a truncate instruction can be turned into a nop. | 
|  | switch (MI->getOpcode()) { | 
|  | default: break; | 
|  | case X86::TRUNC_R32_R16: | 
|  | case X86::TRUNC_R32_R8: | 
|  | case X86::TRUNC_R16_R8: { | 
|  | const MachineOperand &MO0 = MI->getOperand(0); | 
|  | const MachineOperand &MO1 = MI->getOperand(1); | 
|  | unsigned Reg0 = MO0.getReg(); | 
|  | unsigned Reg1 = MO1.getReg(); | 
|  | if (MI->getOpcode() == X86::TRUNC_R32_R16) | 
|  | Reg1 = getX86SubSuperRegister(Reg1, MVT::i16); | 
|  | else | 
|  | Reg1 = getX86SubSuperRegister(Reg1, MVT::i8); | 
|  | O << CommentString << " TRUNCATE "; | 
|  | if (Reg0 != Reg1) | 
|  | O << "\n\t"; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Call the autogenerated instruction printer routines. | 
|  | printInstruction(MI); | 
|  | } | 
|  |  | 
|  | bool X86IntelAsmPrinter::doInitialization(Module &M) { | 
|  | MLSections = true; | 
|  | GlobalPrefix = "_"; | 
|  | CommentString = ";"; | 
|  |  | 
|  | X86SharedAsmPrinter::doInitialization(M); | 
|  |  | 
|  | PrivateGlobalPrefix = "$"; | 
|  | AlignDirective = "\talign\t"; | 
|  | ZeroDirective = "\tdb\t"; | 
|  | ZeroDirectiveSuffix = " dup(0)"; | 
|  | AsciiDirective = "\tdb\t"; | 
|  | AscizDirective = 0; | 
|  | Data8bitsDirective = "\tdb\t"; | 
|  | Data16bitsDirective = "\tdw\t"; | 
|  | Data32bitsDirective = "\tdd\t"; | 
|  | Data64bitsDirective = "\tdq\t"; | 
|  | HasDotTypeDotSizeDirective = false; | 
|  | Mang->markCharUnacceptable('.'); | 
|  |  | 
|  | O << "\t.686\n\t.model flat\n\n"; | 
|  |  | 
|  | // Emit declarations for external functions. | 
|  | for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) | 
|  | if (I->isExternal()) | 
|  | O << "\textern " << Mang->getValueName(I) << ":near\n"; | 
|  |  | 
|  | // Emit declarations for external globals.  Note that VC++ always declares | 
|  | // external globals to have type byte, and if that's good enough for VC++... | 
|  | for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); | 
|  | I != E; ++I) { | 
|  | if (I->isExternal()) | 
|  | O << "\textern " << Mang->getValueName(I) << ":byte\n"; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool X86IntelAsmPrinter::doFinalization(Module &M) { | 
|  | const TargetData *TD = TM.getTargetData(); | 
|  |  | 
|  | // Print out module-level global variables here. | 
|  | for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); | 
|  | I != E; ++I) { | 
|  | if (I->isExternal()) continue;   // External global require no code | 
|  |  | 
|  | // Check to see if this is a special global used by LLVM, if so, emit it. | 
|  | if (EmitSpecialLLVMGlobal(I)) | 
|  | continue; | 
|  |  | 
|  | std::string name = Mang->getValueName(I); | 
|  | Constant *C = I->getInitializer(); | 
|  | unsigned Size = TD->getTypeSize(C->getType()); | 
|  | unsigned Align = getPreferredAlignmentLog(I); | 
|  | bool bCustomSegment = false; | 
|  |  | 
|  | switch (I->getLinkage()) { | 
|  | case GlobalValue::LinkOnceLinkage: | 
|  | case GlobalValue::WeakLinkage: | 
|  | SwitchToDataSection("", 0); | 
|  | O << name << "?\tsegment common 'COMMON'\n"; | 
|  | bCustomSegment = true; | 
|  | // FIXME: the default alignment is 16 bytes, but 1, 2, 4, and 256 | 
|  | // are also available. | 
|  | break; | 
|  | case GlobalValue::AppendingLinkage: | 
|  | SwitchToDataSection("", 0); | 
|  | O << name << "?\tsegment public 'DATA'\n"; | 
|  | bCustomSegment = true; | 
|  | // FIXME: the default alignment is 16 bytes, but 1, 2, 4, and 256 | 
|  | // are also available. | 
|  | break; | 
|  | case GlobalValue::ExternalLinkage: | 
|  | O << "\tpublic " << name << "\n"; | 
|  | // FALL THROUGH | 
|  | case GlobalValue::InternalLinkage: | 
|  | SwitchToDataSection(".data", I); | 
|  | break; | 
|  | default: | 
|  | assert(0 && "Unknown linkage type!"); | 
|  | } | 
|  |  | 
|  | if (!bCustomSegment) | 
|  | EmitAlignment(Align, I); | 
|  |  | 
|  | O << name << ":\t\t\t\t" << CommentString << " " << I->getName() << '\n'; | 
|  |  | 
|  | EmitGlobalConstant(C); | 
|  |  | 
|  | if (bCustomSegment) | 
|  | O << name << "?\tends\n"; | 
|  | } | 
|  |  | 
|  | // Bypass X86SharedAsmPrinter::doFinalization(). | 
|  | AsmPrinter::doFinalization(M); | 
|  | SwitchToDataSection("", 0); | 
|  | O << "\tend\n"; | 
|  | return false; // success | 
|  | } | 
|  |  | 
|  | void X86IntelAsmPrinter::EmitString(const ConstantArray *CVA) const { | 
|  | unsigned NumElts = CVA->getNumOperands(); | 
|  | if (NumElts) { | 
|  | // ML does not have escape sequences except '' for '.  It also has a maximum | 
|  | // string length of 255. | 
|  | unsigned len = 0; | 
|  | bool inString = false; | 
|  | for (unsigned i = 0; i < NumElts; i++) { | 
|  | int n = cast<ConstantInt>(CVA->getOperand(i))->getRawValue() & 255; | 
|  | if (len == 0) | 
|  | O << "\tdb "; | 
|  |  | 
|  | if (n >= 32 && n <= 127) { | 
|  | if (!inString) { | 
|  | if (len > 0) { | 
|  | O << ",'"; | 
|  | len += 2; | 
|  | } else { | 
|  | O << "'"; | 
|  | len++; | 
|  | } | 
|  | inString = true; | 
|  | } | 
|  | if (n == '\'') { | 
|  | O << "'"; | 
|  | len++; | 
|  | } | 
|  | O << char(n); | 
|  | } else { | 
|  | if (inString) { | 
|  | O << "'"; | 
|  | len++; | 
|  | inString = false; | 
|  | } | 
|  | if (len > 0) { | 
|  | O << ","; | 
|  | len++; | 
|  | } | 
|  | O << n; | 
|  | len += 1 + (n > 9) + (n > 99); | 
|  | } | 
|  |  | 
|  | if (len > 60) { | 
|  | if (inString) { | 
|  | O << "'"; | 
|  | inString = false; | 
|  | } | 
|  | O << "\n"; | 
|  | len = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (len > 0) { | 
|  | if (inString) | 
|  | O << "'"; | 
|  | O << "\n"; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Include the auto-generated portion of the assembly writer. | 
|  | #include "X86GenAsmWriter1.inc" |