X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FX86%2FX86AsmPrinter.cpp;h=9e0ab820715d38ab0864e2ac547590467db770f8;hb=9564c1e9b800896a2715ea313f7289945352b6d1;hp=5e35487a21e779f82a141d7609b0db6dfcc26e94;hpb=07103d312aa1d20f1c9bbc40cbdafe1e312c4a3d;p=oota-llvm.git diff --git a/lib/Target/X86/X86AsmPrinter.cpp b/lib/Target/X86/X86AsmPrinter.cpp index 5e35487a21e..9e0ab820715 100644 --- a/lib/Target/X86/X86AsmPrinter.cpp +++ b/lib/Target/X86/X86AsmPrinter.cpp @@ -1,291 +1,713 @@ -//===-- X86AsmPrinter.cpp - Convert X86 LLVM IR to X86 assembly -----------===// +//===-- X86AsmPrinter.cpp - Convert X86 LLVM code to AT&T 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 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'. +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to X86 machine code. // //===----------------------------------------------------------------------===// #include "X86AsmPrinter.h" -#include "X86ATTAsmPrinter.h" -#include "X86IntelAsmPrinter.h" -#include "X86Subtarget.h" -#include "llvm/Constants.h" -#include "llvm/Module.h" -#include "llvm/Type.h" +#include "InstPrinter/X86ATTInstPrinter.h" +#include "X86.h" +#include "X86COFFMachineModuleInfo.h" +#include "X86MachineFunctionInfo.h" +#include "X86TargetMachine.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Assembly/Writer.h" -#include "llvm/Support/Mangler.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/DebugInfo.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetOptions.h" using namespace llvm; -Statistic<> llvm::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), -#ifdef _MSC_VER - cl::init(intel) -#else - cl::init(att) -#endif - ); - -/// doInitialization -bool X86SharedAsmPrinter::doInitialization(Module &M) { - PrivateGlobalPrefix = ".L"; - DefaultTextSection = ".text"; - DefaultDataSection = ".data"; - - switch (Subtarget->TargetType) { - case X86Subtarget::isDarwin: - AlignmentIsInBytes = false; - GlobalPrefix = "_"; - Data64bitsDirective = 0; // we can't emit a 64-bit unit - ZeroDirective = "\t.space\t"; // ".space N" emits N zeros. - PrivateGlobalPrefix = "L"; // Marker for constant pool idxs - ConstantPoolSection = "\t.const\n"; - JumpTableSection = "\t.const\n"; // FIXME: depends on PIC mode - LCOMMDirective = "\t.lcomm\t"; - COMMDirectiveTakesAlignment = false; - HasDotTypeDotSizeDirective = false; - StaticCtorsSection = ".mod_init_func"; - StaticDtorsSection = ".mod_term_func"; - InlineAsmStart = "# InlineAsm Start"; - InlineAsmEnd = "# InlineAsm End"; +//===----------------------------------------------------------------------===// +// Primitive Helper Functions. +//===----------------------------------------------------------------------===// + +/// runOnMachineFunction - Emit the function body. +/// +bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) { + SetupMachineFunction(MF); + + if (Subtarget->isTargetCOFF() && !Subtarget->isTargetEnvMacho()) { + bool Intrn = MF.getFunction()->hasInternalLinkage(); + OutStreamer.BeginCOFFSymbolDef(CurrentFnSym); + OutStreamer.EmitCOFFSymbolStorageClass(Intrn ? COFF::IMAGE_SYM_CLASS_STATIC + : COFF::IMAGE_SYM_CLASS_EXTERNAL); + OutStreamer.EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION + << COFF::SCT_COMPLEX_TYPE_SHIFT); + OutStreamer.EndCOFFSymbolDef(); + } + + // Have common code print out the function header with linkage info etc. + EmitFunctionHeader(); + + // Emit the rest of the function body. + EmitFunctionBody(); + + // We didn't modify anything. + return false; +} + +/// printSymbolOperand - Print a raw symbol reference operand. This handles +/// jump tables, constant pools, global address and external symbols, all of +/// which print to a label with various suffixes for relocation types etc. +void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO, + raw_ostream &O) { + switch (MO.getType()) { + default: llvm_unreachable("unknown symbol type!"); + case MachineOperand::MO_JumpTableIndex: + O << *GetJTISymbol(MO.getIndex()); + break; + case MachineOperand::MO_ConstantPoolIndex: + O << *GetCPISymbol(MO.getIndex()); + printOffset(MO.getOffset(), O); + break; + case MachineOperand::MO_GlobalAddress: { + const GlobalValue *GV = MO.getGlobal(); + + MCSymbol *GVSym; + if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) + GVSym = GetSymbolWithGlobalValueBase(GV, "$stub"); + else if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || + MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE || + MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE) + GVSym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + else + GVSym = Mang->getSymbol(GV); + + // Handle dllimport linkage. + if (MO.getTargetFlags() == X86II::MO_DLLIMPORT) + GVSym = OutContext.GetOrCreateSymbol(Twine("__imp_") + GVSym->getName()); + + if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || + MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE) { + MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getGVStubEntry(Sym); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + } else if (MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE){ + MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getHiddenGVStubEntry(Sym); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + } else if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) { + MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$stub"); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getFnStubEntry(Sym); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + } + + // If the name begins with a dollar-sign, enclose it in parens. We do this + // to avoid having it look like an integer immediate to the assembler. + if (GVSym->getName()[0] != '$') + O << *GVSym; + else + O << '(' << *GVSym << ')'; + printOffset(MO.getOffset(), O); break; - case X86Subtarget::isCygwin: - GlobalPrefix = "_"; - COMMDirectiveTakesAlignment = false; - HasDotTypeDotSizeDirective = false; - StaticCtorsSection = "\t.section .ctors,\"aw\""; - StaticDtorsSection = "\t.section .dtors,\"aw\""; + } + case MachineOperand::MO_ExternalSymbol: { + const MCSymbol *SymToPrint; + if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) { + SmallString<128> TempNameStr; + TempNameStr += StringRef(MO.getSymbolName()); + TempNameStr += StringRef("$stub"); + + MCSymbol *Sym = GetExternalSymbolSymbol(TempNameStr.str()); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getFnStubEntry(Sym); + if (StubSym.getPointer() == 0) { + TempNameStr.erase(TempNameStr.end()-5, TempNameStr.end()); + StubSym = MachineModuleInfoImpl:: + StubValueTy(OutContext.GetOrCreateSymbol(TempNameStr.str()), + true); + } + SymToPrint = StubSym.getPointer(); + } else { + SymToPrint = GetExternalSymbolSymbol(MO.getSymbolName()); + } + + // If the name begins with a dollar-sign, enclose it in parens. We do this + // to avoid having it look like an integer immediate to the assembler. + if (SymToPrint->getName()[0] != '$') + O << *SymToPrint; + else + O << '(' << *SymToPrint << '('; break; - case X86Subtarget::isWindows: - GlobalPrefix = "_"; - HasDotTypeDotSizeDirective = false; + } + } + + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + case X86II::MO_NO_FLAG: // No flag. + break; + case X86II::MO_DARWIN_NONLAZY: + case X86II::MO_DLLIMPORT: + case X86II::MO_DARWIN_STUB: + // These affect the name of the symbol, not any suffix. + break; + case X86II::MO_GOT_ABSOLUTE_ADDRESS: + O << " + [.-" << *MF->getPICBaseSymbol() << ']'; break; - default: break; + case X86II::MO_PIC_BASE_OFFSET: + case X86II::MO_DARWIN_NONLAZY_PIC_BASE: + case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: + O << '-' << *MF->getPICBaseSymbol(); + break; + case X86II::MO_TLSGD: O << "@TLSGD"; break; + case X86II::MO_TLSLD: O << "@TLSLD"; break; + case X86II::MO_TLSLDM: O << "@TLSLDM"; break; + case X86II::MO_GOTTPOFF: O << "@GOTTPOFF"; break; + case X86II::MO_INDNTPOFF: O << "@INDNTPOFF"; break; + case X86II::MO_TPOFF: O << "@TPOFF"; break; + case X86II::MO_DTPOFF: O << "@DTPOFF"; break; + case X86II::MO_NTPOFF: O << "@NTPOFF"; break; + case X86II::MO_GOTNTPOFF: O << "@GOTNTPOFF"; break; + case X86II::MO_GOTPCREL: O << "@GOTPCREL"; break; + case X86II::MO_GOT: O << "@GOT"; break; + case X86II::MO_GOTOFF: O << "@GOTOFF"; break; + case X86II::MO_PLT: O << "@PLT"; break; + case X86II::MO_TLVP: O << "@TLVP"; break; + case X86II::MO_TLVP_PIC_BASE: + O << "@TLVP" << '-' << *MF->getPICBaseSymbol(); + break; + case X86II::MO_SECREL: O << "@SECREL32"; break; } - - if (Subtarget->TargetType == X86Subtarget::isDarwin) { - // Emit initial debug information. - DW.BeginModule(&M); +} + +/// printPCRelImm - This is used to print an immediate value that ends up +/// being encoded as a pc-relative value. These print slightly differently, for +/// example, a $ is not emitted. +void X86AsmPrinter::printPCRelImm(const MachineInstr *MI, unsigned OpNo, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(OpNo); + switch (MO.getType()) { + default: llvm_unreachable("Unknown pcrel immediate operand"); + case MachineOperand::MO_Register: + // pc-relativeness was handled when computing the value in the reg. + printOperand(MI, OpNo, O); + return; + case MachineOperand::MO_Immediate: + O << MO.getImm(); + return; + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_ExternalSymbol: + printSymbolOperand(MO, O); + return; + } +} + + +void X86AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, + raw_ostream &O, const char *Modifier, + unsigned AsmVariant) { + const MachineOperand &MO = MI->getOperand(OpNo); + switch (MO.getType()) { + default: llvm_unreachable("unknown operand type!"); + case MachineOperand::MO_Register: { + // FIXME: Enumerating AsmVariant, so we can remove magic number. + if (AsmVariant == 0) O << '%'; + unsigned Reg = MO.getReg(); + if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) { + MVT::SimpleValueType VT = (strcmp(Modifier+6,"64") == 0) ? + MVT::i64 : ((strcmp(Modifier+6, "32") == 0) ? MVT::i32 : + ((strcmp(Modifier+6,"16") == 0) ? MVT::i16 : MVT::i8)); + Reg = getX86SubSuperRegister(Reg, VT); + } + O << X86ATTInstPrinter::getRegisterName(Reg); + return; + } + + case MachineOperand::MO_Immediate: + if (AsmVariant == 0) O << '$'; + O << MO.getImm(); + return; + + case MachineOperand::MO_JumpTableIndex: + case MachineOperand::MO_ConstantPoolIndex: + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_ExternalSymbol: { + if (AsmVariant == 0) O << '$'; + printSymbolOperand(MO, O); + break; + } + } +} + +void X86AsmPrinter::printLeaMemReference(const MachineInstr *MI, unsigned Op, + raw_ostream &O, const char *Modifier) { + const MachineOperand &BaseReg = MI->getOperand(Op); + const MachineOperand &IndexReg = MI->getOperand(Op+2); + const MachineOperand &DispSpec = MI->getOperand(Op+3); + + // If we really don't want to print out (rip), don't. + bool HasBaseReg = BaseReg.getReg() != 0; + if (HasBaseReg && Modifier && !strcmp(Modifier, "no-rip") && + BaseReg.getReg() == X86::RIP) + HasBaseReg = false; + + // HasParenPart - True if we will print out the () part of the mem ref. + bool HasParenPart = IndexReg.getReg() || HasBaseReg; + + if (DispSpec.isImm()) { + int DispVal = DispSpec.getImm(); + if (DispVal || !HasParenPart) + O << DispVal; + } else { + assert(DispSpec.isGlobal() || DispSpec.isCPI() || + DispSpec.isJTI() || DispSpec.isSymbol()); + printSymbolOperand(MI->getOperand(Op+3), O); } - return AsmPrinter::doInitialization(M); + if (Modifier && strcmp(Modifier, "H") == 0) + O << "+8"; + + if (HasParenPart) { + assert(IndexReg.getReg() != X86::ESP && + "X86 doesn't allow scaling by ESP"); + + O << '('; + if (HasBaseReg) + printOperand(MI, Op, O, Modifier); + + if (IndexReg.getReg()) { + O << ','; + printOperand(MI, Op+2, O, Modifier); + unsigned ScaleVal = MI->getOperand(Op+1).getImm(); + if (ScaleVal != 1) + O << ',' << ScaleVal; + } + O << ')'; + } } -bool X86SharedAsmPrinter::doFinalization(Module &M) { - // Note: this code is not shared by the Intel printer as it is too different - // from how MASM does things. When making changes here don't forget to look - // at X86IntelAsmPrinter::doFinalization(). - 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->hasInitializer()) 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); - - if (C->isNullValue() && /* FIXME: Verify correct */ - (I->hasInternalLinkage() || I->hasWeakLinkage() || - I->hasLinkOnceLinkage() || - (Subtarget->TargetType == X86Subtarget::isDarwin && - I->hasExternalLinkage() && !I->hasSection()))) { - if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. - if (I->hasExternalLinkage()) { - O << "\t.globl\t" << name << "\n"; - O << "\t.zerofill __DATA__, __common, " << name << ", " - << Size << ", " << Align; - } else { - SwitchToDataSection(DefaultDataSection, I); - if (LCOMMDirective != NULL) { - if (I->hasInternalLinkage()) { - O << LCOMMDirective << name << "," << Size; - if (Subtarget->TargetType == X86Subtarget::isDarwin) - O << "," << (AlignmentIsInBytes ? (1 << Align) : Align); - } else - O << COMMDirective << name << "," << Size; - } else { - if (Subtarget->TargetType != X86Subtarget::isCygwin) { - if (I->hasInternalLinkage()) - O << "\t.local\t" << name << "\n"; - } - O << COMMDirective << name << "," << Size; - if (COMMDirectiveTakesAlignment) - O << "," << (AlignmentIsInBytes ? (1 << Align) : Align); +void X86AsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op, + raw_ostream &O, const char *Modifier) { + assert(isMem(MI, Op) && "Invalid memory reference!"); + const MachineOperand &Segment = MI->getOperand(Op+4); + if (Segment.getReg()) { + printOperand(MI, Op+4, O, Modifier); + O << ':'; + } + printLeaMemReference(MI, Op, O, Modifier); +} + +void X86AsmPrinter::printIntelMemReference(const MachineInstr *MI, unsigned Op, + raw_ostream &O, const char *Modifier, + unsigned AsmVariant){ + const MachineOperand &BaseReg = MI->getOperand(Op); + unsigned ScaleVal = MI->getOperand(Op+1).getImm(); + const MachineOperand &IndexReg = MI->getOperand(Op+2); + const MachineOperand &DispSpec = MI->getOperand(Op+3); + const MachineOperand &SegReg = MI->getOperand(Op+4); + + // If this has a segment register, print it. + if (SegReg.getReg()) { + printOperand(MI, Op+4, O, Modifier, AsmVariant); + O << ':'; + } + + O << '['; + + bool NeedPlus = false; + if (BaseReg.getReg()) { + printOperand(MI, Op, O, Modifier, AsmVariant); + NeedPlus = true; + } + + if (IndexReg.getReg()) { + if (NeedPlus) O << " + "; + if (ScaleVal != 1) + O << ScaleVal << '*'; + printOperand(MI, Op+2, O, Modifier, AsmVariant); + NeedPlus = true; + } + + if (!DispSpec.isImm()) { + if (NeedPlus) O << " + "; + printOperand(MI, Op+3, O, Modifier, AsmVariant); + } else { + int64_t DispVal = DispSpec.getImm(); + if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg())) { + if (NeedPlus) { + if (DispVal > 0) + O << " + "; + else { + O << " - "; + DispVal = -DispVal; } } - O << "\t\t" << CommentString << " " << I->getName() << "\n"; - } else { - switch (I->getLinkage()) { - case GlobalValue::LinkOnceLinkage: - case GlobalValue::WeakLinkage: - if (Subtarget->TargetType == X86Subtarget::isDarwin) { - O << "\t.globl " << name << "\n" - << "\t.weak_definition " << name << "\n"; - SwitchToDataSection(".section __DATA,__const_coal,coalesced", I); - } else if (Subtarget->TargetType == X86Subtarget::isCygwin) { - O << "\t.section\t.llvm.linkonce.d." << name << ",\"aw\"\n" - << "\t.weak " << name << "\n"; - } else { - O << "\t.section\t.llvm.linkonce.d." << name << ",\"aw\",@progbits\n" - << "\t.weak " << name << "\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: - SwitchToDataSection(DefaultDataSection, I); - break; - default: - assert(0 && "Unknown linkage type!"); + O << DispVal; + } + } + O << ']'; +} + +bool X86AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode, + raw_ostream &O) { + 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; + case 'q': // Print DImode register + Reg = getX86SubSuperRegister(Reg, MVT::i64); + break; + } + + O << '%' << X86ATTInstPrinter::getRegisterName(Reg); + return false; +} + +/// PrintAsmOperand - Print out an operand for an inline asm expression. +/// +bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode, raw_ostream &O) { + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) return true; // Unknown modifier. + + const MachineOperand &MO = MI->getOperand(OpNo); + + switch (ExtraCode[0]) { + default: + // See if this is a generic print operand + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + case 'a': // This is an address. Currently only 'i' and 'r' are expected. + if (MO.isImm()) { + O << MO.getImm(); + return false; } + if (MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isSymbol()) { + printSymbolOperand(MO, O); + if (Subtarget->isPICStyleRIPRel()) + O << "(%rip)"; + return false; + } + if (MO.isReg()) { + O << '('; + printOperand(MI, OpNo, O); + O << ')'; + return false; + } + return true; + + case 'c': // Don't print "$" before a global var name or constant. + if (MO.isImm()) + O << MO.getImm(); + else if (MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isSymbol()) + printSymbolOperand(MO, O); + else + printOperand(MI, OpNo, O); + return false; + + case 'A': // Print '*' before a register (it must be a register) + if (MO.isReg()) { + O << '*'; + printOperand(MI, OpNo, O); + return false; + } + return true; - EmitAlignment(Align, I); - O << name << ":\t\t\t\t" << CommentString << " " << I->getName() - << "\n"; - if (HasDotTypeDotSizeDirective) - O << "\t.size " << name << ", " << Size << "\n"; + case 'b': // Print QImode register + case 'h': // Print QImode high register + case 'w': // Print HImode register + case 'k': // Print SImode register + case 'q': // Print DImode register + if (MO.isReg()) + return printAsmMRegister(MO, ExtraCode[0], O); + printOperand(MI, OpNo, O); + return false; - EmitGlobalConstant(C); - O << '\n'; + case 'P': // This is the operand of a call, treat specially. + printPCRelImm(MI, OpNo, O); + return false; + + case 'n': // Negate the immediate or print a '-' before the operand. + // Note: this is a temporary solution. It should be handled target + // independently as part of the 'MC' work. + if (MO.isImm()) { + O << -MO.getImm(); + return false; + } + O << '-'; } } - - if (Subtarget->TargetType == X86Subtarget::isDarwin) { - SwitchToDataSection("", 0); - - // Output stubs for dynamically-linked functions - unsigned j = 1; - for (std::set::iterator i = FnStubs.begin(), e = FnStubs.end(); - i != e; ++i, ++j) { - SwitchToDataSection(".section __IMPORT,__jump_table,symbol_stubs," - "self_modifying_code+pure_instructions,5", 0); - O << "L" << *i << "$stub:\n"; - O << "\t.indirect_symbol " << *i << "\n"; - O << "\thlt ; hlt ; hlt ; hlt ; hlt\n"; + + printOperand(MI, OpNo, O, /*Modifier*/ 0, AsmVariant); + return false; +} + +bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + if (AsmVariant) { + printIntelMemReference(MI, OpNo, O); + return false; + } + + 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 + case 'q': // Print SImode register + // These only apply to registers, ignore on mem. + break; + case 'H': + printMemReference(MI, OpNo, O, "H"); + return false; + case 'P': // Don't print @PLT, but do print as memory. + printMemReference(MI, OpNo, O, "no-rip"); + return false; } + } + printMemReference(MI, OpNo, O); + return false; +} + +void X86AsmPrinter::EmitStartOfAsmFile(Module &M) { + if (Subtarget->isTargetEnvMacho()) + OutStreamer.SwitchSection(getObjFileLowering().getTextSection()); +} + - O << "\n"; +void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { + if (Subtarget->isTargetEnvMacho()) { + // All darwin targets use mach-o. + MachineModuleInfoMachO &MMIMacho = + MMI->getObjFileInfo(); + + // Output stubs for dynamically-linked functions. + MachineModuleInfoMachO::SymbolListTy Stubs; + + Stubs = MMIMacho.GetFnStubList(); + if (!Stubs.empty()) { + const MCSection *TheSection = + OutContext.getMachOSection("__IMPORT", "__jump_table", + MCSectionMachO::S_SYMBOL_STUBS | + MCSectionMachO::S_ATTR_SELF_MODIFYING_CODE | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 5, SectionKind::getMetadata()); + OutStreamer.SwitchSection(TheSection); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$stub: + OutStreamer.EmitLabel(Stubs[i].first); + // .indirect_symbol _foo + OutStreamer.EmitSymbolAttribute(Stubs[i].second.getPointer(), + MCSA_IndirectSymbol); + // hlt; hlt; hlt; hlt; hlt hlt = 0xf4. + const char HltInsts[] = "\xf4\xf4\xf4\xf4\xf4"; + OutStreamer.EmitBytes(StringRef(HltInsts, 5)); + } + + Stubs.clear(); + OutStreamer.AddBlankLine(); + } // Output stubs for external and common global variables. - if (GVStubs.begin() != GVStubs.end()) - SwitchToDataSection( - ".section __IMPORT,__pointers,non_lazy_symbol_pointers", 0); - 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"; + Stubs = MMIMacho.GetGVStubList(); + if (!Stubs.empty()) { + const MCSection *TheSection = + OutContext.getMachOSection("__IMPORT", "__pointers", + MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS, + SectionKind::getMetadata()); + OutStreamer.SwitchSection(TheSection); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$non_lazy_ptr: + OutStreamer.EmitLabel(Stubs[i].first); + // .indirect_symbol _foo + MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; + OutStreamer.EmitSymbolAttribute(MCSym.getPointer(), + MCSA_IndirectSymbol); + // .long 0 + if (MCSym.getInt()) + // External to current translation unit. + OutStreamer.EmitIntValue(0, 4/*size*/); + else + // Internal to current translation unit. + // + // When we place the LSDA into the TEXT section, the type info + // pointers need to be indirect and pc-rel. We accomplish this by + // using NLPs. However, sometimes the types are local to the file. So + // we need to fill in the value for the NLP in those cases. + OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), + OutContext), 4/*size*/); + } + Stubs.clear(); + OutStreamer.AddBlankLine(); } - // Emit initial debug information. - DW.EndModule(); + Stubs = MMIMacho.GetHiddenGVStubList(); + if (!Stubs.empty()) { + OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); + EmitAlignment(2); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$non_lazy_ptr: + OutStreamer.EmitLabel(Stubs[i].first); + // .long _foo + OutStreamer.EmitValue(MCSymbolRefExpr:: + Create(Stubs[i].second.getPointer(), + OutContext), 4/*size*/); + } + Stubs.clear(); + OutStreamer.AddBlankLine(); + } // Funny Darwin hack: This flag tells the linker that no global symbols // contain code that falls through to other global symbols (e.g. the obvious // implementation of multiple entry points). If this doesn't occur, the // linker can safely perform dead code stripping. Since LLVM never // generates code that does this, it is always safe to set. - O << "\t.subsections_via_symbols\n"; + OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); } - AsmPrinter::doFinalization(M); - return false; // success -} - -void X86SharedAsmPrinter::EmitConstantPool(MachineConstantPool *MCP) { - if (!Subtarget->TargetType == X86Subtarget::isDarwin) { - AsmPrinter::EmitConstantPool(MCP); - return; + if (Subtarget->isTargetWindows() && !Subtarget->isTargetCygMing() && + MMI->usesVAFloatArgument()) { + StringRef SymbolName = Subtarget->is64Bit() ? "_fltused" : "__fltused"; + MCSymbol *S = MMI->getContext().GetOrCreateSymbol(SymbolName); + OutStreamer.EmitSymbolAttribute(S, MCSA_Global); } - const std::vector &CP = MCP->getConstants(); - if (CP.empty()) return; - - std::vector FloatCPs; - std::vector DoubleCPs; - std::vector OtherCPs; - // const TargetData *TD = TM.getTargetData(); - // unsigned Align = MCP->getConstantPoolAlignment(); - for (unsigned i = 0, e = CP.size(); i != e; ++i) { - MachineConstantPoolEntry CPE = CP[i]; - const Constant *CV = CPE.Val; - const Type *Ty = CV->getType(); - if (Ty->getTypeID() == Type::FloatTyID) - FloatCPs.push_back(CPE); - else if (Ty->getTypeID() == Type::DoubleTyID) - DoubleCPs.push_back(CPE); - else - OtherCPs.push_back(CPE); + if (Subtarget->isTargetCOFF() && !Subtarget->isTargetEnvMacho()) { + X86COFFMachineModuleInfo &COFFMMI = + MMI->getObjFileInfo(); + + // Emit type information for external functions + typedef X86COFFMachineModuleInfo::externals_iterator externals_iterator; + for (externals_iterator I = COFFMMI.externals_begin(), + E = COFFMMI.externals_end(); + I != E; ++I) { + OutStreamer.BeginCOFFSymbolDef(CurrentFnSym); + OutStreamer.EmitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL); + OutStreamer.EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION + << COFF::SCT_COMPLEX_TYPE_SHIFT); + OutStreamer.EndCOFFSymbolDef(); + } + + // Necessary for dllexport support + std::vector DLLExportedFns, DLLExportedGlobals; + + const TargetLoweringObjectFileCOFF &TLOFCOFF = + static_cast(getObjFileLowering()); + + for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) + if (I->hasDLLExportLinkage()) + DLLExportedFns.push_back(Mang->getSymbol(I)); + + for (Module::const_global_iterator I = M.global_begin(), + E = M.global_end(); I != E; ++I) + if (I->hasDLLExportLinkage()) + DLLExportedGlobals.push_back(Mang->getSymbol(I)); + + // Output linker support code for dllexported globals on windows. + if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { + OutStreamer.SwitchSection(TLOFCOFF.getDrectveSection()); + SmallString<128> name; + for (unsigned i = 0, e = DLLExportedGlobals.size(); i != e; ++i) { + if (Subtarget->isTargetWindows()) + name = " /EXPORT:"; + else + name = " -export:"; + name += DLLExportedGlobals[i]->getName(); + if (Subtarget->isTargetWindows()) + name += ",DATA"; + else + name += ",data"; + OutStreamer.EmitBytes(name); + } + + for (unsigned i = 0, e = DLLExportedFns.size(); i != e; ++i) { + if (Subtarget->isTargetWindows()) + name = " /EXPORT:"; + else + name = " -export:"; + name += DLLExportedFns[i]->getName(); + OutStreamer.EmitBytes(name); + } + } } - EmitConstantPool(MCP, FloatCPs, "\t.literal4"); - EmitConstantPool(MCP, DoubleCPs, "\t.literal8"); - EmitConstantPool(MCP, OtherCPs, ConstantPoolSection); -} -void -X86SharedAsmPrinter::EmitConstantPool(MachineConstantPool *MCP, - std::vector &CP, - const char *Section) { - if (CP.empty()) return; - - SwitchToDataSection(Section, 0); - EmitAlignment(MCP->getConstantPoolAlignment()); - for (unsigned i = 0, e = CP.size(); i != e; ++i) { - O << PrivateGlobalPrefix << "CPI" << getFunctionNumber() << '_' << i - << ":\t\t\t\t\t" << CommentString << " "; - WriteTypeSymbolic(O, CP[i].Val->getType(), 0) << '\n'; - EmitGlobalConstant(CP[i].Val); - if (i != e-1) { - unsigned EntSize = TM.getTargetData()->getTypeSize(CP[i].Val->getType()); - unsigned ValEnd = CP[i].Offset + EntSize; - // Emit inter-object padding for alignment. - EmitZeros(CP[i+1].Offset-ValEnd); + if (Subtarget->isTargetELF()) { + const TargetLoweringObjectFileELF &TLOFELF = + static_cast(getObjFileLowering()); + + MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo(); + + // Output stubs for external and common global variables. + MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); + if (!Stubs.empty()) { + OutStreamer.SwitchSection(TLOFELF.getDataRelSection()); + const DataLayout *TD = TM.getDataLayout(); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + OutStreamer.EmitLabel(Stubs[i].first); + OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), + TD->getPointerSize()); + } + Stubs.clear(); } } } -/// 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, - X86TargetMachine &tm){ - switch (AsmWriterFlavor) { - default: - assert(0 && "Unknown asm flavor!"); - case intel: - return new X86IntelAsmPrinter(o, tm); - case att: - return new X86ATTAsmPrinter(o, tm); - } +//===----------------------------------------------------------------------===// +// Target Registry Stuff +//===----------------------------------------------------------------------===// + +// Force static initialization. +extern "C" void LLVMInitializeX86AsmPrinter() { + RegisterAsmPrinter X(TheX86_32Target); + RegisterAsmPrinter Y(TheX86_64Target); }