blob: 03644af367fa8434343c74c5115d3436c9c74e6c [file] [log] [blame]
Scott Michel266bc8f2007-12-04 22:23:35 +00001//===-- SPUAsmPrinter.cpp - Print machine instrs to Cell SPU assembly -------=//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by a team from the Computer Systems Research
Scott Michel2466c372007-12-05 01:40:25 +00006// Department at The Aerospace Corporation and is distributed under the
7// University of Illinois Open Source License. See LICENSE.TXT for details.
Scott Michel266bc8f2007-12-04 22:23:35 +00008//
9//===----------------------------------------------------------------------===//
10//
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'.
14//
15// Documentation at http://developer.apple.com/documentation/DeveloperTools/
16// Reference/Assembler/ASMIntroduction/chapter_1_section_1.html
17//
18//===----------------------------------------------------------------------===//
19
20#define DEBUG_TYPE "asmprinter"
21#include "SPU.h"
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"
43#include <set>
44using namespace llvm;
45
46namespace {
47 STATISTIC(EmittedInsts, "Number of machine instrs printed");
48
49 const std::string bss_section(".bss");
50
51 struct VISIBILITY_HIDDEN SPUAsmPrinter : public AsmPrinter {
52 std::set<std::string> FnStubs, GVStubs;
53
54 SPUAsmPrinter(std::ostream &O, TargetMachine &TM, const TargetAsmInfo *T) :
55 AsmPrinter(O, TM, T)
56 {
57 }
58
59 virtual const char *getPassName() const {
60 return "STI CBEA SPU Assembly Printer";
61 }
62
63 SPUTargetMachine &getTM() {
64 return static_cast<SPUTargetMachine&>(TM);
65 }
66
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
70 /// returns false.
71 bool printInstruction(const MachineInstr *MI);
72
73 void printMachineInstruction(const MachineInstr *MI);
74 void printOp(const MachineOperand &MO);
75
76 /// printRegister - Print register according to target requirements.
77 ///
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;
82 }
83
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();
91 } else {
92 printOp(MO);
93 }
94 }
95
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);
100
101
102 void
103 printS7ImmOperand(const MachineInstr *MI, unsigned OpNo)
104 {
105 int value = MI->getOperand(OpNo).getImmedValue();
106 value = (value << (32 - 7)) >> (32 - 7);
107
108 assert((value >= -(1 << 8) && value <= (1 << 7) - 1)
109 && "Invalid s7 argument");
110 O << value;
111 }
112
113 void
114 printU7ImmOperand(const MachineInstr *MI, unsigned OpNo)
115 {
116 unsigned int value = MI->getOperand(OpNo).getImmedValue();
117 assert(value < (1 << 8) && "Invalid u7 argument");
118 O << value;
119 }
120
121 void
122 printMemRegImmS7(const MachineInstr *MI, unsigned OpNo)
123 {
124 char value = MI->getOperand(OpNo).getImmedValue();
125 O << (int) value;
126 O << "(";
127 printOperand(MI, OpNo+1);
128 O << ")";
129 }
130
131 void
132 printS16ImmOperand(const MachineInstr *MI, unsigned OpNo)
133 {
134 O << (short) MI->getOperand(OpNo).getImmedValue();
135 }
136
137 void
138 printU16ImmOperand(const MachineInstr *MI, unsigned OpNo)
139 {
140 O << (unsigned short)MI->getOperand(OpNo).getImmedValue();
141 }
142
143 void
144 printU32ImmOperand(const MachineInstr *MI, unsigned OpNo)
145 {
146 O << (unsigned)MI->getOperand(OpNo).getImmedValue();
147 }
148
149 void
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;
156 O << ", ";
157 printOperand(MI, OpNo+1);
158 }
159
160 void
161 printU18ImmOperand(const MachineInstr *MI, unsigned OpNo)
162 {
163 unsigned int value = MI->getOperand(OpNo).getImmedValue();
164 assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
165 O << value;
166 }
167
168 void
169 printS10ImmOperand(const MachineInstr *MI, unsigned OpNo)
170 {
171 short value = (short) (((int) MI->getOperand(OpNo).getImmedValue() << 16)
172 >> 16);
173 assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
174 && "Invalid s10 argument");
175 O << value;
176 }
177
178 void
179 printU10ImmOperand(const MachineInstr *MI, unsigned OpNo)
180 {
181 short value = (short) (((int) MI->getOperand(OpNo).getImmedValue() << 16)
182 >> 16);
183 assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
184 O << value;
185 }
186
187 void
188 printMemRegImmS10(const MachineInstr *MI, unsigned OpNo)
189 {
190 const MachineOperand &MO = MI->getOperand(OpNo);
191 assert(MO.isImmediate()
192 && "printMemRegImmS10 first operand is not immedate");
193 printS10ImmOperand(MI, OpNo);
194 O << "(";
195 printOperand(MI, OpNo+1);
196 O << ")";
197 }
198
199 void
200 printAddr256K(const MachineInstr *MI, unsigned OpNo)
201 {
202 /* Note: operand 1 is an offset or symbol name. Operand 2 is
203 ignored. */
204 if (MI->getOperand(OpNo).isImmediate()) {
205 printS16ImmOperand(MI, OpNo);
206 } else {
207 printOp(MI->getOperand(OpNo));
208 }
209 }
210
211 void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
212 printOp(MI->getOperand(OpNo));
213 }
214
215 void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo) {
216 printOp(MI->getOperand(OpNo));
217 O << "-.";
218 }
219
220 void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
221 if (MI->getOperand(OpNo).isImmediate()) {
222 printS16ImmOperand(MI, OpNo);
223 } else {
224 printOp(MI->getOperand(OpNo));
225 O << "@h";
226 }
227 }
228
229 void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
230 if (MI->getOperand(OpNo).isImmediate()) {
231 printS16ImmOperand(MI, OpNo);
232 } else {
233 printOp(MI->getOperand(OpNo));
234 O << "@l";
235 }
236 }
237
238 /// Print local store address
239 void printSymbolLSA(const MachineInstr *MI, unsigned OpNo) {
240 printOp(MI->getOperand(OpNo));
241 }
242
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");
248 O << -value;
249 } else {
250 assert(0 && "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
251 }
252 }
253
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");
259 O << -value;
260 } else {
261 assert(0 && "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
262 }
263 }
264
265 virtual bool runOnMachineFunction(MachineFunction &F) = 0;
266 virtual bool doFinalization(Module &M) = 0;
267 };
268
269 /// LinuxAsmPrinter - SPU assembly printer, customized for Linux
270 struct VISIBILITY_HIDDEN LinuxAsmPrinter : public SPUAsmPrinter {
271
272 DwarfWriter DW;
273
274 LinuxAsmPrinter(std::ostream &O, SPUTargetMachine &TM,
275 const TargetAsmInfo *T) :
276 SPUAsmPrinter(O, TM, T),
277 DW(O, this, T)
278 { }
279
280 virtual const char *getPassName() const {
281 return "STI CBEA SPU Assembly Printer";
282 }
283
284 bool runOnMachineFunction(MachineFunction &F);
285 bool doInitialization(Module &M);
286 bool doFinalization(Module &M);
287
288 void getAnalysisUsage(AnalysisUsage &AU) const {
289 AU.setPreservesAll();
290 AU.addRequired<MachineModuleInfo>();
291 SPUAsmPrinter::getAnalysisUsage(AU);
292 }
293
294 /// getSectionForFunction - Return the section that we should emit the
295 /// specified function body into.
296 virtual std::string getSectionForFunction(const Function &F) const;
297 };
298} // end of anonymous namespace
299
300// Include the auto-generated portion of the assembly writer
301#include "SPUGenAsmWriter.inc"
302
303void SPUAsmPrinter::printOp(const MachineOperand &MO) {
304 switch (MO.getType()) {
305 case MachineOperand::MO_Immediate:
306 cerr << "printOp() does not handle immediate values\n";
307 abort();
308 return;
309
310 case MachineOperand::MO_MachineBasicBlock:
311 printBasicBlockLabel(MO.getMachineBasicBlock());
312 return;
313 case MachineOperand::MO_JumpTableIndex:
314 O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
315 << '_' << MO.getJumpTableIndex();
316 // FIXME: PIC relocation model
317 return;
318 case MachineOperand::MO_ConstantPoolIndex:
319 O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
320 << '_' << MO.getConstantPoolIndex();
321 return;
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";
328 return;
329 }
330 O << TAI->getGlobalPrefix() << MO.getSymbolName();
331 return;
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);
336
337 // External or weakly linked global variables need non-lazily-resolved
338 // stubs
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";
344 return;
345 }
346 }
347 O << Name;
348
349 if (GV->hasExternalWeakLinkage())
350 ExtWeakSymbols.insert(GV);
351 return;
352 }
353
354 default:
355 O << "<unknown operand type: " << MO.getType() << ">";
356 return;
357 }
358}
359
360/// PrintAsmOperand - Print out an operand for an inline asm expression.
361///
362bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
363 unsigned AsmVariant,
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.
368
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())
376 return true;
377 ++OpNo; // Return the high-part.
378 break;
379 }
380 }
381
382 printOperand(MI, OpNo);
383 return false;
384}
385
386bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
387 unsigned OpNo,
388 unsigned AsmVariant,
389 const char *ExtraCode) {
390 if (ExtraCode && ExtraCode[0])
391 return true; // Unknown modifier.
392 printMemRegReg(MI, OpNo);
393 return false;
394}
395
396/// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax
397/// to the current output stream.
398///
399void SPUAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
400 ++EmittedInsts;
401 printInstruction(MI);
402}
403
404
405
406std::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...
414 }
415}
416
417/// runOnMachineFunction - This uses the printMachineInstruction()
418/// method to print assembly for each instruction.
419///
420bool
421LinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF)
422{
423 DW.SetModuleInfo(&getAnalysis<MachineModuleInfo>());
424
425 SetupMachineFunction(MF);
426 O << "\n\n";
427
428 // Print out constants referenced by the function
429 EmitConstantPool(MF.getConstantPool());
430
431 // Print out labels for the function.
432 const Function *F = MF.getFunction();
433
434 SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
435 EmitAlignment(3, F);
436
437 switch (F->getLinkage()) {
438 default: assert(0 && "Unknown linkage type!");
439 case Function::InternalLinkage: // Symbols default to internal.
440 break;
441 case Function::ExternalLinkage:
442 O << "\t.global\t" << CurrentFnName << "\n"
443 << "\t.type\t" << CurrentFnName << ", @function\n";
444 break;
445 case Function::WeakLinkage:
446 case Function::LinkOnceLinkage:
447 O << "\t.global\t" << CurrentFnName << "\n";
448 O << "\t.weak_definition\t" << CurrentFnName << "\n";
449 break;
450 }
451 O << CurrentFnName << ":\n";
452
453 // Emit pre-function debug information.
454 DW.BeginFunction(&MF);
455
456 // Print out code for the function.
457 for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
458 I != E; ++I) {
459 // Print a label for the basic block.
460 if (I != MF.begin()) {
461 printBasicBlockLabel(I, true);
462 O << '\n';
463 }
464 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
465 II != E; ++II) {
466 // Print the assembly for the instruction.
467 O << "\t";
468 printMachineInstruction(II);
469 }
470 }
471
472 O << "\t.size\t" << CurrentFnName << ",.-" << CurrentFnName << "\n";
473
474 // Print out jump tables referenced by the function.
475 EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
476
477 // Emit post-function debug information.
478 DW.EndFunction();
479
480 // We didn't modify anything.
481 return false;
482}
483
484
485bool LinuxAsmPrinter::doInitialization(Module &M) {
486 bool Result = AsmPrinter::doInitialization(M);
487 SwitchToTextSection(TAI->getTextSection());
488 // Emit initial debug information.
489 DW.BeginModule(&M);
490 return Result;
491}
492
493bool LinuxAsmPrinter::doFinalization(Module &M) {
494 const TargetData *TD = TM.getTargetData();
495
496 // Print out module-level global variables here.
497 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
498 I != E; ++I) {
499 if (!I->hasInitializer()) continue; // External global require no code
500
501 // Check to see if this is a special global used by LLVM, if so, emit it.
502 if (EmitSpecialLLVMGlobal(I))
503 continue;
504
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);
509
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';
524 O << name << ":\n";
525 O << "\t.zero\t" << Size;
526 } else if (I->hasInternalLinkage()) {
527 SwitchToDataSection("\t.data", I);
528 O << TAI->getLCOMMDirective() << name << "," << Size << "," << Align;
529 } else {
530 SwitchToDataSection("\t.data", I);
531 O << ".comm " << name << "," << Size;
532 }
533 O << "\t\t# '" << I->getName() << "'\n";
534 } else {
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);
541 break;
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";
548 // FALL THROUGH
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);
554 break;
555 }
556 }
557
558 SwitchToDataSection("\t.data", I);
559 break;
560 default:
561 cerr << "Unknown linkage type!";
562 abort();
563 }
564
565 EmitAlignment(Align, I);
566 O << name << ":\t\t\t\t# '" << I->getName() << "'\n";
567
568 // If the initializer is a extern weak symbol, remember to emit the weak
569 // reference!
570 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
571 if (GV->hasExternalWeakLinkage())
572 ExtWeakSymbols.insert(GV);
573
574 EmitGlobalConstant(C);
575 O << '\n';
576 }
577 }
578
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();
582 i != e; ++i) {
583 SwitchToTextSection(".section __TEXT,__picsymbolstub1,symbol_stubs,"
584 "pure_instructions,32");
585 EmitAlignment(4);
586 O << "L" << *i << "$stub:\n";
587 O << "\t.indirect_symbol " << *i << "\n";
588 O << "\tmflr r0\n";
589 O << "\tbcl 20,31,L0$" << *i << "\n";
590 O << "L0$" << *i << ":\n";
591 O << "\tmflr r11\n";
592 O << "\taddis r11,r11,ha16(L" << *i << "$lazy_ptr-L0$" << *i << ")\n";
593 O << "\tmtlr r0\n";
594 O << "\tlwzu r12,lo16(L" << *i << "$lazy_ptr-L0$" << *i << ")(r11)\n";
595 O << "\tmtctr r12\n";
596 O << "\tbctr\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";
601 }
602 } else {
603 for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
604 i != e; ++i) {
605 SwitchToTextSection(".section __TEXT,__symbol_stub1,symbol_stubs,"
606 "pure_instructions,16");
607 EmitAlignment(4);
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";
613 O << "\tbctr\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";
618 }
619 }
620
621 O << "\n";
622
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";
630 O << "\t.long\t0\n";
631 }
632 }
633
634 // Emit initial debug information.
635 DW.EndModule();
636
637 // Emit ident information
Scott Michel86c041f2007-12-20 00:44:13 +0000638 O << "\t.ident\t\"(llvm 2.2+) STI CBEA Cell SPU backend\"\n";
Scott Michel266bc8f2007-12-04 22:23:35 +0000639
640 return AsmPrinter::doFinalization(M);
641}
642
643
644
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.
648///
649FunctionPass *llvm::createSPUAsmPrinterPass(std::ostream &o,
650 SPUTargetMachine &tm) {
651 return new LinuxAsmPrinter(o, tm, tm.getTargetAsmInfo());
652}
653