Fix the DWARF EH encodings for Sparc PIC code.
[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 {
112   MCInst CallInst;
113   CallInst.setOpcode(SP::CALL);
114   CallInst.addOperand(Callee);
115   OutStreamer.EmitInstruction(CallInst);
116 }
117
118 static void EmitSETHI(MCStreamer &OutStreamer,
119                       MCOperand &Imm, MCOperand &RD)
120 {
121   MCInst SETHIInst;
122   SETHIInst.setOpcode(SP::SETHIi);
123   SETHIInst.addOperand(RD);
124   SETHIInst.addOperand(Imm);
125   OutStreamer.EmitInstruction(SETHIInst);
126 }
127
128 static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
129                        MCOperand &RS1, MCOperand &Src2, MCOperand &RD)
130 {
131   MCInst Inst;
132   Inst.setOpcode(Opcode);
133   Inst.addOperand(RD);
134   Inst.addOperand(RS1);
135   Inst.addOperand(Src2);
136   OutStreamer.EmitInstruction(Inst);
137 }
138
139 static void EmitOR(MCStreamer &OutStreamer,
140                    MCOperand &RS1, MCOperand &Imm, MCOperand &RD) {
141   EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD);
142 }
143
144 static void EmitADD(MCStreamer &OutStreamer,
145                     MCOperand &RS1, MCOperand &RS2, MCOperand &RD) {
146   EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD);
147 }
148
149 static void EmitSHL(MCStreamer &OutStreamer,
150                     MCOperand &RS1, MCOperand &Imm, MCOperand &RD) {
151   EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD);
152 }
153
154
155 static void EmitHiLo(MCStreamer &OutStreamer,  MCSymbol *GOTSym,
156                      SparcMCExpr::VariantKind HiKind,
157                      SparcMCExpr::VariantKind LoKind,
158                      MCOperand &RD,
159                      MCContext &OutContext) {
160
161   MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);
162   MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);
163   EmitSETHI(OutStreamer, hi, RD);
164   EmitOR(OutStreamer, RD, lo, RD);
165 }
166
167 void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI)
168 {
169   MCSymbol *GOTLabel   =
170     OutContext.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
171
172   const MachineOperand &MO = MI->getOperand(0);
173   assert(MO.getReg() != SP::O7 &&
174          "%o7 is assigned as destination for getpcx!");
175
176   MCOperand MCRegOP = MCOperand::CreateReg(MO.getReg());
177
178
179   if (TM.getRelocationModel() != Reloc::PIC_) {
180     // Just load the address of GOT to MCRegOP.
181     switch(TM.getCodeModel()) {
182     default:
183       llvm_unreachable("Unsupported absolute code model");
184     case CodeModel::Small:
185       EmitHiLo(OutStreamer, GOTLabel,
186                SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
187                MCRegOP, OutContext);
188       break;
189     case CodeModel::Medium: {
190       EmitHiLo(OutStreamer, GOTLabel,
191                SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44,
192                MCRegOP, OutContext);
193       MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(12,
194                                                                    OutContext));
195       EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
196       MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44,
197                                           GOTLabel, OutContext);
198       EmitOR(OutStreamer, MCRegOP, lo, MCRegOP);
199       break;
200     }
201     case CodeModel::Large: {
202       EmitHiLo(OutStreamer, GOTLabel,
203                SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM,
204                MCRegOP, OutContext);
205       MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(32,
206                                                                    OutContext));
207       EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
208       // Use register %o7 to load the lower 32 bits.
209       MCOperand RegO7 = MCOperand::CreateReg(SP::O7);
210       EmitHiLo(OutStreamer, GOTLabel,
211                SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
212                RegO7, OutContext);
213       EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP);
214     }
215     }
216     return;
217   }
218
219   MCSymbol *StartLabel = OutContext.CreateTempSymbol();
220   MCSymbol *EndLabel   = OutContext.CreateTempSymbol();
221   MCSymbol *SethiLabel = OutContext.CreateTempSymbol();
222
223   MCOperand RegO7   = MCOperand::CreateReg(SP::O7);
224
225   // <StartLabel>:
226   //   call <EndLabel>
227   // <SethiLabel>:
228   //     sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
229   // <EndLabel>:
230   //   or  <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
231   //   add <MO>, %o7, <MO>
232
233   OutStreamer.EmitLabel(StartLabel);
234   MCOperand Callee =  createPCXCallOP(EndLabel, OutContext);
235   EmitCall(OutStreamer, Callee);
236   OutStreamer.EmitLabel(SethiLabel);
237   MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_HI,
238                                        GOTLabel, StartLabel, SethiLabel,
239                                        OutContext);
240   EmitSETHI(OutStreamer, hiImm, MCRegOP);
241   OutStreamer.EmitLabel(EndLabel);
242   MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_LO,
243                                        GOTLabel, StartLabel, EndLabel,
244                                        OutContext);
245   EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP);
246   EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP);
247 }
248
249 void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI)
250 {
251
252   switch (MI->getOpcode()) {
253   default: break;
254   case TargetOpcode::DBG_VALUE:
255     // FIXME: Debug Value.
256     return;
257   case SP::GETPCX:
258     LowerGETPCXAndEmitMCInsts(MI);
259     return;
260   }
261   MachineBasicBlock::const_instr_iterator I = MI;
262   MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
263   do {
264     MCInst TmpInst;
265     LowerSparcMachineInstrToMCInst(I, TmpInst, *this);
266     OutStreamer.EmitInstruction(TmpInst);
267   } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
268 }
269
270 void SparcAsmPrinter::EmitFunctionBodyStart() {
271   if (!TM.getSubtarget<SparcSubtarget>().is64Bit())
272     return;
273
274   const MachineRegisterInfo &MRI = MF->getRegInfo();
275   const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };
276   for (unsigned i = 0; globalRegs[i] != 0; ++i) {
277     unsigned reg = globalRegs[i];
278     if (MRI.use_empty(reg))
279       continue;
280
281     if  (reg == SP::G6 || reg == SP::G7)
282       getTargetStreamer().emitSparcRegisterIgnore(reg);
283     else
284       getTargetStreamer().emitSparcRegisterScratch(reg);
285   }
286 }
287
288 void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
289                                    raw_ostream &O) {
290   const DataLayout *DL = TM.getDataLayout();
291   const MachineOperand &MO = MI->getOperand (opNum);
292   unsigned TF = MO.getTargetFlags();
293 #ifndef NDEBUG
294   // Verify the target flags.
295   if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) {
296     if (MI->getOpcode() == SP::CALL)
297       assert(TF == SPII::MO_NO_FLAG &&
298              "Cannot handle target flags on call address");
299     else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi)
300       assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH
301               || TF == SPII::MO_TLS_GD_HI22
302               || TF == SPII::MO_TLS_LDM_HI22
303               || TF == SPII::MO_TLS_LDO_HIX22
304               || TF == SPII::MO_TLS_IE_HI22
305               || TF == SPII::MO_TLS_LE_HIX22) &&
306              "Invalid target flags for address operand on sethi");
307     else if (MI->getOpcode() == SP::TLS_CALL)
308       assert((TF == SPII::MO_NO_FLAG
309               || TF == SPII::MO_TLS_GD_CALL
310               || TF == SPII::MO_TLS_LDM_CALL) &&
311              "Cannot handle target flags on tls call address");
312     else if (MI->getOpcode() == SP::TLS_ADDrr)
313       assert((TF == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD
314               || TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) &&
315              "Cannot handle target flags on add for TLS");
316     else if (MI->getOpcode() == SP::TLS_LDrr)
317       assert(TF == SPII::MO_TLS_IE_LD &&
318              "Cannot handle target flags on ld for TLS");
319     else if (MI->getOpcode() == SP::TLS_LDXrr)
320       assert(TF == SPII::MO_TLS_IE_LDX &&
321              "Cannot handle target flags on ldx for TLS");
322     else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri)
323       assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) &&
324              "Cannot handle target flags on xor for TLS");
325     else
326       assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44
327               || TF == SPII::MO_HM
328               || TF == SPII::MO_TLS_GD_LO10
329               || TF == SPII::MO_TLS_LDM_LO10
330               || TF == SPII::MO_TLS_IE_LO10 ) &&
331              "Invalid target flags for small address operand");
332   }
333 #endif
334
335   bool CloseParen = true;
336   switch (TF) {
337   default:
338       llvm_unreachable("Unknown target flags on operand");
339   case SPII::MO_NO_FLAG:
340     CloseParen = false;
341     break;
342   case SPII::MO_LO:  O << "%lo(";  break;
343   case SPII::MO_HI:  O << "%hi(";  break;
344   case SPII::MO_H44: O << "%h44("; break;
345   case SPII::MO_M44: O << "%m44("; break;
346   case SPII::MO_L44: O << "%l44("; break;
347   case SPII::MO_HH:  O << "%hh(";  break;
348   case SPII::MO_HM:  O << "%hm(";  break;
349   case SPII::MO_TLS_GD_HI22:   O << "%tgd_hi22(";   break;
350   case SPII::MO_TLS_GD_LO10:   O << "%tgd_lo10(";   break;
351   case SPII::MO_TLS_GD_ADD:    O << "%tgd_add(";    break;
352   case SPII::MO_TLS_GD_CALL:   O << "%tgd_call(";   break;
353   case SPII::MO_TLS_LDM_HI22:  O << "%tldm_hi22(";  break;
354   case SPII::MO_TLS_LDM_LO10:  O << "%tldm_lo10(";  break;
355   case SPII::MO_TLS_LDM_ADD:   O << "%tldm_add(";   break;
356   case SPII::MO_TLS_LDM_CALL:  O << "%tldm_call(";  break;
357   case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break;
358   case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break;
359   case SPII::MO_TLS_LDO_ADD:   O << "%tldo_add(";   break;
360   case SPII::MO_TLS_IE_HI22:   O << "%tie_hi22(";   break;
361   case SPII::MO_TLS_IE_LO10:   O << "%tie_lo10(";   break;
362   case SPII::MO_TLS_IE_LD:     O << "%tie_ld(";     break;
363   case SPII::MO_TLS_IE_LDX:    O << "%tie_ldx(";    break;
364   case SPII::MO_TLS_IE_ADD:    O << "%tie_add(";    break;
365   case SPII::MO_TLS_LE_HIX22:  O << "%tle_hix22(";  break;
366   case SPII::MO_TLS_LE_LOX10:  O << "%tle_lox10(";   break;
367   }
368
369   switch (MO.getType()) {
370   case MachineOperand::MO_Register:
371     O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
372     break;
373
374   case MachineOperand::MO_Immediate:
375     O << (int)MO.getImm();
376     break;
377   case MachineOperand::MO_MachineBasicBlock:
378     O << *MO.getMBB()->getSymbol();
379     return;
380   case MachineOperand::MO_GlobalAddress:
381     O << *getSymbol(MO.getGlobal());
382     break;
383   case MachineOperand::MO_BlockAddress:
384     O <<  GetBlockAddressSymbol(MO.getBlockAddress())->getName();
385     break;
386   case MachineOperand::MO_ExternalSymbol:
387     O << MO.getSymbolName();
388     break;
389   case MachineOperand::MO_ConstantPoolIndex:
390     O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
391       << MO.getIndex();
392     break;
393   default:
394     llvm_unreachable("<unknown operand type>");
395   }
396   if (CloseParen) O << ")";
397 }
398
399 void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
400                                       raw_ostream &O, const char *Modifier) {
401   printOperand(MI, opNum, O);
402
403   // If this is an ADD operand, emit it like normal operands.
404   if (Modifier && !strcmp(Modifier, "arith")) {
405     O << ", ";
406     printOperand(MI, opNum+1, O);
407     return;
408   }
409
410   if (MI->getOperand(opNum+1).isReg() &&
411       MI->getOperand(opNum+1).getReg() == SP::G0)
412     return;   // don't print "+%g0"
413   if (MI->getOperand(opNum+1).isImm() &&
414       MI->getOperand(opNum+1).getImm() == 0)
415     return;   // don't print "+0"
416
417   O << "+";
418   printOperand(MI, opNum+1, O);
419 }
420
421 /// PrintAsmOperand - Print out an operand for an inline asm expression.
422 ///
423 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
424                                       unsigned AsmVariant,
425                                       const char *ExtraCode,
426                                       raw_ostream &O) {
427   if (ExtraCode && ExtraCode[0]) {
428     if (ExtraCode[1] != 0) return true; // Unknown modifier.
429
430     switch (ExtraCode[0]) {
431     default:
432       // See if this is a generic print operand
433       return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O);
434     case 'r':
435      break;
436     }
437   }
438
439   printOperand(MI, OpNo, O);
440
441   return false;
442 }
443
444 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
445                                             unsigned OpNo, unsigned AsmVariant,
446                                             const char *ExtraCode,
447                                             raw_ostream &O) {
448   if (ExtraCode && ExtraCode[0])
449     return true;  // Unknown modifier
450
451   O << '[';
452   printMemOperand(MI, OpNo, O);
453   O << ']';
454
455   return false;
456 }
457
458 void SparcAsmPrinter::EmitEndOfAsmFile(Module &M) {
459   const TargetLoweringObjectFileELF &TLOFELF =
460     static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering());
461   MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
462
463   // Generate stubs for global variables.
464   MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList();
465   if (!Stubs.empty()) {
466     OutStreamer.SwitchSection(TLOFELF.getDataSection());
467     unsigned PtrSize = TM.getDataLayout()->getPointerSize(0);
468     for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
469       OutStreamer.EmitLabel(Stubs[i].first);
470       OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), PtrSize);
471     }
472   }
473 }
474
475 // Force static initialization.
476 extern "C" void LLVMInitializeSparcAsmPrinter() {
477   RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
478   RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target);
479 }