X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;ds=sidebyside;f=lib%2FTarget%2FX86%2FX86ATTAsmPrinter.cpp;h=1dd53c7a02a1d282f38fe6a24782e6739a75dd36;hb=5032e5a61381437174e035de2a7dd728978f7bd5;hp=230baad096ff95bede50436576de61e2dbefbc6a;hpb=6c7cb2903836905f5ac483e8cd5382e541fa73f3;p=oota-llvm.git diff --git a/lib/Target/X86/X86ATTAsmPrinter.cpp b/lib/Target/X86/X86ATTAsmPrinter.cpp index 230baad096f..1dd53c7a02a 100755 --- a/lib/Target/X86/X86ATTAsmPrinter.cpp +++ b/lib/Target/X86/X86ATTAsmPrinter.cpp @@ -13,39 +13,155 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "asm-printer" #include "X86ATTAsmPrinter.h" #include "X86.h" +#include "X86COFF.h" +#include "X86MachineFunctionInfo.h" #include "X86TargetMachine.h" +#include "X86TargetAsmInfo.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/CallingConv.h" #include "llvm/Module.h" #include "llvm/Support/Mangler.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/ADT/Statistic.h" using namespace llvm; -using namespace x86; + +STATISTIC(EmittedInsts, "Number of machine instrs printed"); + +static std::string computePICLabel(unsigned fnNumber, + const X86Subtarget* Subtarget) +{ + std::string label; + + if (Subtarget->isTargetDarwin()) { + label = "\"L" + utostr_32(fnNumber) + "$pb\""; + } else if (Subtarget->isTargetELF()) { + label = ".Lllvm$" + utostr_32(fnNumber) + "$piclabel"; + } else + assert(0 && "Don't know how to print PIC label!\n"); + + return label; +} + +/// getSectionForFunction - Return the section that we should emit the +/// specified function body into. +std::string X86ATTAsmPrinter::getSectionForFunction(const Function &F) const { + switch (F.getLinkage()) { + default: assert(0 && "Unknown linkage type!"); + case Function::InternalLinkage: + case Function::DLLExportLinkage: + case Function::ExternalLinkage: + return TAI->getTextSection(); + case Function::WeakLinkage: + case Function::LinkOnceLinkage: + if (Subtarget->isTargetDarwin()) { + return ".section __TEXT,__textcoal_nt,coalesced,pure_instructions"; + } else if (Subtarget->isTargetCygMing()) { + return "\t.section\t.text$linkonce." + CurrentFnName + ",\"ax\"\n"; + } else { + return "\t.section\t.llvm.linkonce.t." + CurrentFnName + + ",\"ax\",@progbits\n"; + } + } +} /// runOnMachineFunction - This uses the printMachineInstruction() /// method to print assembly for each instruction. /// bool X86ATTAsmPrinter::runOnMachineFunction(MachineFunction &MF) { - setupMachineFunction(MF); + if (Subtarget->isTargetDarwin() || + Subtarget->isTargetELF() || + Subtarget->isTargetCygMing()) { + // Let PassManager know we need debug information and relay + // the MachineDebugInfo address on to DwarfWriter. + DW.SetDebugInfo(&getAnalysis()); + } + + SetupMachineFunction(MF); O << "\n\n"; // Print out constants referenced by the function - printConstantPool(MF.getConstantPool()); + EmitConstantPool(MF.getConstantPool()); // Print out labels for the function. - O << "\t.text\n"; - emitAlignment(4); // FIXME: This should be parameterized somewhere. - O << "\t.globl\t" << CurrentFnName << "\n"; - if (!forCygwin && !forDarwin) - O << "\t.type\t" << CurrentFnName << ", @function\n"; + const Function *F = MF.getFunction(); + unsigned CC = F->getCallingConv(); + + // Populate function information map. Actually, We don't want to populate + // non-stdcall or non-fastcall functions' information right now. + if (CC == CallingConv::X86_StdCall || CC == CallingConv::X86_FastCall) + FunctionInfoMap[F] = *MF.getInfo(); + + X86SharedAsmPrinter::decorateName(CurrentFnName, F); + + SwitchToTextSection(getSectionForFunction(*F).c_str(), F); + + switch (F->getLinkage()) { + default: assert(0 && "Unknown linkage type!"); + case Function::InternalLinkage: // Symbols default to internal. + EmitAlignment(4, F); // FIXME: This should be parameterized somewhere. + break; + case Function::DLLExportLinkage: + DLLExportedFns.insert(Mang->makeNameProper(F->getName(), "")); + //FALLS THROUGH + case Function::ExternalLinkage: + EmitAlignment(4, F); // FIXME: This should be parameterized somewhere. + O << "\t.globl\t" << CurrentFnName << "\n"; + break; + case Function::LinkOnceLinkage: + case Function::WeakLinkage: + if (Subtarget->isTargetDarwin()) { + O << "\t.globl\t" << CurrentFnName << "\n"; + O << "\t.weak_definition\t" << CurrentFnName << "\n"; + } else if (Subtarget->isTargetCygMing()) { + EmitAlignment(4, F); // FIXME: This should be parameterized somewhere. + O << "\t.linkonce discard\n"; + O << "\t.globl " << CurrentFnName << "\n"; + } else { + EmitAlignment(4, F); // FIXME: This should be parameterized somewhere. + O << "\t.weak " << CurrentFnName << "\n"; + } + break; + } + if (F->hasHiddenVisibility()) + if (const char *Directive = TAI->getHiddenDirective()) + O << Directive << CurrentFnName << "\n"; + + if (Subtarget->isTargetELF()) + O << "\t.type " << CurrentFnName << ",@function\n"; + else if (Subtarget->isTargetCygMing()) { + O << "\t.def\t " << CurrentFnName + << ";\t.scl\t" << + (F->getLinkage() == Function::InternalLinkage ? COFF::C_STAT : COFF::C_EXT) + << ";\t.type\t" << (COFF::DT_FCN << COFF::N_BTSHFT) + << ";\t.endef\n"; + } + O << CurrentFnName << ":\n"; + // Add some workaround for linkonce linkage on Cygwin\MinGW + if (Subtarget->isTargetCygMing() && + (F->getLinkage() == Function::LinkOnceLinkage || + F->getLinkage() == Function::WeakLinkage)) + O << "Lllvm$workaround$fake$stub$" << CurrentFnName << ":\n"; + + if (Subtarget->isTargetDarwin() || + Subtarget->isTargetELF() || + Subtarget->isTargetCygMing()) { + // Emit pre-function debug information. + DW.BeginFunction(&MF); + } // 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 (I->pred_begin() != I->pred_end()) - O << ".LBB" << CurrentFnName << "_" << I->getNumber() << ":\t" - << CommentString << " " << I->getBasicBlock()->getName() << "\n"; + 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. @@ -53,98 +169,217 @@ bool X86ATTAsmPrinter::runOnMachineFunction(MachineFunction &MF) { printMachineInstruction(II); } } - if (!forDarwin) + + // Print out jump tables referenced by the function. + + // Mac OS X requires that the jump table follow the function, so that the jump + // table is part of the same atom that the function is in. + EmitJumpTableInfo(MF.getJumpTableInfo(), MF); + + if (TAI->hasDotTypeDotSizeDirective()) O << "\t.size " << CurrentFnName << ", .-" << CurrentFnName << "\n"; + if (Subtarget->isTargetDarwin() || + Subtarget->isTargetELF() || + Subtarget->isTargetCygMing()) { + // Emit post-function debug information. + DW.EndFunction(); + } + // We didn't modify anything. return false; } -void X86ATTAsmPrinter::printOp(const MachineOperand &MO, bool isCallOp) { +void X86ATTAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, + const char *Modifier, bool NotRIPRel) { + const MachineOperand &MO = MI->getOperand(OpNo); const MRegisterInfo &RI = *TM.getRegisterInfo(); switch (MO.getType()) { - case MachineOperand::MO_VirtualRegister: - case MachineOperand::MO_MachineRegister: + case MachineOperand::MO_Register: { assert(MRegisterInfo::isPhysicalRegister(MO.getReg()) && "Virtual registers should not make it this far!"); O << '%'; - for (const char *Name = RI.get(MO.getReg()).Name; *Name; ++Name) + unsigned Reg = MO.getReg(); + if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) { + MVT::ValueType 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); + } + for (const char *Name = RI.get(Reg).Name; *Name; ++Name) O << (char)tolower(*Name); return; + } - case MachineOperand::MO_SignExtendedImmed: - case MachineOperand::MO_UnextendedImmed: - O << '$' << (int)MO.getImmedValue(); + case MachineOperand::MO_Immediate: + if (!Modifier || strcmp(Modifier, "debug") != 0) + O << '$'; + O << MO.getImmedValue(); return; - case MachineOperand::MO_MachineBasicBlock: { - MachineBasicBlock *MBBOp = MO.getMachineBasicBlock(); - O << ".LBB" << Mang->getValueName(MBBOp->getParent()->getFunction()) - << "_" << MBBOp->getNumber () << "\t# " - << MBBOp->getBasicBlock ()->getName (); + case MachineOperand::MO_MachineBasicBlock: + printBasicBlockLabel(MO.getMachineBasicBlock()); + return; + case MachineOperand::MO_JumpTableIndex: { + bool isMemOp = Modifier && !strcmp(Modifier, "mem"); + if (!isMemOp) O << '$'; + O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << "_" + << MO.getJumpTableIndex(); + + if (TM.getRelocationModel() == Reloc::PIC_) { + if (Subtarget->isPICStyleStub()) + O << "-\"L" << getFunctionNumber() << "$pb\""; + else if (Subtarget->isPICStyleGOT()) + O << "@GOTOFF"; + } + + if (isMemOp && Subtarget->is64Bit() && !NotRIPRel) + O << "(%rip)"; return; } - case MachineOperand::MO_PCRelativeDisp: - std::cerr << "Shouldn't use addPCDisp() when building X86 MachineInstrs"; - abort (); + case MachineOperand::MO_ConstantPoolIndex: { + bool isMemOp = Modifier && !strcmp(Modifier, "mem"); + if (!isMemOp) O << '$'; + O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" + << MO.getConstantPoolIndex(); + + if (TM.getRelocationModel() == Reloc::PIC_) { + if (Subtarget->isPICStyleStub()) + O << "-\"L" << getFunctionNumber() << "$pb\""; + if (Subtarget->isPICStyleGOT()) + O << "@GOTOFF"; + } + + int Offset = MO.getOffset(); + if (Offset > 0) + O << "+" << Offset; + else if (Offset < 0) + O << Offset; + + if (isMemOp && Subtarget->is64Bit() && !NotRIPRel) + O << "(%rip)"; return; + } case MachineOperand::MO_GlobalAddress: { - // Darwin block shameless ripped from PowerPCAsmPrinter.cpp - if (forDarwin) { - if (!isCallOp) O << '$'; - GlobalValue *GV = MO.getGlobal(); - std::string Name = Mang->getValueName(GV); - - // Dynamically-resolved functions need a stub for the function. Be - // wary however not to output $stub for external functions whose addresses - // are taken. Those should be emitted as $non_lazy_ptr below. - Function *F = dyn_cast(GV); - if (F && isCallOp && F->isExternal()) { - FnStubs.insert(Name); - O << "L" << Name << "$stub"; - } else if (GV->hasLinkOnceLinkage()) { - // Link-once, External, or Weakly-linked global variables need - // non-lazily-resolved stubs - LinkOnceStubs.insert(Name); - O << "L" << Name << "$non_lazy_ptr"; - } else if (GV->isExternal() || GV->hasWeakLinkage()) { - GVStubs.insert(Name); - O << "L" << Name << "$non_lazy_ptr"; + bool isCallOp = Modifier && !strcmp(Modifier, "call"); + bool isMemOp = Modifier && !strcmp(Modifier, "mem"); + if (!isMemOp && !isCallOp) O << '$'; + + GlobalValue *GV = MO.getGlobal(); + std::string Name = Mang->getValueName(GV); + + bool isExt = (GV->isExternal() || GV->hasWeakLinkage() || + GV->hasLinkOnceLinkage()); + bool isHidden = GV->hasHiddenVisibility(); + + X86SharedAsmPrinter::decorateName(Name, GV); + + if (Subtarget->isPICStyleStub()) { + // Link-once, External, or Weakly-linked global variables need + // non-lazily-resolved stubs + if (isExt) { + // Dynamically-resolved functions need a stub for the function. + if (isCallOp && isa(GV)) { + FnStubs.insert(Name); + O << "L" << Name << "$stub"; + } else { + GVStubs.insert(Name); + O << "L" << Name << "$non_lazy_ptr"; + } } else { - O << Mang->getValueName(GV); + if (GV->hasDLLImportLinkage()) { + O << "__imp_"; + } + O << Name; + } + + if (!isCallOp && TM.getRelocationModel() == Reloc::PIC_) + O << "-\"L" << getFunctionNumber() << "$pb\""; + } else { + if (GV->hasDLLImportLinkage()) { + O << "__imp_"; + } + O << Name; + + if (isCallOp && isa(GV)) { + if (Subtarget->isPICStyleGOT()) { + // Assemble call via PLT for non-local symbols + if (!isHidden || GV->isExternal()) + O << "@PLT"; + } + if (Subtarget->isTargetCygMing() && GV->isExternal()) { + // Save function name for later type emission + FnStubs.insert(Name); + } } - int Offset = MO.getOffset(); - if (Offset > 0) - O << "+" << Offset; - else if (Offset < 0) - O << Offset; - return; } - if (!isCallOp) O << '$'; - O << Mang->getValueName(MO.getGlobal()); + + if (GV->hasExternalWeakLinkage()) + ExtWeakSymbols.insert(GV); + int Offset = MO.getOffset(); if (Offset > 0) O << "+" << Offset; else if (Offset < 0) O << Offset; + + if (isMemOp) { + if (Subtarget->isPICStyleGOT()) { + if (Subtarget->GVRequiresExtraLoad(GV, TM, false)) + O << "@GOT"; + else + O << "@GOTOFF"; + } else + if (isExt && Subtarget->isPICStyleRIPRel()) + O << "@GOTPCREL(%rip)"; + else if (Subtarget->is64Bit() && !NotRIPRel) + // Use rip when possible to reduce code size, except when + // index or base register are also part of the address. e.g. + // foo(%rip)(%rcx,%rax,4) is not legal + O << "(%rip)"; + } + return; } - case MachineOperand::MO_ExternalSymbol: - if (isCallOp && forDarwin) { - std::string Name(GlobalPrefix); Name += MO.getSymbolName(); + case MachineOperand::MO_ExternalSymbol: { + bool isCallOp = Modifier && !strcmp(Modifier, "call"); + std::string Name(TAI->getGlobalPrefix()); + Name += MO.getSymbolName(); + if (isCallOp && Subtarget->isPICStyleStub()) { FnStubs.insert(Name); O << "L" << Name << "$stub"; return; } if (!isCallOp) O << '$'; - O << GlobalPrefix << MO.getSymbolName(); + O << Name; + + if (Subtarget->isPICStyleGOT()) { + std::string GOTName(TAI->getGlobalPrefix()); + GOTName+="_GLOBAL_OFFSET_TABLE_"; + if (Name == GOTName) + // Really hack! Emit extra offset to PC during printing GOT offset to + // compensate size of popl instruction. The resulting code should look + // like: + // call .piclabel + // piclabel: + // popl %some_register + // addl $_GLOBAL_ADDRESS_TABLE_ + [.-piclabel], %some_register + O << " + [.-" << computePICLabel(getFunctionNumber(), Subtarget) << "]"; + } + + if (isCallOp && Subtarget->isPICStyleGOT()) + O << "@PLT"; + + if (!isCallOp && Subtarget->is64Bit()) + O << "(%rip)"; + return; + } default: O << ""; return; } } -void X86ATTAsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op, - MVT::ValueType VT) { +void X86ATTAsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op) { unsigned char value = MI->getOperand(Op).getImmedValue(); assert(value <= 7 && "Invalid ssecc argument!"); switch (value) { @@ -159,37 +394,18 @@ void X86ATTAsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op, } } -void X86ATTAsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op){ +void X86ATTAsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op, + const char *Modifier){ 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); + MachineOperand BaseReg = MI->getOperand(Op); + 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; - } else if (BaseReg.isConstantPoolIndex()) { - O << ".CPI" << CurrentFnName << "_" - << BaseReg.getConstantPoolIndex(); - if (DispSpec.getImmedValue()) - O << "+" << DispSpec.getImmedValue(); - if (IndexReg.getReg()) { - O << "(,"; - printOp(IndexReg); - if (ScaleVal != 1) - O << "," << ScaleVal; - O << ")"; - } - return; - } - - if (DispSpec.isGlobalAddress()) { - printOp(DispSpec, true); + bool NotRIPRel = IndexReg.getReg() || BaseReg.getReg(); + if (DispSpec.isGlobalAddress() || + DispSpec.isConstantPoolIndex() || + DispSpec.isJumpTableIndex()) { + printOperand(MI, Op+3, "mem", NotRIPRel); } else { int DispVal = DispSpec.getImmedValue(); if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg())) @@ -197,26 +413,137 @@ void X86ATTAsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op){ } if (IndexReg.getReg() || BaseReg.getReg()) { + unsigned ScaleVal = MI->getOperand(Op+1).getImmedValue(); + unsigned BaseRegOperand = 0, IndexRegOperand = 2; + + // There are cases where we can end up with ESP/RSP in the indexreg slot. + // If this happens, swap the base/index register to support assemblers that + // don't work when the index is *SP. + if (IndexReg.getReg() == X86::ESP || IndexReg.getReg() == X86::RSP) { + assert(ScaleVal == 1 && "Scale not supported for stack pointer!"); + std::swap(BaseReg, IndexReg); + std::swap(BaseRegOperand, IndexRegOperand); + } + O << "("; if (BaseReg.getReg()) - printOp(BaseReg); + printOperand(MI, Op+BaseRegOperand, Modifier); if (IndexReg.getReg()) { O << ","; - printOp(IndexReg); + printOperand(MI, Op+IndexRegOperand, Modifier); if (ScaleVal != 1) O << "," << ScaleVal; } - O << ")"; } } +void X86ATTAsmPrinter::printPICLabel(const MachineInstr *MI, unsigned Op) { + std::string label = computePICLabel(getFunctionNumber(), Subtarget); + O << label << "\n" << label << ":"; +} + + +bool X86ATTAsmPrinter::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 << '%'; + for (const char *Name = RI.get(Reg).Name; *Name; ++Name) + O << (char)tolower(*Name); + return false; +} + +/// PrintAsmOperand - Print out an operand for an inline asm expression. +/// +bool X86ATTAsmPrinter::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 'c': // Don't print "$" before a global var name. + printOperand(MI, OpNo, "mem"); + return false; + 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 X86ATTAsmPrinter::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 X86ATTAsmPrinter::printMachineInstruction(const MachineInstr *MI) { ++EmittedInsts; + + // See if a truncate instruction can be turned into a nop. + switch (MI->getOpcode()) { + default: break; + case X86::TRUNC_64to32: + case X86::TRUNC_64to16: + case X86::TRUNC_32to16: + case X86::TRUNC_32to8: + case X86::TRUNC_16to8: + case X86::TRUNC_32_to8: + case X86::TRUNC_16_to8: { + const MachineOperand &MO0 = MI->getOperand(0); + const MachineOperand &MO1 = MI->getOperand(1); + unsigned Reg0 = MO0.getReg(); + unsigned Reg1 = MO1.getReg(); + unsigned Opc = MI->getOpcode(); + if (Opc == X86::TRUNC_64to32) + Reg1 = getX86SubSuperRegister(Reg1, MVT::i32); + else if (Opc == X86::TRUNC_32to16 || Opc == X86::TRUNC_64to16) + Reg1 = getX86SubSuperRegister(Reg1, MVT::i16); + else + Reg1 = getX86SubSuperRegister(Reg1, MVT::i8); + O << TAI->getCommentString() << " TRUNCATE "; + if (Reg0 != Reg1) + O << "\n\t"; + break; + } + case X86::PsMOVZX64rr32: + O << TAI->getCommentString() << " ZERO-EXTEND " << "\n\t"; + break; + } + // Call the autogenerated instruction printer routines. printInstruction(MI); }