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/Target/TargetLoweringObjectFile.h"
31 #include "llvm/Target/TargetInstrInfo.h"
32 #include "llvm/Target/TargetOptions.h"
33 #include "llvm/Target/TargetRegisterInfo.h"
34 #include "llvm/Target/TargetRegistry.h"
35 #include "llvm/ADT/Statistic.h"
36 #include "llvm/ADT/StringExtras.h"
37 #include "llvm/Support/CommandLine.h"
38 #include "llvm/Support/Compiler.h"
39 #include "llvm/Support/Debug.h"
40 #include "llvm/Support/ErrorHandling.h"
41 #include "llvm/Support/FormattedStream.h"
42 #include "llvm/Support/Mangler.h"
43 #include "llvm/Support/MathExtras.h"
48 STATISTIC(EmittedInsts, "Number of machine instrs printed");
50 const std::string bss_section(".bss");
52 class VISIBILITY_HIDDEN SPUAsmPrinter : public AsmPrinter {
53 std::set<std::string> FnStubs, GVStubs;
55 explicit SPUAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
56 const MCAsmInfo *T, bool V) :
57 AsmPrinter(O, TM, T, V) {}
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 void 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(TargetRegisterInfo::isPhysicalRegister(RegNo) &&
82 O << TM.getRegisterInfo()->get(RegNo).AsmName;
85 void printOperand(const MachineInstr *MI, unsigned OpNo) {
86 const MachineOperand &MO = MI->getOperand(OpNo);
88 assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physreg??");
89 O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
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 << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
158 printOperand(MI, OpNo+1);
162 printU18ImmOperand(const MachineInstr *MI, unsigned OpNo)
164 unsigned int value = MI->getOperand(OpNo).getImm();
165 assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
170 printS10ImmOperand(const MachineInstr *MI, unsigned OpNo)
172 short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
174 assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
175 && "Invalid s10 argument");
180 printU10ImmOperand(const MachineInstr *MI, unsigned OpNo)
182 short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
184 assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
189 printDFormAddr(const MachineInstr *MI, unsigned OpNo)
191 assert(MI->getOperand(OpNo).isImm() &&
192 "printDFormAddr first operand is not immediate");
193 int64_t value = int64_t(MI->getOperand(OpNo).getImm());
194 int16_t value16 = int16_t(value);
195 assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
196 && "Invalid dform s10 offset argument");
197 O << (value16 & ~0xf) << "(";
198 printOperand(MI, OpNo+1);
203 printAddr256K(const MachineInstr *MI, unsigned OpNo)
205 /* Note: operand 1 is an offset or symbol name. */
206 if (MI->getOperand(OpNo).isImm()) {
207 printS16ImmOperand(MI, OpNo);
209 printOp(MI->getOperand(OpNo));
210 if (MI->getOperand(OpNo+1).isImm()) {
211 int displ = int(MI->getOperand(OpNo+1).getImm());
220 void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
221 printOp(MI->getOperand(OpNo));
224 void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo) {
225 // Used to generate a ".-<target>", but it turns out that the assembler
226 // really wants the target.
228 // N.B.: This operand is used for call targets. Branch hints are another
230 printOp(MI->getOperand(OpNo));
233 void printHBROperand(const MachineInstr *MI, unsigned OpNo) {
234 // HBR operands are generated in front of branches, hence, the
235 // program counter plus the target.
237 printOp(MI->getOperand(OpNo));
240 void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
241 if (MI->getOperand(OpNo).isImm()) {
242 printS16ImmOperand(MI, OpNo);
244 printOp(MI->getOperand(OpNo));
249 void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
250 if (MI->getOperand(OpNo).isImm()) {
251 printS16ImmOperand(MI, OpNo);
253 printOp(MI->getOperand(OpNo));
258 /// Print local store address
259 void printSymbolLSA(const MachineInstr *MI, unsigned OpNo) {
260 printOp(MI->getOperand(OpNo));
263 void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
264 if (MI->getOperand(OpNo).isImm()) {
265 int value = (int) MI->getOperand(OpNo).getImm();
266 assert((value >= 0 && value < 16)
267 && "Invalid negated immediate rotate 7-bit argument");
270 llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
274 void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
275 if (MI->getOperand(OpNo).isImm()) {
276 int value = (int) MI->getOperand(OpNo).getImm();
277 assert((value >= 0 && value <= 32)
278 && "Invalid negated immediate rotate 7-bit argument");
281 llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
285 virtual bool runOnMachineFunction(MachineFunction &F) = 0;
288 /// LinuxAsmPrinter - SPU assembly printer, customized for Linux
289 class VISIBILITY_HIDDEN LinuxAsmPrinter : public SPUAsmPrinter {
292 explicit LinuxAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
293 const MCAsmInfo *T, bool V)
294 : SPUAsmPrinter(O, TM, T, V), DW(0) {}
296 virtual const char *getPassName() const {
297 return "STI CBEA SPU Assembly Printer";
300 bool runOnMachineFunction(MachineFunction &F);
301 bool doInitialization(Module &M);
303 void getAnalysisUsage(AnalysisUsage &AU) const {
304 AU.setPreservesAll();
305 AU.addRequired<MachineModuleInfo>();
306 AU.addRequired<DwarfWriter>();
307 SPUAsmPrinter::getAnalysisUsage(AU);
310 //! Emit a global variable according to its section and type
311 void PrintGlobalVariable(const GlobalVariable* GVar);
313 } // end of anonymous namespace
315 // Include the auto-generated portion of the assembly writer
316 #include "SPUGenAsmWriter.inc"
318 void SPUAsmPrinter::printOp(const MachineOperand &MO) {
319 switch (MO.getType()) {
320 case MachineOperand::MO_Immediate:
321 llvm_report_error("printOp() does not handle immediate values");
324 case MachineOperand::MO_MachineBasicBlock:
325 printBasicBlockLabel(MO.getMBB());
327 case MachineOperand::MO_JumpTableIndex:
328 O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
329 << '_' << MO.getIndex();
331 case MachineOperand::MO_ConstantPoolIndex:
332 O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
333 << '_' << MO.getIndex();
335 case MachineOperand::MO_ExternalSymbol:
336 // Computing the address of an external symbol, not calling it.
337 if (TM.getRelocationModel() != Reloc::Static) {
338 std::string Name(MAI->getGlobalPrefix()); Name += MO.getSymbolName();
339 GVStubs.insert(Name);
340 O << "L" << Name << "$non_lazy_ptr";
343 O << MAI->getGlobalPrefix() << MO.getSymbolName();
345 case MachineOperand::MO_GlobalAddress: {
346 // Computing the address of a global symbol, not calling it.
347 GlobalValue *GV = MO.getGlobal();
348 std::string Name = Mang->getMangledName(GV);
350 // External or weakly linked global variables need non-lazily-resolved
352 if (TM.getRelocationModel() != Reloc::Static) {
353 if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
354 GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
355 GVStubs.insert(Name);
356 O << "L" << Name << "$non_lazy_ptr";
365 O << "<unknown operand type: " << MO.getType() << ">";
370 /// PrintAsmOperand - Print out an operand for an inline asm expression.
372 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
374 const char *ExtraCode) {
375 // Does this asm operand have a single letter operand modifier?
376 if (ExtraCode && ExtraCode[0]) {
377 if (ExtraCode[1] != 0) return true; // Unknown modifier.
379 switch (ExtraCode[0]) {
380 default: return true; // Unknown modifier.
381 case 'L': // Write second word of DImode reference.
382 // Verify that this operand has two consecutive registers.
383 if (!MI->getOperand(OpNo).isReg() ||
384 OpNo+1 == MI->getNumOperands() ||
385 !MI->getOperand(OpNo+1).isReg())
387 ++OpNo; // Return the high-part.
392 printOperand(MI, OpNo);
396 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
399 const char *ExtraCode) {
400 if (ExtraCode && ExtraCode[0])
401 return true; // Unknown modifier.
402 printMemRegReg(MI, OpNo);
406 /// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax
407 /// to the current output stream.
409 void SPUAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
411 processDebugLoc(MI->getDebugLoc());
412 printInstruction(MI);
415 /// runOnMachineFunction - This uses the printMachineInstruction()
416 /// method to print assembly for each instruction.
418 bool LinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
421 SetupMachineFunction(MF);
424 // Print out constants referenced by the function
425 EmitConstantPool(MF.getConstantPool());
427 // Print out labels for the function.
428 const Function *F = MF.getFunction();
430 OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
431 EmitAlignment(MF.getAlignment(), F);
433 switch (F->getLinkage()) {
434 default: llvm_unreachable("Unknown linkage type!");
435 case Function::PrivateLinkage:
436 case Function::LinkerPrivateLinkage:
437 case Function::InternalLinkage: // Symbols default to internal.
439 case Function::ExternalLinkage:
440 O << "\t.global\t" << CurrentFnName << "\n"
441 << "\t.type\t" << CurrentFnName << ", @function\n";
443 case Function::WeakAnyLinkage:
444 case Function::WeakODRLinkage:
445 case Function::LinkOnceAnyLinkage:
446 case Function::LinkOnceODRLinkage:
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, true);
464 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
466 // Print the assembly for the instruction.
467 printMachineInstruction(II);
471 O << "\t.size\t" << CurrentFnName << ",.-" << CurrentFnName << "\n";
473 // Print out jump tables referenced by the function.
474 EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
476 // Emit post-function debug information.
477 DW->EndFunction(&MF);
479 // We didn't modify anything.
484 bool LinuxAsmPrinter::doInitialization(Module &M) {
485 bool Result = AsmPrinter::doInitialization(M);
486 DW = getAnalysisIfAvailable<DwarfWriter>();
491 Emit a global variable according to its section, alignment, etc.
493 \note This code was shamelessly copied from the PowerPC's assembly printer,
494 which sort of screams for some kind of refactorization of common code.
496 void LinuxAsmPrinter::PrintGlobalVariable(const GlobalVariable *GVar) {
497 const TargetData *TD = TM.getTargetData();
499 if (!GVar->hasInitializer())
502 // Check to see if this is a special global used by LLVM, if so, emit it.
503 if (EmitSpecialLLVMGlobal(GVar))
506 std::string name = Mang->getMangledName(GVar);
508 printVisibility(name, GVar->getVisibility());
510 Constant *C = GVar->getInitializer();
511 const Type *Type = C->getType();
512 unsigned Size = TD->getTypeAllocSize(Type);
513 unsigned Align = TD->getPreferredAlignmentLog(GVar);
515 OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GVar, Mang,
518 if (C->isNullValue() && /* FIXME: Verify correct */
519 !GVar->hasSection() &&
520 (GVar->hasLocalLinkage() || GVar->hasExternalLinkage() ||
521 GVar->isWeakForLinker())) {
522 if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
524 if (GVar->hasExternalLinkage()) {
525 O << "\t.global " << name << '\n';
526 O << "\t.type " << name << ", @object\n";
528 O << "\t.zero " << Size << '\n';
529 } else if (GVar->hasLocalLinkage()) {
530 O << MAI->getLCOMMDirective() << name << ',' << Size;
532 O << ".comm " << name << ',' << Size;
534 O << "\t\t" << MAI->getCommentString() << " '";
535 WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
540 switch (GVar->getLinkage()) {
541 // Should never be seen for the CellSPU platform...
542 case GlobalValue::LinkOnceAnyLinkage:
543 case GlobalValue::LinkOnceODRLinkage:
544 case GlobalValue::WeakAnyLinkage:
545 case GlobalValue::WeakODRLinkage:
546 case GlobalValue::CommonLinkage:
547 O << "\t.global " << name << '\n'
548 << "\t.type " << name << ", @object\n"
549 << "\t.weak " << name << '\n';
551 case GlobalValue::AppendingLinkage:
552 // FIXME: appending linkage variables should go into a section of
553 // their name or something. For now, just emit them as external.
554 case GlobalValue::ExternalLinkage:
555 // If external or appending, declare as a global symbol
556 O << "\t.global " << name << '\n'
557 << "\t.type " << name << ", @object\n";
559 case GlobalValue::PrivateLinkage:
560 case GlobalValue::LinkerPrivateLinkage:
561 case GlobalValue::InternalLinkage:
564 llvm_report_error("Unknown linkage type!");
567 EmitAlignment(Align, GVar);
568 O << name << ":\t\t\t\t" << MAI->getCommentString() << " '";
569 WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
572 EmitGlobalConstant(C);
576 // Force static initialization.
577 extern "C" void LLVMInitializeCellSPUAsmPrinter() {
578 RegisterAsmPrinter<LinuxAsmPrinter> X(TheCellSPUTarget);