//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "asm-printer"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/DerivedTypes.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/FormattedStream.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormattedStream.h"
#include <cerrno>
using namespace llvm;
-static cl::opt<cl::boolOrDefault>
-AsmVerbose("asm-verbose", cl::desc("Add comments to directives."),
- cl::init(cl::BOU_UNSET));
-
-static bool getVerboseAsm(bool VDef) {
- switch (AsmVerbose) {
- default:
- case cl::BOU_UNSET: return VDef;
- case cl::BOU_TRUE: return true;
- case cl::BOU_FALSE: return false;
- }
-}
+STATISTIC(EmittedInsts, "Number of machine instrs printed");
char AsmPrinter::ID = 0;
AsmPrinter::AsmPrinter(formatted_raw_ostream &o, TargetMachine &tm,
- const MCAsmInfo *T, bool VDef)
+ MCContext &Ctx, MCStreamer &Streamer,
+ const MCAsmInfo *T)
: MachineFunctionPass(&ID), O(o),
TM(tm), MAI(T), TRI(tm.getRegisterInfo()),
-
- OutContext(*new MCContext()),
- // FIXME: Pass instprinter to streamer.
- OutStreamer(*createAsmStreamer(OutContext, O, *T,
- TM.getTargetData()->isLittleEndian(),
- getVerboseAsm(VDef), 0)),
-
+ OutContext(Ctx), OutStreamer(Streamer),
LastMI(0), LastFn(0), Counter(~0U), PrevDLT(NULL) {
DW = 0; MMI = 0;
- VerboseAsm = getVerboseAsm(VDef);
+ VerboseAsm = Streamer.isVerboseAsm();
}
AsmPrinter::~AsmPrinter() {
return false;
}
+void AsmPrinter::EmitLinkage(unsigned Linkage, MCSymbol *GVSym) const {
+ switch ((GlobalValue::LinkageTypes)Linkage) {
+ case GlobalValue::CommonLinkage:
+ case GlobalValue::LinkOnceAnyLinkage:
+ case GlobalValue::LinkOnceODRLinkage:
+ case GlobalValue::WeakAnyLinkage:
+ case GlobalValue::WeakODRLinkage:
+ case GlobalValue::LinkerPrivateLinkage:
+ if (MAI->getWeakDefDirective() != 0) {
+ // .globl _foo
+ OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
+ // .weak_definition _foo
+ OutStreamer.EmitSymbolAttribute(GVSym, MCSA_WeakDefinition);
+ } else if (const char *LinkOnce = MAI->getLinkOnceDirective()) {
+ // .globl _foo
+ OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
+ // FIXME: linkonce should be a section attribute, handled by COFF Section
+ // assignment.
+ // http://sourceware.org/binutils/docs-2.20/as/Linkonce.html#Linkonce
+ // .linkonce discard
+ // FIXME: It would be nice to use .linkonce samesize for non-common
+ // globals.
+ O << LinkOnce;
+ } else {
+ // .weak _foo
+ OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak);
+ }
+ break;
+ case GlobalValue::DLLExportLinkage:
+ 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.
+ // .globl _foo
+ OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
+ break;
+ case GlobalValue::PrivateLinkage:
+ case GlobalValue::InternalLinkage:
+ break;
+ default:
+ llvm_unreachable("Unknown linkage type!");
+ }
+}
+
+
/// EmitGlobalVariable - Emit the specified global variable to the .s file.
void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
if (!GV->hasInitializer()) // External globals require no code.
return;
MCSymbol *GVSym = GetGlobalValueSymbol(GV);
- printVisibility(GVSym, GV->getVisibility());
+ EmitVisibility(GVSym, GV->getVisibility());
if (MAI->hasDotTypeDotSizeDirective())
OutStreamer.EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject);
OutStreamer.SwitchSection(TheSection);
- // TODO: Factor into an 'emit linkage' thing that is shared with function
- // bodies.
- switch (GV->getLinkage()) {
- case GlobalValue::CommonLinkage:
- case GlobalValue::LinkOnceAnyLinkage:
- case GlobalValue::LinkOnceODRLinkage:
- case GlobalValue::WeakAnyLinkage:
- case GlobalValue::WeakODRLinkage:
- case GlobalValue::LinkerPrivateLinkage:
- if (MAI->getWeakDefDirective() != 0) {
- // .globl _foo
- OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
- // .weak_definition _foo
- OutStreamer.EmitSymbolAttribute(GVSym, MCSA_WeakDefinition);
- } else if (const char *LinkOnce = MAI->getLinkOnceDirective()) {
- // .globl _foo
- OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
- // FIXME: linkonce should be a section attribute, handled by COFF Section
- // assignment.
- // http://sourceware.org/binutils/docs-2.20/as/Linkonce.html#Linkonce
- // .linkonce same_size
- O << LinkOnce;
- } else {
- // .weak _foo
- OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak);
- }
- break;
- case GlobalValue::DLLExportLinkage:
- 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.
- // .globl _foo
- OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
- break;
- case GlobalValue::PrivateLinkage:
- case GlobalValue::InternalLinkage:
- break;
- default:
- llvm_unreachable("Unknown linkage type!");
- }
-
+ EmitLinkage(GV->getLinkage(), GVSym);
EmitAlignment(AlignLog, GV);
+
if (VerboseAsm) {
WriteAsOperand(OutStreamer.GetCommentOS(), GV,
/*PrintType=*/false, GV->getParent());
OutStreamer.AddBlankLine();
}
+/// EmitFunctionHeader - This method emits the header for the current
+/// function.
+void AsmPrinter::EmitFunctionHeader() {
+ // Print out constants referenced by the function
+ EmitConstantPool();
+
+ // Print the 'header' of function.
+ const Function *F = MF->getFunction();
+
+ OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
+ EmitVisibility(CurrentFnSym, F->getVisibility());
+
+ EmitLinkage(F->getLinkage(), CurrentFnSym);
+ EmitAlignment(MF->getAlignment(), F);
+
+ if (MAI->hasDotTypeDotSizeDirective())
+ OutStreamer.EmitSymbolAttribute(CurrentFnSym, MCSA_ELF_TypeFunction);
+
+ if (VerboseAsm) {
+ WriteAsOperand(OutStreamer.GetCommentOS(), F,
+ /*PrintType=*/false, F->getParent());
+ OutStreamer.GetCommentOS() << '\n';
+ }
+
+ // Emit the CurrentFnSym. This is is a virtual function to allow targets to
+ // do their wild and crazy things as required.
+ EmitFunctionEntryLabel();
+
+ // Add some workaround for linkonce linkage on Cygwin\MinGW.
+ if (MAI->getLinkOnceDirective() != 0 &&
+ (F->hasLinkOnceLinkage() || F->hasWeakLinkage()))
+ // FIXME: What is this?
+ O << "Lllvm$workaround$fake$stub$" << *CurrentFnSym << ":\n";
+
+ // Emit pre-function debug and/or EH information.
+ if (MAI->doesSupportDebugInformation() || MAI->doesSupportExceptionHandling())
+ DW->BeginFunction(MF);
+}
+
+/// EmitFunctionEntryLabel - Emit the label that is the entrypoint for the
+/// function. This can be overridden by targets as required to do custom stuff.
+void AsmPrinter::EmitFunctionEntryLabel() {
+ OutStreamer.EmitLabel(CurrentFnSym);
+}
+
+
+/// EmitFunctionBody - This method emits the body and trailer for a
+/// function.
+void AsmPrinter::EmitFunctionBody() {
+ // Emit target-specific gunk before the function body.
+ EmitFunctionBodyStart();
+
+ // Print out code for the function.
+ bool HasAnyRealCode = false;
+ for (MachineFunction::const_iterator I = MF->begin(), E = MF->end();
+ I != E; ++I) {
+ // Print a label for the basic block.
+ EmitBasicBlockStart(I);
+ for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end();
+ II != IE; ++II) {
+ // Print the assembly for the instruction.
+ if (!II->isLabel())
+ HasAnyRealCode = true;
+
+ ++EmittedInsts;
+
+ // FIXME: Clean up processDebugLoc.
+ processDebugLoc(II, true);
+
+ switch (II->getOpcode()) {
+ case TargetInstrInfo::DBG_LABEL:
+ case TargetInstrInfo::EH_LABEL:
+ case TargetInstrInfo::GC_LABEL:
+ printLabelInst(II);
+ break;
+ case TargetInstrInfo::INLINEASM:
+ printInlineAsm(II);
+ break;
+ case TargetInstrInfo::IMPLICIT_DEF:
+ printImplicitDef(II);
+ break;
+ case TargetInstrInfo::KILL:
+ printKill(II);
+ break;
+ default:
+ EmitInstruction(II);
+ break;
+ }
+ if (VerboseAsm)
+ EmitComments(*II);
+
+ // FIXME: Clean up processDebugLoc.
+ processDebugLoc(II, false);
+ }
+ }
+
+ // If the function is empty and the object file uses .subsections_via_symbols,
+ // then we need to emit *something* to the function body to prevent the
+ // labels from collapsing together. Just emit a 0 byte.
+ if (MAI->hasSubsectionsViaSymbols() && !HasAnyRealCode)
+ OutStreamer.EmitIntValue(0, 1, 0/*addrspace*/);
+
+ // Emit target-specific gunk after the function body.
+ EmitFunctionBodyEnd();
+
+ if (MAI->hasDotTypeDotSizeDirective())
+ O << "\t.size\t" << *CurrentFnSym << ", .-" << *CurrentFnSym << '\n';
+
+ // Emit post-function debug information.
+ if (MAI->doesSupportDebugInformation() || MAI->doesSupportExceptionHandling())
+ DW->EndFunction(MF);
+
+ // Print out jump tables referenced by the function.
+ EmitJumpTableInfo();
+
+ OutStreamer.AddBlankLine();
+}
+
bool AsmPrinter::doFinalization(Module &M) {
// Emit global variables.
else
assert(I->hasLocalLinkage() && "Invalid alias linkage");
- printVisibility(Name, I->getVisibility());
+ EmitVisibility(Name, I->getVisibility());
- O << "\t.set\t" << *Name << ", " << *Target << '\n';
+ // Emit the directives as assignments aka .set:
+ OutStreamer.EmitAssignment(Name,
+ MCSymbolRefExpr::Create(Target, OutContext));
}
}
/// used to print out constants which have been "spilled to memory" by
/// the code generator.
///
-void AsmPrinter::EmitConstantPool(MachineConstantPool *MCP) {
+void AsmPrinter::EmitConstantPool() {
+ const MachineConstantPool *MCP = MF->getConstantPool();
const std::vector<MachineConstantPoolEntry> &CP = MCP->getConstants();
if (CP.empty()) return;
/// EmitJumpTableInfo - Print assembly representations of the jump tables used
/// by the current function to the current output stream.
///
-void AsmPrinter::EmitJumpTableInfo(MachineFunction &MF) {
- MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
+void AsmPrinter::EmitJumpTableInfo() {
+ const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
if (MJTI == 0) return;
const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
if (JT.empty()) return;
// Pick the directive to use to print the jump table entries, and switch to
// the appropriate section.
- const Function *F = MF.getFunction();
+ const Function *F = MF->getFunction();
bool JTInDiffSection = false;
if (// In PIC mode, we need to emit the jump table to the same section as the
// function body itself, otherwise the label differences won't make sense.
// FIXME: this isn't the right predicate, should be based on the MCSection
// for the function.
F->isWeakForLinker()) {
- OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang,
- TM));
+ OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F,Mang,TM));
} else {
// Otherwise, drop it in the readonly section.
const MCSection *ReadOnlySection =
MAI->hasSetDirective()) {
SmallPtrSet<const MachineBasicBlock*, 16> EmittedSets;
const TargetLowering *TLI = TM.getTargetLowering();
- const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(&MF, JTI,
- OutContext);
+ const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF,JTI,OutContext);
for (unsigned ii = 0, ee = JTBBs.size(); ii != ee; ++ii) {
const MachineBasicBlock *MBB = JTBBs[ii];
if (!EmittedSets.insert(MBB)) continue;
- O << "\t.set\t"
- << *GetJTSetSymbol(JTI, MBB->getNumber()) << ','
- << *MBB->getSymbol(OutContext) << '-' << *Base << '\n';
+ // .set LJTSet, LBB32-base
+ const MCExpr *LHS =
+ MCSymbolRefExpr::Create(MBB->getSymbol(OutContext), OutContext);
+ OutStreamer.EmitAssignment(GetJTSetSymbol(JTI, MBB->getNumber()),
+ MCBinaryExpr::CreateSub(LHS, Base, OutContext));
}
}
void AsmPrinter::EmitGlobalConstant(const Constant *CV, unsigned AddrSpace) {
if (isa<ConstantAggregateZero>(CV) || isa<UndefValue>(CV)) {
uint64_t Size = TM.getTargetData()->getTypeAllocSize(CV->getType());
+ if (Size == 0) Size = 1; // An empty "_foo:" followed by a section is undef.
return OutStreamer.EmitZeros(Size, AddrSpace);
}
}
}
}
- O << "\n\t" << MAI->getCommentString() << MAI->getInlineAsmEnd();
+ O << "\n\t" << MAI->getCommentString() << MAI->getInlineAsmEnd() << '\n';
}
/// printImplicitDef - This method prints the specified machine instruction
if (!VerboseAsm) return;
O.PadToColumn(MAI->getCommentColumn());
O << MAI->getCommentString() << " implicit-def: "
- << TRI->getName(MI->getOperand(0).getReg());
+ << TRI->getName(MI->getOperand(0).getReg()) << '\n';
}
void AsmPrinter::printKill(const MachineInstr *MI) const {
assert(op.isReg() && "KILL instruction must have only register operands");
O << ' ' << TRI->getName(op.getReg()) << (op.isDef() ? "<def>" : "<kill>");
}
+ O << '\n';
}
/// printLabel - This method prints a local label used by debug and
/// exception handling tables.
-void AsmPrinter::printLabel(const MachineInstr *MI) const {
+void AsmPrinter::printLabelInst(const MachineInstr *MI) const {
printLabel(MI->getOperand(0).getImm());
+ O << '\n';
}
void AsmPrinter::printLabel(unsigned Id) const {
}
}
-/// EmitComments - Pretty-print comments for basic blocks.
+/// PrintBasicBlockLoopComments - Pretty-print comments for basic blocks.
static void PrintBasicBlockLoopComments(const MachineBasicBlock &MBB,
const MachineLoopInfo *LI,
const AsmPrinter &AP) {
}
}
-void AsmPrinter::printVisibility(MCSymbol *Sym, unsigned Visibility) const {
+void AsmPrinter::EmitVisibility(MCSymbol *Sym, unsigned Visibility) const {
MCSymbolAttr Attr = MCSA_Invalid;
switch (Visibility) {
if (!VerboseAsm)
return;
- bool Newline = false;
-
if (!MI.getDebugLoc().isUnknown()) {
DILocation DLT = MF->getDILocation(MI.getDebugLoc());
O << ':' << DLT.getLineNumber();
if (DLT.getColumnNumber() != 0)
O << ':' << DLT.getColumnNumber();
- Newline = true;
+ O << '\n';
}
// Check for spills and reloads
if (TM.getInstrInfo()->isLoadFromStackSlotPostFE(&MI, FI)) {
if (FrameInfo->isSpillSlotObjectIndex(FI)) {
MMO = *MI.memoperands_begin();
- if (Newline) O << '\n';
O.PadToColumn(MAI->getCommentColumn());
- O << MAI->getCommentString() << ' ' << MMO->getSize() << "-byte Reload";
- Newline = true;
+ O << MAI->getCommentString() << ' ' << MMO->getSize() << "-byte Reload\n";
}
}
else if (TM.getInstrInfo()->hasLoadFromStackSlot(&MI, MMO, FI)) {
if (FrameInfo->isSpillSlotObjectIndex(FI)) {
- if (Newline) O << '\n';
O.PadToColumn(MAI->getCommentColumn());
O << MAI->getCommentString() << ' '
- << MMO->getSize() << "-byte Folded Reload";
- Newline = true;
+ << MMO->getSize() << "-byte Folded Reload\n";
}
}
else if (TM.getInstrInfo()->isStoreToStackSlotPostFE(&MI, FI)) {
if (FrameInfo->isSpillSlotObjectIndex(FI)) {
MMO = *MI.memoperands_begin();
- if (Newline) O << '\n';
O.PadToColumn(MAI->getCommentColumn());
- O << MAI->getCommentString() << ' ' << MMO->getSize() << "-byte Spill";
- Newline = true;
+ O << MAI->getCommentString() << ' ' << MMO->getSize() << "-byte Spill\n";
}
}
else if (TM.getInstrInfo()->hasStoreToStackSlot(&MI, MMO, FI)) {
if (FrameInfo->isSpillSlotObjectIndex(FI)) {
- if (Newline) O << '\n';
O.PadToColumn(MAI->getCommentColumn());
O << MAI->getCommentString() << ' '
- << MMO->getSize() << "-byte Folded Spill";
- Newline = true;
+ << MMO->getSize() << "-byte Folded Spill\n";
}
}
if (TM.getInstrInfo()->isMoveInstr(MI, SrcReg, DstReg,
SrcSubIdx, DstSubIdx)) {
if (MI.getAsmPrinterFlag(ReloadReuse)) {
- if (Newline) O << '\n';
O.PadToColumn(MAI->getCommentColumn());
- O << MAI->getCommentString() << " Reload Reuse";
+ O << MAI->getCommentString() << " Reload Reuse\n";
}
}
}