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