[Sparc] Use SparcMCExpr::VariantKind itself as MachineOperand's target flags.
[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/SparcMCExpr.h"
19 #include "SparcInstrInfo.h"
20 #include "SparcTargetMachine.h"
21 #include "SparcTargetStreamer.h"
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/CodeGen/AsmPrinter.h"
24 #include "llvm/CodeGen/MachineInstr.h"
25 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
26 #include "llvm/CodeGen/MachineRegisterInfo.h"
27 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
28 #include "llvm/IR/Mangler.h"
29 #include "llvm/MC/MCAsmInfo.h"
30 #include "llvm/MC/MCContext.h"
31 #include "llvm/MC/MCInst.h"
32 #include "llvm/MC/MCStreamer.h"
33 #include "llvm/MC/MCSymbol.h"
34 #include "llvm/Support/TargetRegistry.h"
35 #include "llvm/Support/raw_ostream.h"
36 using namespace llvm;
37
38 namespace {
39   class SparcAsmPrinter : public AsmPrinter {
40     SparcTargetStreamer &getTargetStreamer() {
41       return static_cast<SparcTargetStreamer &>(
42           *OutStreamer.getTargetStreamer());
43     }
44   public:
45     explicit SparcAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
46       : AsmPrinter(TM, Streamer) {}
47
48     virtual const char *getPassName() const {
49       return "Sparc Assembly Printer";
50     }
51
52     void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
53     void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS,
54                          const char *Modifier = 0);
55     void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
56
57     virtual void EmitFunctionBodyStart();
58     virtual void EmitInstruction(const MachineInstr *MI);
59     virtual void EmitEndOfAsmFile(Module &M);
60
61     static const char *getRegisterName(unsigned RegNo) {
62       return SparcInstPrinter::getRegisterName(RegNo);
63     }
64
65     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
66                          unsigned AsmVariant, const char *ExtraCode,
67                          raw_ostream &O);
68     bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
69                                unsigned AsmVariant, const char *ExtraCode,
70                                raw_ostream &O);
71
72     void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
73                                    const MCSubtargetInfo &STI);
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, STI);
196       break;
197     case CodeModel::Medium: {
198       EmitHiLo(OutStreamer, GOTLabel,
199                SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44,
200                MCRegOP, OutContext, STI);
201       MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(12,
202                                                                    OutContext));
203       EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP, STI);
204       MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44,
205                                           GOTLabel, OutContext);
206       EmitOR(OutStreamer, MCRegOP, lo, MCRegOP, STI);
207       break;
208     }
209     case CodeModel::Large: {
210       EmitHiLo(OutStreamer, GOTLabel,
211                SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM,
212                MCRegOP, OutContext, STI);
213       MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(32,
214                                                                    OutContext));
215       EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP, STI);
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, STI);
221       EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
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   SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags();
301
302 #ifndef NDEBUG
303   // Verify the target flags.
304   if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) {
305     if (MI->getOpcode() == SP::CALL)
306       assert(TF == SparcMCExpr::VK_Sparc_None &&
307              "Cannot handle target flags on call address");
308     else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi)
309       assert((TF == SparcMCExpr::VK_Sparc_HI
310               || TF == SparcMCExpr::VK_Sparc_H44
311               || TF == SparcMCExpr::VK_Sparc_HH
312               || TF == SparcMCExpr::VK_Sparc_TLS_GD_HI22
313               || TF == SparcMCExpr::VK_Sparc_TLS_LDM_HI22
314               || TF == SparcMCExpr::VK_Sparc_TLS_LDO_HIX22
315               || TF == SparcMCExpr::VK_Sparc_TLS_IE_HI22
316               || TF == SparcMCExpr::VK_Sparc_TLS_LE_HIX22) &&
317              "Invalid target flags for address operand on sethi");
318     else if (MI->getOpcode() == SP::TLS_CALL)
319       assert((TF == SparcMCExpr::VK_Sparc_None
320               || TF == SparcMCExpr::VK_Sparc_TLS_GD_CALL
321               || TF == SparcMCExpr::VK_Sparc_TLS_LDM_CALL) &&
322              "Cannot handle target flags on tls call address");
323     else if (MI->getOpcode() == SP::TLS_ADDrr)
324       assert((TF == SparcMCExpr::VK_Sparc_TLS_GD_ADD
325               || TF == SparcMCExpr::VK_Sparc_TLS_LDM_ADD
326               || TF == SparcMCExpr::VK_Sparc_TLS_LDO_ADD
327               || TF == SparcMCExpr::VK_Sparc_TLS_IE_ADD) &&
328              "Cannot handle target flags on add for TLS");
329     else if (MI->getOpcode() == SP::TLS_LDrr)
330       assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LD &&
331              "Cannot handle target flags on ld for TLS");
332     else if (MI->getOpcode() == SP::TLS_LDXrr)
333       assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LDX &&
334              "Cannot handle target flags on ldx for TLS");
335     else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri)
336       assert((TF == SparcMCExpr::VK_Sparc_TLS_LDO_LOX10
337               || TF == SparcMCExpr::VK_Sparc_TLS_LE_LOX10) &&
338              "Cannot handle target flags on xor for TLS");
339     else
340       assert((TF == SparcMCExpr::VK_Sparc_LO
341               || TF == SparcMCExpr::VK_Sparc_M44
342               || TF == SparcMCExpr::VK_Sparc_L44
343               || TF == SparcMCExpr::VK_Sparc_HM
344               || TF == SparcMCExpr::VK_Sparc_TLS_GD_LO10
345               || TF == SparcMCExpr::VK_Sparc_TLS_LDM_LO10
346               || TF == SparcMCExpr::VK_Sparc_TLS_IE_LO10 ) &&
347              "Invalid target flags for small address operand");
348   }
349 #endif
350
351
352   bool CloseParen = SparcMCExpr::printVariantKind(O, TF);
353
354   switch (MO.getType()) {
355   case MachineOperand::MO_Register:
356     O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
357     break;
358
359   case MachineOperand::MO_Immediate:
360     O << (int)MO.getImm();
361     break;
362   case MachineOperand::MO_MachineBasicBlock:
363     O << *MO.getMBB()->getSymbol();
364     return;
365   case MachineOperand::MO_GlobalAddress:
366     O << *getSymbol(MO.getGlobal());
367     break;
368   case MachineOperand::MO_BlockAddress:
369     O <<  GetBlockAddressSymbol(MO.getBlockAddress())->getName();
370     break;
371   case MachineOperand::MO_ExternalSymbol:
372     O << MO.getSymbolName();
373     break;
374   case MachineOperand::MO_ConstantPoolIndex:
375     O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
376       << MO.getIndex();
377     break;
378   default:
379     llvm_unreachable("<unknown operand type>");
380   }
381   if (CloseParen) O << ")";
382 }
383
384 void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
385                                       raw_ostream &O, const char *Modifier) {
386   printOperand(MI, opNum, O);
387
388   // If this is an ADD operand, emit it like normal operands.
389   if (Modifier && !strcmp(Modifier, "arith")) {
390     O << ", ";
391     printOperand(MI, opNum+1, O);
392     return;
393   }
394
395   if (MI->getOperand(opNum+1).isReg() &&
396       MI->getOperand(opNum+1).getReg() == SP::G0)
397     return;   // don't print "+%g0"
398   if (MI->getOperand(opNum+1).isImm() &&
399       MI->getOperand(opNum+1).getImm() == 0)
400     return;   // don't print "+0"
401
402   O << "+";
403   printOperand(MI, opNum+1, O);
404 }
405
406 /// PrintAsmOperand - Print out an operand for an inline asm expression.
407 ///
408 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
409                                       unsigned AsmVariant,
410                                       const char *ExtraCode,
411                                       raw_ostream &O) {
412   if (ExtraCode && ExtraCode[0]) {
413     if (ExtraCode[1] != 0) return true; // Unknown modifier.
414
415     switch (ExtraCode[0]) {
416     default:
417       // See if this is a generic print operand
418       return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O);
419     case 'r':
420      break;
421     }
422   }
423
424   printOperand(MI, OpNo, O);
425
426   return false;
427 }
428
429 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
430                                             unsigned OpNo, unsigned AsmVariant,
431                                             const char *ExtraCode,
432                                             raw_ostream &O) {
433   if (ExtraCode && ExtraCode[0])
434     return true;  // Unknown modifier
435
436   O << '[';
437   printMemOperand(MI, OpNo, O);
438   O << ']';
439
440   return false;
441 }
442
443 void SparcAsmPrinter::EmitEndOfAsmFile(Module &M) {
444   const TargetLoweringObjectFileELF &TLOFELF =
445     static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering());
446   MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
447
448   // Generate stubs for global variables.
449   MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList();
450   if (!Stubs.empty()) {
451     OutStreamer.SwitchSection(TLOFELF.getDataSection());
452     unsigned PtrSize = TM.getDataLayout()->getPointerSize(0);
453     for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
454       OutStreamer.EmitLabel(Stubs[i].first);
455       OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), PtrSize);
456     }
457   }
458 }
459
460 // Force static initialization.
461 extern "C" void LLVMInitializeSparcAsmPrinter() {
462   RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
463   RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target);
464 }