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