Change MCStreamer EmitInstruction interface to take subtarget info
[oota-llvm.git] / lib / Target / Sparc / SparcAsmPrinter.cpp
1 //===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains a printer that converts from our internal representation
11 // of machine-dependent LLVM code to GAS-format SPARC assembly language.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #define DEBUG_TYPE "asm-printer"
16 #include "Sparc.h"
17 #include "InstPrinter/SparcInstPrinter.h"
18 #include "MCTargetDesc/SparcBaseInfo.h"
19 #include "MCTargetDesc/SparcMCExpr.h"
20 #include "SparcInstrInfo.h"
21 #include "SparcTargetMachine.h"
22 #include "SparcTargetStreamer.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/CodeGen/AsmPrinter.h"
25 #include "llvm/CodeGen/MachineInstr.h"
26 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
27 #include "llvm/CodeGen/MachineRegisterInfo.h"
28 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
29 #include "llvm/IR/Mangler.h"
30 #include "llvm/MC/MCAsmInfo.h"
31 #include "llvm/MC/MCContext.h"
32 #include "llvm/MC/MCInst.h"
33 #include "llvm/MC/MCStreamer.h"
34 #include "llvm/MC/MCSymbol.h"
35 #include "llvm/Support/TargetRegistry.h"
36 #include "llvm/Support/raw_ostream.h"
37 using namespace llvm;
38
39 namespace {
40   class SparcAsmPrinter : public AsmPrinter {
41     SparcTargetStreamer &getTargetStreamer() {
42       return static_cast<SparcTargetStreamer &>(
43           *OutStreamer.getTargetStreamer());
44     }
45   public:
46     explicit SparcAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
47       : AsmPrinter(TM, Streamer) {}
48
49     virtual const char *getPassName() const {
50       return "Sparc Assembly Printer";
51     }
52
53     void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
54     void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS,
55                          const char *Modifier = 0);
56     void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
57
58     virtual void EmitFunctionBodyStart();
59     virtual void EmitInstruction(const MachineInstr *MI);
60     virtual void EmitEndOfAsmFile(Module &M);
61
62     static const char *getRegisterName(unsigned RegNo) {
63       return SparcInstPrinter::getRegisterName(RegNo);
64     }
65
66     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
67                          unsigned AsmVariant, const char *ExtraCode,
68                          raw_ostream &O);
69     bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
70                                unsigned AsmVariant, const char *ExtraCode,
71                                raw_ostream &O);
72
73     void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI);
74
75   };
76 } // end of anonymous namespace
77
78 static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind,
79                                       MCSymbol *Sym, MCContext &OutContext) {
80   const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Sym,
81                                                          OutContext);
82   const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym, OutContext);
83   return MCOperand::CreateExpr(expr);
84
85 }
86 static MCOperand createPCXCallOP(MCSymbol *Label,
87                                  MCContext &OutContext) {
88   return createSparcMCOperand(SparcMCExpr::VK_Sparc_None, Label, OutContext);
89 }
90
91 static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind,
92                                     MCSymbol *GOTLabel, MCSymbol *StartLabel,
93                                     MCSymbol *CurLabel,
94                                     MCContext &OutContext)
95 {
96   const MCSymbolRefExpr *GOT = MCSymbolRefExpr::Create(GOTLabel, OutContext);
97   const MCSymbolRefExpr *Start = MCSymbolRefExpr::Create(StartLabel,
98                                                          OutContext);
99   const MCSymbolRefExpr *Cur = MCSymbolRefExpr::Create(CurLabel,
100                                                        OutContext);
101
102   const MCBinaryExpr *Sub = MCBinaryExpr::CreateSub(Cur, Start, OutContext);
103   const MCBinaryExpr *Add = MCBinaryExpr::CreateAdd(GOT, Sub, OutContext);
104   const SparcMCExpr *expr = SparcMCExpr::Create(Kind,
105                                                 Add, OutContext);
106   return MCOperand::CreateExpr(expr);
107 }
108
109 static void EmitCall(MCStreamer &OutStreamer,
110                      MCOperand &Callee,
111                      const MCSubtargetInfo &STI)
112 {
113   MCInst CallInst;
114   CallInst.setOpcode(SP::CALL);
115   CallInst.addOperand(Callee);
116   OutStreamer.EmitInstruction(CallInst, STI);
117 }
118
119 static void EmitSETHI(MCStreamer &OutStreamer,
120                       MCOperand &Imm, MCOperand &RD,
121                       const MCSubtargetInfo &STI)
122 {
123   MCInst SETHIInst;
124   SETHIInst.setOpcode(SP::SETHIi);
125   SETHIInst.addOperand(RD);
126   SETHIInst.addOperand(Imm);
127   OutStreamer.EmitInstruction(SETHIInst, STI);
128 }
129
130 static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
131                        MCOperand &RS1, MCOperand &Src2, MCOperand &RD,
132                        const MCSubtargetInfo &STI)
133 {
134   MCInst Inst;
135   Inst.setOpcode(Opcode);
136   Inst.addOperand(RD);
137   Inst.addOperand(RS1);
138   Inst.addOperand(Src2);
139   OutStreamer.EmitInstruction(Inst, STI);
140 }
141
142 static void EmitOR(MCStreamer &OutStreamer,
143                    MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
144                    const MCSubtargetInfo &STI) {
145   EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD, STI);
146 }
147
148 static void EmitADD(MCStreamer &OutStreamer,
149                     MCOperand &RS1, MCOperand &RS2, MCOperand &RD,
150                     const MCSubtargetInfo &STI) {
151   EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD, STI);
152 }
153
154 static void EmitSHL(MCStreamer &OutStreamer,
155                     MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
156                     const MCSubtargetInfo &STI) {
157   EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD, STI);
158 }
159
160
161 static void EmitHiLo(MCStreamer &OutStreamer,  MCSymbol *GOTSym,
162                      SparcMCExpr::VariantKind HiKind,
163                      SparcMCExpr::VariantKind LoKind,
164                      MCOperand &RD,
165                      MCContext &OutContext,
166                      const MCSubtargetInfo &STI) {
167
168   MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);
169   MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);
170   EmitSETHI(OutStreamer, hi, RD, STI);
171   EmitOR(OutStreamer, RD, lo, RD, STI);
172 }
173
174 void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
175                                                 const MCSubtargetInfo &STI)
176 {
177   MCSymbol *GOTLabel   =
178     OutContext.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
179
180   const MachineOperand &MO = MI->getOperand(0);
181   assert(MO.getReg() != SP::O7 &&
182          "%o7 is assigned as destination for getpcx!");
183
184   MCOperand MCRegOP = MCOperand::CreateReg(MO.getReg());
185
186
187   if (TM.getRelocationModel() != Reloc::PIC_) {
188     // Just load the address of GOT to MCRegOP.
189     switch(TM.getCodeModel()) {
190     default:
191       llvm_unreachable("Unsupported absolute code model");
192     case CodeModel::Small:
193       EmitHiLo(OutStreamer, GOTLabel,
194                SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
195                MCRegOP, OutContext);
196       break;
197     case CodeModel::Medium: {
198       EmitHiLo(OutStreamer, GOTLabel,
199                SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44,
200                MCRegOP, OutContext);
201       MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(12,
202                                                                    OutContext));
203       EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
204       MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44,
205                                           GOTLabel, OutContext);
206       EmitOR(OutStreamer, MCRegOP, lo, MCRegOP);
207       break;
208     }
209     case CodeModel::Large: {
210       EmitHiLo(OutStreamer, GOTLabel,
211                SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM,
212                MCRegOP, OutContext);
213       MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(32,
214                                                                    OutContext));
215       EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
216       // Use register %o7 to load the lower 32 bits.
217       MCOperand RegO7 = MCOperand::CreateReg(SP::O7);
218       EmitHiLo(OutStreamer, GOTLabel,
219                SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
220                RegO7, OutContext);
221       EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP);
222     }
223     }
224     return;
225   }
226
227   MCSymbol *StartLabel = OutContext.CreateTempSymbol();
228   MCSymbol *EndLabel   = OutContext.CreateTempSymbol();
229   MCSymbol *SethiLabel = OutContext.CreateTempSymbol();
230
231   MCOperand RegO7   = MCOperand::CreateReg(SP::O7);
232
233   // <StartLabel>:
234   //   call <EndLabel>
235   // <SethiLabel>:
236   //     sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
237   // <EndLabel>:
238   //   or  <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
239   //   add <MO>, %o7, <MO>
240
241   OutStreamer.EmitLabel(StartLabel);
242   MCOperand Callee =  createPCXCallOP(EndLabel, OutContext);
243   EmitCall(OutStreamer, Callee, STI);
244   OutStreamer.EmitLabel(SethiLabel);
245   MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_HI,
246                                        GOTLabel, StartLabel, SethiLabel,
247                                        OutContext);
248   EmitSETHI(OutStreamer, hiImm, MCRegOP, STI);
249   OutStreamer.EmitLabel(EndLabel);
250   MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_LO,
251                                        GOTLabel, StartLabel, EndLabel,
252                                        OutContext);
253   EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP, STI);
254   EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
255 }
256
257 void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI)
258 {
259
260   switch (MI->getOpcode()) {
261   default: break;
262   case TargetOpcode::DBG_VALUE:
263     // FIXME: Debug Value.
264     return;
265   case SP::GETPCX:
266     LowerGETPCXAndEmitMCInsts(MI, getSubtargetInfo());
267     return;
268   }
269   MachineBasicBlock::const_instr_iterator I = MI;
270   MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
271   do {
272     MCInst TmpInst;
273     LowerSparcMachineInstrToMCInst(I, TmpInst, *this);
274     EmitToStreamer(OutStreamer, TmpInst);
275   } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
276 }
277
278 void SparcAsmPrinter::EmitFunctionBodyStart() {
279   if (!TM.getSubtarget<SparcSubtarget>().is64Bit())
280     return;
281
282   const MachineRegisterInfo &MRI = MF->getRegInfo();
283   const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };
284   for (unsigned i = 0; globalRegs[i] != 0; ++i) {
285     unsigned reg = globalRegs[i];
286     if (MRI.use_empty(reg))
287       continue;
288
289     if  (reg == SP::G6 || reg == SP::G7)
290       getTargetStreamer().emitSparcRegisterIgnore(reg);
291     else
292       getTargetStreamer().emitSparcRegisterScratch(reg);
293   }
294 }
295
296 void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
297                                    raw_ostream &O) {
298   const DataLayout *DL = TM.getDataLayout();
299   const MachineOperand &MO = MI->getOperand (opNum);
300   unsigned TF = MO.getTargetFlags();
301 #ifndef NDEBUG
302   // Verify the target flags.
303   if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) {
304     if (MI->getOpcode() == SP::CALL)
305       assert(TF == SPII::MO_NO_FLAG &&
306              "Cannot handle target flags on call address");
307     else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi)
308       assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH
309               || TF == SPII::MO_TLS_GD_HI22
310               || TF == SPII::MO_TLS_LDM_HI22
311               || TF == SPII::MO_TLS_LDO_HIX22
312               || TF == SPII::MO_TLS_IE_HI22
313               || TF == SPII::MO_TLS_LE_HIX22) &&
314              "Invalid target flags for address operand on sethi");
315     else if (MI->getOpcode() == SP::TLS_CALL)
316       assert((TF == SPII::MO_NO_FLAG
317               || TF == SPII::MO_TLS_GD_CALL
318               || TF == SPII::MO_TLS_LDM_CALL) &&
319              "Cannot handle target flags on tls call address");
320     else if (MI->getOpcode() == SP::TLS_ADDrr)
321       assert((TF == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD
322               || TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) &&
323              "Cannot handle target flags on add for TLS");
324     else if (MI->getOpcode() == SP::TLS_LDrr)
325       assert(TF == SPII::MO_TLS_IE_LD &&
326              "Cannot handle target flags on ld for TLS");
327     else if (MI->getOpcode() == SP::TLS_LDXrr)
328       assert(TF == SPII::MO_TLS_IE_LDX &&
329              "Cannot handle target flags on ldx for TLS");
330     else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri)
331       assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) &&
332              "Cannot handle target flags on xor for TLS");
333     else
334       assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44
335               || TF == SPII::MO_HM
336               || TF == SPII::MO_TLS_GD_LO10
337               || TF == SPII::MO_TLS_LDM_LO10
338               || TF == SPII::MO_TLS_IE_LO10 ) &&
339              "Invalid target flags for small address operand");
340   }
341 #endif
342
343   bool CloseParen = true;
344   switch (TF) {
345   default:
346       llvm_unreachable("Unknown target flags on operand");
347   case SPII::MO_NO_FLAG:
348     CloseParen = false;
349     break;
350   case SPII::MO_LO:  O << "%lo(";  break;
351   case SPII::MO_HI:  O << "%hi(";  break;
352   case SPII::MO_H44: O << "%h44("; break;
353   case SPII::MO_M44: O << "%m44("; break;
354   case SPII::MO_L44: O << "%l44("; break;
355   case SPII::MO_HH:  O << "%hh(";  break;
356   case SPII::MO_HM:  O << "%hm(";  break;
357   case SPII::MO_TLS_GD_HI22:   O << "%tgd_hi22(";   break;
358   case SPII::MO_TLS_GD_LO10:   O << "%tgd_lo10(";   break;
359   case SPII::MO_TLS_GD_ADD:    O << "%tgd_add(";    break;
360   case SPII::MO_TLS_GD_CALL:   O << "%tgd_call(";   break;
361   case SPII::MO_TLS_LDM_HI22:  O << "%tldm_hi22(";  break;
362   case SPII::MO_TLS_LDM_LO10:  O << "%tldm_lo10(";  break;
363   case SPII::MO_TLS_LDM_ADD:   O << "%tldm_add(";   break;
364   case SPII::MO_TLS_LDM_CALL:  O << "%tldm_call(";  break;
365   case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break;
366   case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break;
367   case SPII::MO_TLS_LDO_ADD:   O << "%tldo_add(";   break;
368   case SPII::MO_TLS_IE_HI22:   O << "%tie_hi22(";   break;
369   case SPII::MO_TLS_IE_LO10:   O << "%tie_lo10(";   break;
370   case SPII::MO_TLS_IE_LD:     O << "%tie_ld(";     break;
371   case SPII::MO_TLS_IE_LDX:    O << "%tie_ldx(";    break;
372   case SPII::MO_TLS_IE_ADD:    O << "%tie_add(";    break;
373   case SPII::MO_TLS_LE_HIX22:  O << "%tle_hix22(";  break;
374   case SPII::MO_TLS_LE_LOX10:  O << "%tle_lox10(";   break;
375   }
376
377   switch (MO.getType()) {
378   case MachineOperand::MO_Register:
379     O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
380     break;
381
382   case MachineOperand::MO_Immediate:
383     O << (int)MO.getImm();
384     break;
385   case MachineOperand::MO_MachineBasicBlock:
386     O << *MO.getMBB()->getSymbol();
387     return;
388   case MachineOperand::MO_GlobalAddress:
389     O << *getSymbol(MO.getGlobal());
390     break;
391   case MachineOperand::MO_BlockAddress:
392     O <<  GetBlockAddressSymbol(MO.getBlockAddress())->getName();
393     break;
394   case MachineOperand::MO_ExternalSymbol:
395     O << MO.getSymbolName();
396     break;
397   case MachineOperand::MO_ConstantPoolIndex:
398     O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
399       << MO.getIndex();
400     break;
401   default:
402     llvm_unreachable("<unknown operand type>");
403   }
404   if (CloseParen) O << ")";
405 }
406
407 void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
408                                       raw_ostream &O, const char *Modifier) {
409   printOperand(MI, opNum, O);
410
411   // If this is an ADD operand, emit it like normal operands.
412   if (Modifier && !strcmp(Modifier, "arith")) {
413     O << ", ";
414     printOperand(MI, opNum+1, O);
415     return;
416   }
417
418   if (MI->getOperand(opNum+1).isReg() &&
419       MI->getOperand(opNum+1).getReg() == SP::G0)
420     return;   // don't print "+%g0"
421   if (MI->getOperand(opNum+1).isImm() &&
422       MI->getOperand(opNum+1).getImm() == 0)
423     return;   // don't print "+0"
424
425   O << "+";
426   printOperand(MI, opNum+1, O);
427 }
428
429 /// PrintAsmOperand - Print out an operand for an inline asm expression.
430 ///
431 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
432                                       unsigned AsmVariant,
433                                       const char *ExtraCode,
434                                       raw_ostream &O) {
435   if (ExtraCode && ExtraCode[0]) {
436     if (ExtraCode[1] != 0) return true; // Unknown modifier.
437
438     switch (ExtraCode[0]) {
439     default:
440       // See if this is a generic print operand
441       return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O);
442     case 'r':
443      break;
444     }
445   }
446
447   printOperand(MI, OpNo, O);
448
449   return false;
450 }
451
452 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
453                                             unsigned OpNo, unsigned AsmVariant,
454                                             const char *ExtraCode,
455                                             raw_ostream &O) {
456   if (ExtraCode && ExtraCode[0])
457     return true;  // Unknown modifier
458
459   O << '[';
460   printMemOperand(MI, OpNo, O);
461   O << ']';
462
463   return false;
464 }
465
466 void SparcAsmPrinter::EmitEndOfAsmFile(Module &M) {
467   const TargetLoweringObjectFileELF &TLOFELF =
468     static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering());
469   MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
470
471   // Generate stubs for global variables.
472   MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList();
473   if (!Stubs.empty()) {
474     OutStreamer.SwitchSection(TLOFELF.getDataSection());
475     unsigned PtrSize = TM.getDataLayout()->getPointerSize(0);
476     for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
477       OutStreamer.EmitLabel(Stubs[i].first);
478       OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), PtrSize);
479     }
480   }
481 }
482
483 // Force static initialization.
484 extern "C" void LLVMInitializeSparcAsmPrinter() {
485   RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
486   RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target);
487 }