1 //===-- SPUAsmPrinter.cpp - Print machine instrs to Cell SPU assembly -------=//
3 // The LLVM Compiler Infrastructure
5 // This file was developed by a team from the Computer Systems Research
6 // Department at The Aerospace Corporation and is distributed under the
7 // University of Illinois Open Source License. See LICENSE.TXT for details.
9 //===----------------------------------------------------------------------===//
11 // This file contains a printer that converts from our internal representation
12 // of machine-dependent LLVM code to Cell SPU assembly language. This printer
13 // is the output mechanism used by `llc'.
15 // Documentation at http://developer.apple.com/documentation/DeveloperTools/
16 // Reference/Assembler/ASMIntroduction/chapter_1_section_1.html
18 //===----------------------------------------------------------------------===//
20 #define DEBUG_TYPE "asmprinter"
22 #include "SPUTargetMachine.h"
23 #include "llvm/Constants.h"
24 #include "llvm/DerivedTypes.h"
25 #include "llvm/Module.h"
26 #include "llvm/Assembly/Writer.h"
27 #include "llvm/CodeGen/AsmPrinter.h"
28 #include "llvm/CodeGen/DwarfWriter.h"
29 #include "llvm/CodeGen/MachineModuleInfo.h"
30 #include "llvm/CodeGen/MachineFunctionPass.h"
31 #include "llvm/CodeGen/MachineInstr.h"
32 #include "llvm/Support/Mangler.h"
33 #include "llvm/Support/MathExtras.h"
34 #include "llvm/Support/CommandLine.h"
35 #include "llvm/Support/Debug.h"
36 #include "llvm/Support/Compiler.h"
37 #include "llvm/Target/TargetAsmInfo.h"
38 #include "llvm/Target/MRegisterInfo.h"
39 #include "llvm/Target/TargetInstrInfo.h"
40 #include "llvm/Target/TargetOptions.h"
41 #include "llvm/ADT/Statistic.h"
42 #include "llvm/ADT/StringExtras.h"
47 STATISTIC(EmittedInsts, "Number of machine instrs printed");
49 const std::string bss_section(".bss");
51 struct VISIBILITY_HIDDEN SPUAsmPrinter : public AsmPrinter {
52 std::set<std::string> FnStubs, GVStubs;
54 SPUAsmPrinter(std::ostream &O, TargetMachine &TM, const TargetAsmInfo *T) :
59 virtual const char *getPassName() const {
60 return "STI CBEA SPU Assembly Printer";
63 SPUTargetMachine &getTM() {
64 return static_cast<SPUTargetMachine&>(TM);
67 /// printInstruction - This method is automatically generated by tablegen
68 /// from the instruction set description. This method returns true if the
69 /// machine instruction was sufficiently described to print it, otherwise it
71 bool printInstruction(const MachineInstr *MI);
73 void printMachineInstruction(const MachineInstr *MI);
74 void printOp(const MachineOperand &MO);
76 /// printRegister - Print register according to target requirements.
78 void printRegister(const MachineOperand &MO, bool R0AsZero) {
79 unsigned RegNo = MO.getReg();
80 assert(MRegisterInfo::isPhysicalRegister(RegNo) && "Not physreg??");
81 O << TM.getRegisterInfo()->get(RegNo).Name;
84 void printOperand(const MachineInstr *MI, unsigned OpNo) {
85 const MachineOperand &MO = MI->getOperand(OpNo);
86 if (MO.isRegister()) {
87 assert(MRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physreg??");
88 O << TM.getRegisterInfo()->get(MO.getReg()).Name;
89 } else if (MO.isImmediate()) {
90 O << MO.getImmedValue();
96 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
97 unsigned AsmVariant, const char *ExtraCode);
98 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
99 unsigned AsmVariant, const char *ExtraCode);
103 printS7ImmOperand(const MachineInstr *MI, unsigned OpNo)
105 int value = MI->getOperand(OpNo).getImmedValue();
106 value = (value << (32 - 7)) >> (32 - 7);
108 assert((value >= -(1 << 8) && value <= (1 << 7) - 1)
109 && "Invalid s7 argument");
114 printU7ImmOperand(const MachineInstr *MI, unsigned OpNo)
116 unsigned int value = MI->getOperand(OpNo).getImmedValue();
117 assert(value < (1 << 8) && "Invalid u7 argument");
122 printMemRegImmS7(const MachineInstr *MI, unsigned OpNo)
124 char value = MI->getOperand(OpNo).getImmedValue();
127 printOperand(MI, OpNo+1);
132 printS16ImmOperand(const MachineInstr *MI, unsigned OpNo)
134 O << (short) MI->getOperand(OpNo).getImmedValue();
138 printU16ImmOperand(const MachineInstr *MI, unsigned OpNo)
140 O << (unsigned short)MI->getOperand(OpNo).getImmedValue();
144 printU32ImmOperand(const MachineInstr *MI, unsigned OpNo)
146 O << (unsigned)MI->getOperand(OpNo).getImmedValue();
150 printMemRegReg(const MachineInstr *MI, unsigned OpNo) {
151 // When used as the base register, r0 reads constant zero rather than
152 // the value contained in the register. For this reason, the darwin
153 // assembler requires that we print r0 as 0 (no r) when used as the base.
154 const MachineOperand &MO = MI->getOperand(OpNo);
155 O << TM.getRegisterInfo()->get(MO.getReg()).Name;
157 printOperand(MI, OpNo+1);
161 printU18ImmOperand(const MachineInstr *MI, unsigned OpNo)
163 unsigned int value = MI->getOperand(OpNo).getImmedValue();
164 assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
169 printS10ImmOperand(const MachineInstr *MI, unsigned OpNo)
171 short value = (short) (((int) MI->getOperand(OpNo).getImmedValue() << 16)
173 assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
174 && "Invalid s10 argument");
179 printU10ImmOperand(const MachineInstr *MI, unsigned OpNo)
181 short value = (short) (((int) MI->getOperand(OpNo).getImmedValue() << 16)
183 assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
188 printMemRegImmS10(const MachineInstr *MI, unsigned OpNo)
190 const MachineOperand &MO = MI->getOperand(OpNo);
191 assert(MO.isImmediate()
192 && "printMemRegImmS10 first operand is not immedate");
193 printS10ImmOperand(MI, OpNo);
195 printOperand(MI, OpNo+1);
200 printAddr256K(const MachineInstr *MI, unsigned OpNo)
202 /* Note: operand 1 is an offset or symbol name. Operand 2 is
204 if (MI->getOperand(OpNo).isImmediate()) {
205 printS16ImmOperand(MI, OpNo);
207 printOp(MI->getOperand(OpNo));
211 void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
212 printOp(MI->getOperand(OpNo));
215 void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo) {
216 printOp(MI->getOperand(OpNo));
220 void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
221 if (MI->getOperand(OpNo).isImmediate()) {
222 printS16ImmOperand(MI, OpNo);
224 printOp(MI->getOperand(OpNo));
229 void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
230 if (MI->getOperand(OpNo).isImmediate()) {
231 printS16ImmOperand(MI, OpNo);
233 printOp(MI->getOperand(OpNo));
238 /// Print local store address
239 void printSymbolLSA(const MachineInstr *MI, unsigned OpNo) {
240 printOp(MI->getOperand(OpNo));
243 void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
244 if (MI->getOperand(OpNo).isImmediate()) {
245 int value = (int) MI->getOperand(OpNo).getImmedValue();
246 assert((value >= 0 && value < 16)
247 && "Invalid negated immediate rotate 7-bit argument");
250 assert(0 && "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
254 void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
255 if (MI->getOperand(OpNo).isImmediate()) {
256 int value = (int) MI->getOperand(OpNo).getImmedValue();
257 assert((value >= 0 && value < 32)
258 && "Invalid negated immediate rotate 7-bit argument");
261 assert(0 && "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
265 virtual bool runOnMachineFunction(MachineFunction &F) = 0;
266 virtual bool doFinalization(Module &M) = 0;
269 /// LinuxAsmPrinter - SPU assembly printer, customized for Linux
270 struct VISIBILITY_HIDDEN LinuxAsmPrinter : public SPUAsmPrinter {
274 LinuxAsmPrinter(std::ostream &O, SPUTargetMachine &TM,
275 const TargetAsmInfo *T) :
276 SPUAsmPrinter(O, TM, T),
280 virtual const char *getPassName() const {
281 return "STI CBEA SPU Assembly Printer";
284 bool runOnMachineFunction(MachineFunction &F);
285 bool doInitialization(Module &M);
286 bool doFinalization(Module &M);
288 void getAnalysisUsage(AnalysisUsage &AU) const {
289 AU.setPreservesAll();
290 AU.addRequired<MachineModuleInfo>();
291 SPUAsmPrinter::getAnalysisUsage(AU);
294 /// getSectionForFunction - Return the section that we should emit the
295 /// specified function body into.
296 virtual std::string getSectionForFunction(const Function &F) const;
298 } // end of anonymous namespace
300 // Include the auto-generated portion of the assembly writer
301 #include "SPUGenAsmWriter.inc"
303 void SPUAsmPrinter::printOp(const MachineOperand &MO) {
304 switch (MO.getType()) {
305 case MachineOperand::MO_Immediate:
306 cerr << "printOp() does not handle immediate values\n";
310 case MachineOperand::MO_MachineBasicBlock:
311 printBasicBlockLabel(MO.getMachineBasicBlock());
313 case MachineOperand::MO_JumpTableIndex:
314 O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
315 << '_' << MO.getJumpTableIndex();
316 // FIXME: PIC relocation model
318 case MachineOperand::MO_ConstantPoolIndex:
319 O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
320 << '_' << MO.getConstantPoolIndex();
322 case MachineOperand::MO_ExternalSymbol:
323 // Computing the address of an external symbol, not calling it.
324 if (TM.getRelocationModel() != Reloc::Static) {
325 std::string Name(TAI->getGlobalPrefix()); Name += MO.getSymbolName();
326 GVStubs.insert(Name);
327 O << "L" << Name << "$non_lazy_ptr";
330 O << TAI->getGlobalPrefix() << MO.getSymbolName();
332 case MachineOperand::MO_GlobalAddress: {
333 // Computing the address of a global symbol, not calling it.
334 GlobalValue *GV = MO.getGlobal();
335 std::string Name = Mang->getValueName(GV);
337 // External or weakly linked global variables need non-lazily-resolved
339 if (TM.getRelocationModel() != Reloc::Static) {
340 if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
341 GV->hasLinkOnceLinkage()))) {
342 GVStubs.insert(Name);
343 O << "L" << Name << "$non_lazy_ptr";
349 if (GV->hasExternalWeakLinkage())
350 ExtWeakSymbols.insert(GV);
355 O << "<unknown operand type: " << MO.getType() << ">";
360 /// PrintAsmOperand - Print out an operand for an inline asm expression.
362 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
364 const char *ExtraCode) {
365 // Does this asm operand have a single letter operand modifier?
366 if (ExtraCode && ExtraCode[0]) {
367 if (ExtraCode[1] != 0) return true; // Unknown modifier.
369 switch (ExtraCode[0]) {
370 default: return true; // Unknown modifier.
371 case 'L': // Write second word of DImode reference.
372 // Verify that this operand has two consecutive registers.
373 if (!MI->getOperand(OpNo).isRegister() ||
374 OpNo+1 == MI->getNumOperands() ||
375 !MI->getOperand(OpNo+1).isRegister())
377 ++OpNo; // Return the high-part.
382 printOperand(MI, OpNo);
386 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
389 const char *ExtraCode) {
390 if (ExtraCode && ExtraCode[0])
391 return true; // Unknown modifier.
392 printMemRegReg(MI, OpNo);
396 /// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax
397 /// to the current output stream.
399 void SPUAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
401 printInstruction(MI);
406 std::string LinuxAsmPrinter::getSectionForFunction(const Function &F) const {
407 switch (F.getLinkage()) {
408 default: assert(0 && "Unknown linkage type!");
409 case Function::ExternalLinkage:
410 case Function::InternalLinkage: return TAI->getTextSection();
411 case Function::WeakLinkage:
412 case Function::LinkOnceLinkage:
413 return ""; // Print nothing for the time being...
417 /// runOnMachineFunction - This uses the printMachineInstruction()
418 /// method to print assembly for each instruction.
421 LinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF)
423 DW.SetModuleInfo(&getAnalysis<MachineModuleInfo>());
425 SetupMachineFunction(MF);
428 // Print out constants referenced by the function
429 EmitConstantPool(MF.getConstantPool());
431 // Print out labels for the function.
432 const Function *F = MF.getFunction();
434 SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
437 switch (F->getLinkage()) {
438 default: assert(0 && "Unknown linkage type!");
439 case Function::InternalLinkage: // Symbols default to internal.
441 case Function::ExternalLinkage:
442 O << "\t.global\t" << CurrentFnName << "\n"
443 << "\t.type\t" << CurrentFnName << ", @function\n";
445 case Function::WeakLinkage:
446 case Function::LinkOnceLinkage:
447 O << "\t.global\t" << CurrentFnName << "\n";
448 O << "\t.weak_definition\t" << CurrentFnName << "\n";
451 O << CurrentFnName << ":\n";
453 // Emit pre-function debug information.
454 DW.BeginFunction(&MF);
456 // Print out code for the function.
457 for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
459 // Print a label for the basic block.
460 if (I != MF.begin()) {
461 printBasicBlockLabel(I, true);
464 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
466 // Print the assembly for the instruction.
468 printMachineInstruction(II);
472 O << "\t.size\t" << CurrentFnName << ",.-" << CurrentFnName << "\n";
474 // Print out jump tables referenced by the function.
475 EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
477 // Emit post-function debug information.
480 // We didn't modify anything.
485 bool LinuxAsmPrinter::doInitialization(Module &M) {
486 bool Result = AsmPrinter::doInitialization(M);
487 SwitchToTextSection(TAI->getTextSection());
488 // Emit initial debug information.
493 bool LinuxAsmPrinter::doFinalization(Module &M) {
494 const TargetData *TD = TM.getTargetData();
496 // Print out module-level global variables here.
497 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
499 if (!I->hasInitializer()) continue; // External global require no code
501 // Check to see if this is a special global used by LLVM, if so, emit it.
502 if (EmitSpecialLLVMGlobal(I))
505 std::string name = Mang->getValueName(I);
506 Constant *C = I->getInitializer();
507 unsigned Size = TD->getTypeStoreSize(C->getType());
508 unsigned Align = TD->getPreferredAlignmentLog(I);
510 if (C->isNullValue() && /* FIXME: Verify correct */
511 (I->hasInternalLinkage() || I->hasWeakLinkage() ||
512 I->hasLinkOnceLinkage() ||
513 (I->hasExternalLinkage() && !I->hasSection()))) {
514 if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
515 if (I->hasExternalLinkage()) {
516 // External linkage globals -> .bss section
517 // FIXME: Want to set the global variable's section so that
518 // SwitchToDataSection emits the ".section" directive
519 SwitchToDataSection("\t.section\t.bss", I);
520 O << "\t.global\t" << name << '\n';
521 O << "\t.align\t" << Align << '\n';
522 O << "\t.type\t" << name << ", @object\n";
523 O << "\t.size\t" << name << ", " << Size << '\n';
525 O << "\t.zero\t" << Size;
526 } else if (I->hasInternalLinkage()) {
527 SwitchToDataSection("\t.data", I);
528 O << TAI->getLCOMMDirective() << name << "," << Size << "," << Align;
530 SwitchToDataSection("\t.data", I);
531 O << ".comm " << name << "," << Size;
533 O << "\t\t# '" << I->getName() << "'\n";
535 switch (I->getLinkage()) {
536 case GlobalValue::LinkOnceLinkage:
537 case GlobalValue::WeakLinkage:
538 O << "\t.global " << name << '\n'
539 << "\t.weak_definition " << name << '\n';
540 SwitchToDataSection(".section __DATA,__datacoal_nt,coalesced", I);
542 case GlobalValue::AppendingLinkage:
543 // FIXME: appending linkage variables should go into a section of
544 // their name or something. For now, just emit them as external.
545 case GlobalValue::ExternalLinkage:
546 // If external or appending, declare as a global symbol
547 O << "\t.global " << name << "\n";
549 case GlobalValue::InternalLinkage:
550 if (I->isConstant()) {
551 const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
552 if (TAI->getCStringSection() && CVA && CVA->isCString()) {
553 SwitchToDataSection(TAI->getCStringSection(), I);
558 SwitchToDataSection("\t.data", I);
561 cerr << "Unknown linkage type!";
565 EmitAlignment(Align, I);
566 O << name << ":\t\t\t\t# '" << I->getName() << "'\n";
568 // If the initializer is a extern weak symbol, remember to emit the weak
570 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
571 if (GV->hasExternalWeakLinkage())
572 ExtWeakSymbols.insert(GV);
574 EmitGlobalConstant(C);
579 // Output stubs for dynamically-linked functions
580 if (TM.getRelocationModel() == Reloc::PIC_) {
581 for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
583 SwitchToTextSection(".section __TEXT,__picsymbolstub1,symbol_stubs,"
584 "pure_instructions,32");
586 O << "L" << *i << "$stub:\n";
587 O << "\t.indirect_symbol " << *i << "\n";
589 O << "\tbcl 20,31,L0$" << *i << "\n";
590 O << "L0$" << *i << ":\n";
592 O << "\taddis r11,r11,ha16(L" << *i << "$lazy_ptr-L0$" << *i << ")\n";
594 O << "\tlwzu r12,lo16(L" << *i << "$lazy_ptr-L0$" << *i << ")(r11)\n";
595 O << "\tmtctr r12\n";
597 SwitchToDataSection(".lazy_symbol_pointer");
598 O << "L" << *i << "$lazy_ptr:\n";
599 O << "\t.indirect_symbol " << *i << "\n";
600 O << "\t.long dyld_stub_binding_helper\n";
603 for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
605 SwitchToTextSection(".section __TEXT,__symbol_stub1,symbol_stubs,"
606 "pure_instructions,16");
608 O << "L" << *i << "$stub:\n";
609 O << "\t.indirect_symbol " << *i << "\n";
610 O << "\tlis r11,ha16(L" << *i << "$lazy_ptr)\n";
611 O << "\tlwzu r12,lo16(L" << *i << "$lazy_ptr)(r11)\n";
612 O << "\tmtctr r12\n";
614 SwitchToDataSection(".lazy_symbol_pointer");
615 O << "L" << *i << "$lazy_ptr:\n";
616 O << "\t.indirect_symbol " << *i << "\n";
617 O << "\t.long dyld_stub_binding_helper\n";
623 // Output stubs for external and common global variables.
624 if (GVStubs.begin() != GVStubs.end()) {
625 SwitchToDataSection(".non_lazy_symbol_pointer");
626 for (std::set<std::string>::iterator I = GVStubs.begin(),
627 E = GVStubs.end(); I != E; ++I) {
628 O << "L" << *I << "$non_lazy_ptr:\n";
629 O << "\t.indirect_symbol " << *I << "\n";
634 // Emit initial debug information.
637 // Emit ident information
638 O << "\t.ident\t\"(llvm 1.9+) STI CBEA Cell SPU backend\"\n";
640 return AsmPrinter::doFinalization(M);
645 /// createSPUCodePrinterPass - Returns a pass that prints the Cell SPU
646 /// assembly code for a MachineFunction to the given output stream, in a format
647 /// that the Linux SPU assembler can deal with.
649 FunctionPass *llvm::createSPUAsmPrinterPass(std::ostream &o,
650 SPUTargetMachine &tm) {
651 return new LinuxAsmPrinter(o, tm, tm.getTargetAsmInfo());