//===-- XCoreAsmPrinter.cpp - XCore 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 XAS-format XCore assembly language. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "asm-printer" #include "XCore.h" #include "InstPrinter/XCoreInstPrinter.h" #include "XCoreInstrInfo.h" #include "XCoreMCInstLower.h" #include "XCoreSubtarget.h" #include "XCoreTargetMachine.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/DebugInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCExpr.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include #include using namespace llvm; namespace { class XCoreAsmPrinter : public AsmPrinter { const XCoreSubtarget &Subtarget; XCoreMCInstLower MCInstLowering; public: explicit XCoreAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) : AsmPrinter(TM, Streamer), Subtarget(TM.getSubtarget()), MCInstLowering(*this) {} virtual const char *getPassName() const { return "XCore Assembly Printer"; } void printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O, const std::string &directive = ".jmptable"); void printInlineJT32(const MachineInstr *MI, int opNum, raw_ostream &O) { printInlineJT(MI, opNum, O, ".jmptable32"); } void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O); void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV); virtual void EmitGlobalVariable(const GlobalVariable *GV); void EmitFunctionEntryLabel(); void EmitInstruction(const MachineInstr *MI); void EmitFunctionBodyStart(); void EmitFunctionBodyEnd(); }; } // end of anonymous namespace void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) { assert(((GV->hasExternalLinkage() || GV->hasWeakLinkage()) || GV->hasLinkOnceLinkage()) && "Unexpected linkage"); if (ArrayType *ATy = dyn_cast( cast(GV->getType())->getElementType())) { MCSymbol *SymGlob = OutContext.GetOrCreateSymbol( Twine(Sym->getName() + StringRef(".globound"))); OutStreamer.EmitSymbolAttribute(SymGlob, MCSA_Global); OutStreamer.EmitAssignment(SymGlob, MCConstantExpr::Create(ATy->getNumElements(), OutContext)); if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) { // TODO Use COMDAT groups for LinkOnceLinkage OutStreamer.EmitSymbolAttribute(SymGlob, MCSA_Weak); } } } void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { // Check to see if this is a special global used by LLVM, if so, emit it. if (!GV->hasInitializer() || EmitSpecialLLVMGlobal(GV)) return; const DataLayout *TD = TM.getDataLayout(); OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GV, Mang,TM)); MCSymbol *GVSym = getSymbol(GV); const Constant *C = GV->getInitializer(); unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType()); // Mark the start of the global OutStreamer.EmitRawText("\t.cc_top " + Twine(GVSym->getName()) + ".data," + GVSym->getName()); switch (GV->getLinkage()) { case GlobalValue::AppendingLinkage: report_fatal_error("AppendingLinkage is not supported by this target!"); case GlobalValue::LinkOnceAnyLinkage: case GlobalValue::LinkOnceODRLinkage: case GlobalValue::WeakAnyLinkage: case GlobalValue::WeakODRLinkage: case GlobalValue::ExternalLinkage: emitArrayBound(GVSym, GV); OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global); // TODO Use COMDAT groups for LinkOnceLinkage if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak); // FALL THROUGH case GlobalValue::InternalLinkage: case GlobalValue::PrivateLinkage: break; case GlobalValue::DLLImportLinkage: llvm_unreachable("DLLImport linkage is not supported by this target!"); case GlobalValue::DLLExportLinkage: llvm_unreachable("DLLExport linkage is not supported by this target!"); default: llvm_unreachable("Unknown linkage type!"); } EmitAlignment(Align > 2 ? Align : 2, GV); if (GV->isThreadLocal()) { report_fatal_error("TLS is not supported by this target!"); } unsigned Size = TD->getTypeAllocSize(C->getType()); if (MAI->hasDotTypeDotSizeDirective()) { OutStreamer.EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject); OutStreamer.EmitRawText("\t.size " + Twine(GVSym->getName()) + "," + Twine(Size)); } OutStreamer.EmitLabel(GVSym); EmitGlobalConstant(C); // The ABI requires that unsigned scalar types smaller than 32 bits // are padded to 32 bits. if (Size < 4) OutStreamer.EmitZeros(4 - Size); // Mark the end of the global OutStreamer.EmitRawText("\t.cc_bottom " + Twine(GVSym->getName()) + ".data"); } void XCoreAsmPrinter::EmitFunctionBodyStart() { MCInstLowering.Initialize(Mang, &MF->getContext()); } /// EmitFunctionBodyEnd - Targets can override this to emit stuff after /// the last basic block in the function. void XCoreAsmPrinter::EmitFunctionBodyEnd() { // Emit function end directives OutStreamer.EmitRawText("\t.cc_bottom " + Twine(CurrentFnSym->getName()) + ".function"); } void XCoreAsmPrinter::EmitFunctionEntryLabel() { // Mark the start of the function OutStreamer.EmitRawText("\t.cc_top " + Twine(CurrentFnSym->getName()) + ".function," + CurrentFnSym->getName()); OutStreamer.EmitLabel(CurrentFnSym); } void XCoreAsmPrinter:: printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O, const std::string &directive) { unsigned JTI = MI->getOperand(opNum).getIndex(); const MachineFunction *MF = MI->getParent()->getParent(); const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); const std::vector &JT = MJTI->getJumpTables(); const std::vector &JTBBs = JT[JTI].MBBs; O << "\t" << directive << " "; for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { MachineBasicBlock *MBB = JTBBs[i]; if (i > 0) O << ","; O << *MBB->getSymbol(); } } void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { const MachineOperand &MO = MI->getOperand(opNum); switch (MO.getType()) { case MachineOperand::MO_Register: O << XCoreInstPrinter::getRegisterName(MO.getReg()); break; case MachineOperand::MO_Immediate: O << MO.getImm(); break; case MachineOperand::MO_MachineBasicBlock: O << *MO.getMBB()->getSymbol(); break; case MachineOperand::MO_GlobalAddress: O << *getSymbol(MO.getGlobal()); break; case MachineOperand::MO_ConstantPoolIndex: O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_' << MO.getIndex(); break; case MachineOperand::MO_BlockAddress: O << *GetBlockAddressSymbol(MO.getBlockAddress()); break; default: llvm_unreachable("not implemented"); } } /// PrintAsmOperand - Print out an operand for an inline asm expression. /// bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant,const char *ExtraCode, raw_ostream &O) { // Print the operand if there is no operand modifier. if (!ExtraCode || !ExtraCode[0]) { printOperand(MI, OpNo, O); return false; } // Otherwise fallback on the default implementation. return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); } void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) { SmallString<128> Str; raw_svector_ostream O(Str); switch (MI->getOpcode()) { case XCore::DBG_VALUE: llvm_unreachable("Should be handled target independently"); case XCore::ADD_2rus: if (MI->getOperand(2).getImm() == 0) { O << "\tmov " << XCoreInstPrinter::getRegisterName(MI->getOperand(0).getReg()) << ", " << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg()); OutStreamer.EmitRawText(O.str()); return; } break; case XCore::BR_JT: case XCore::BR_JT32: O << "\tbru " << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg()) << '\n'; if (MI->getOpcode() == XCore::BR_JT) printInlineJT(MI, 0, O); else printInlineJT32(MI, 0, O); O << '\n'; OutStreamer.EmitRawText(O.str()); return; } MCInst TmpInst; MCInstLowering.Lower(MI, TmpInst); OutStreamer.EmitInstruction(TmpInst); } // Force static initialization. extern "C" void LLVMInitializeXCoreAsmPrinter() { RegisterAsmPrinter X(TheXCoreTarget); }