diff options
Diffstat (limited to 'llvm/lib/Target/Mips/MipsAsmPrinter.cpp')
-rw-r--r-- | llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp new file mode 100644 index 00000000000..fdf60d92a24 --- /dev/null +++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp @@ -0,0 +1,294 @@ +//===-- MipsAsmPrinter.cpp - Mips LLVM assembly writer --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes 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 GAS-format MIPS assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-asm-printer" + +#include "Mips.h" +#include "MipsInstrInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Mangler.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/MathExtras.h" +#include <cctype> + +using namespace llvm; + +STATISTIC(EmittedInsts, "Number of machine instrs printed"); + +namespace { + struct VISIBILITY_HIDDEN MipsAsmPrinter : public AsmPrinter { + MipsAsmPrinter(std::ostream &O, MipsTargetMachine &TM, + const TargetAsmInfo *T): + AsmPrinter(O, TM, T) {} + + virtual const char *getPassName() const { + return "Mips Assembly Printer"; + } + + void printOperand(const MachineInstr *MI, int opNum); + void printMemOperand(const MachineInstr *MI, int opNum, + const char *Modifier = 0); + + bool printInstruction(const MachineInstr *MI); // autogenerated. + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + }; +} // end of anonymous namespace + +#include "MipsGenAsmWriter.inc" + +/// createMipsCodePrinterPass - Returns a pass that prints the MIPS +/// 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()); +} + +/// runOnMachineFunction - This uses the printMachineInstruction() +/// method to print assembly for each instruction. +bool MipsAsmPrinter:: +runOnMachineFunction(MachineFunction &MF) +{ + SetupMachineFunction(MF); + + // Print out constants referenced by the function + EmitConstantPool(MF.getConstantPool()); + + O << "\n\n"; + + // What's my mangled name? + CurrentFnName = Mang->getValueName(MF.getFunction()); + + // Print out the label for the function. + const Function *F = MF.getFunction(); + SwitchToTextSection(getSectionForFunction(*F).c_str(), F); + + // On Mips GAS if .align #n is present, #n means the number of bits + // to be cleared to align. So, if we want 4 byte alignment, we must + // have .align 2 + // TODO: + // add gas ".mask" and ".fmask" + EmitAlignment(1, F); + O << "\t.globl\t" << CurrentFnName << "\n"; + O << "\t.ent\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 != MF.begin()) { + printBasicBlockLabel(I, true); + O << '\n'; + } + + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + O << "\t"; + printInstruction(II); + ++EmittedInsts; + } + } + + // close function with asm directive + O << "\t.end\t" << CurrentFnName << "\n"; + + // We didn't modify anything. + return false; +} + +void MipsAsmPrinter:: +printOperand(const MachineInstr *MI, int opNum) +{ + const MachineOperand &MO = MI->getOperand(opNum); + const MRegisterInfo &RI = *TM.getRegisterInfo(); + bool closeP=false; + + // %hi and %lo used on mips gas to break large constants + if (MI->getOpcode() == Mips::LUi && !MO.isRegister() + && !MO.isImmediate()) { + O << "%hi("; + closeP = true; + } else if ((MI->getOpcode() == Mips::ADDiu) && !MO.isRegister() + && !MO.isImmediate()) { + O << "%lo("; + closeP = true; + } + + switch (MO.getType()) + { + case MachineOperand::MO_Register: + if (MRegisterInfo::isPhysicalRegister(MO.getReg())) + O << "$" << LowercaseString (RI.get(MO.getReg()).Name); + else + 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 int)MO.getImmedValue(); + else + O << (int)MO.getImmedValue(); + break; + + case MachineOperand::MO_MachineBasicBlock: + printBasicBlockLabel(MO.getMachineBasicBlock()); + return; + + case MachineOperand::MO_GlobalAddress: + O << Mang->getValueName(MO.getGlobal()); + break; + + case MachineOperand::MO_ExternalSymbol: + O << MO.getSymbolName(); + break; + + case MachineOperand::MO_ConstantPoolIndex: + O << TAI->getPrivateGlobalPrefix() << "CPI" + << getFunctionNumber() << "_" << MO.getConstantPoolIndex(); + break; + + default: + O << "<unknown operand type>"; abort (); break; + } + + if (closeP) O << ")"; +} + +void MipsAsmPrinter:: +printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier) +{ + // lw/sw $reg, MemOperand + // will turn into : + // lw/sw $reg, imm($reg) + printOperand(MI, opNum); + O << "("; + printOperand(MI, opNum+1); + O << ")"; +} + +bool MipsAsmPrinter:: +doInitialization(Module &M) +{ + Mang = new Mangler(M); + return false; // success +} + +bool MipsAsmPrinter:: +doFinalization(Module &M) +{ + 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) + + // 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->getTypeSize(C->getType()); + unsigned Align = TD->getPrefTypeAlignment(C->getType()); + + if (C->isNullValue() && (I->hasLinkOnceLinkage() || + I->hasInternalLinkage() || I->hasWeakLinkage() + /* FIXME: Verify correct */)) { + + SwitchToDataSection(".data", I); + if (I->hasInternalLinkage()) + O << "\t.local " << name << "\n"; + + O << "\t.comm " << name << "," + << TD->getTypeSize(C->getType()) + << "," << Align << "\n"; + + } else { + + switch (I->getLinkage()) + { + case GlobalValue::LinkOnceLinkage: + 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 << "\t.globl " << name << "\n"; + case GlobalValue::InternalLinkage: + if (C->isNullValue()) + SwitchToDataSection(".bss", I); + else + SwitchToDataSection(".data", 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"; + O << "\t.type " << name << ",@object\n"; + O << "\t.size " << name << "," << Size << "\n"; + O << name << ":\n"; + EmitGlobalConstant(C); + } + } + + AsmPrinter::doFinalization(M); + return false; // success +} |