1 //===-- XCoreAsmPrinter.cpp - XCore LLVM assembly writer ------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains a printer that converts from our internal representation 11 // of machine-dependent LLVM code to the XAS-format XCore assembly language. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #define DEBUG_TYPE "asm-printer" 16 #include "XCore.h" 17 #include "InstPrinter/XCoreInstPrinter.h" 18 #include "XCoreInstrInfo.h" 19 #include "XCoreMCInstLower.h" 20 #include "XCoreSubtarget.h" 21 #include "XCoreTargetMachine.h" 22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/ADT/StringExtras.h" 24 #include "llvm/CodeGen/AsmPrinter.h" 25 #include "llvm/CodeGen/MachineConstantPool.h" 26 #include "llvm/CodeGen/MachineFunctionPass.h" 27 #include "llvm/CodeGen/MachineInstr.h" 28 #include "llvm/CodeGen/MachineJumpTableInfo.h" 29 #include "llvm/CodeGen/MachineModuleInfo.h" 30 #include "llvm/DebugInfo.h" 31 #include "llvm/IR/Constants.h" 32 #include "llvm/IR/DataLayout.h" 33 #include "llvm/IR/DerivedTypes.h" 34 #include "llvm/IR/Module.h" 35 #include "llvm/MC/MCAsmInfo.h" 36 #include "llvm/MC/MCInst.h" 37 #include "llvm/MC/MCStreamer.h" 38 #include "llvm/MC/MCSymbol.h" 39 #include "llvm/Support/ErrorHandling.h" 40 #include "llvm/Support/TargetRegistry.h" 41 #include "llvm/Support/raw_ostream.h" 42 #include "llvm/Target/Mangler.h" 43 #include "llvm/Target/TargetLoweringObjectFile.h" 44 #include <algorithm> 45 #include <cctype> 46 using namespace llvm; 47 48 namespace { 49 class XCoreAsmPrinter : public AsmPrinter { 50 const XCoreSubtarget &Subtarget; 51 XCoreMCInstLower MCInstLowering; 52 public: 53 explicit XCoreAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) 54 : AsmPrinter(TM, Streamer), Subtarget(TM.getSubtarget<XCoreSubtarget>()), 55 MCInstLowering(*this) {} 56 57 virtual const char *getPassName() const { 58 return "XCore Assembly Printer"; 59 } 60 61 void printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O, 62 const std::string &directive = ".jmptable"); 63 void printInlineJT32(const MachineInstr *MI, int opNum, raw_ostream &O) { 64 printInlineJT(MI, opNum, O, ".jmptable32"); 65 } 66 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); 67 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 68 unsigned AsmVariant, const char *ExtraCode, 69 raw_ostream &O); 70 71 void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV); 72 virtual void EmitGlobalVariable(const GlobalVariable *GV); 73 74 void EmitFunctionEntryLabel(); 75 void EmitInstruction(const MachineInstr *MI); 76 void EmitFunctionBodyStart(); 77 void EmitFunctionBodyEnd(); 78 }; 79 } // end of anonymous namespace 80 81 void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) { 82 assert(((GV->hasExternalLinkage() || 83 GV->hasWeakLinkage()) || 84 GV->hasLinkOnceLinkage()) && "Unexpected linkage"); 85 if (ArrayType *ATy = dyn_cast<ArrayType>( 86 cast<PointerType>(GV->getType())->getElementType())) { 87 OutStreamer.EmitSymbolAttribute(Sym, MCSA_Global); 88 // FIXME: MCStreamerize. 89 OutStreamer.EmitRawText(StringRef(".globound")); 90 OutStreamer.EmitRawText("\t.set\t" + Twine(Sym->getName())); 91 OutStreamer.EmitRawText(".globound," + Twine(ATy->getNumElements())); 92 if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) { 93 // TODO Use COMDAT groups for LinkOnceLinkage 94 OutStreamer.EmitRawText(MAI->getWeakDefDirective() +Twine(Sym->getName())+ 95 ".globound"); 96 } 97 } 98 } 99 100 void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { 101 // Check to see if this is a special global used by LLVM, if so, emit it. 102 if (!GV->hasInitializer() || 103 EmitSpecialLLVMGlobal(GV)) 104 return; 105 106 const DataLayout *TD = TM.getDataLayout(); 107 OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GV, Mang,TM)); 108 109 110 MCSymbol *GVSym = Mang->getSymbol(GV); 111 const Constant *C = GV->getInitializer(); 112 unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType()); 113 114 // Mark the start of the global 115 OutStreamer.EmitRawText("\t.cc_top " + Twine(GVSym->getName()) + ".data," + 116 GVSym->getName()); 117 118 switch (GV->getLinkage()) { 119 case GlobalValue::AppendingLinkage: 120 report_fatal_error("AppendingLinkage is not supported by this target!"); 121 case GlobalValue::LinkOnceAnyLinkage: 122 case GlobalValue::LinkOnceODRLinkage: 123 case GlobalValue::WeakAnyLinkage: 124 case GlobalValue::WeakODRLinkage: 125 case GlobalValue::ExternalLinkage: 126 emitArrayBound(GVSym, GV); 127 OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global); 128 129 // TODO Use COMDAT groups for LinkOnceLinkage 130 if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) 131 OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak); 132 // FALL THROUGH 133 case GlobalValue::InternalLinkage: 134 case GlobalValue::PrivateLinkage: 135 break; 136 case GlobalValue::DLLImportLinkage: 137 llvm_unreachable("DLLImport linkage is not supported by this target!"); 138 case GlobalValue::DLLExportLinkage: 139 llvm_unreachable("DLLExport linkage is not supported by this target!"); 140 default: 141 llvm_unreachable("Unknown linkage type!"); 142 } 143 144 EmitAlignment(Align > 2 ? Align : 2, GV); 145 146 if (GV->isThreadLocal()) { 147 report_fatal_error("TLS is not supported by this target!"); 148 } 149 unsigned Size = TD->getTypeAllocSize(C->getType()); 150 if (MAI->hasDotTypeDotSizeDirective()) { 151 OutStreamer.EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject); 152 OutStreamer.EmitRawText("\t.size " + Twine(GVSym->getName()) + "," + 153 Twine(Size)); 154 } 155 OutStreamer.EmitLabel(GVSym); 156 157 EmitGlobalConstant(C); 158 // The ABI requires that unsigned scalar types smaller than 32 bits 159 // are padded to 32 bits. 160 if (Size < 4) 161 OutStreamer.EmitZeros(4 - Size); 162 163 // Mark the end of the global 164 OutStreamer.EmitRawText("\t.cc_bottom " + Twine(GVSym->getName()) + ".data"); 165 } 166 167 void XCoreAsmPrinter::EmitFunctionBodyStart() { 168 MCInstLowering.Initialize(Mang, &MF->getContext()); 169 } 170 171 /// EmitFunctionBodyEnd - Targets can override this to emit stuff after 172 /// the last basic block in the function. 173 void XCoreAsmPrinter::EmitFunctionBodyEnd() { 174 // Emit function end directives 175 OutStreamer.EmitRawText("\t.cc_bottom " + Twine(CurrentFnSym->getName()) + 176 ".function"); 177 } 178 179 void XCoreAsmPrinter::EmitFunctionEntryLabel() { 180 // Mark the start of the function 181 OutStreamer.EmitRawText("\t.cc_top " + Twine(CurrentFnSym->getName()) + 182 ".function," + CurrentFnSym->getName()); 183 OutStreamer.EmitLabel(CurrentFnSym); 184 } 185 186 void XCoreAsmPrinter:: 187 printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O, 188 const std::string &directive) { 189 unsigned JTI = MI->getOperand(opNum).getIndex(); 190 const MachineFunction *MF = MI->getParent()->getParent(); 191 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); 192 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); 193 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs; 194 O << "\t" << directive << " "; 195 for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { 196 MachineBasicBlock *MBB = JTBBs[i]; 197 if (i > 0) 198 O << ","; 199 O << *MBB->getSymbol(); 200 } 201 } 202 203 void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum, 204 raw_ostream &O) { 205 const MachineOperand &MO = MI->getOperand(opNum); 206 switch (MO.getType()) { 207 case MachineOperand::MO_Register: 208 O << XCoreInstPrinter::getRegisterName(MO.getReg()); 209 break; 210 case MachineOperand::MO_Immediate: 211 O << MO.getImm(); 212 break; 213 case MachineOperand::MO_MachineBasicBlock: 214 O << *MO.getMBB()->getSymbol(); 215 break; 216 case MachineOperand::MO_GlobalAddress: 217 O << *Mang->getSymbol(MO.getGlobal()); 218 break; 219 case MachineOperand::MO_ExternalSymbol: 220 O << MO.getSymbolName(); 221 break; 222 case MachineOperand::MO_ConstantPoolIndex: 223 O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() 224 << '_' << MO.getIndex(); 225 break; 226 case MachineOperand::MO_JumpTableIndex: 227 O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() 228 << '_' << MO.getIndex(); 229 break; 230 case MachineOperand::MO_BlockAddress: 231 O << *GetBlockAddressSymbol(MO.getBlockAddress()); 232 break; 233 default: 234 llvm_unreachable("not implemented"); 235 } 236 } 237 238 /// PrintAsmOperand - Print out an operand for an inline asm expression. 239 /// 240 bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 241 unsigned AsmVariant,const char *ExtraCode, 242 raw_ostream &O) { 243 // Print the operand if there is no operand modifier. 244 if (!ExtraCode || !ExtraCode[0]) { 245 printOperand(MI, OpNo, O); 246 return false; 247 } 248 249 // Otherwise fallback on the default implementation. 250 return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); 251 } 252 253 void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) { 254 SmallString<128> Str; 255 raw_svector_ostream O(Str); 256 257 switch (MI->getOpcode()) { 258 case XCore::DBG_VALUE: 259 llvm_unreachable("Should be handled target independently"); 260 case XCore::ADD_2rus: 261 if (MI->getOperand(2).getImm() == 0) { 262 O << "\tmov " 263 << XCoreInstPrinter::getRegisterName(MI->getOperand(0).getReg()) << ", " 264 << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg()); 265 OutStreamer.EmitRawText(O.str()); 266 return; 267 } 268 break; 269 case XCore::BR_JT: 270 case XCore::BR_JT32: 271 O << "\tbru " 272 << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg()) << '\n'; 273 if (MI->getOpcode() == XCore::BR_JT) 274 printInlineJT(MI, 0, O); 275 else 276 printInlineJT32(MI, 0, O); 277 O << '\n'; 278 OutStreamer.EmitRawText(O.str()); 279 return; 280 } 281 282 MCInst TmpInst; 283 MCInstLowering.Lower(MI, TmpInst); 284 285 OutStreamer.EmitInstruction(TmpInst); 286 } 287 288 // Force static initialization. 289 extern "C" void LLVMInitializeXCoreAsmPrinter() { 290 RegisterAsmPrinter<XCoreAsmPrinter> X(TheXCoreTarget); 291 } 292