1 //===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains a printer that converts from our internal representation
10 // of machine-dependent LLVM code to GAS-format SPARC assembly language.
12 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/SparcInstPrinter.h"
15 #include "MCTargetDesc/SparcMCExpr.h"
16 #include "MCTargetDesc/SparcMCTargetDesc.h"
17 #include "MCTargetDesc/SparcTargetStreamer.h"
19 #include "SparcInstrInfo.h"
20 #include "SparcTargetMachine.h"
21 #include "TargetInfo/SparcTargetInfo.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/MC/TargetRegistry.h"
34 #include "llvm/Support/raw_ostream.h"
37 #define DEBUG_TYPE "asm-printer"
40 class SparcAsmPrinter
: public AsmPrinter
{
41 SparcTargetStreamer
&getTargetStreamer() {
42 return static_cast<SparcTargetStreamer
&>(
43 *OutStreamer
->getTargetStreamer());
46 explicit SparcAsmPrinter(TargetMachine
&TM
,
47 std::unique_ptr
<MCStreamer
> Streamer
)
48 : AsmPrinter(TM
, std::move(Streamer
)) {}
50 StringRef
getPassName() const override
{ return "Sparc Assembly Printer"; }
52 void printOperand(const MachineInstr
*MI
, int opNum
, raw_ostream
&OS
);
53 void printMemOperand(const MachineInstr
*MI
, int opNum
, raw_ostream
&OS
);
55 void emitFunctionBodyStart() override
;
56 void emitInstruction(const MachineInstr
*MI
) override
;
58 static const char *getRegisterName(MCRegister Reg
) {
59 return SparcInstPrinter::getRegisterName(Reg
);
62 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
63 const char *ExtraCode
, raw_ostream
&O
) override
;
64 bool PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
65 const char *ExtraCode
, raw_ostream
&O
) override
;
67 void LowerGETPCXAndEmitMCInsts(const MachineInstr
*MI
,
68 const MCSubtargetInfo
&STI
);
71 } // end of anonymous namespace
73 static MCOperand
createSparcMCOperand(SparcMCExpr::VariantKind Kind
,
74 MCSymbol
*Sym
, MCContext
&OutContext
) {
75 const MCSymbolRefExpr
*MCSym
= MCSymbolRefExpr::create(Sym
,
77 const SparcMCExpr
*expr
= SparcMCExpr::create(Kind
, MCSym
, OutContext
);
78 return MCOperand::createExpr(expr
);
81 static MCOperand
createPCXCallOP(MCSymbol
*Label
,
82 MCContext
&OutContext
) {
83 return createSparcMCOperand(SparcMCExpr::VK_Sparc_WDISP30
, Label
, OutContext
);
86 static MCOperand
createPCXRelExprOp(SparcMCExpr::VariantKind Kind
,
87 MCSymbol
*GOTLabel
, MCSymbol
*StartLabel
,
89 MCContext
&OutContext
)
91 const MCSymbolRefExpr
*GOT
= MCSymbolRefExpr::create(GOTLabel
, OutContext
);
92 const MCSymbolRefExpr
*Start
= MCSymbolRefExpr::create(StartLabel
,
94 const MCSymbolRefExpr
*Cur
= MCSymbolRefExpr::create(CurLabel
,
97 const MCBinaryExpr
*Sub
= MCBinaryExpr::createSub(Cur
, Start
, OutContext
);
98 const MCBinaryExpr
*Add
= MCBinaryExpr::createAdd(GOT
, Sub
, OutContext
);
99 const SparcMCExpr
*expr
= SparcMCExpr::create(Kind
,
101 return MCOperand::createExpr(expr
);
104 static void EmitCall(MCStreamer
&OutStreamer
,
106 const MCSubtargetInfo
&STI
)
109 CallInst
.setOpcode(SP::CALL
);
110 CallInst
.addOperand(Callee
);
111 OutStreamer
.emitInstruction(CallInst
, STI
);
114 static void EmitRDPC(MCStreamer
&OutStreamer
, MCOperand
&RD
,
115 const MCSubtargetInfo
&STI
) {
117 RDPCInst
.setOpcode(SP::RDASR
);
118 RDPCInst
.addOperand(RD
);
119 RDPCInst
.addOperand(MCOperand::createReg(SP::ASR5
));
120 OutStreamer
.emitInstruction(RDPCInst
, STI
);
123 static void EmitSETHI(MCStreamer
&OutStreamer
,
124 MCOperand
&Imm
, MCOperand
&RD
,
125 const MCSubtargetInfo
&STI
)
128 SETHIInst
.setOpcode(SP::SETHIi
);
129 SETHIInst
.addOperand(RD
);
130 SETHIInst
.addOperand(Imm
);
131 OutStreamer
.emitInstruction(SETHIInst
, STI
);
134 static void EmitBinary(MCStreamer
&OutStreamer
, unsigned Opcode
,
135 MCOperand
&RS1
, MCOperand
&Src2
, MCOperand
&RD
,
136 const MCSubtargetInfo
&STI
)
139 Inst
.setOpcode(Opcode
);
141 Inst
.addOperand(RS1
);
142 Inst
.addOperand(Src2
);
143 OutStreamer
.emitInstruction(Inst
, STI
);
146 static void EmitOR(MCStreamer
&OutStreamer
,
147 MCOperand
&RS1
, MCOperand
&Imm
, MCOperand
&RD
,
148 const MCSubtargetInfo
&STI
) {
149 EmitBinary(OutStreamer
, SP::ORri
, RS1
, Imm
, RD
, STI
);
152 static void EmitADD(MCStreamer
&OutStreamer
,
153 MCOperand
&RS1
, MCOperand
&RS2
, MCOperand
&RD
,
154 const MCSubtargetInfo
&STI
) {
155 EmitBinary(OutStreamer
, SP::ADDrr
, RS1
, RS2
, RD
, STI
);
158 static void EmitSHL(MCStreamer
&OutStreamer
,
159 MCOperand
&RS1
, MCOperand
&Imm
, MCOperand
&RD
,
160 const MCSubtargetInfo
&STI
) {
161 EmitBinary(OutStreamer
, SP::SLLri
, RS1
, Imm
, RD
, STI
);
165 static void EmitHiLo(MCStreamer
&OutStreamer
, MCSymbol
*GOTSym
,
166 SparcMCExpr::VariantKind HiKind
,
167 SparcMCExpr::VariantKind LoKind
,
169 MCContext
&OutContext
,
170 const MCSubtargetInfo
&STI
) {
172 MCOperand hi
= createSparcMCOperand(HiKind
, GOTSym
, OutContext
);
173 MCOperand lo
= createSparcMCOperand(LoKind
, GOTSym
, OutContext
);
174 EmitSETHI(OutStreamer
, hi
, RD
, STI
);
175 EmitOR(OutStreamer
, RD
, lo
, RD
, STI
);
178 void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr
*MI
,
179 const MCSubtargetInfo
&STI
)
182 OutContext
.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
184 const MachineOperand
&MO
= MI
->getOperand(0);
185 assert(MO
.getReg() != SP::O7
&&
186 "%o7 is assigned as destination for getpcx!");
188 MCOperand MCRegOP
= MCOperand::createReg(MO
.getReg());
191 if (!isPositionIndependent()) {
192 // Just load the address of GOT to MCRegOP.
193 switch(TM
.getCodeModel()) {
195 llvm_unreachable("Unsupported absolute code model");
196 case CodeModel::Small
:
197 EmitHiLo(*OutStreamer
, GOTLabel
,
198 SparcMCExpr::VK_Sparc_HI
, SparcMCExpr::VK_Sparc_LO
,
199 MCRegOP
, OutContext
, STI
);
201 case CodeModel::Medium
: {
202 EmitHiLo(*OutStreamer
, GOTLabel
,
203 SparcMCExpr::VK_Sparc_H44
, SparcMCExpr::VK_Sparc_M44
,
204 MCRegOP
, OutContext
, STI
);
205 MCOperand imm
= MCOperand::createExpr(MCConstantExpr::create(12,
207 EmitSHL(*OutStreamer
, MCRegOP
, imm
, MCRegOP
, STI
);
208 MCOperand lo
= createSparcMCOperand(SparcMCExpr::VK_Sparc_L44
,
209 GOTLabel
, OutContext
);
210 EmitOR(*OutStreamer
, MCRegOP
, lo
, MCRegOP
, STI
);
213 case CodeModel::Large
: {
214 EmitHiLo(*OutStreamer
, GOTLabel
,
215 SparcMCExpr::VK_Sparc_HH
, SparcMCExpr::VK_Sparc_HM
,
216 MCRegOP
, OutContext
, STI
);
217 MCOperand imm
= MCOperand::createExpr(MCConstantExpr::create(32,
219 EmitSHL(*OutStreamer
, MCRegOP
, imm
, MCRegOP
, STI
);
220 // Use register %o7 to load the lower 32 bits.
221 MCOperand RegO7
= MCOperand::createReg(SP::O7
);
222 EmitHiLo(*OutStreamer
, GOTLabel
,
223 SparcMCExpr::VK_Sparc_HI
, SparcMCExpr::VK_Sparc_LO
,
224 RegO7
, OutContext
, STI
);
225 EmitADD(*OutStreamer
, MCRegOP
, RegO7
, MCRegOP
, STI
);
231 MCSymbol
*StartLabel
= OutContext
.createTempSymbol();
232 MCSymbol
*EndLabel
= OutContext
.createTempSymbol();
233 MCSymbol
*SethiLabel
= OutContext
.createTempSymbol();
235 MCOperand RegO7
= MCOperand::createReg(SP::O7
);
238 // <GET-PC> // This will be either `call <EndLabel>` or `rd %pc, %o7`.
240 // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
242 // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
243 // add <MO>, %o7, <MO>
245 OutStreamer
->emitLabel(StartLabel
);
246 if (!STI
.getTargetTriple().isSPARC64() ||
247 STI
.hasFeature(Sparc::TuneSlowRDPC
)) {
248 MCOperand Callee
= createPCXCallOP(EndLabel
, OutContext
);
249 EmitCall(*OutStreamer
, Callee
, STI
);
251 // TODO find out whether it is possible to store PC
252 // in other registers, to enable leaf function optimization.
253 // (On the other hand, approx. over 97.8% of GETPCXes happen
254 // in non-leaf functions, so would this be worth the effort?)
255 EmitRDPC(*OutStreamer
, RegO7
, STI
);
257 OutStreamer
->emitLabel(SethiLabel
);
258 MCOperand hiImm
= createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22
,
259 GOTLabel
, StartLabel
, SethiLabel
,
261 EmitSETHI(*OutStreamer
, hiImm
, MCRegOP
, STI
);
262 OutStreamer
->emitLabel(EndLabel
);
263 MCOperand loImm
= createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10
,
264 GOTLabel
, StartLabel
, EndLabel
,
266 EmitOR(*OutStreamer
, MCRegOP
, loImm
, MCRegOP
, STI
);
267 EmitADD(*OutStreamer
, MCRegOP
, RegO7
, MCRegOP
, STI
);
270 void SparcAsmPrinter::emitInstruction(const MachineInstr
*MI
) {
271 Sparc_MC::verifyInstructionPredicates(MI
->getOpcode(),
272 getSubtargetInfo().getFeatureBits());
274 switch (MI
->getOpcode()) {
276 case TargetOpcode::DBG_VALUE
:
277 // FIXME: Debug Value.
282 if (MF
->getSubtarget
<SparcSubtarget
>().fixTN0011())
283 OutStreamer
->emitCodeAlignment(Align(16), &getSubtargetInfo());
286 LowerGETPCXAndEmitMCInsts(MI
, getSubtargetInfo());
289 MachineBasicBlock::const_instr_iterator I
= MI
->getIterator();
290 MachineBasicBlock::const_instr_iterator E
= MI
->getParent()->instr_end();
293 LowerSparcMachineInstrToMCInst(&*I
, TmpInst
, *this);
294 EmitToStreamer(*OutStreamer
, TmpInst
);
295 } while ((++I
!= E
) && I
->isInsideBundle()); // Delay slot check.
298 void SparcAsmPrinter::emitFunctionBodyStart() {
299 if (!MF
->getSubtarget
<SparcSubtarget
>().is64Bit())
302 const MachineRegisterInfo
&MRI
= MF
->getRegInfo();
303 const unsigned globalRegs
[] = { SP::G2
, SP::G3
, SP::G6
, SP::G7
, 0 };
304 for (unsigned i
= 0; globalRegs
[i
] != 0; ++i
) {
305 unsigned reg
= globalRegs
[i
];
306 if (MRI
.use_empty(reg
))
309 if (reg
== SP::G6
|| reg
== SP::G7
)
310 getTargetStreamer().emitSparcRegisterIgnore(reg
);
312 getTargetStreamer().emitSparcRegisterScratch(reg
);
316 void SparcAsmPrinter::printOperand(const MachineInstr
*MI
, int opNum
,
318 const DataLayout
&DL
= getDataLayout();
319 const MachineOperand
&MO
= MI
->getOperand (opNum
);
320 SparcMCExpr::VariantKind TF
= (SparcMCExpr::VariantKind
) MO
.getTargetFlags();
322 bool CloseParen
= SparcMCExpr::printVariantKind(O
, TF
);
324 switch (MO
.getType()) {
325 case MachineOperand::MO_Register
:
326 O
<< "%" << StringRef(getRegisterName(MO
.getReg())).lower();
329 case MachineOperand::MO_Immediate
:
332 case MachineOperand::MO_MachineBasicBlock
:
333 MO
.getMBB()->getSymbol()->print(O
, MAI
);
335 case MachineOperand::MO_GlobalAddress
:
336 PrintSymbolOperand(MO
, O
);
338 case MachineOperand::MO_BlockAddress
:
339 O
<< GetBlockAddressSymbol(MO
.getBlockAddress())->getName();
341 case MachineOperand::MO_ExternalSymbol
:
342 O
<< MO
.getSymbolName();
344 case MachineOperand::MO_ConstantPoolIndex
:
345 O
<< DL
.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
348 case MachineOperand::MO_Metadata
:
349 MO
.getMetadata()->printAsOperand(O
, MMI
->getModule());
352 llvm_unreachable("<unknown operand type>");
354 if (CloseParen
) O
<< ")";
357 void SparcAsmPrinter::printMemOperand(const MachineInstr
*MI
, int opNum
,
359 printOperand(MI
, opNum
, O
);
361 if (MI
->getOperand(opNum
+1).isReg() &&
362 MI
->getOperand(opNum
+1).getReg() == SP::G0
)
363 return; // don't print "+%g0"
364 if (MI
->getOperand(opNum
+1).isImm() &&
365 MI
->getOperand(opNum
+1).getImm() == 0)
366 return; // don't print "+0"
369 printOperand(MI
, opNum
+1, O
);
372 /// PrintAsmOperand - Print out an operand for an inline asm expression.
374 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
375 const char *ExtraCode
,
377 if (ExtraCode
&& ExtraCode
[0]) {
378 if (ExtraCode
[1] != 0) return true; // Unknown modifier.
380 switch (ExtraCode
[0]) {
382 // See if this is a generic print operand
383 return AsmPrinter::PrintAsmOperand(MI
, OpNo
, ExtraCode
, O
);
384 case 'L': // Low order register of a twin word register operand
385 case 'H': // High order register of a twin word register operand
387 const SparcSubtarget
&Subtarget
= MF
->getSubtarget
<SparcSubtarget
>();
388 const MachineOperand
&MO
= MI
->getOperand(OpNo
);
389 const SparcRegisterInfo
*RegisterInfo
= Subtarget
.getRegisterInfo();
390 Register MOReg
= MO
.getReg();
392 Register HiReg
, LoReg
;
393 if (!SP::IntPairRegClass
.contains(MOReg
)) {
394 // If we aren't given a register pair already, find out which pair it
395 // belongs to. Note that here, the specified register operand, which
396 // refers to the high part of the twinword, needs to be an even-numbered
398 MOReg
= RegisterInfo
->getMatchingSuperReg(MOReg
, SP::sub_even
,
399 &SP::IntPairRegClass
);
402 OutContext
.reportError(
403 Loc
, "Hi part of pair should point to an even-numbered register");
404 OutContext
.reportError(
405 Loc
, "(note that in some cases it might be necessary to manually "
406 "bind the input/output registers instead of relying on "
407 "automatic allocation)");
412 HiReg
= RegisterInfo
->getSubReg(MOReg
, SP::sub_even
);
413 LoReg
= RegisterInfo
->getSubReg(MOReg
, SP::sub_odd
);
416 switch (ExtraCode
[0]) {
425 O
<< '%' << SparcInstPrinter::getRegisterName(Reg
);
434 printOperand(MI
, OpNo
, O
);
439 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
441 const char *ExtraCode
,
443 if (ExtraCode
&& ExtraCode
[0])
444 return true; // Unknown modifier
447 printMemOperand(MI
, OpNo
, O
);
453 // Force static initialization.
454 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeSparcAsmPrinter() {
455 RegisterAsmPrinter
<SparcAsmPrinter
> X(getTheSparcTarget());
456 RegisterAsmPrinter
<SparcAsmPrinter
> Y(getTheSparcV9Target());
457 RegisterAsmPrinter
<SparcAsmPrinter
> Z(getTheSparcelTarget());