1//===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains a printer that converts from our internal representation
10// of machine-dependent LLVM code to GAS-format SPARC assembly language.
11//
12//===----------------------------------------------------------------------===//
13
14#include "MCTargetDesc/SparcInstPrinter.h"
15#include "MCTargetDesc/SparcMCAsmInfo.h"
16#include "MCTargetDesc/SparcMCTargetDesc.h"
17#include "MCTargetDesc/SparcTargetStreamer.h"
18#include "Sparc.h"
19#include "SparcInstrInfo.h"
20#include "SparcTargetMachine.h"
21#include "TargetInfo/SparcTargetInfo.h"
22#include "llvm/BinaryFormat/ELF.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/MC/TargetRegistry.h"
35#include "llvm/Support/Compiler.h"
36#include "llvm/Support/raw_ostream.h"
37using namespace llvm;
38
39#define DEBUG_TYPE "asm-printer"
40
41namespace {
42class SparcAsmPrinter : public AsmPrinter {
43 SparcTargetStreamer &getTargetStreamer() {
44 return static_cast<SparcTargetStreamer &>(
45 *OutStreamer->getTargetStreamer());
46 }
47
48public:
49 explicit SparcAsmPrinter(TargetMachine &TM,
50 std::unique_ptr<MCStreamer> Streamer)
51 : AsmPrinter(TM, std::move(Streamer), ID) {}
52
53 StringRef getPassName() const override { return "Sparc Assembly Printer"; }
54
55 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
56 void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
57
58 void emitFunctionBodyStart() override;
59 void emitInstruction(const MachineInstr *MI) override;
60
61 static const char *getRegisterName(MCRegister Reg) {
62 return SparcInstPrinter::getRegisterName(Reg);
63 }
64
65 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
66 const char *ExtraCode, raw_ostream &O) override;
67 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
68 const char *ExtraCode, raw_ostream &O) override;
69
70 void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
71 const MCSubtargetInfo &STI);
72
73 MCOperand lowerOperand(const MachineOperand &MO) const;
74
75private:
76 void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);
77
78public:
79 static char ID;
80};
81} // end of anonymous namespace
82
83static MCOperand createSparcMCOperand(uint16_t Kind, MCSymbol *Sym,
84 MCContext &OutContext) {
85 const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext);
86 auto *expr = MCSpecifierExpr::create(Expr: MCSym, S: Kind, Ctx&: OutContext);
87 return MCOperand::createExpr(Val: expr);
88}
89static MCOperand createPCXCallOP(MCSymbol *Label,
90 MCContext &OutContext) {
91 return MCOperand::createExpr(Val: MCSymbolRefExpr::create(Symbol: Label, Ctx&: OutContext));
92}
93
94static MCOperand createPCXRelExprOp(uint16_t Spec, MCSymbol *GOTLabel,
95 MCSymbol *StartLabel, MCSymbol *CurLabel,
96 MCContext &OutContext) {
97 const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(Symbol: GOTLabel, Ctx&: OutContext);
98 const MCSymbolRefExpr *Start = MCSymbolRefExpr::create(Symbol: StartLabel,
99 Ctx&: OutContext);
100 const MCSymbolRefExpr *Cur = MCSymbolRefExpr::create(Symbol: CurLabel,
101 Ctx&: OutContext);
102
103 const MCBinaryExpr *Sub = MCBinaryExpr::createSub(LHS: Cur, RHS: Start, Ctx&: OutContext);
104 const MCBinaryExpr *Add = MCBinaryExpr::createAdd(LHS: GOT, RHS: Sub, Ctx&: OutContext);
105 auto *expr = MCSpecifierExpr::create(Expr: Add, S: Spec, Ctx&: OutContext);
106 return MCOperand::createExpr(Val: expr);
107}
108
109static void EmitCall(MCStreamer &OutStreamer,
110 MCOperand &Callee,
111 const MCSubtargetInfo &STI)
112{
113 MCInst CallInst;
114 CallInst.setOpcode(SP::CALL);
115 CallInst.addOperand(Op: Callee);
116 OutStreamer.emitInstruction(Inst: CallInst, STI);
117}
118
119static void EmitRDPC(MCStreamer &OutStreamer, MCOperand &RD,
120 const MCSubtargetInfo &STI) {
121 MCInst RDPCInst;
122 RDPCInst.setOpcode(SP::RDASR);
123 RDPCInst.addOperand(Op: RD);
124 RDPCInst.addOperand(Op: MCOperand::createReg(Reg: SP::ASR5));
125 OutStreamer.emitInstruction(Inst: RDPCInst, STI);
126}
127
128static void EmitSETHI(MCStreamer &OutStreamer,
129 MCOperand &Imm, MCOperand &RD,
130 const MCSubtargetInfo &STI)
131{
132 MCInst SETHIInst;
133 SETHIInst.setOpcode(SP::SETHIi);
134 SETHIInst.addOperand(Op: RD);
135 SETHIInst.addOperand(Op: Imm);
136 OutStreamer.emitInstruction(Inst: SETHIInst, STI);
137}
138
139static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
140 MCOperand &RS1, MCOperand &Src2, MCOperand &RD,
141 const MCSubtargetInfo &STI)
142{
143 MCInst Inst;
144 Inst.setOpcode(Opcode);
145 Inst.addOperand(Op: RD);
146 Inst.addOperand(Op: RS1);
147 Inst.addOperand(Op: Src2);
148 OutStreamer.emitInstruction(Inst, STI);
149}
150
151static void EmitOR(MCStreamer &OutStreamer,
152 MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
153 const MCSubtargetInfo &STI) {
154 EmitBinary(OutStreamer, Opcode: SP::ORri, RS1, Src2&: Imm, RD, STI);
155}
156
157static void EmitADD(MCStreamer &OutStreamer,
158 MCOperand &RS1, MCOperand &RS2, MCOperand &RD,
159 const MCSubtargetInfo &STI) {
160 EmitBinary(OutStreamer, Opcode: SP::ADDrr, RS1, Src2&: RS2, RD, STI);
161}
162
163static void EmitSHL(MCStreamer &OutStreamer,
164 MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
165 const MCSubtargetInfo &STI) {
166 EmitBinary(OutStreamer, Opcode: SP::SLLri, RS1, Src2&: Imm, RD, STI);
167}
168
169static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, uint16_t HiKind,
170 uint16_t LoKind, MCOperand &RD, MCContext &OutContext,
171 const MCSubtargetInfo &STI) {
172 MCOperand hi = createSparcMCOperand(Kind: HiKind, Sym: GOTSym, OutContext);
173 MCOperand lo = createSparcMCOperand(Kind: LoKind, Sym: GOTSym, OutContext);
174 EmitSETHI(OutStreamer, Imm&: hi, RD, STI);
175 EmitOR(OutStreamer, RS1&: RD, Imm&: lo, RD, STI);
176}
177
178void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
179 const MCSubtargetInfo &STI)
180{
181 MCSymbol *GOTLabel =
182 OutContext.getOrCreateSymbol(Name: Twine("_GLOBAL_OFFSET_TABLE_"));
183
184 const MachineOperand &MO = MI->getOperand(i: 0);
185 assert(MO.getReg() != SP::O7 &&
186 "%o7 is assigned as destination for getpcx!");
187
188 MCOperand MCRegOP = MCOperand::createReg(Reg: MO.getReg());
189
190
191 if (!isPositionIndependent()) {
192 // Just load the address of GOT to MCRegOP.
193 switch(TM.getCodeModel()) {
194 default:
195 llvm_unreachable("Unsupported absolute code model");
196 case CodeModel::Small:
197 emitHiLo(OutStreamer&: *OutStreamer, GOTSym: GOTLabel, HiKind: ELF::R_SPARC_HI22, LoKind: ELF::R_SPARC_LO10,
198 RD&: MCRegOP, OutContext, STI);
199 break;
200 case CodeModel::Medium: {
201 emitHiLo(OutStreamer&: *OutStreamer, GOTSym: GOTLabel, HiKind: ELF::R_SPARC_H44, LoKind: ELF::R_SPARC_M44,
202 RD&: MCRegOP, OutContext, STI);
203 MCOperand imm = MCOperand::createExpr(Val: MCConstantExpr::create(Value: 12,
204 Ctx&: OutContext));
205 EmitSHL(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: imm, RD&: MCRegOP, STI);
206 MCOperand lo =
207 createSparcMCOperand(Kind: ELF::R_SPARC_L44, Sym: GOTLabel, OutContext);
208 EmitOR(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: lo, RD&: MCRegOP, STI);
209 break;
210 }
211 case CodeModel::Large: {
212 emitHiLo(OutStreamer&: *OutStreamer, GOTSym: GOTLabel, HiKind: ELF::R_SPARC_HH22, LoKind: ELF::R_SPARC_HM10,
213 RD&: MCRegOP, OutContext, STI);
214 MCOperand imm = MCOperand::createExpr(Val: MCConstantExpr::create(Value: 32,
215 Ctx&: OutContext));
216 EmitSHL(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: imm, RD&: MCRegOP, STI);
217 // Use register %o7 to load the lower 32 bits.
218 MCOperand RegO7 = MCOperand::createReg(Reg: SP::O7);
219 emitHiLo(OutStreamer&: *OutStreamer, GOTSym: GOTLabel, HiKind: ELF::R_SPARC_HI22, LoKind: ELF::R_SPARC_LO10,
220 RD&: RegO7, OutContext, STI);
221 EmitADD(OutStreamer&: *OutStreamer, RS1&: MCRegOP, RS2&: RegO7, RD&: 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(Reg: SP::O7);
232
233 // <StartLabel>:
234 // <GET-PC> // This will be either `call <EndLabel>` or `rd %pc, %o7`.
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(Symbol: StartLabel);
242 if (!STI.getTargetTriple().isSPARC64() ||
243 STI.hasFeature(Feature: Sparc::TuneSlowRDPC)) {
244 MCOperand Callee = createPCXCallOP(Label: EndLabel, OutContext);
245 EmitCall(OutStreamer&: *OutStreamer, Callee, STI);
246 } else {
247 // TODO find out whether it is possible to store PC
248 // in other registers, to enable leaf function optimization.
249 // (On the other hand, approx. over 97.8% of GETPCXes happen
250 // in non-leaf functions, so would this be worth the effort?)
251 EmitRDPC(OutStreamer&: *OutStreamer, RD&: RegO7, STI);
252 }
253 OutStreamer->emitLabel(Symbol: SethiLabel);
254 MCOperand hiImm = createPCXRelExprOp(Spec: ELF::R_SPARC_PC22, GOTLabel, StartLabel,
255 CurLabel: SethiLabel, OutContext);
256 EmitSETHI(OutStreamer&: *OutStreamer, Imm&: hiImm, RD&: MCRegOP, STI);
257 OutStreamer->emitLabel(Symbol: EndLabel);
258 MCOperand loImm = createPCXRelExprOp(Spec: ELF::R_SPARC_PC10, GOTLabel, StartLabel,
259 CurLabel: EndLabel, OutContext);
260 EmitOR(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: loImm, RD&: MCRegOP, STI);
261 EmitADD(OutStreamer&: *OutStreamer, RS1&: MCRegOP, RS2&: RegO7, RD&: MCRegOP, STI);
262}
263
264MCOperand SparcAsmPrinter::lowerOperand(const MachineOperand &MO) const {
265 switch (MO.getType()) {
266 default:
267 llvm_unreachable("unknown operand type");
268 break;
269 case MachineOperand::MO_Register:
270 if (MO.isImplicit())
271 break;
272 return MCOperand::createReg(Reg: MO.getReg());
273
274 case MachineOperand::MO_Immediate:
275 return MCOperand::createImm(Val: MO.getImm());
276
277 case MachineOperand::MO_MachineBasicBlock:
278 case MachineOperand::MO_GlobalAddress:
279 case MachineOperand::MO_BlockAddress:
280 case MachineOperand::MO_ExternalSymbol:
281 case MachineOperand::MO_ConstantPoolIndex: {
282 auto RelType = MO.getTargetFlags();
283 const MCSymbol *Symbol = nullptr;
284 switch (MO.getType()) {
285 default:
286 llvm_unreachable("");
287 case MachineOperand::MO_MachineBasicBlock:
288 Symbol = MO.getMBB()->getSymbol();
289 break;
290 case MachineOperand::MO_GlobalAddress:
291 Symbol = getSymbol(GV: MO.getGlobal());
292 break;
293 case MachineOperand::MO_BlockAddress:
294 Symbol = GetBlockAddressSymbol(BA: MO.getBlockAddress());
295 break;
296 case MachineOperand::MO_ExternalSymbol:
297 Symbol = GetExternalSymbolSymbol(Sym: MO.getSymbolName());
298 break;
299 case MachineOperand::MO_ConstantPoolIndex:
300 Symbol = GetCPISymbol(CPID: MO.getIndex());
301 break;
302 }
303
304 const MCExpr *expr = MCSymbolRefExpr::create(Symbol, Ctx&: OutContext);
305 if (RelType)
306 expr = MCSpecifierExpr::create(Expr: expr, S: RelType, Ctx&: OutContext);
307 return MCOperand::createExpr(Val: expr);
308 }
309
310 case MachineOperand::MO_RegisterMask:
311 break;
312 }
313 return MCOperand();
314}
315
316void SparcAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
317 OutMI.setOpcode(MI->getOpcode());
318
319 for (const MachineOperand &MO : MI->operands()) {
320 MCOperand MCOp = lowerOperand(MO);
321 if (MCOp.isValid())
322 OutMI.addOperand(Op: MCOp);
323 }
324}
325
326void SparcAsmPrinter::emitInstruction(const MachineInstr *MI) {
327 Sparc_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(),
328 Features: getSubtargetInfo().getFeatureBits());
329 if (MI->isBundle()) {
330 const MachineBasicBlock *MBB = MI->getParent();
331 MachineBasicBlock::const_instr_iterator I = ++MI->getIterator();
332 while (I != MBB->instr_end() && I->isInsideBundle()) {
333 emitInstruction(MI: &*I);
334 ++I;
335 }
336 return;
337 }
338
339 switch (MI->getOpcode()) {
340 default: break;
341 case TargetOpcode::DBG_VALUE:
342 // FIXME: Debug Value.
343 return;
344 case SP::CASArr:
345 case SP::SWAPrr:
346 case SP::SWAPri:
347 case SP::LDSTUBrr:
348 case SP::LDSTUBri:
349 case SP::LDSTUBArr:
350 if (MF->getSubtarget<SparcSubtarget>().fixTN0011())
351 OutStreamer->emitCodeAlignment(Alignment: Align(16), STI: getSubtargetInfo());
352 break;
353 case SP::GETPCX:
354 LowerGETPCXAndEmitMCInsts(MI, STI: getSubtargetInfo());
355 return;
356 }
357 MachineBasicBlock::const_instr_iterator I = MI->getIterator();
358 MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
359 do {
360 MCInst TmpInst;
361 lowerToMCInst(MI: &*I, OutMI&: TmpInst);
362 EmitToStreamer(S&: *OutStreamer, Inst: TmpInst);
363 } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
364}
365
366void SparcAsmPrinter::emitFunctionBodyStart() {
367 if (!MF->getSubtarget<SparcSubtarget>().is64Bit())
368 return;
369
370 const MachineRegisterInfo &MRI = MF->getRegInfo();
371 const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };
372 for (unsigned i = 0; globalRegs[i] != 0; ++i) {
373 unsigned reg = globalRegs[i];
374 if (MRI.use_empty(RegNo: reg))
375 continue;
376
377 if (reg == SP::G6 || reg == SP::G7)
378 getTargetStreamer().emitSparcRegisterIgnore(reg);
379 else
380 getTargetStreamer().emitSparcRegisterScratch(reg);
381 }
382}
383
384void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
385 raw_ostream &O) {
386 const DataLayout &DL = getDataLayout();
387 const MachineOperand &MO = MI->getOperand(i: opNum);
388 switch (MO.getType()) {
389 case MachineOperand::MO_Register:
390 O << "%" << StringRef(getRegisterName(Reg: MO.getReg())).lower();
391 break;
392
393 case MachineOperand::MO_Immediate:
394 O << MO.getImm();
395 break;
396 case MachineOperand::MO_MachineBasicBlock:
397 MO.getMBB()->getSymbol()->print(OS&: O, MAI);
398 return;
399 case MachineOperand::MO_GlobalAddress:
400 PrintSymbolOperand(MO, OS&: O);
401 break;
402 case MachineOperand::MO_BlockAddress:
403 O << GetBlockAddressSymbol(BA: MO.getBlockAddress())->getName();
404 break;
405 case MachineOperand::MO_ExternalSymbol:
406 O << MO.getSymbolName();
407 break;
408 case MachineOperand::MO_ConstantPoolIndex:
409 O << DL.getInternalSymbolPrefix() << "CPI" << getFunctionNumber() << "_"
410 << MO.getIndex();
411 break;
412 case MachineOperand::MO_Metadata:
413 MO.getMetadata()->printAsOperand(OS&: O, M: MMI->getModule());
414 break;
415 default:
416 llvm_unreachable("<unknown operand type>");
417 }
418}
419
420void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
421 raw_ostream &O) {
422 printOperand(MI, opNum, O);
423
424 if (MI->getOperand(i: opNum+1).isReg() &&
425 MI->getOperand(i: opNum+1).getReg() == SP::G0)
426 return; // don't print "+%g0"
427 if (MI->getOperand(i: opNum+1).isImm() &&
428 MI->getOperand(i: opNum+1).getImm() == 0)
429 return; // don't print "+0"
430
431 O << "+";
432 printOperand(MI, opNum: opNum+1, O);
433}
434
435/// PrintAsmOperand - Print out an operand for an inline asm expression.
436///
437bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
438 const char *ExtraCode,
439 raw_ostream &O) {
440 if (ExtraCode && ExtraCode[0]) {
441 if (ExtraCode[1] != 0) return true; // Unknown modifier.
442
443 switch (ExtraCode[0]) {
444 default:
445 // See if this is a generic print operand
446 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O);
447 case 'L': // Low order register of a twin word register operand
448 case 'H': // High order register of a twin word register operand
449 {
450 const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>();
451 const MachineOperand &MO = MI->getOperand(i: OpNo);
452 const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo();
453 Register MOReg = MO.getReg();
454
455 Register HiReg, LoReg;
456 if (!SP::IntPairRegClass.contains(Reg: MOReg)) {
457 // If we aren't given a register pair already, find out which pair it
458 // belongs to. Note that here, the specified register operand, which
459 // refers to the high part of the twinword, needs to be an even-numbered
460 // register.
461 MOReg = RegisterInfo->getMatchingSuperReg(Reg: MOReg, SubIdx: SP::sub_even,
462 RC: &SP::IntPairRegClass);
463 if (!MOReg) {
464 SMLoc Loc;
465 OutContext.reportError(
466 L: Loc, Msg: "Hi part of pair should point to an even-numbered register");
467 OutContext.reportError(
468 L: Loc, Msg: "(note that in some cases it might be necessary to manually "
469 "bind the input/output registers instead of relying on "
470 "automatic allocation)");
471 return true;
472 }
473 }
474
475 HiReg = RegisterInfo->getSubReg(Reg: MOReg, Idx: SP::sub_even);
476 LoReg = RegisterInfo->getSubReg(Reg: MOReg, Idx: SP::sub_odd);
477
478 Register Reg;
479 switch (ExtraCode[0]) {
480 case 'L':
481 Reg = LoReg;
482 break;
483 case 'H':
484 Reg = HiReg;
485 break;
486 }
487
488 O << '%' << SparcInstPrinter::getRegisterName(Reg);
489 return false;
490 }
491 case 'f':
492 case 'r':
493 break;
494 }
495 }
496
497 printOperand(MI, opNum: OpNo, O);
498
499 return false;
500}
501
502bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
503 unsigned OpNo,
504 const char *ExtraCode,
505 raw_ostream &O) {
506 if (ExtraCode && ExtraCode[0])
507 return true; // Unknown modifier
508
509 O << '[';
510 printMemOperand(MI, opNum: OpNo, O);
511 O << ']';
512
513 return false;
514}
515
516char SparcAsmPrinter::ID = 0;
517
518INITIALIZE_PASS(SparcAsmPrinter, "sparc-asm-printer", "Sparc Assembly Printer",
519 false, false)
520
521// Force static initialization.
522extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
523LLVMInitializeSparcAsmPrinter() {
524 RegisterAsmPrinter<SparcAsmPrinter> X(getTheSparcTarget());
525 RegisterAsmPrinter<SparcAsmPrinter> Y(getTheSparcV9Target());
526 RegisterAsmPrinter<SparcAsmPrinter> Z(getTheSparcelTarget());
527}
528