#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
#include <cctype>
using namespace llvm;
STATISTIC(EmittedInsts, "Number of machine instrs printed");
namespace {
- struct VISIBILITY_HIDDEN MipsAsmPrinter : public AsmPrinter {
-
+ class VISIBILITY_HIDDEN MipsAsmPrinter : public AsmPrinter {
const MipsSubtarget *Subtarget;
-
- MipsAsmPrinter(std::ostream &O, MipsTargetMachine &TM,
- const TargetAsmInfo *T):
- AsmPrinter(O, TM, T) {
+ public:
+ MipsAsmPrinter(raw_ostream &O, MipsTargetMachine &TM,
+ const TargetAsmInfo *T, bool F)
+ : AsmPrinter(O, TM, T, F) {
Subtarget = &TM.getSubtarget<MipsSubtarget>();
}
return "Mips Assembly Printer";
}
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode);
void printOperand(const MachineInstr *MI, int opNum);
+ void printUnsignedImm(const MachineInstr *MI, int opNum);
void printMemOperand(const MachineInstr *MI, int opNum,
const char *Modifier = 0);
void printFCCOperand(const MachineInstr *MI, int opNum,
const char *Modifier = 0);
-
- unsigned int getSavedRegsBitmask(bool isFloat, MachineFunction &MF);
+ void printModuleLevelGV(const GlobalVariable* GVar);
+ void printSavedRegsBitmask(MachineFunction &MF);
void printHex32(unsigned int Value);
const char *emitCurrentABIString(void);
void emitFunctionStart(MachineFunction &MF);
void emitFunctionEnd(MachineFunction &MF);
void emitFrameDirective(MachineFunction &MF);
- void emitMaskDirective(MachineFunction &MF);
- void emitFMaskDirective(MachineFunction &MF);
-
+
bool printInstruction(const MachineInstr *MI); // autogenerated.
bool runOnMachineFunction(MachineFunction &F);
bool doInitialization(Module &M);
/// assembly code for a MachineFunction to the given output stream,
/// using the given target machine description. This should work
/// regardless of whether the function is in SSA form.
-FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o,
- MipsTargetMachine &tm)
-{
- return new MipsAsmPrinter(o, tm, tm.getTargetAsmInfo());
+FunctionPass *llvm::createMipsCodePrinterPass(raw_ostream &o,
+ MipsTargetMachine &tm,
+ bool fast) {
+ return new MipsAsmPrinter(o, tm, tm.getTargetAsmInfo(), fast);
}
//===----------------------------------------------------------------------===//
// Mask directives
//===----------------------------------------------------------------------===//
-/// Mask directive for GPR
+// Create a bitmask with all callee saved registers for CPU or Floating Point
+// registers. For CPU registers consider RA, GP and FP for saving if necessary.
void MipsAsmPrinter::
-emitMaskDirective(MachineFunction &MF)
-{
- MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
-
- int StackSize = MF.getFrameInfo()->getStackSize();
- int Offset = (!MipsFI->getTopSavedRegOffset()) ? 0 :
- (-(StackSize-MipsFI->getTopSavedRegOffset()));
-
- #ifndef NDEBUG
- DOUT << "--> emitMaskDirective" << "\n";
- DOUT << "StackSize : " << StackSize << "\n";
- DOUT << "getTopSavedReg : " << MipsFI->getTopSavedRegOffset() << "\n";
- DOUT << "Offset : " << Offset << "\n\n";
- #endif
-
- unsigned int Bitmask = getSavedRegsBitmask(false, MF);
- O << "\t.mask \t";
- printHex32(Bitmask);
- O << "," << Offset << "\n";
-}
-
-/// TODO: Mask Directive for Floating Point
-void MipsAsmPrinter::
-emitFMaskDirective(MachineFunction &MF)
-{
- unsigned int Bitmask = getSavedRegsBitmask(true, MF);
-
- O << "\t.fmask\t";
- printHex32(Bitmask);
- O << ",0" << "\n";
-}
-
-// Create a bitmask with all callee saved registers for CPU
-// or Floating Point registers. For CPU registers consider RA,
-// GP and FP for saving if necessary.
-unsigned int MipsAsmPrinter::
-getSavedRegsBitmask(bool isFloat, MachineFunction &MF)
+printSavedRegsBitmask(MachineFunction &MF)
{
const TargetRegisterInfo &RI = *TM.getRegisterInfo();
+ MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
- // Floating Point Registers, TODO
- if (isFloat)
- return 0;
-
- // CPU Registers
- unsigned int Bitmask = 0;
+ // CPU and FPU Saved Registers Bitmasks
+ unsigned int CPUBitmask = 0;
+ unsigned int FPUBitmask = 0;
+ // Set the CPU and FPU Bitmasks
MachineFrameInfo *MFI = MF.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
- for (unsigned i = 0, e = CSI.size(); i != e; ++i)
- Bitmask |= (1 << MipsRegisterInfo::getRegisterNumbering(CSI[i].getReg()));
+ for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
+ unsigned RegNum = MipsRegisterInfo::getRegisterNumbering(CSI[i].getReg());
+ if (CSI[i].getRegClass() == Mips::CPURegsRegisterClass)
+ CPUBitmask |= (1 << RegNum);
+ else
+ FPUBitmask |= (1 << RegNum);
+ }
+ // Return Address and Frame registers must also be set in CPUBitmask.
if (RI.hasFP(MF))
- Bitmask |= (1 << MipsRegisterInfo::
+ CPUBitmask |= (1 << MipsRegisterInfo::
getRegisterNumbering(RI.getFrameRegister(MF)));
if (MF.getFrameInfo()->hasCalls())
- Bitmask |= (1 << MipsRegisterInfo::
+ CPUBitmask |= (1 << MipsRegisterInfo::
getRegisterNumbering(RI.getRARegister()));
- return Bitmask;
+ // Print CPUBitmask
+ O << "\t.mask \t"; printHex32(CPUBitmask); O << ','
+ << MipsFI->getCPUTopSavedRegOff() << '\n';
+
+ // Print FPUBitmask
+ O << "\t.fmask\t"; printHex32(FPUBitmask); O << ","
+ << MipsFI->getFPUTopSavedRegOff() << '\n';
}
// Print a 32 bit hex number with all numbers.
void MipsAsmPrinter::
printHex32(unsigned int Value)
{
- O << "0x" << std::hex;
+ O << "0x";
for (int i = 7; i >= 0; i--)
- O << std::hex << ( (Value & (0xF << (i*4))) >> (i*4) );
- O << std::dec;
+ O << utohexstr( (Value & (0xF << (i*4))) >> (i*4) );
}
//===----------------------------------------------------------------------===//
unsigned stackSize = MF.getFrameInfo()->getStackSize();
- O << "\t.frame\t" << "$" << LowercaseString(RI.get(stackReg).AsmName)
- << "," << stackSize << ","
- << "$" << LowercaseString(RI.get(returnReg).AsmName)
- << "\n";
+ O << "\t.frame\t" << '$' << LowercaseString(RI.get(stackReg).AsmName)
+ << ',' << stackSize << ','
+ << '$' << LowercaseString(RI.get(returnReg).AsmName)
+ << '\n';
}
/// Emit Set directives.
{
// Print out the label for the function.
const Function *F = MF.getFunction();
- SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
+ SwitchToSection(TAI->SectionForGlobal(F));
// 2 bits aligned
EmitAlignment(2, F);
- O << "\t.globl\t" << CurrentFnName << "\n";
- O << "\t.ent\t" << CurrentFnName << "\n";
+ O << "\t.globl\t" << CurrentFnName << '\n';
+ O << "\t.ent\t" << CurrentFnName << '\n';
+
+ printVisibility(CurrentFnName, F->getVisibility());
if ((TAI->hasDotTypeDotSizeDirective()) && Subtarget->isLinux())
O << "\t.type\t" << CurrentFnName << ", @function\n";
O << CurrentFnName << ":\n";
emitFrameDirective(MF);
- emitMaskDirective(MF);
- emitFMaskDirective(MF);
+ printSavedRegsBitmask(MF);
- O << "\n";
+ O << '\n';
}
/// Emit the directives used by GAS on the end of functions
O << "\t.set\tmacro\n";
O << "\t.set\treorder\n";
- O << "\t.end\t" << CurrentFnName << "\n";
+ O << "\t.end\t" << CurrentFnName << '\n';
if (TAI->hasDotTypeDotSizeDirective() && !Subtarget->isLinux())
- O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << "\n";
+ O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << '\n';
}
/// runOnMachineFunction - This uses the printMachineInstruction()
bool MipsAsmPrinter::
runOnMachineFunction(MachineFunction &MF)
{
+ this->MF = &MF;
+
SetupMachineFunction(MF);
// Print out constants referenced by the function
O << "\n\n";
- // What's my mangled name?
- CurrentFnName = Mang->getValueName(MF.getFunction());
-
// Emit the function start directives
emitFunctionStart(MF);
return false;
}
+// Print out an operand for an inline asm expression.
+bool MipsAsmPrinter::
+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])
+ return true; // Unknown modifier.
+
+ printOperand(MI, OpNo);
+ return false;
+}
+
void MipsAsmPrinter::
printOperand(const MachineInstr *MI, int opNum)
{
// using PIC_. %call16 is used to load direct call targets
// on PIC_ and small code size. %call_lo and %call_hi load
// direct call targets on PIC_ and large code size.
- if (MI->getOpcode() == Mips::LUi && !MO.isRegister()
- && !MO.isImmediate()) {
+ if (MI->getOpcode() == Mips::LUi && !MO.isReg() && !MO.isImm()) {
if ((isPIC) && (isCodeLarge))
O << "%call_hi(";
else
O << "%hi(";
closeP = true;
- } else if ((MI->getOpcode() == Mips::ADDiu) && !MO.isRegister()
- && !MO.isImmediate()) {
- O << "%lo(";
+ } else if ((MI->getOpcode() == Mips::ADDiu) && !MO.isReg() && !MO.isImm()) {
+ const MachineOperand &firstMO = MI->getOperand(opNum-1);
+ if (firstMO.getReg() == Mips::GP)
+ O << "%gp_rel(";
+ else
+ O << "%lo(";
closeP = true;
- } else if ((isPIC) && (MI->getOpcode() == Mips::LW)
- && (!MO.isRegister()) && (!MO.isImmediate())) {
+ } else if ((isPIC) && (MI->getOpcode() == Mips::LW) &&
+ (!MO.isReg()) && (!MO.isImm())) {
const MachineOperand &firstMO = MI->getOperand(opNum-1);
const MachineOperand &lastMO = MI->getOperand(opNum+1);
- if ((firstMO.isRegister()) && (lastMO.isRegister())) {
+ if ((firstMO.isReg()) && (lastMO.isReg())) {
if ((firstMO.getReg() == Mips::T9) && (lastMO.getReg() == Mips::GP)
&& (!isCodeLarge))
O << "%call16(";
{
case MachineOperand::MO_Register:
if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
- O << "$" << LowercaseString (RI.get(MO.getReg()).AsmName);
+ O << '$' << LowercaseString (RI.get(MO.getReg()).AsmName);
else
- O << "$" << MO.getReg();
+ O << '$' << MO.getReg();
break;
case MachineOperand::MO_Immediate:
- if ((MI->getOpcode() == Mips::SLTiu) || (MI->getOpcode() == Mips::ORi) ||
- (MI->getOpcode() == Mips::LUi) || (MI->getOpcode() == Mips::ANDi))
- O << (unsigned short int)MO.getImm();
- else
- O << (short int)MO.getImm();
+ O << (short int)MO.getImm();
break;
case MachineOperand::MO_MachineBasicBlock:
return;
case MachineOperand::MO_GlobalAddress:
- O << Mang->getValueName(MO.getGlobal());
+ {
+ const GlobalValue *GV = MO.getGlobal();
+ O << Mang->getValueName(GV);
+ }
break;
case MachineOperand::MO_ExternalSymbol:
<< '_' << MO.getIndex();
break;
- // FIXME: Verify correct
case MachineOperand::MO_ConstantPoolIndex:
O << TAI->getPrivateGlobalPrefix() << "CPI"
<< getFunctionNumber() << "_" << MO.getIndex();
if (closeP) O << ")";
}
+void MipsAsmPrinter::
+printUnsignedImm(const MachineInstr *MI, int opNum)
+{
+ const MachineOperand &MO = MI->getOperand(opNum);
+ if (MO.getType() == MachineOperand::MO_Immediate)
+ O << (unsigned short int)MO.getImm();
+ else
+ printOperand(MI, opNum);
+}
+
void MipsAsmPrinter::
printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier)
{
bool MipsAsmPrinter::
doInitialization(Module &M)
{
- Mang = new Mangler(M);
+ Mang = new Mangler(M, "", TAI->getPrivateGlobalPrefix());
// Tell the assembler which ABI we are using
- O << "\t.section .mdebug." << emitCurrentABIString() << "\n";
+ O << "\t.section .mdebug." << emitCurrentABIString() << '\n';
// TODO: handle O64 ABI
if (Subtarget->isABI_EABI())
O << "\t.section .gcc_compiled_long" <<
- (Subtarget->isGP32bit() ? "32" : "64") << "\n";
+ (Subtarget->isGP32bit() ? "32" : "64") << '\n';
// return to previous section
- O << "\t.previous" << "\n";
+ O << "\t.previous" << '\n';
return false; // success
}
-bool MipsAsmPrinter::
-doFinalization(Module &M)
-{
+void MipsAsmPrinter::
+printModuleLevelGV(const GlobalVariable* GVar) {
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 (!GVar->hasInitializer())
+ return; // External global require no code
- // External global require no code
- if (I->hasInitializer()) {
-
- // Check to see if this is a special global
- // used by LLVM, if so, emit it.
- if (EmitSpecialLLVMGlobal(I))
- continue;
-
- O << "\n\n";
- std::string name = Mang->getValueName(I);
- Constant *C = I->getInitializer();
- unsigned Size = TD->getABITypeSize(C->getType());
- unsigned Align = TD->getPreferredAlignmentLog(I);
-
- // Is this correct ?
- if (C->isNullValue() && (I->hasLinkOnceLinkage() ||
- I->hasInternalLinkage() || I->hasWeakLinkage() ||
- I->hasCommonLinkage()))
- {
- if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
-
- if (!NoZerosInBSS && TAI->getBSSSection())
- SwitchToDataSection(TAI->getBSSSection(), I);
- else
- SwitchToDataSection(TAI->getDataSection(), I);
-
- if (I->hasInternalLinkage()) {
- if (TAI->getLCOMMDirective())
- O << TAI->getLCOMMDirective() << name << "," << Size;
- else
- O << "\t.local\t" << name << "\n";
- } else {
- O << TAI->getCOMMDirective() << name << "," << Size;
- // The .comm alignment in bytes.
- if (TAI->getCOMMDirectiveTakesAlignment())
- O << "," << (1 << Align);
- }
-
- } else {
-
- switch (I->getLinkage())
- {
- case GlobalValue::LinkOnceLinkage:
- case GlobalValue::CommonLinkage:
- case GlobalValue::WeakLinkage:
- // FIXME: Verify correct for weak.
- // Nonnull linkonce -> weak
- O << "\t.weak " << name << "\n";
- SwitchToDataSection("", I);
- 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 << TAI->getGlobalDirective() << name << "\n";
- // Fall Through
- case GlobalValue::InternalLinkage:
- // FIXME: special handling for ".ctors" & ".dtors" sections
- if (I->hasSection() && (I->getSection() == ".ctors" ||
- I->getSection() == ".dtors")) {
- std::string SectionName = ".section " + I->getSection();
- SectionName += ",\"aw\",%progbits";
- SwitchToDataSection(SectionName.c_str());
- } else {
- if (C->isNullValue() && !NoZerosInBSS && TAI->getBSSSection())
- SwitchToDataSection(TAI->getBSSSection(), I);
- else if (!I->isConstant())
- SwitchToDataSection(TAI->getDataSection(), I);
- else {
- // Read-only data.
- if (TAI->getReadOnlySection())
- SwitchToDataSection(TAI->getReadOnlySection(), I);
- else
- SwitchToDataSection(TAI->getDataSection(), I);
- }
- }
- break;
- case GlobalValue::GhostLinkage:
- cerr << "Should not have any unmaterialized functions!\n";
- abort();
- case GlobalValue::DLLImportLinkage:
- cerr << "DLLImport linkage is not supported by this target!\n";
- abort();
- case GlobalValue::DLLExportLinkage:
- cerr << "DLLExport linkage is not supported by this target!\n";
- abort();
- default:
- assert(0 && "Unknown linkage type!");
- }
-
- O << "\t.align " << Align << "\n";
-
- if (TAI->hasDotTypeDotSizeDirective()) {
- O << "\t.type " << name << ",@object\n";
- O << "\t.size " << name << "," << Size << "\n";
- }
- O << name << ":\n";
- EmitGlobalConstant(C);
+ // Check to see if this is a special global used by LLVM, if so, emit it.
+ if (EmitSpecialLLVMGlobal(GVar))
+ return;
+
+ O << "\n\n";
+ std::string name = Mang->getValueName(GVar);
+ Constant *C = GVar->getInitializer();
+ const Type *CTy = C->getType();
+ unsigned Size = TD->getTypePaddedSize(CTy);
+ const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
+ bool printSizeAndType = true;
+
+ // A data structure or array is aligned in memory to the largest
+ // alignment boundary required by any data type inside it (this matches
+ // the Preferred Type Alignment). For integral types, the alignment is
+ // the type size.
+ unsigned Align;
+ if (CTy->getTypeID() == Type::IntegerTyID ||
+ CTy->getTypeID() == Type::VoidTyID) {
+ assert(!(Size & (Size-1)) && "Alignment is not a power of two!");
+ Align = Log2_32(Size);
+ } else
+ Align = TD->getPreferredTypeAlignmentShift(CTy);
+
+ printVisibility(name, GVar->getVisibility());
+
+ SwitchToSection(TAI->SectionForGlobal(GVar));
+
+ if (C->isNullValue() && !GVar->hasSection()) {
+ if (!GVar->isThreadLocal() &&
+ (GVar->hasLocalLinkage() || GVar->mayBeOverridden())) {
+ if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
+
+ if (GVar->hasLocalLinkage())
+ O << "\t.local\t" << name << '\n';
+
+ O << TAI->getCOMMDirective() << name << ',' << Size;
+ if (TAI->getCOMMDirectiveTakesAlignment())
+ O << ',' << (1 << Align);
+
+ O << '\n';
+ return;
}
}
+ switch (GVar->getLinkage()) {
+ case GlobalValue::LinkOnceLinkage:
+ case GlobalValue::CommonLinkage:
+ case GlobalValue::WeakLinkage:
+ // FIXME: Verify correct for weak.
+ // Nonnull linkonce -> weak
+ O << "\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 << TAI->getGlobalDirective() << name << '\n';
+ // Fall Through
+ case GlobalValue::PrivateLinkage:
+ case GlobalValue::InternalLinkage:
+ if (CVA && CVA->isCString())
+ printSizeAndType = false;
+ break;
+ case GlobalValue::GhostLinkage:
+ cerr << "Should not have any unmaterialized functions!\n";
+ abort();
+ case GlobalValue::DLLImportLinkage:
+ cerr << "DLLImport linkage is not supported by this target!\n";
+ abort();
+ case GlobalValue::DLLExportLinkage:
+ cerr << "DLLExport linkage is not supported by this target!\n";
+ abort();
+ default:
+ assert(0 && "Unknown linkage type!");
+ }
+
+ EmitAlignment(Align, GVar);
+
+ if (TAI->hasDotTypeDotSizeDirective() && printSizeAndType) {
+ O << "\t.type " << name << ",@object\n";
+ O << "\t.size " << name << ',' << Size << '\n';
+ }
+
+ O << name << ":\n";
+ EmitGlobalConstant(C);
+}
+
+bool MipsAsmPrinter::
+doFinalization(Module &M)
+{
+ // Print out module-level global variables here.
+ for (Module::const_global_iterator I = M.global_begin(),
+ E = M.global_end(); I != E; ++I)
+ printModuleLevelGV(I);
- O << "\n";
+ O << '\n';
return AsmPrinter::doFinalization(M);
}