| //===-- MSP430AsmPrinter.cpp - MSP430 LLVM assembly writer ------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file 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 the MSP430 assembly language. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "asm-printer" |
| #include "MSP430.h" |
| #include "MSP430InstrInfo.h" |
| #include "MSP430TargetMachine.h" |
| #include "llvm/Constants.h" |
| #include "llvm/DerivedTypes.h" |
| #include "llvm/Module.h" |
| #include "llvm/CodeGen/AsmPrinter.h" |
| #include "llvm/CodeGen/DwarfWriter.h" |
| #include "llvm/CodeGen/MachineModuleInfo.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/ADT/Statistic.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/FormattedStream.h" |
| #include "llvm/Support/Mangler.h" |
| #include "llvm/Support/ErrorHandling.h" |
| |
| using namespace llvm; |
| |
| STATISTIC(EmittedInsts, "Number of machine instrs printed"); |
| |
| namespace { |
| class VISIBILITY_HIDDEN MSP430AsmPrinter : public AsmPrinter { |
| public: |
| MSP430AsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, |
| const TargetAsmInfo *TAI, bool V) |
| : AsmPrinter(O, TM, TAI, V) {} |
| |
| virtual const char *getPassName() const { |
| return "MSP430 Assembly Printer"; |
| } |
| |
| void printOperand(const MachineInstr *MI, int OpNum, |
| const char* Modifier = 0); |
| void printSrcMemOperand(const MachineInstr *MI, int OpNum, |
| const char* Modifier = 0); |
| void printCCOperand(const MachineInstr *MI, int OpNum); |
| bool printInstruction(const MachineInstr *MI); // autogenerated. |
| void printMachineInstruction(const MachineInstr * MI); |
| |
| void emitFunctionHeader(const MachineFunction &MF); |
| bool runOnMachineFunction(MachineFunction &F); |
| bool doInitialization(Module &M); |
| bool doFinalization(Module &M); |
| |
| void getAnalysisUsage(AnalysisUsage &AU) const { |
| AsmPrinter::getAnalysisUsage(AU); |
| AU.setPreservesAll(); |
| } |
| }; |
| } // end of anonymous namespace |
| |
| #include "MSP430GenAsmWriter.inc" |
| |
| /// createMSP430CodePrinterPass - Returns a pass that prints the MSP430 |
| /// 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::createMSP430CodePrinterPass(formatted_raw_ostream &o, |
| TargetMachine &tm, |
| bool verbose) { |
| return new MSP430AsmPrinter(o, tm, tm.getTargetAsmInfo(), verbose); |
| } |
| |
| bool MSP430AsmPrinter::doInitialization(Module &M) { |
| Mang = new Mangler(M, "", TAI->getPrivateGlobalPrefix(), |
| TAI->getLessPrivateGlobalPrefix()); |
| return false; // success |
| } |
| |
| |
| bool MSP430AsmPrinter::doFinalization(Module &M) { |
| return AsmPrinter::doFinalization(M); |
| } |
| |
| void MSP430AsmPrinter::emitFunctionHeader(const MachineFunction &MF) { |
| const Function *F = MF.getFunction(); |
| |
| SwitchToSection(TAI->SectionForGlobal(F)); |
| |
| unsigned FnAlign = MF.getAlignment(); |
| EmitAlignment(FnAlign, F); |
| |
| switch (F->getLinkage()) { |
| default: llvm_unreachable("Unknown linkage type!"); |
| case Function::InternalLinkage: // Symbols default to internal. |
| case Function::PrivateLinkage: |
| case Function::LinkerPrivateLinkage: |
| break; |
| case Function::ExternalLinkage: |
| O << "\t.globl\t" << CurrentFnName << '\n'; |
| break; |
| case Function::LinkOnceAnyLinkage: |
| case Function::LinkOnceODRLinkage: |
| case Function::WeakAnyLinkage: |
| case Function::WeakODRLinkage: |
| O << "\t.weak\t" << CurrentFnName << '\n'; |
| break; |
| } |
| |
| printVisibility(CurrentFnName, F->getVisibility()); |
| |
| O << "\t.type\t" << CurrentFnName << ",@function\n" |
| << CurrentFnName << ":\n"; |
| } |
| |
| bool MSP430AsmPrinter::runOnMachineFunction(MachineFunction &MF) { |
| SetupMachineFunction(MF); |
| O << "\n\n"; |
| |
| // Print the 'header' of function |
| emitFunctionHeader(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 (!VerboseAsm && (I->pred_empty() || I->isOnlyReachableByFallthrough())) { |
| // This is an entry block or a block that's only reachable via a |
| // fallthrough edge. In non-VerboseAsm mode, don't print the label. |
| } else { |
| printBasicBlockLabel(I, true, true, VerboseAsm); |
| O << '\n'; |
| } |
| |
| for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); |
| II != E; ++II) |
| // Print the assembly for the instruction. |
| printMachineInstruction(II); |
| } |
| |
| if (TAI->hasDotTypeDotSizeDirective()) |
| O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << '\n'; |
| |
| O.flush(); |
| |
| // We didn't modify anything |
| return false; |
| } |
| |
| void MSP430AsmPrinter::printMachineInstruction(const MachineInstr *MI) { |
| ++EmittedInsts; |
| |
| // Call the autogenerated instruction printer routines. |
| if (printInstruction(MI)) |
| return; |
| |
| llvm_unreachable("Should not happen"); |
| } |
| |
| void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum, |
| const char* Modifier) { |
| const MachineOperand &MO = MI->getOperand(OpNum); |
| switch (MO.getType()) { |
| case MachineOperand::MO_Register: |
| assert (TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && |
| "Virtual registers should be already mapped!"); |
| O << TM.getRegisterInfo()->get(MO.getReg()).AsmName; |
| return; |
| case MachineOperand::MO_Immediate: |
| if (!Modifier || strcmp(Modifier, "nohash")) |
| O << '#'; |
| O << MO.getImm(); |
| return; |
| case MachineOperand::MO_MachineBasicBlock: |
| printBasicBlockLabel(MO.getMBB()); |
| return; |
| case MachineOperand::MO_GlobalAddress: { |
| bool isMemOp = Modifier && !strcmp(Modifier, "mem"); |
| bool isCallOp = Modifier && !strcmp(Modifier, "call"); |
| std::string Name = Mang->getMangledName(MO.getGlobal()); |
| assert(MO.getOffset() == 0 && "No offsets allowed!"); |
| |
| if (isCallOp) |
| O << '#'; |
| else if (isMemOp) |
| O << '&'; |
| |
| O << Name; |
| |
| return; |
| } |
| case MachineOperand::MO_ExternalSymbol: { |
| bool isCallOp = Modifier && !strcmp(Modifier, "call"); |
| std::string Name(TAI->getGlobalPrefix()); |
| Name += MO.getSymbolName(); |
| if (isCallOp) |
| O << '#'; |
| O << Name; |
| return; |
| } |
| default: |
| llvm_unreachable("Not implemented yet!"); |
| } |
| } |
| |
| void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum, |
| const char* Modifier) { |
| const MachineOperand &Base = MI->getOperand(OpNum); |
| const MachineOperand &Disp = MI->getOperand(OpNum+1); |
| |
| if (Base.isGlobal()) |
| printOperand(MI, OpNum, "mem"); |
| else if (Disp.isImm() && !Base.getReg()) |
| printOperand(MI, OpNum); |
| else if (Base.getReg()) { |
| if (Disp.getImm()) { |
| printOperand(MI, OpNum + 1, "nohash"); |
| O << '('; |
| printOperand(MI, OpNum); |
| O << ')'; |
| } else { |
| O << '@'; |
| printOperand(MI, OpNum); |
| } |
| } else |
| llvm_unreachable("Unsupported memory operand"); |
| } |
| |
| void MSP430AsmPrinter::printCCOperand(const MachineInstr *MI, int OpNum) { |
| unsigned CC = MI->getOperand(OpNum).getImm(); |
| |
| switch (CC) { |
| default: |
| llvm_unreachable("Unsupported CC code"); |
| break; |
| case MSP430::COND_E: |
| O << "eq"; |
| break; |
| case MSP430::COND_NE: |
| O << "ne"; |
| break; |
| case MSP430::COND_HS: |
| O << "hs"; |
| break; |
| case MSP430::COND_LO: |
| O << "lo"; |
| break; |
| case MSP430::COND_GE: |
| O << "ge"; |
| break; |
| case MSP430::COND_L: |
| O << 'l'; |
| break; |
| } |
| } |