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