//===-- X86AsmPrinter.cpp - Convert X86 LLVM IR to X86 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 the shared super class printer that converts from our internal // representation of machine-dependent LLVM code to Intel and AT&T format // assembly language. // This printer is the output mechanism used by `llc'. // //===----------------------------------------------------------------------===// #include "X86ATTAsmPrinter.h" #include "X86IntelAsmPrinter.h" #include "X86.h" #include "llvm/Module.h" #include "llvm/Assembly/Writer.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/Support/Mangler.h" #include "llvm/Support/CommandLine.h" using namespace llvm; using namespace x86; Statistic<> llvm::x86::EmittedInsts("asm-printer", "Number of machine instrs printed"); enum AsmWriterFlavorTy { att, intel }; cl::opt AsmWriterFlavor("x86-asm-syntax", cl::desc("Choose style of code to emit from X86 backend:"), cl::values( clEnumVal(att, " Emit AT&T-style assembly"), clEnumVal(intel, " Emit Intel-style assembly"), clEnumValEnd), cl::init(att)); /// doInitialization bool X86SharedAsmPrinter::doInitialization(Module& M) { bool leadingUnderscore = false; forCygwin = false; const std::string& TT = M.getTargetTriple(); if (TT.length() > 5) { forCygwin = TT.find("cygwin") != std::string::npos || TT.find("mingw") != std::string::npos; forDarwin = TT.find("darwin") != std::string::npos; } else if (TT.empty()) { #if defined(__CYGWIN__) || defined(__MINGW32__) forCygwin = true; #elif defined(__APPLE__) forDarwin = true; #elif defined(_WIN32) leadingUnderscore = true; #else leadingUnderscore = false; #endif } if (leadingUnderscore || forCygwin || forDarwin) GlobalPrefix = "_"; if (forDarwin) { AlignmentIsInBytes = false; Data64bitsDirective = 0; // we can't emit a 64-bit unit ZeroDirective = "\t.space\t"; // ".space N" emits N zeros. } return AsmPrinter::doInitialization(M); } /// printConstantPool - Print to the current output stream assembly /// representations of the constants in the constant pool MCP. This is /// used to print out constants which have been "spilled to memory" by /// the code generator. /// void X86SharedAsmPrinter::printConstantPool(MachineConstantPool *MCP) { const std::vector &CP = MCP->getConstants(); const TargetData &TD = TM.getTargetData(); if (CP.empty()) return; for (unsigned i = 0, e = CP.size(); i != e; ++i) { if (forDarwin) O << "\t.data\n"; else O << "\t.section .rodata\n"; emitAlignment(TD.getTypeAlignmentShift(CP[i]->getType())); O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t" << CommentString << *CP[i] << "\n"; emitGlobalConstant(CP[i]); } } bool X86SharedAsmPrinter::doFinalization(Module &M) { const TargetData &TD = TM.getTargetData(); std::string CurSection; // 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->hasInitializer()) { // External global require no code O << "\n\n"; std::string name = Mang->getValueName(I); Constant *C = I->getInitializer(); unsigned Size = TD.getTypeSize(C->getType()); unsigned Align = TD.getTypeAlignmentShift(C->getType()); if (C->isNullValue() && (I->hasLinkOnceLinkage() || I->hasInternalLinkage() || I->hasWeakLinkage() /* FIXME: Verify correct */)) { SwitchSection(O, CurSection, ".data"); if (!forCygwin && !forDarwin && I->hasInternalLinkage()) O << "\t.local " << name << "\n"; if (forDarwin && I->hasInternalLinkage()) O << "\t.lcomm " << name << "," << Size << "," << Align; else O << "\t.comm " << name << "," << Size; if (!forCygwin && !forDarwin) O << "," << (1 << Align); O << "\t\t# "; WriteAsOperand(O, I, true, true, &M); O << "\n"; } else { switch (I->getLinkage()) { default: assert(0 && "Unknown linkage type!"); case GlobalValue::LinkOnceLinkage: case GlobalValue::WeakLinkage: // FIXME: Verify correct for weak. // Nonnull linkonce -> weak O << "\t.weak " << name << "\n"; SwitchSection(O, CurSection, ""); O << "\t.section\t.llvm.linkonce.d." << name << ",\"aw\",@progbits\n"; break; case GlobalValue::AppendingLinkage: // FIXME: appending linkage variables should go into a section of // their name or something. For now, just emit them as external. case GlobalValue::ExternalLinkage: // If external or appending, declare as a global symbol O << "\t.globl " << name << "\n"; // FALL THROUGH case GlobalValue::InternalLinkage: if (C->isNullValue()) SwitchSection(O, CurSection, ".bss"); else SwitchSection(O, CurSection, ".data"); break; } emitAlignment(Align); if (!forCygwin && !forDarwin) { O << "\t.type " << name << ",@object\n"; O << "\t.size " << name << "," << Size << "\n"; } O << name << ":\t\t\t\t# "; WriteAsOperand(O, I, true, true, &M); O << " = "; WriteAsOperand(O, C, false, false, &M); O << "\n"; emitGlobalConstant(C); } } if (forDarwin) { // Output stubs for external global variables if (GVStubs.begin() != GVStubs.end()) O << "\t.non_lazy_symbol_pointer\n"; for (std::set::iterator i = GVStubs.begin(), e = GVStubs.end(); i != e; ++i) { O << "L" << *i << "$non_lazy_ptr:\n"; O << "\t.indirect_symbol " << *i << "\n"; O << "\t.long\t0\n"; } // Output stubs for dynamically-linked functions unsigned j = 1; for (std::set::iterator i = FnStubs.begin(), e = FnStubs.end(); i != e; ++i, ++j) { O << "\t.symbol_stub\n"; O << "L" << *i << "$stub:\n"; O << "\t.indirect_symbol " << *i << "\n"; O << "\tjmp\t*L" << j << "$lz\n"; O << "L" << *i << "$stub_binder:\n"; O << "\tpushl\t$L" << j << "$lz\n"; O << "\tjmp\tdyld_stub_binding_helper\n"; O << "\t.section __DATA, __la_sym_ptr3,lazy_symbol_pointers\n"; O << "L" << j << "$lz:\n"; O << "\t.indirect_symbol " << *i << "\n"; O << "\t.long\tL" << *i << "$stub_binder\n"; } O << "\n"; // Output stubs for link-once variables if (LinkOnceStubs.begin() != LinkOnceStubs.end()) O << ".data\n.align 2\n"; for (std::set::iterator i = LinkOnceStubs.begin(), e = LinkOnceStubs.end(); i != e; ++i) { O << "L" << *i << "$non_lazy_ptr:\n" << "\t.long\t" << *i << '\n'; } } AsmPrinter::doFinalization(M); return false; // success } /// createX86CodePrinterPass - Returns a pass that prints the X86 assembly code /// for a MachineFunction to the given output stream, using the given target /// machine description. /// FunctionPass *llvm::createX86CodePrinterPass(std::ostream &o,TargetMachine &tm){ switch (AsmWriterFlavor) { default: assert(0 && "Unknown asm flavor!"); case intel: return new X86IntelAsmPrinter(o, tm); case att: return new X86ATTAsmPrinter(o, tm); } }