llvm-6502/lib/Target/X86/X86AsmPrinter.cpp

610 lines
20 KiB
C++
Raw Normal View History

//===-- X86AsmPrinter.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 and AT&T format assembly
// language. This printer is the output mechanism used by `llc' and `lli
// -print-machineinstrs' on X86.
//
//===----------------------------------------------------------------------===//
#include "X86.h"
#include "X86TargetMachine.h"
#include "llvm/Module.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Mangler.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
namespace {
Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed");
enum AsmWriterFlavor { att, intel };
cl::opt<AsmWriterFlavor>
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));
struct X86SharedAsmPrinter : public AsmPrinter {
X86SharedAsmPrinter(std::ostream &O, TargetMachine &TM)
: AsmPrinter(O, TM) { }
void printConstantPool(MachineConstantPool *MCP);
bool doFinalization(Module &M);
};
}
static bool isScale(const MachineOperand &MO) {
return MO.isImmediate() &&
(MO.getImmedValue() == 1 || MO.getImmedValue() == 2 ||
MO.getImmedValue() == 4 || MO.getImmedValue() == 8);
}
static bool isMem(const MachineInstr *MI, unsigned Op) {
if (MI->getOperand(Op).isFrameIndex()) return true;
if (MI->getOperand(Op).isConstantPoolIndex()) return true;
return Op+4 <= MI->getNumOperands() &&
MI->getOperand(Op ).isRegister() && isScale(MI->getOperand(Op+1)) &&
MI->getOperand(Op+2).isRegister() && (MI->getOperand(Op+3).isImmediate() ||
MI->getOperand(Op+3).isGlobalAddress());
}
// SwitchSection - Switch to the specified section of the executable if we are
// not already in it!
//
static void SwitchSection(std::ostream &OS, std::string &CurSection,
const char *NewSection) {
if (CurSection != NewSection) {
CurSection = NewSection;
if (!CurSection.empty())
OS << "\t" << NewSection << "\n";
}
}
/// 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<Constant*> &CP = MCP->getConstants();
const TargetData &TD = TM.getTargetData();
if (CP.empty()) return;
for (unsigned i = 0, e = CP.size(); i != e; ++i) {
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_giterator I = M.gbegin(), E = M.gend(); 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 (I->hasInternalLinkage())
O << "\t.local " << name << "\n";
O << "\t.comm " << name << "," << TD.getTypeSize(C->getType())
<< "," << (1 << Align);
O << "\t\t# ";
WriteAsOperand(O, I, true, true, &M);
O << "\n";
} else {
switch (I->getLinkage()) {
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;
case GlobalValue::GhostLinkage:
std::cerr << "GhostLinkage cannot appear in X86AsmPrinter!\n";
abort();
}
emitAlignment(Align);
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);
}
}
AsmPrinter::doFinalization(M);
return false; // success
}
namespace {
struct X86IntelAsmPrinter : public X86SharedAsmPrinter {
X86IntelAsmPrinter(std::ostream &O, TargetMachine &TM)
: X86SharedAsmPrinter(O, TM) { }
virtual const char *getPassName() const {
return "X86 Intel-Style Assembly Printer";
}
/// printInstruction - This method is automatically generated by tablegen
/// from the instruction set description. This method returns true if the
/// machine instruction was sufficiently described to print it, otherwise it
/// returns false.
bool printInstruction(const MachineInstr *MI);
// This method is used by the tablegen'erated instruction printer.
void printOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT){
const MachineOperand &MO = MI->getOperand(OpNo);
if (MO.getType() == MachineOperand::MO_MachineRegister) {
assert(MRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physref??");
// Bug Workaround: See note in Printer::doInitialization about %.
O << "%" << TM.getRegisterInfo()->get(MO.getReg()).Name;
} else {
printOp(MO);
}
}
void printCallOperand(const MachineInstr *MI, unsigned OpNo,
MVT::ValueType VT) {
printOp(MI->getOperand(OpNo), true); // Don't print "OFFSET".
}
void printMemoryOperand(const MachineInstr *MI, unsigned OpNo,
MVT::ValueType VT) {
switch (VT) {
default: assert(0 && "Unknown arg size!");
case MVT::i8: O << "BYTE PTR "; break;
case MVT::i16: O << "WORD PTR "; break;
case MVT::i32:
case MVT::f32: O << "DWORD PTR "; break;
case MVT::i64:
case MVT::f64: O << "QWORD PTR "; break;
case MVT::f80: O << "XWORD PTR "; break;
}
printMemReference(MI, OpNo);
}
void printMachineInstruction(const MachineInstr *MI);
void printOp(const MachineOperand &MO, bool elideOffsetKeyword = false);
void printMemReference(const MachineInstr *MI, unsigned Op);
bool runOnMachineFunction(MachineFunction &F);
bool doInitialization(Module &M);
};
Nice tasty llc fixes. These should fix LLC for x86 for everything in SingleSource except oopack and Oscar. (Sorry, Oscar.) include/llvm/Target/TargetInstrInfo.h: Remove virtual print method. Add accessors for ImplicitUses/Defs. lib/Target/TargetInstrInfo.cpp: Remove virtual print method. If you really wanted this, just use MI->print(O, TM); instead... lib/Target/X86: FloatingPoint.cpp: ...like this. X86InstrInfo.h: Remove virtual print method. Define the PrintImplUses target-specific flag bit. X86InstrInfo.def: Add the PrintImplUses flag to all the instructions which implicitly use CL, because the assembler needs to see the CL in order to generate the right instruction. Printer.cpp: Ditch fnIndex at Chris's request. Now we use CurrentFnName to name constants in the constant pool for each function instead. This avoids keeping state between runOnMachineFunction() invocations, which is a no-no. Having MangledGlobals be global is a bogon I'd like to get rid of too, but making it a static member of Printer causes link errors (why???). Make NumberForBB into a member of Printer instead of a global, too. Make printOp and printMemReference into methods of Printer. X86InstrInfo::print is now Printer::printMachineInstruction, because TargetInstrInfo::print is history. (Because of this, we have to qualify the names of some TargetInstrInfo methods we call.) Print out the ImplicitUses field of any instruction we print that has the PrintImplUses bit set. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6924 91177308-0d34-0410-b5e6-96231b3b80d8
2003-06-27 00:00:48 +00:00
} // end of anonymous namespace
// Include the auto-generated portion of the assembly writer.
#include "X86GenIntelAsmWriter.inc"
/// runOnMachineFunction - This uses the printMachineInstruction()
/// method to print assembly for each instruction.
///
bool X86IntelAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
setupMachineFunction(MF);
O << "\n\n";
Nice tasty llc fixes. These should fix LLC for x86 for everything in SingleSource except oopack and Oscar. (Sorry, Oscar.) include/llvm/Target/TargetInstrInfo.h: Remove virtual print method. Add accessors for ImplicitUses/Defs. lib/Target/TargetInstrInfo.cpp: Remove virtual print method. If you really wanted this, just use MI->print(O, TM); instead... lib/Target/X86: FloatingPoint.cpp: ...like this. X86InstrInfo.h: Remove virtual print method. Define the PrintImplUses target-specific flag bit. X86InstrInfo.def: Add the PrintImplUses flag to all the instructions which implicitly use CL, because the assembler needs to see the CL in order to generate the right instruction. Printer.cpp: Ditch fnIndex at Chris's request. Now we use CurrentFnName to name constants in the constant pool for each function instead. This avoids keeping state between runOnMachineFunction() invocations, which is a no-no. Having MangledGlobals be global is a bogon I'd like to get rid of too, but making it a static member of Printer causes link errors (why???). Make NumberForBB into a member of Printer instead of a global, too. Make printOp and printMemReference into methods of Printer. X86InstrInfo::print is now Printer::printMachineInstruction, because TargetInstrInfo::print is history. (Because of this, we have to qualify the names of some TargetInstrInfo methods we call.) Print out the ImplicitUses field of any instruction we print that has the PrintImplUses bit set. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6924 91177308-0d34-0410-b5e6-96231b3b80d8
2003-06-27 00:00:48 +00:00
// Print out constants referenced by the function
printConstantPool(MF.getConstantPool());
// Print out labels for the function.
O << "\t.text\n";
emitAlignment(4);
Nice tasty llc fixes. These should fix LLC for x86 for everything in SingleSource except oopack and Oscar. (Sorry, Oscar.) include/llvm/Target/TargetInstrInfo.h: Remove virtual print method. Add accessors for ImplicitUses/Defs. lib/Target/TargetInstrInfo.cpp: Remove virtual print method. If you really wanted this, just use MI->print(O, TM); instead... lib/Target/X86: FloatingPoint.cpp: ...like this. X86InstrInfo.h: Remove virtual print method. Define the PrintImplUses target-specific flag bit. X86InstrInfo.def: Add the PrintImplUses flag to all the instructions which implicitly use CL, because the assembler needs to see the CL in order to generate the right instruction. Printer.cpp: Ditch fnIndex at Chris's request. Now we use CurrentFnName to name constants in the constant pool for each function instead. This avoids keeping state between runOnMachineFunction() invocations, which is a no-no. Having MangledGlobals be global is a bogon I'd like to get rid of too, but making it a static member of Printer causes link errors (why???). Make NumberForBB into a member of Printer instead of a global, too. Make printOp and printMemReference into methods of Printer. X86InstrInfo::print is now Printer::printMachineInstruction, because TargetInstrInfo::print is history. (Because of this, we have to qualify the names of some TargetInstrInfo methods we call.) Print out the ImplicitUses field of any instruction we print that has the PrintImplUses bit set. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6924 91177308-0d34-0410-b5e6-96231b3b80d8
2003-06-27 00:00:48 +00:00
O << "\t.globl\t" << CurrentFnName << "\n";
O << "\t.type\t" << CurrentFnName << ", @function\n";
Nice tasty llc fixes. These should fix LLC for x86 for everything in SingleSource except oopack and Oscar. (Sorry, Oscar.) include/llvm/Target/TargetInstrInfo.h: Remove virtual print method. Add accessors for ImplicitUses/Defs. lib/Target/TargetInstrInfo.cpp: Remove virtual print method. If you really wanted this, just use MI->print(O, TM); instead... lib/Target/X86: FloatingPoint.cpp: ...like this. X86InstrInfo.h: Remove virtual print method. Define the PrintImplUses target-specific flag bit. X86InstrInfo.def: Add the PrintImplUses flag to all the instructions which implicitly use CL, because the assembler needs to see the CL in order to generate the right instruction. Printer.cpp: Ditch fnIndex at Chris's request. Now we use CurrentFnName to name constants in the constant pool for each function instead. This avoids keeping state between runOnMachineFunction() invocations, which is a no-no. Having MangledGlobals be global is a bogon I'd like to get rid of too, but making it a static member of Printer causes link errors (why???). Make NumberForBB into a member of Printer instead of a global, too. Make printOp and printMemReference into methods of Printer. X86InstrInfo::print is now Printer::printMachineInstruction, because TargetInstrInfo::print is history. (Because of this, we have to qualify the names of some TargetInstrInfo methods we call.) Print out the ImplicitUses field of any instruction we print that has the PrintImplUses bit set. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6924 91177308-0d34-0410-b5e6-96231b3b80d8
2003-06-27 00:00:48 +00:00
O << CurrentFnName << ":\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())
O << ".LBB" << CurrentFnName << "_" << I->getNumber() << ":\t"
<< CommentString << " " << I->getBasicBlock()->getName() << "\n";
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
II != E; ++II) {
// Print the assembly for the instruction.
O << "\t";
printMachineInstruction(II);
}
}
// We didn't modify anything.
return false;
}
void X86IntelAsmPrinter::printOp(const MachineOperand &MO,
bool elideOffsetKeyword /* = false */) {
const MRegisterInfo &RI = *TM.getRegisterInfo();
switch (MO.getType()) {
case MachineOperand::MO_VirtualRegister:
if (Value *V = MO.getVRegValueOrNull()) {
O << "<" << V->getName() << ">";
return;
}
// FALLTHROUGH
case MachineOperand::MO_MachineRegister:
if (MRegisterInfo::isPhysicalRegister(MO.getReg()))
// Bug Workaround: See note in Printer::doInitialization about %.
O << "%" << RI.get(MO.getReg()).Name;
else
O << "%reg" << MO.getReg();
return;
case MachineOperand::MO_SignExtendedImmed:
case MachineOperand::MO_UnextendedImmed:
O << (int)MO.getImmedValue();
return;
case MachineOperand::MO_MachineBasicBlock: {
MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
O << ".LBB" << Mang->getValueName(MBBOp->getParent()->getFunction())
<< "_" << MBBOp->getNumber () << "\t# "
<< MBBOp->getBasicBlock ()->getName ();
return;
}
case MachineOperand::MO_PCRelativeDisp:
std::cerr << "Shouldn't use addPCDisp() when building X86 MachineInstrs";
abort ();
return;
case MachineOperand::MO_GlobalAddress: {
if (!elideOffsetKeyword)
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:
O << 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;
} else if (BaseReg.isConstantPoolIndex()) {
Nice tasty llc fixes. These should fix LLC for x86 for everything in SingleSource except oopack and Oscar. (Sorry, Oscar.) include/llvm/Target/TargetInstrInfo.h: Remove virtual print method. Add accessors for ImplicitUses/Defs. lib/Target/TargetInstrInfo.cpp: Remove virtual print method. If you really wanted this, just use MI->print(O, TM); instead... lib/Target/X86: FloatingPoint.cpp: ...like this. X86InstrInfo.h: Remove virtual print method. Define the PrintImplUses target-specific flag bit. X86InstrInfo.def: Add the PrintImplUses flag to all the instructions which implicitly use CL, because the assembler needs to see the CL in order to generate the right instruction. Printer.cpp: Ditch fnIndex at Chris's request. Now we use CurrentFnName to name constants in the constant pool for each function instead. This avoids keeping state between runOnMachineFunction() invocations, which is a no-no. Having MangledGlobals be global is a bogon I'd like to get rid of too, but making it a static member of Printer causes link errors (why???). Make NumberForBB into a member of Printer instead of a global, too. Make printOp and printMemReference into methods of Printer. X86InstrInfo::print is now Printer::printMachineInstruction, because TargetInstrInfo::print is history. (Because of this, we have to qualify the names of some TargetInstrInfo methods we call.) Print out the ImplicitUses field of any instruction we print that has the PrintImplUses bit set. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6924 91177308-0d34-0410-b5e6-96231b3b80d8
2003-06-27 00:00:48 +00:00
O << "[.CPI" << CurrentFnName << "_"
<< BaseReg.getConstantPoolIndex();
if (IndexReg.getReg()) {
O << " + ";
if (ScaleVal != 1)
O << ScaleVal << "*";
printOp(IndexReg);
}
if (DispSpec.getImmedValue())
O << " + " << DispSpec.getImmedValue();
O << "]";
return;
}
O << "[";
bool NeedPlus = false;
if (BaseReg.getReg()) {
printOp(BaseReg, true);
NeedPlus = true;
}
if (IndexReg.getReg()) {
if (NeedPlus) O << " + ";
if (ScaleVal != 1)
O << ScaleVal << "*";
printOp(IndexReg);
NeedPlus = true;
}
if (DispSpec.isGlobalAddress()) {
if (NeedPlus)
O << " + ";
printOp(DispSpec, true);
} else {
int DispVal = DispSpec.getImmedValue();
if (DispVal) {
if (NeedPlus)
if (DispVal > 0)
O << " + ";
else {
O << " - ";
DispVal = -DispVal;
}
O << DispVal;
}
}
O << "]";
}
/// printMachineInstruction -- Print out a single X86 LLVM instruction
/// MI in Intel syntax to the current output stream.
Nice tasty llc fixes. These should fix LLC for x86 for everything in SingleSource except oopack and Oscar. (Sorry, Oscar.) include/llvm/Target/TargetInstrInfo.h: Remove virtual print method. Add accessors for ImplicitUses/Defs. lib/Target/TargetInstrInfo.cpp: Remove virtual print method. If you really wanted this, just use MI->print(O, TM); instead... lib/Target/X86: FloatingPoint.cpp: ...like this. X86InstrInfo.h: Remove virtual print method. Define the PrintImplUses target-specific flag bit. X86InstrInfo.def: Add the PrintImplUses flag to all the instructions which implicitly use CL, because the assembler needs to see the CL in order to generate the right instruction. Printer.cpp: Ditch fnIndex at Chris's request. Now we use CurrentFnName to name constants in the constant pool for each function instead. This avoids keeping state between runOnMachineFunction() invocations, which is a no-no. Having MangledGlobals be global is a bogon I'd like to get rid of too, but making it a static member of Printer causes link errors (why???). Make NumberForBB into a member of Printer instead of a global, too. Make printOp and printMemReference into methods of Printer. X86InstrInfo::print is now Printer::printMachineInstruction, because TargetInstrInfo::print is history. (Because of this, we have to qualify the names of some TargetInstrInfo methods we call.) Print out the ImplicitUses field of any instruction we print that has the PrintImplUses bit set. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6924 91177308-0d34-0410-b5e6-96231b3b80d8
2003-06-27 00:00:48 +00:00
///
void X86IntelAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
++EmittedInsts;
// Call the autogenerated instruction printer routines.
printInstruction(MI);
}
bool X86IntelAsmPrinter::doInitialization(Module &M) {
AsmPrinter::doInitialization(M);
// Tell gas we are outputting Intel syntax (not AT&T syntax) assembly.
//
// Bug: gas in `intel_syntax noprefix' mode interprets the symbol `Sp' in an
// instruction as a reference to the register named sp, and if you try to
// reference a symbol `Sp' (e.g. `mov ECX, OFFSET Sp') then it gets lowercased
// before being looked up in the symbol table. This creates spurious
// `undefined symbol' errors when linking. Workaround: Do not use `noprefix'
// mode, and decorate all register names with percent signs.
O << "\t.intel_syntax\n";
return false;
}
namespace {
struct X86ATTAsmPrinter : public X86SharedAsmPrinter {
X86ATTAsmPrinter(std::ostream &O, TargetMachine &TM)
: X86SharedAsmPrinter(O, TM) { }
virtual const char *getPassName() const {
return "X86 AT&T-Style Assembly Printer";
}
/// printInstruction - This method is automatically generated by tablegen
/// from the instruction set description. This method returns true if the
/// machine instruction was sufficiently described to print it, otherwise it
/// returns false.
bool printInstruction(const MachineInstr *MI);
// This method is used by the tablegen'erated instruction printer.
void printOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT){
printOp(MI->getOperand(OpNo));
}
void printCallOperand(const MachineInstr *MI, unsigned OpNo,
MVT::ValueType VT) {
printOp(MI->getOperand(OpNo), true); // Don't print '$' prefix.
}
void printMemoryOperand(const MachineInstr *MI, unsigned OpNo,
MVT::ValueType VT) {
printMemReference(MI, OpNo);
}
void printMachineInstruction(const MachineInstr *MI);
void printOp(const MachineOperand &MO, bool isCallOperand = false);
void printMemReference(const MachineInstr *MI, unsigned Op);
bool runOnMachineFunction(MachineFunction &F);
};
} // end of anonymous namespace
// Include the auto-generated portion of the assembly writer.
#include "X86GenATTAsmWriter.inc"
/// runOnMachineFunction - This uses the printMachineInstruction()
/// method to print assembly for each instruction.
///
bool X86ATTAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
setupMachineFunction(MF);
O << "\n\n";
// Print out constants referenced by the function
printConstantPool(MF.getConstantPool());
// Print out labels for the function.
O << "\t.text\n";
emitAlignment(4);
O << "\t.globl\t" << CurrentFnName << "\n";
O << "\t.type\t" << CurrentFnName << ", @function\n";
O << CurrentFnName << ":\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 (I->pred_begin() != I->pred_end())
O << ".LBB" << CurrentFnName << "_" << I->getNumber() << ":\t"
<< CommentString << " " << I->getBasicBlock()->getName() << "\n";
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
II != E; ++II) {
// Print the assembly for the instruction.
O << "\t";
printMachineInstruction(II);
}
}
// We didn't modify anything.
return false;
}
void X86ATTAsmPrinter::printOp(const MachineOperand &MO, bool isCallOp) {
const MRegisterInfo &RI = *TM.getRegisterInfo();
switch (MO.getType()) {
case MachineOperand::MO_VirtualRegister:
case MachineOperand::MO_MachineRegister:
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)
O << (char)tolower(*Name);
return;
case MachineOperand::MO_SignExtendedImmed:
case MachineOperand::MO_UnextendedImmed:
O << '$' << (int)MO.getImmedValue();
return;
case MachineOperand::MO_MachineBasicBlock: {
MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
O << ".LBB" << Mang->getValueName(MBBOp->getParent()->getFunction())
<< "_" << MBBOp->getNumber () << "\t# "
<< MBBOp->getBasicBlock ()->getName ();
return;
}
case MachineOperand::MO_PCRelativeDisp:
std::cerr << "Shouldn't use addPCDisp() when building X86 MachineInstrs";
abort ();
return;
case MachineOperand::MO_GlobalAddress: {
if (!isCallOp) O << '$';
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:
if (!isCallOp) O << '$';
O << MO.getSymbolName();
return;
default:
O << "<unknown operand type>"; return;
}
}
void X86ATTAsmPrinter::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;
} 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);
} else {
int DispVal = DispSpec.getImmedValue();
if (DispVal)
O << DispVal;
}
if (IndexReg.getReg() || BaseReg.getReg()) {
O << "(";
if (BaseReg.getReg())
printOp(BaseReg);
if (IndexReg.getReg()) {
O << ",";
printOp(IndexReg);
if (ScaleVal != 1)
O << "," << ScaleVal;
}
O << ")";
}
}
/// printMachineInstruction -- Print out a single X86 LLVM instruction
/// MI in Intel syntax to the current output stream.
///
void X86ATTAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
++EmittedInsts;
// Call the autogenerated instruction printer routines.
printInstruction(MI);
}
/// 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);
}
}