1 //===-- SPUAsmPrinter.cpp - Print machine instrs to Cell SPU assembly -------=//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains a printer that converts from our internal representation
11 // of machine-dependent LLVM code to Cell SPU assembly language. This printer
12 // is the output mechanism used by `llc'.
14 //===----------------------------------------------------------------------===//
16 #define DEBUG_TYPE "asmprinter"
18 #include "SPUTargetMachine.h"
19 #include "llvm/Constants.h"
20 #include "llvm/DerivedTypes.h"
21 #include "llvm/Module.h"
22 #include "llvm/Assembly/Writer.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/MachineInstr.h"
28 #include "llvm/Support/Mangler.h"
29 #include "llvm/Support/MathExtras.h"
30 #include "llvm/Support/CommandLine.h"
31 #include "llvm/Support/Debug.h"
32 #include "llvm/Support/Compiler.h"
33 #include "llvm/Support/raw_ostream.h"
34 #include "llvm/Target/TargetAsmInfo.h"
35 #include "llvm/Target/TargetRegisterInfo.h"
36 #include "llvm/Target/TargetInstrInfo.h"
37 #include "llvm/Target/TargetOptions.h"
38 #include "llvm/ADT/Statistic.h"
39 #include "llvm/ADT/StringExtras.h"
44 STATISTIC(EmittedInsts, "Number of machine instrs printed");
46 const std::string bss_section(".bss");
48 struct VISIBILITY_HIDDEN SPUAsmPrinter : public AsmPrinter {
49 std::set<std::string> FnStubs, GVStubs;
51 SPUAsmPrinter(raw_ostream &O, TargetMachine &TM, const TargetAsmInfo *T) :
56 virtual const char *getPassName() const {
57 return "STI CBEA SPU Assembly Printer";
60 SPUTargetMachine &getTM() {
61 return static_cast<SPUTargetMachine&>(TM);
64 /// printInstruction - This method is automatically generated by tablegen
65 /// from the instruction set description. This method returns true if the
66 /// machine instruction was sufficiently described to print it, otherwise it
68 bool printInstruction(const MachineInstr *MI);
70 void printMachineInstruction(const MachineInstr *MI);
71 void printOp(const MachineOperand &MO);
73 /// printRegister - Print register according to target requirements.
75 void printRegister(const MachineOperand &MO, bool R0AsZero) {
76 unsigned RegNo = MO.getReg();
77 assert(TargetRegisterInfo::isPhysicalRegister(RegNo) &&
79 O << TM.getRegisterInfo()->get(RegNo).AsmName;
82 void printOperand(const MachineInstr *MI, unsigned OpNo) {
83 const MachineOperand &MO = MI->getOperand(OpNo);
85 assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physreg??");
86 O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
87 } else if (MO.isImm()) {
94 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
95 unsigned AsmVariant, const char *ExtraCode);
96 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
97 unsigned AsmVariant, const char *ExtraCode);
101 printS7ImmOperand(const MachineInstr *MI, unsigned OpNo)
103 int value = MI->getOperand(OpNo).getImm();
104 value = (value << (32 - 7)) >> (32 - 7);
106 assert((value >= -(1 << 8) && value <= (1 << 7) - 1)
107 && "Invalid s7 argument");
112 printU7ImmOperand(const MachineInstr *MI, unsigned OpNo)
114 unsigned int value = MI->getOperand(OpNo).getImm();
115 assert(value < (1 << 8) && "Invalid u7 argument");
120 printMemRegImmS7(const MachineInstr *MI, unsigned OpNo)
122 char value = MI->getOperand(OpNo).getImm();
125 printOperand(MI, OpNo+1);
130 printS16ImmOperand(const MachineInstr *MI, unsigned OpNo)
132 O << (short) MI->getOperand(OpNo).getImm();
136 printU16ImmOperand(const MachineInstr *MI, unsigned OpNo)
138 O << (unsigned short)MI->getOperand(OpNo).getImm();
142 printU32ImmOperand(const MachineInstr *MI, unsigned OpNo)
144 O << (unsigned)MI->getOperand(OpNo).getImm();
148 printMemRegReg(const MachineInstr *MI, unsigned OpNo) {
149 // When used as the base register, r0 reads constant zero rather than
150 // the value contained in the register. For this reason, the darwin
151 // assembler requires that we print r0 as 0 (no r) when used as the base.
152 const MachineOperand &MO = MI->getOperand(OpNo);
153 O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
155 printOperand(MI, OpNo+1);
159 printU18ImmOperand(const MachineInstr *MI, unsigned OpNo)
161 unsigned int value = MI->getOperand(OpNo).getImm();
162 assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
167 printS10ImmOperand(const MachineInstr *MI, unsigned OpNo)
169 short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
171 assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
172 && "Invalid s10 argument");
177 printU10ImmOperand(const MachineInstr *MI, unsigned OpNo)
179 short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
181 assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
186 printMemRegImmS10(const MachineInstr *MI, unsigned OpNo)
188 const MachineOperand &MO = MI->getOperand(OpNo);
190 "printMemRegImmS10 first operand is not immedate");
191 int64_t value = int64_t(MI->getOperand(OpNo).getImm());
192 assert((value >= -(1 << (9+4)) && value <= (1 << (9+4)) - 1)
193 && "Invalid dform s10 offset argument");
195 printOperand(MI, OpNo+1);
200 printAddr256K(const MachineInstr *MI, unsigned OpNo)
202 /* Note: operand 1 is an offset or symbol name. */
203 if (MI->getOperand(OpNo).isImm()) {
204 printS16ImmOperand(MI, OpNo);
206 printOp(MI->getOperand(OpNo));
207 if (MI->getOperand(OpNo+1).isImm()) {
208 int displ = int(MI->getOperand(OpNo+1).getImm());
217 void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
218 printOp(MI->getOperand(OpNo));
221 void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo) {
222 printOp(MI->getOperand(OpNo));
226 void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
227 if (MI->getOperand(OpNo).isImm()) {
228 printS16ImmOperand(MI, OpNo);
230 printOp(MI->getOperand(OpNo));
235 void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
236 if (MI->getOperand(OpNo).isImm()) {
237 printS16ImmOperand(MI, OpNo);
239 printOp(MI->getOperand(OpNo));
244 /// Print local store address
245 void printSymbolLSA(const MachineInstr *MI, unsigned OpNo) {
246 printOp(MI->getOperand(OpNo));
249 void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
250 if (MI->getOperand(OpNo).isImm()) {
251 int value = (int) MI->getOperand(OpNo).getImm();
252 assert((value >= 0 && value < 16)
253 && "Invalid negated immediate rotate 7-bit argument");
256 assert(0 &&"Invalid/non-immediate rotate amount in printRotateNeg7Imm");
260 void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
261 if (MI->getOperand(OpNo).isImm()) {
262 int value = (int) MI->getOperand(OpNo).getImm();
263 assert((value >= 0 && value < 32)
264 && "Invalid negated immediate rotate 7-bit argument");
267 assert(0 &&"Invalid/non-immediate rotate amount in printRotateNeg7Imm");
271 virtual bool runOnMachineFunction(MachineFunction &F) = 0;
272 //! Assembly printer cleanup after function has been emitted
273 virtual bool doFinalization(Module &M) = 0;
276 /// LinuxAsmPrinter - SPU assembly printer, customized for Linux
277 struct VISIBILITY_HIDDEN LinuxAsmPrinter : public SPUAsmPrinter {
280 MachineModuleInfo *MMI;
282 LinuxAsmPrinter(raw_ostream &O, SPUTargetMachine &TM,
283 const TargetAsmInfo *T) :
284 SPUAsmPrinter(O, TM, T),
289 virtual const char *getPassName() const {
290 return "STI CBEA SPU Assembly Printer";
293 bool runOnMachineFunction(MachineFunction &F);
294 bool doInitialization(Module &M);
295 //! Dump globals, perform cleanup after function emission
296 bool doFinalization(Module &M);
298 void getAnalysisUsage(AnalysisUsage &AU) const {
299 AU.setPreservesAll();
300 AU.addRequired<MachineModuleInfo>();
301 SPUAsmPrinter::getAnalysisUsage(AU);
304 //! Emit a global variable according to its section and type
305 void printModuleLevelGV(const GlobalVariable* GVar);
307 } // end of anonymous namespace
309 // Include the auto-generated portion of the assembly writer
310 #include "SPUGenAsmWriter.inc"
312 void SPUAsmPrinter::printOp(const MachineOperand &MO) {
313 switch (MO.getType()) {
314 case MachineOperand::MO_Immediate:
315 cerr << "printOp() does not handle immediate values\n";
319 case MachineOperand::MO_MachineBasicBlock:
320 printBasicBlockLabel(MO.getMBB());
322 case MachineOperand::MO_JumpTableIndex:
323 O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
324 << '_' << MO.getIndex();
326 case MachineOperand::MO_ConstantPoolIndex:
327 O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
328 << '_' << MO.getIndex();
330 case MachineOperand::MO_ExternalSymbol:
331 // Computing the address of an external symbol, not calling it.
332 if (TM.getRelocationModel() != Reloc::Static) {
333 std::string Name(TAI->getGlobalPrefix()); Name += MO.getSymbolName();
334 GVStubs.insert(Name);
335 O << "L" << Name << "$non_lazy_ptr";
338 O << TAI->getGlobalPrefix() << MO.getSymbolName();
340 case MachineOperand::MO_GlobalAddress: {
341 // Computing the address of a global symbol, not calling it.
342 GlobalValue *GV = MO.getGlobal();
343 std::string Name = Mang->getValueName(GV);
345 // External or weakly linked global variables need non-lazily-resolved
347 if (TM.getRelocationModel() != Reloc::Static) {
348 if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
349 GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
350 GVStubs.insert(Name);
351 O << "L" << Name << "$non_lazy_ptr";
357 if (GV->hasExternalWeakLinkage())
358 ExtWeakSymbols.insert(GV);
363 O << "<unknown operand type: " << MO.getType() << ">";
368 /// PrintAsmOperand - Print out an operand for an inline asm expression.
370 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
372 const char *ExtraCode) {
373 // Does this asm operand have a single letter operand modifier?
374 if (ExtraCode && ExtraCode[0]) {
375 if (ExtraCode[1] != 0) return true; // Unknown modifier.
377 switch (ExtraCode[0]) {
378 default: return true; // Unknown modifier.
379 case 'L': // Write second word of DImode reference.
380 // Verify that this operand has two consecutive registers.
381 if (!MI->getOperand(OpNo).isReg() ||
382 OpNo+1 == MI->getNumOperands() ||
383 !MI->getOperand(OpNo+1).isReg())
385 ++OpNo; // Return the high-part.
390 printOperand(MI, OpNo);
394 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
397 const char *ExtraCode) {
398 if (ExtraCode && ExtraCode[0])
399 return true; // Unknown modifier.
400 printMemRegReg(MI, OpNo);
404 /// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax
405 /// to the current output stream.
407 void SPUAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
409 printInstruction(MI);
412 /// runOnMachineFunction - This uses the printMachineInstruction()
413 /// method to print assembly for each instruction.
416 LinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF)
418 SetupMachineFunction(MF);
421 // Print out constants referenced by the function
422 EmitConstantPool(MF.getConstantPool());
424 // Print out labels for the function.
425 const Function *F = MF.getFunction();
427 SwitchToSection(TAI->SectionForGlobal(F));
430 switch (F->getLinkage()) {
431 default: assert(0 && "Unknown linkage type!");
432 case Function::InternalLinkage: // Symbols default to internal.
434 case Function::ExternalLinkage:
435 O << "\t.global\t" << CurrentFnName << "\n"
436 << "\t.type\t" << CurrentFnName << ", @function\n";
438 case Function::WeakLinkage:
439 case Function::LinkOnceLinkage:
440 O << "\t.global\t" << CurrentFnName << "\n";
441 O << "\t.weak_definition\t" << CurrentFnName << "\n";
444 O << CurrentFnName << ":\n";
446 // Emit pre-function debug information.
447 DW.BeginFunction(&MF);
449 // Print out code for the function.
450 for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
452 // Print a label for the basic block.
453 if (I != MF.begin()) {
454 printBasicBlockLabel(I, true, true);
457 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
459 // Print the assembly for the instruction.
460 printMachineInstruction(II);
464 O << "\t.size\t" << CurrentFnName << ",.-" << CurrentFnName << "\n";
466 // Print out jump tables referenced by the function.
467 EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
469 // Emit post-function debug information.
472 // We didn't modify anything.
477 bool LinuxAsmPrinter::doInitialization(Module &M) {
478 bool Result = AsmPrinter::doInitialization(M);
479 SwitchToTextSection("\t.text");
480 // Emit initial debug information.
482 MMI = getAnalysisToUpdate<MachineModuleInfo>();
483 DW.SetModuleInfo(MMI);
487 /// PrintUnmangledNameSafely - Print out the printable characters in the name.
488 /// Don't print things like \n or \0.
489 static void PrintUnmangledNameSafely(const Value *V, raw_ostream &OS) {
490 for (const char *Name = V->getNameStart(), *E = Name+V->getNameLen();
497 Emit a global variable according to its section, alignment, etc.
499 \note This code was shamelessly copied from the PowerPC's assembly printer,
500 which sort of screams for some kind of refactorization of common code.
502 void LinuxAsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) {
503 const TargetData *TD = TM.getTargetData();
505 if (!GVar->hasInitializer())
508 // Check to see if this is a special global used by LLVM, if so, emit it.
509 if (EmitSpecialLLVMGlobal(GVar))
512 std::string name = Mang->getValueName(GVar);
514 printVisibility(name, GVar->getVisibility());
516 Constant *C = GVar->getInitializer();
517 const Type *Type = C->getType();
518 unsigned Size = TD->getABITypeSize(Type);
519 unsigned Align = TD->getPreferredAlignmentLog(GVar);
521 SwitchToSection(TAI->SectionForGlobal(GVar));
523 if (C->isNullValue() && /* FIXME: Verify correct */
524 !GVar->hasSection() &&
525 (GVar->hasInternalLinkage() || GVar->hasExternalLinkage() ||
526 GVar->mayBeOverridden())) {
527 if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
529 if (GVar->hasExternalLinkage()) {
530 O << "\t.global " << name << '\n';
531 O << "\t.type " << name << ", @object\n";
533 O << "\t.zero " << Size << '\n';
534 } else if (GVar->hasInternalLinkage()) {
535 O << TAI->getLCOMMDirective() << name << ',' << Size;
537 O << ".comm " << name << ',' << Size;
539 O << "\t\t" << TAI->getCommentString() << " '";
540 PrintUnmangledNameSafely(GVar, O);
545 switch (GVar->getLinkage()) {
546 // Should never be seen for the CellSPU platform...
547 case GlobalValue::LinkOnceLinkage:
548 case GlobalValue::WeakLinkage:
549 case GlobalValue::CommonLinkage:
550 O << "\t.global " << name << '\n'
551 << "\t.type " << name << ", @object\n"
552 << "\t.weak " << name << '\n';
554 case GlobalValue::AppendingLinkage:
555 // FIXME: appending linkage variables should go into a section of
556 // their name or something. For now, just emit them as external.
557 case GlobalValue::ExternalLinkage:
558 // If external or appending, declare as a global symbol
559 O << "\t.global " << name << '\n'
560 << "\t.type " << name << ", @object\n";
562 case GlobalValue::InternalLinkage:
565 cerr << "Unknown linkage type!";
569 EmitAlignment(Align, GVar);
570 O << name << ":\t\t\t\t" << TAI->getCommentString() << " '";
571 PrintUnmangledNameSafely(GVar, O);
574 // If the initializer is a extern weak symbol, remember to emit the weak
576 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
577 if (GV->hasExternalWeakLinkage())
578 ExtWeakSymbols.insert(GV);
580 EmitGlobalConstant(C);
584 bool LinuxAsmPrinter::doFinalization(Module &M) {
585 // Print out module-level global variables here.
586 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
588 printModuleLevelGV(I);
592 // Emit initial debug information.
595 return AsmPrinter::doFinalization(M);
598 /// createSPUCodePrinterPass - Returns a pass that prints the Cell SPU
599 /// assembly code for a MachineFunction to the given output stream, in a format
600 /// that the Linux SPU assembler can deal with.
602 FunctionPass *llvm::createSPUAsmPrinterPass(raw_ostream &o,
603 SPUTargetMachine &tm) {
604 return new LinuxAsmPrinter(o, tm, tm.getTargetAsmInfo());