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 "XCoreInstrInfo.h" 18 #include "XCoreSubtarget.h" 19 #include "XCoreTargetMachine.h" 20 #include "llvm/Constants.h" 21 #include "llvm/DerivedTypes.h" 22 #include "llvm/Module.h" 23 #include "llvm/CodeGen/AsmPrinter.h" 24 #include "llvm/CodeGen/DwarfWriter.h" 25 #include "llvm/CodeGen/MachineModuleInfo.h" 26 #include "llvm/CodeGen/MachineFunctionPass.h" 27 #include "llvm/CodeGen/MachineConstantPool.h" 28 #include "llvm/CodeGen/MachineInstr.h" 29 #include "llvm/Target/TargetAsmInfo.h" 30 #include "llvm/Target/TargetData.h" 31 #include "llvm/Support/Mangler.h" 32 #include "llvm/ADT/Statistic.h" 33 #include "llvm/ADT/StringExtras.h" 34 #include "llvm/Support/CommandLine.h" 35 #include "llvm/Support/ErrorHandling.h" 36 #include "llvm/Support/MathExtras.h" 37 #include "llvm/Support/raw_ostream.h" 38 #include <algorithm> 39 #include <cctype> 40 using namespace llvm; 41 42 STATISTIC(EmittedInsts, "Number of machine instrs printed"); 43 44 static cl::opt<std::string> FileDirective("xcore-file-directive", cl::Optional, 45 cl::desc("Output a file directive into the assembly file"), 46 cl::Hidden, 47 cl::value_desc("filename"), 48 cl::init("")); 49 50 static cl::opt<unsigned> MaxThreads("xcore-max-threads", cl::Optional, 51 cl::desc("Maximum number of threads (for emulation thread-local storage)"), 52 cl::Hidden, 53 cl::value_desc("number"), 54 cl::init(8)); 55 56 namespace { 57 class VISIBILITY_HIDDEN XCoreAsmPrinter : public AsmPrinter { 58 DwarfWriter *DW; 59 const XCoreSubtarget &Subtarget; 60 public: 61 explicit XCoreAsmPrinter(raw_ostream &O, XCoreTargetMachine &TM, 62 const TargetAsmInfo *T, bool V) 63 : AsmPrinter(O, TM, T, V), DW(0), 64 Subtarget(*TM.getSubtargetImpl()) {} 65 66 virtual const char *getPassName() const { 67 return "XCore Assembly Printer"; 68 } 69 70 void printMemOperand(const MachineInstr *MI, int opNum); 71 void printOperand(const MachineInstr *MI, int opNum); 72 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 73 unsigned AsmVariant, const char *ExtraCode); 74 75 void emitFileDirective(const std::string &filename); 76 void emitGlobalDirective(const std::string &name); 77 void emitExternDirective(const std::string &name); 78 79 void emitArrayBound(const std::string &name, const GlobalVariable *GV); 80 void emitGlobal(const GlobalVariable *GV); 81 82 void emitFunctionStart(MachineFunction &MF); 83 void emitFunctionEnd(MachineFunction &MF); 84 85 bool printInstruction(const MachineInstr *MI); // autogenerated. 86 void printMachineInstruction(const MachineInstr *MI); 87 bool runOnMachineFunction(MachineFunction &F); 88 bool doInitialization(Module &M); 89 bool doFinalization(Module &M); 90 91 void getAnalysisUsage(AnalysisUsage &AU) const { 92 AsmPrinter::getAnalysisUsage(AU); 93 AU.setPreservesAll(); 94 AU.addRequired<MachineModuleInfo>(); 95 AU.addRequired<DwarfWriter>(); 96 } 97 }; 98 } // end of anonymous namespace 99 100 #include "XCoreGenAsmWriter.inc" 101 102 /// createXCoreCodePrinterPass - Returns a pass that prints the XCore 103 /// assembly code for a MachineFunction to the given output stream, 104 /// using the given target machine description. This should work 105 /// regardless of whether the function is in SSA form. 106 /// 107 FunctionPass *llvm::createXCoreCodePrinterPass(raw_ostream &o, 108 XCoreTargetMachine &tm, 109 bool verbose) { 110 return new XCoreAsmPrinter(o, tm, tm.getTargetAsmInfo(), verbose); 111 } 112 113 // PrintEscapedString - Print each character of the specified string, escaping 114 // it if it is not printable or if it is an escape char. 115 static void PrintEscapedString(const std::string &Str, raw_ostream &Out) { 116 for (unsigned i = 0, e = Str.size(); i != e; ++i) { 117 unsigned char C = Str[i]; 118 if (isprint(C) && C != '"' && C != '\\') { 119 Out << C; 120 } else { 121 Out << '\\' 122 << (char) ((C/16 < 10) ? ( C/16 +'0') : ( C/16 -10+'A')) 123 << (char)(((C&15) < 10) ? ((C&15)+'0') : ((C&15)-10+'A')); 124 } 125 } 126 } 127 128 void XCoreAsmPrinter:: 129 emitFileDirective(const std::string &name) 130 { 131 O << "\t.file\t\""; 132 PrintEscapedString(name, O); 133 O << "\"\n"; 134 } 135 136 void XCoreAsmPrinter:: 137 emitGlobalDirective(const std::string &name) 138 { 139 O << TAI->getGlobalDirective() << name; 140 O << "\n"; 141 } 142 143 void XCoreAsmPrinter:: 144 emitExternDirective(const std::string &name) 145 { 146 O << "\t.extern\t" << name; 147 O << '\n'; 148 } 149 150 void XCoreAsmPrinter:: 151 emitArrayBound(const std::string &name, const GlobalVariable *GV) 152 { 153 assert(((GV->hasExternalLinkage() || 154 GV->hasWeakLinkage()) || 155 GV->hasLinkOnceLinkage()) && "Unexpected linkage"); 156 if (const ArrayType *ATy = dyn_cast<ArrayType>( 157 cast<PointerType>(GV->getType())->getElementType())) 158 { 159 O << TAI->getGlobalDirective() << name << ".globound" << "\n"; 160 O << TAI->getSetDirective() << name << ".globound" << "," 161 << ATy->getNumElements() << "\n"; 162 if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) { 163 // TODO Use COMDAT groups for LinkOnceLinkage 164 O << TAI->getWeakDefDirective() << name << ".globound" << "\n"; 165 } 166 } 167 } 168 169 void XCoreAsmPrinter:: 170 emitGlobal(const GlobalVariable *GV) 171 { 172 const TargetData *TD = TM.getTargetData(); 173 174 if (GV->hasInitializer()) { 175 // Check to see if this is a special global used by LLVM, if so, emit it. 176 if (EmitSpecialLLVMGlobal(GV)) 177 return; 178 179 SwitchToSection(TAI->SectionForGlobal(GV)); 180 181 std::string name = Mang->getValueName(GV); 182 Constant *C = GV->getInitializer(); 183 unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType()); 184 185 // Mark the start of the global 186 O << "\t.cc_top " << name << ".data," << name << "\n"; 187 188 switch (GV->getLinkage()) { 189 case GlobalValue::AppendingLinkage: 190 llvm_report_error("AppendingLinkage is not supported by this target!"); 191 case GlobalValue::LinkOnceAnyLinkage: 192 case GlobalValue::LinkOnceODRLinkage: 193 case GlobalValue::WeakAnyLinkage: 194 case GlobalValue::WeakODRLinkage: 195 case GlobalValue::ExternalLinkage: 196 emitArrayBound(name, GV); 197 emitGlobalDirective(name); 198 // TODO Use COMDAT groups for LinkOnceLinkage 199 if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) { 200 O << TAI->getWeakDefDirective() << name << "\n"; 201 } 202 // FALL THROUGH 203 case GlobalValue::InternalLinkage: 204 case GlobalValue::PrivateLinkage: 205 break; 206 case GlobalValue::GhostLinkage: 207 LLVM_UNREACHABLE("Should not have any unmaterialized functions!"); 208 case GlobalValue::DLLImportLinkage: 209 LLVM_UNREACHABLE("DLLImport linkage is not supported by this target!"); 210 case GlobalValue::DLLExportLinkage: 211 LLVM_UNREACHABLE("DLLExport linkage is not supported by this target!"); 212 default: 213 LLVM_UNREACHABLE("Unknown linkage type!"); 214 } 215 216 EmitAlignment(Align, GV, 2); 217 218 unsigned Size = TD->getTypeAllocSize(C->getType()); 219 if (GV->isThreadLocal()) { 220 Size *= MaxThreads; 221 } 222 if (TAI->hasDotTypeDotSizeDirective()) { 223 O << "\t.type " << name << ",@object\n"; 224 O << "\t.size " << name << "," << Size << "\n"; 225 } 226 O << name << ":\n"; 227 228 EmitGlobalConstant(C); 229 if (GV->isThreadLocal()) { 230 for (unsigned i = 1; i < MaxThreads; ++i) { 231 EmitGlobalConstant(C); 232 } 233 } 234 if (Size < 4) { 235 // The ABI requires that unsigned scalar types smaller than 32 bits 236 // are are padded to 32 bits. 237 EmitZeros(4 - Size); 238 } 239 240 // Mark the end of the global 241 O << "\t.cc_bottom " << name << ".data\n"; 242 } 243 } 244 245 /// Emit the directives on the start of functions 246 void XCoreAsmPrinter:: 247 emitFunctionStart(MachineFunction &MF) 248 { 249 // Print out the label for the function. 250 const Function *F = MF.getFunction(); 251 252 SwitchToSection(TAI->SectionForGlobal(F)); 253 254 // Mark the start of the function 255 O << "\t.cc_top " << CurrentFnName << ".function," << CurrentFnName << "\n"; 256 257 switch (F->getLinkage()) { 258 default: assert(0 && "Unknown linkage type!"); 259 case Function::InternalLinkage: // Symbols default to internal. 260 case Function::PrivateLinkage: 261 break; 262 case Function::ExternalLinkage: 263 emitGlobalDirective(CurrentFnName); 264 break; 265 case Function::LinkOnceAnyLinkage: 266 case Function::LinkOnceODRLinkage: 267 case Function::WeakAnyLinkage: 268 case Function::WeakODRLinkage: 269 // TODO Use COMDAT groups for LinkOnceLinkage 270 O << TAI->getGlobalDirective() << CurrentFnName << "\n"; 271 O << TAI->getWeakDefDirective() << CurrentFnName << "\n"; 272 break; 273 } 274 // (1 << 1) byte aligned 275 EmitAlignment(MF.getAlignment(), F, 1); 276 if (TAI->hasDotTypeDotSizeDirective()) { 277 O << "\t.type " << CurrentFnName << ",@function\n"; 278 } 279 O << CurrentFnName << ":\n"; 280 } 281 282 /// Emit the directives on the end of functions 283 void XCoreAsmPrinter:: 284 emitFunctionEnd(MachineFunction &MF) 285 { 286 // Mark the end of the function 287 O << "\t.cc_bottom " << CurrentFnName << ".function\n"; 288 } 289 290 /// runOnMachineFunction - This uses the printMachineInstruction() 291 /// method to print assembly for each instruction. 292 /// 293 bool XCoreAsmPrinter::runOnMachineFunction(MachineFunction &MF) 294 { 295 this->MF = &MF; 296 297 SetupMachineFunction(MF); 298 299 // Print out constants referenced by the function 300 EmitConstantPool(MF.getConstantPool()); 301 302 // Print out jump tables referenced by the function 303 EmitJumpTableInfo(MF.getJumpTableInfo(), MF); 304 305 // Emit the function start directives 306 emitFunctionStart(MF); 307 308 // Emit pre-function debug information. 309 DW->BeginFunction(&MF); 310 311 // Print out code for the function. 312 for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); 313 I != E; ++I) { 314 315 // Print a label for the basic block. 316 if (I != MF.begin()) { 317 printBasicBlockLabel(I, true , true); 318 O << '\n'; 319 } 320 321 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); 322 II != E; ++II) { 323 // Print the assembly for the instruction. 324 O << "\t"; 325 printMachineInstruction(II); 326 } 327 328 // Each Basic Block is separated by a newline 329 O << '\n'; 330 } 331 332 // Emit function end directives 333 emitFunctionEnd(MF); 334 335 // Emit post-function debug information. 336 DW->EndFunction(&MF); 337 338 // We didn't modify anything. 339 return false; 340 } 341 342 void XCoreAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum) 343 { 344 printOperand(MI, opNum); 345 346 if (MI->getOperand(opNum+1).isImm() 347 && MI->getOperand(opNum+1).getImm() == 0) 348 return; 349 350 O << "+"; 351 printOperand(MI, opNum+1); 352 } 353 354 void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum) { 355 const MachineOperand &MO = MI->getOperand(opNum); 356 switch (MO.getType()) { 357 case MachineOperand::MO_Register: 358 if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) 359 O << TM.getRegisterInfo()->get(MO.getReg()).AsmName; 360 else 361 assert(0 && "not implemented"); 362 break; 363 case MachineOperand::MO_Immediate: 364 O << MO.getImm(); 365 break; 366 case MachineOperand::MO_MachineBasicBlock: 367 printBasicBlockLabel(MO.getMBB()); 368 break; 369 case MachineOperand::MO_GlobalAddress: 370 O << Mang->getValueName(MO.getGlobal()); 371 break; 372 case MachineOperand::MO_ExternalSymbol: 373 O << MO.getSymbolName(); 374 break; 375 case MachineOperand::MO_ConstantPoolIndex: 376 O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() 377 << '_' << MO.getIndex(); 378 break; 379 case MachineOperand::MO_JumpTableIndex: 380 O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() 381 << '_' << MO.getIndex(); 382 break; 383 default: 384 assert(0 && "not implemented"); 385 } 386 } 387 388 /// PrintAsmOperand - Print out an operand for an inline asm expression. 389 /// 390 bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 391 unsigned AsmVariant, 392 const char *ExtraCode) { 393 printOperand(MI, OpNo); 394 return false; 395 } 396 397 void XCoreAsmPrinter::printMachineInstruction(const MachineInstr *MI) { 398 ++EmittedInsts; 399 400 // Check for mov mnemonic 401 unsigned src, dst, srcSR, dstSR; 402 if (TM.getInstrInfo()->isMoveInstr(*MI, src, dst, srcSR, dstSR)) { 403 O << "\tmov "; 404 O << TM.getRegisterInfo()->get(dst).AsmName; 405 O << ", "; 406 O << TM.getRegisterInfo()->get(src).AsmName; 407 O << "\n"; 408 return; 409 } 410 if (printInstruction(MI)) { 411 return; 412 } 413 assert(0 && "Unhandled instruction in asm writer!"); 414 } 415 416 bool XCoreAsmPrinter::doInitialization(Module &M) { 417 bool Result = AsmPrinter::doInitialization(M); 418 DW = getAnalysisIfAvailable<DwarfWriter>(); 419 420 if (!FileDirective.empty()) 421 emitFileDirective(FileDirective); 422 423 return Result; 424 } 425 426 bool XCoreAsmPrinter::doFinalization(Module &M) { 427 428 // Print out module-level global variables. 429 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); 430 I != E; ++I) { 431 emitGlobal(I); 432 } 433 434 return AsmPrinter::doFinalization(M); 435 } 436