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