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/MC/MCStreamer.h"
29 #include "llvm/MC/MCAsmInfo.h"
30 #include "llvm/MC/MCSymbol.h"
31 #include "llvm/Target/TargetLoweringObjectFile.h"
32 #include "llvm/Target/TargetInstrInfo.h"
33 #include "llvm/Target/TargetOptions.h"
34 #include "llvm/Target/TargetRegisterInfo.h"
35 #include "llvm/Target/TargetRegistry.h"
36 #include "llvm/ADT/Statistic.h"
37 #include "llvm/ADT/StringExtras.h"
38 #include "llvm/Support/CommandLine.h"
39 #include "llvm/Support/Compiler.h"
40 #include "llvm/Support/Debug.h"
41 #include "llvm/Support/ErrorHandling.h"
42 #include "llvm/Support/FormattedStream.h"
43 #include "llvm/Support/Mangler.h"
44 #include "llvm/Support/MathExtras.h"
49 STATISTIC(EmittedInsts, "Number of machine instrs printed");
51 const std::string bss_section(".bss");
53 class VISIBILITY_HIDDEN SPUAsmPrinter : public AsmPrinter {
54 std::set<std::string> FnStubs, GVStubs;
56 explicit SPUAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
57 const MCAsmInfo *T, bool V) :
58 AsmPrinter(O, TM, T, V) {}
60 virtual const char *getPassName() const {
61 return "STI CBEA SPU Assembly Printer";
64 SPUTargetMachine &getTM() {
65 return static_cast<SPUTargetMachine&>(TM);
68 /// printInstruction - This method is automatically generated by tablegen
69 /// from the instruction set description.
70 void printInstruction(const MachineInstr *MI);
71 static const char *getRegisterName(unsigned RegNo);
74 void printMachineInstruction(const MachineInstr *MI);
75 void printOp(const MachineOperand &MO);
77 /// printRegister - Print register according to target requirements.
79 void printRegister(const MachineOperand &MO, bool R0AsZero) {
80 unsigned RegNo = MO.getReg();
81 assert(TargetRegisterInfo::isPhysicalRegister(RegNo) &&
83 O << getRegisterName(RegNo);
86 void printOperand(const MachineInstr *MI, unsigned OpNo) {
87 const MachineOperand &MO = MI->getOperand(OpNo);
89 O << getRegisterName(MO.getReg());
90 } else if (MO.isImm()) {
97 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
98 unsigned AsmVariant, const char *ExtraCode);
99 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
100 unsigned AsmVariant, const char *ExtraCode);
104 printS7ImmOperand(const MachineInstr *MI, unsigned OpNo)
106 int value = MI->getOperand(OpNo).getImm();
107 value = (value << (32 - 7)) >> (32 - 7);
109 assert((value >= -(1 << 8) && value <= (1 << 7) - 1)
110 && "Invalid s7 argument");
115 printU7ImmOperand(const MachineInstr *MI, unsigned OpNo)
117 unsigned int value = MI->getOperand(OpNo).getImm();
118 assert(value < (1 << 8) && "Invalid u7 argument");
123 printShufAddr(const MachineInstr *MI, unsigned OpNo)
125 char value = MI->getOperand(OpNo).getImm();
128 printOperand(MI, OpNo+1);
133 printS16ImmOperand(const MachineInstr *MI, unsigned OpNo)
135 O << (short) MI->getOperand(OpNo).getImm();
139 printU16ImmOperand(const MachineInstr *MI, unsigned OpNo)
141 O << (unsigned short)MI->getOperand(OpNo).getImm();
145 printU32ImmOperand(const MachineInstr *MI, unsigned OpNo)
147 O << (unsigned)MI->getOperand(OpNo).getImm();
151 printMemRegReg(const MachineInstr *MI, unsigned OpNo) {
152 // When used as the base register, r0 reads constant zero rather than
153 // the value contained in the register. For this reason, the darwin
154 // assembler requires that we print r0 as 0 (no r) when used as the base.
155 const MachineOperand &MO = MI->getOperand(OpNo);
156 O << getRegisterName(MO.getReg()) << ", ";
157 printOperand(MI, OpNo+1);
161 printU18ImmOperand(const MachineInstr *MI, unsigned OpNo)
163 unsigned int value = MI->getOperand(OpNo).getImm();
164 assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
169 printS10ImmOperand(const MachineInstr *MI, unsigned OpNo)
171 short value = (short) (((int) MI->getOperand(OpNo).getImm() << 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).getImm() << 16)
183 assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
188 printDFormAddr(const MachineInstr *MI, unsigned OpNo)
190 assert(MI->getOperand(OpNo).isImm() &&
191 "printDFormAddr first operand is not immediate");
192 int64_t value = int64_t(MI->getOperand(OpNo).getImm());
193 int16_t value16 = int16_t(value);
194 assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
195 && "Invalid dform s10 offset argument");
196 O << (value16 & ~0xf) << "(";
197 printOperand(MI, OpNo+1);
202 printAddr256K(const MachineInstr *MI, unsigned OpNo)
204 /* Note: operand 1 is an offset or symbol name. */
205 if (MI->getOperand(OpNo).isImm()) {
206 printS16ImmOperand(MI, OpNo);
208 printOp(MI->getOperand(OpNo));
209 if (MI->getOperand(OpNo+1).isImm()) {
210 int displ = int(MI->getOperand(OpNo+1).getImm());
219 void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
220 printOp(MI->getOperand(OpNo));
223 void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo) {
224 // Used to generate a ".-<target>", but it turns out that the assembler
225 // really wants the target.
227 // N.B.: This operand is used for call targets. Branch hints are another
229 printOp(MI->getOperand(OpNo));
232 void printHBROperand(const MachineInstr *MI, unsigned OpNo) {
233 // HBR operands are generated in front of branches, hence, the
234 // program counter plus the target.
236 printOp(MI->getOperand(OpNo));
239 void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
240 if (MI->getOperand(OpNo).isImm()) {
241 printS16ImmOperand(MI, OpNo);
243 printOp(MI->getOperand(OpNo));
248 void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
249 if (MI->getOperand(OpNo).isImm()) {
250 printS16ImmOperand(MI, OpNo);
252 printOp(MI->getOperand(OpNo));
257 /// Print local store address
258 void printSymbolLSA(const MachineInstr *MI, unsigned OpNo) {
259 printOp(MI->getOperand(OpNo));
262 void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
263 if (MI->getOperand(OpNo).isImm()) {
264 int value = (int) MI->getOperand(OpNo).getImm();
265 assert((value >= 0 && value < 16)
266 && "Invalid negated immediate rotate 7-bit argument");
269 llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
273 void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
274 if (MI->getOperand(OpNo).isImm()) {
275 int value = (int) MI->getOperand(OpNo).getImm();
276 assert((value >= 0 && value <= 32)
277 && "Invalid negated immediate rotate 7-bit argument");
280 llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
284 virtual bool runOnMachineFunction(MachineFunction &F) = 0;
287 /// LinuxAsmPrinter - SPU assembly printer, customized for Linux
288 class VISIBILITY_HIDDEN LinuxAsmPrinter : public SPUAsmPrinter {
290 explicit LinuxAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
291 const MCAsmInfo *T, bool V)
292 : SPUAsmPrinter(O, TM, T, V) {}
294 virtual const char *getPassName() const {
295 return "STI CBEA SPU Assembly Printer";
298 bool runOnMachineFunction(MachineFunction &F);
300 void getAnalysisUsage(AnalysisUsage &AU) const {
301 AU.setPreservesAll();
302 AU.addRequired<MachineModuleInfo>();
303 AU.addRequired<DwarfWriter>();
304 SPUAsmPrinter::getAnalysisUsage(AU);
307 //! Emit a global variable according to its section and type
308 void PrintGlobalVariable(const GlobalVariable* GVar);
310 } // end of anonymous namespace
312 // Include the auto-generated portion of the assembly writer
313 #include "SPUGenAsmWriter.inc"
315 void SPUAsmPrinter::printOp(const MachineOperand &MO) {
316 switch (MO.getType()) {
317 case MachineOperand::MO_Immediate:
318 llvm_report_error("printOp() does not handle immediate values");
321 case MachineOperand::MO_MachineBasicBlock:
322 GetMBBSymbol(MO.getMBB()->getNumber())->print(O, MAI);
324 case MachineOperand::MO_JumpTableIndex:
325 O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
326 << '_' << MO.getIndex();
328 case MachineOperand::MO_ConstantPoolIndex:
329 O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
330 << '_' << MO.getIndex();
332 case MachineOperand::MO_ExternalSymbol:
333 // Computing the address of an external symbol, not calling it.
334 if (TM.getRelocationModel() != Reloc::Static) {
335 std::string Name(MAI->getGlobalPrefix()); Name += MO.getSymbolName();
336 GVStubs.insert(Name);
337 O << "L" << Name << "$non_lazy_ptr";
340 O << MAI->getGlobalPrefix() << MO.getSymbolName();
342 case MachineOperand::MO_GlobalAddress: {
343 // Computing the address of a global symbol, not calling it.
344 GlobalValue *GV = MO.getGlobal();
345 std::string Name = Mang->getMangledName(GV);
347 // External or weakly linked global variables need non-lazily-resolved
349 if (TM.getRelocationModel() != Reloc::Static) {
350 if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
351 GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
352 GVStubs.insert(Name);
353 O << "L" << Name << "$non_lazy_ptr";
362 O << "<unknown operand type: " << MO.getType() << ">";
367 /// PrintAsmOperand - Print out an operand for an inline asm expression.
369 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
371 const char *ExtraCode) {
372 // Does this asm operand have a single letter operand modifier?
373 if (ExtraCode && ExtraCode[0]) {
374 if (ExtraCode[1] != 0) return true; // Unknown modifier.
376 switch (ExtraCode[0]) {
377 default: return true; // Unknown modifier.
378 case 'L': // Write second word of DImode reference.
379 // Verify that this operand has two consecutive registers.
380 if (!MI->getOperand(OpNo).isReg() ||
381 OpNo+1 == MI->getNumOperands() ||
382 !MI->getOperand(OpNo+1).isReg())
384 ++OpNo; // Return the high-part.
389 printOperand(MI, OpNo);
393 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
396 const char *ExtraCode) {
397 if (ExtraCode && ExtraCode[0])
398 return true; // Unknown modifier.
399 printMemRegReg(MI, OpNo);
403 /// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax
404 /// to the current output stream.
406 void SPUAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
408 processDebugLoc(MI->getDebugLoc());
409 printInstruction(MI);
411 if (VerboseAsm && !MI->getDebugLoc().isUnknown())
416 /// runOnMachineFunction - This uses the printMachineInstruction()
417 /// method to print assembly for each instruction.
419 bool LinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
422 SetupMachineFunction(MF);
425 // Print out constants referenced by the function
426 EmitConstantPool(MF.getConstantPool());
428 // Print out labels for the function.
429 const Function *F = MF.getFunction();
431 OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
432 EmitAlignment(MF.getAlignment(), F);
434 switch (F->getLinkage()) {
435 default: llvm_unreachable("Unknown linkage type!");
436 case Function::PrivateLinkage:
437 case Function::LinkerPrivateLinkage:
438 case Function::InternalLinkage: // Symbols default to internal.
440 case Function::ExternalLinkage:
441 O << "\t.global\t" << CurrentFnName << "\n"
442 << "\t.type\t" << CurrentFnName << ", @function\n";
444 case Function::WeakAnyLinkage:
445 case Function::WeakODRLinkage:
446 case Function::LinkOnceAnyLinkage:
447 case Function::LinkOnceODRLinkage:
448 O << "\t.global\t" << CurrentFnName << "\n";
449 O << "\t.weak_definition\t" << CurrentFnName << "\n";
452 O << CurrentFnName << ":\n";
454 // Emit pre-function debug information.
455 DW->BeginFunction(&MF);
457 // Print out code for the function.
458 for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
460 // Print a label for the basic block.
461 if (I != MF.begin()) {
462 EmitBasicBlockStart(I);
465 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
467 // 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.
478 DW->EndFunction(&MF);
480 // We didn't modify anything.
486 Emit a global variable according to its section, alignment, etc.
488 \note This code was shamelessly copied from the PowerPC's assembly printer,
489 which sort of screams for some kind of refactorization of common code.
491 void LinuxAsmPrinter::PrintGlobalVariable(const GlobalVariable *GVar) {
492 const TargetData *TD = TM.getTargetData();
494 if (!GVar->hasInitializer())
497 // Check to see if this is a special global used by LLVM, if so, emit it.
498 if (EmitSpecialLLVMGlobal(GVar))
501 std::string name = Mang->getMangledName(GVar);
503 printVisibility(name, GVar->getVisibility());
505 Constant *C = GVar->getInitializer();
506 const Type *Type = C->getType();
507 unsigned Size = TD->getTypeAllocSize(Type);
508 unsigned Align = TD->getPreferredAlignmentLog(GVar);
510 OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GVar, Mang,
513 if (C->isNullValue() && /* FIXME: Verify correct */
514 !GVar->hasSection() &&
515 (GVar->hasLocalLinkage() || GVar->hasExternalLinkage() ||
516 GVar->isWeakForLinker())) {
517 if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
519 if (GVar->hasExternalLinkage()) {
520 O << "\t.global " << name << '\n';
521 O << "\t.type " << name << ", @object\n";
523 O << "\t.zero " << Size << '\n';
524 } else if (GVar->hasLocalLinkage()) {
525 O << MAI->getLCOMMDirective() << name << ',' << Size;
527 O << ".comm " << name << ',' << Size;
529 O << "\t\t" << MAI->getCommentString() << " '";
530 WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
535 switch (GVar->getLinkage()) {
536 // Should never be seen for the CellSPU platform...
537 case GlobalValue::LinkOnceAnyLinkage:
538 case GlobalValue::LinkOnceODRLinkage:
539 case GlobalValue::WeakAnyLinkage:
540 case GlobalValue::WeakODRLinkage:
541 case GlobalValue::CommonLinkage:
542 O << "\t.global " << name << '\n'
543 << "\t.type " << name << ", @object\n"
544 << "\t.weak " << name << '\n';
546 case GlobalValue::AppendingLinkage:
547 // FIXME: appending linkage variables should go into a section of
548 // their name or something. For now, just emit them as external.
549 case GlobalValue::ExternalLinkage:
550 // If external or appending, declare as a global symbol
551 O << "\t.global " << name << '\n'
552 << "\t.type " << name << ", @object\n";
554 case GlobalValue::PrivateLinkage:
555 case GlobalValue::LinkerPrivateLinkage:
556 case GlobalValue::InternalLinkage:
559 llvm_report_error("Unknown linkage type!");
562 EmitAlignment(Align, GVar);
563 O << name << ":\t\t\t\t" << MAI->getCommentString() << " '";
564 WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
567 EmitGlobalConstant(C);
571 // Force static initialization.
572 extern "C" void LLVMInitializeCellSPUAsmPrinter() {
573 RegisterAsmPrinter<LinuxAsmPrinter> X(TheCellSPUTarget);