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/SparcTargetStreamer.h"
18 #include "SparcInstrInfo.h"
19 #include "SparcTargetMachine.h"
20 #include "TargetInfo/SparcTargetInfo.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"
36 #define DEBUG_TYPE "asm-printer"
39 class SparcAsmPrinter
: public AsmPrinter
{
40 SparcTargetStreamer
&getTargetStreamer() {
41 return static_cast<SparcTargetStreamer
&>(
42 *OutStreamer
->getTargetStreamer());
45 explicit SparcAsmPrinter(TargetMachine
&TM
,
46 std::unique_ptr
<MCStreamer
> Streamer
)
47 : AsmPrinter(TM
, std::move(Streamer
)) {}
49 StringRef
getPassName() const override
{ return "Sparc Assembly Printer"; }
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
= nullptr);
55 void EmitFunctionBodyStart() override
;
56 void EmitInstruction(const MachineInstr
*MI
) override
;
58 static const char *getRegisterName(unsigned RegNo
) {
59 return SparcInstPrinter::getRegisterName(RegNo
);
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_None
, 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 EmitSETHI(MCStreamer
&OutStreamer
,
115 MCOperand
&Imm
, MCOperand
&RD
,
116 const MCSubtargetInfo
&STI
)
119 SETHIInst
.setOpcode(SP::SETHIi
);
120 SETHIInst
.addOperand(RD
);
121 SETHIInst
.addOperand(Imm
);
122 OutStreamer
.EmitInstruction(SETHIInst
, STI
);
125 static void EmitBinary(MCStreamer
&OutStreamer
, unsigned Opcode
,
126 MCOperand
&RS1
, MCOperand
&Src2
, MCOperand
&RD
,
127 const MCSubtargetInfo
&STI
)
130 Inst
.setOpcode(Opcode
);
132 Inst
.addOperand(RS1
);
133 Inst
.addOperand(Src2
);
134 OutStreamer
.EmitInstruction(Inst
, STI
);
137 static void EmitOR(MCStreamer
&OutStreamer
,
138 MCOperand
&RS1
, MCOperand
&Imm
, MCOperand
&RD
,
139 const MCSubtargetInfo
&STI
) {
140 EmitBinary(OutStreamer
, SP::ORri
, RS1
, Imm
, RD
, STI
);
143 static void EmitADD(MCStreamer
&OutStreamer
,
144 MCOperand
&RS1
, MCOperand
&RS2
, MCOperand
&RD
,
145 const MCSubtargetInfo
&STI
) {
146 EmitBinary(OutStreamer
, SP::ADDrr
, RS1
, RS2
, RD
, STI
);
149 static void EmitSHL(MCStreamer
&OutStreamer
,
150 MCOperand
&RS1
, MCOperand
&Imm
, MCOperand
&RD
,
151 const MCSubtargetInfo
&STI
) {
152 EmitBinary(OutStreamer
, SP::SLLri
, RS1
, Imm
, RD
, STI
);
156 static void EmitHiLo(MCStreamer
&OutStreamer
, MCSymbol
*GOTSym
,
157 SparcMCExpr::VariantKind HiKind
,
158 SparcMCExpr::VariantKind LoKind
,
160 MCContext
&OutContext
,
161 const MCSubtargetInfo
&STI
) {
163 MCOperand hi
= createSparcMCOperand(HiKind
, GOTSym
, OutContext
);
164 MCOperand lo
= createSparcMCOperand(LoKind
, GOTSym
, OutContext
);
165 EmitSETHI(OutStreamer
, hi
, RD
, STI
);
166 EmitOR(OutStreamer
, RD
, lo
, RD
, STI
);
169 void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr
*MI
,
170 const MCSubtargetInfo
&STI
)
173 OutContext
.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
175 const MachineOperand
&MO
= MI
->getOperand(0);
176 assert(MO
.getReg() != SP::O7
&&
177 "%o7 is assigned as destination for getpcx!");
179 MCOperand MCRegOP
= MCOperand::createReg(MO
.getReg());
182 if (!isPositionIndependent()) {
183 // Just load the address of GOT to MCRegOP.
184 switch(TM
.getCodeModel()) {
186 llvm_unreachable("Unsupported absolute code model");
187 case CodeModel::Small
:
188 EmitHiLo(*OutStreamer
, GOTLabel
,
189 SparcMCExpr::VK_Sparc_HI
, SparcMCExpr::VK_Sparc_LO
,
190 MCRegOP
, OutContext
, STI
);
192 case CodeModel::Medium
: {
193 EmitHiLo(*OutStreamer
, GOTLabel
,
194 SparcMCExpr::VK_Sparc_H44
, SparcMCExpr::VK_Sparc_M44
,
195 MCRegOP
, OutContext
, STI
);
196 MCOperand imm
= MCOperand::createExpr(MCConstantExpr::create(12,
198 EmitSHL(*OutStreamer
, MCRegOP
, imm
, MCRegOP
, STI
);
199 MCOperand lo
= createSparcMCOperand(SparcMCExpr::VK_Sparc_L44
,
200 GOTLabel
, OutContext
);
201 EmitOR(*OutStreamer
, MCRegOP
, lo
, MCRegOP
, STI
);
204 case CodeModel::Large
: {
205 EmitHiLo(*OutStreamer
, GOTLabel
,
206 SparcMCExpr::VK_Sparc_HH
, SparcMCExpr::VK_Sparc_HM
,
207 MCRegOP
, OutContext
, STI
);
208 MCOperand imm
= MCOperand::createExpr(MCConstantExpr::create(32,
210 EmitSHL(*OutStreamer
, MCRegOP
, imm
, MCRegOP
, STI
);
211 // Use register %o7 to load the lower 32 bits.
212 MCOperand RegO7
= MCOperand::createReg(SP::O7
);
213 EmitHiLo(*OutStreamer
, GOTLabel
,
214 SparcMCExpr::VK_Sparc_HI
, SparcMCExpr::VK_Sparc_LO
,
215 RegO7
, OutContext
, STI
);
216 EmitADD(*OutStreamer
, MCRegOP
, RegO7
, MCRegOP
, STI
);
222 MCSymbol
*StartLabel
= OutContext
.createTempSymbol();
223 MCSymbol
*EndLabel
= OutContext
.createTempSymbol();
224 MCSymbol
*SethiLabel
= OutContext
.createTempSymbol();
226 MCOperand RegO7
= MCOperand::createReg(SP::O7
);
231 // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
233 // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
234 // add <MO>, %o7, <MO>
236 OutStreamer
->EmitLabel(StartLabel
);
237 MCOperand Callee
= createPCXCallOP(EndLabel
, OutContext
);
238 EmitCall(*OutStreamer
, Callee
, STI
);
239 OutStreamer
->EmitLabel(SethiLabel
);
240 MCOperand hiImm
= createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22
,
241 GOTLabel
, StartLabel
, SethiLabel
,
243 EmitSETHI(*OutStreamer
, hiImm
, MCRegOP
, STI
);
244 OutStreamer
->EmitLabel(EndLabel
);
245 MCOperand loImm
= createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10
,
246 GOTLabel
, StartLabel
, EndLabel
,
248 EmitOR(*OutStreamer
, MCRegOP
, loImm
, MCRegOP
, STI
);
249 EmitADD(*OutStreamer
, MCRegOP
, RegO7
, MCRegOP
, STI
);
252 void SparcAsmPrinter::EmitInstruction(const MachineInstr
*MI
)
255 switch (MI
->getOpcode()) {
257 case TargetOpcode::DBG_VALUE
:
258 // FIXME: Debug Value.
261 LowerGETPCXAndEmitMCInsts(MI
, getSubtargetInfo());
264 MachineBasicBlock::const_instr_iterator I
= MI
->getIterator();
265 MachineBasicBlock::const_instr_iterator E
= MI
->getParent()->instr_end();
268 LowerSparcMachineInstrToMCInst(&*I
, TmpInst
, *this);
269 EmitToStreamer(*OutStreamer
, TmpInst
);
270 } while ((++I
!= E
) && I
->isInsideBundle()); // Delay slot check.
273 void SparcAsmPrinter::EmitFunctionBodyStart() {
274 if (!MF
->getSubtarget
<SparcSubtarget
>().is64Bit())
277 const MachineRegisterInfo
&MRI
= MF
->getRegInfo();
278 const unsigned globalRegs
[] = { SP::G2
, SP::G3
, SP::G6
, SP::G7
, 0 };
279 for (unsigned i
= 0; globalRegs
[i
] != 0; ++i
) {
280 unsigned reg
= globalRegs
[i
];
281 if (MRI
.use_empty(reg
))
284 if (reg
== SP::G6
|| reg
== SP::G7
)
285 getTargetStreamer().emitSparcRegisterIgnore(reg
);
287 getTargetStreamer().emitSparcRegisterScratch(reg
);
291 void SparcAsmPrinter::printOperand(const MachineInstr
*MI
, int opNum
,
293 const DataLayout
&DL
= getDataLayout();
294 const MachineOperand
&MO
= MI
->getOperand (opNum
);
295 SparcMCExpr::VariantKind TF
= (SparcMCExpr::VariantKind
) MO
.getTargetFlags();
298 // Verify the target flags.
299 if (MO
.isGlobal() || MO
.isSymbol() || MO
.isCPI()) {
300 if (MI
->getOpcode() == SP::CALL
)
301 assert(TF
== SparcMCExpr::VK_Sparc_None
&&
302 "Cannot handle target flags on call address");
303 else if (MI
->getOpcode() == SP::SETHIi
|| MI
->getOpcode() == SP::SETHIXi
)
304 assert((TF
== SparcMCExpr::VK_Sparc_HI
305 || TF
== SparcMCExpr::VK_Sparc_H44
306 || TF
== SparcMCExpr::VK_Sparc_HH
307 || TF
== SparcMCExpr::VK_Sparc_TLS_GD_HI22
308 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_HI22
309 || TF
== SparcMCExpr::VK_Sparc_TLS_LDO_HIX22
310 || TF
== SparcMCExpr::VK_Sparc_TLS_IE_HI22
311 || TF
== SparcMCExpr::VK_Sparc_TLS_LE_HIX22
) &&
312 "Invalid target flags for address operand on sethi");
313 else if (MI
->getOpcode() == SP::TLS_CALL
)
314 assert((TF
== SparcMCExpr::VK_Sparc_None
315 || TF
== SparcMCExpr::VK_Sparc_TLS_GD_CALL
316 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_CALL
) &&
317 "Cannot handle target flags on tls call address");
318 else if (MI
->getOpcode() == SP::TLS_ADDrr
)
319 assert((TF
== SparcMCExpr::VK_Sparc_TLS_GD_ADD
320 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_ADD
321 || TF
== SparcMCExpr::VK_Sparc_TLS_LDO_ADD
322 || TF
== SparcMCExpr::VK_Sparc_TLS_IE_ADD
) &&
323 "Cannot handle target flags on add for TLS");
324 else if (MI
->getOpcode() == SP::TLS_LDrr
)
325 assert(TF
== SparcMCExpr::VK_Sparc_TLS_IE_LD
&&
326 "Cannot handle target flags on ld for TLS");
327 else if (MI
->getOpcode() == SP::TLS_LDXrr
)
328 assert(TF
== SparcMCExpr::VK_Sparc_TLS_IE_LDX
&&
329 "Cannot handle target flags on ldx for TLS");
330 else if (MI
->getOpcode() == SP::XORri
|| MI
->getOpcode() == SP::XORXri
)
331 assert((TF
== SparcMCExpr::VK_Sparc_TLS_LDO_LOX10
332 || TF
== SparcMCExpr::VK_Sparc_TLS_LE_LOX10
) &&
333 "Cannot handle target flags on xor for TLS");
335 assert((TF
== SparcMCExpr::VK_Sparc_LO
336 || TF
== SparcMCExpr::VK_Sparc_M44
337 || TF
== SparcMCExpr::VK_Sparc_L44
338 || TF
== SparcMCExpr::VK_Sparc_HM
339 || TF
== SparcMCExpr::VK_Sparc_TLS_GD_LO10
340 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_LO10
341 || TF
== SparcMCExpr::VK_Sparc_TLS_IE_LO10
) &&
342 "Invalid target flags for small address operand");
347 bool CloseParen
= SparcMCExpr::printVariantKind(O
, TF
);
349 switch (MO
.getType()) {
350 case MachineOperand::MO_Register
:
351 O
<< "%" << StringRef(getRegisterName(MO
.getReg())).lower();
354 case MachineOperand::MO_Immediate
:
355 O
<< (int)MO
.getImm();
357 case MachineOperand::MO_MachineBasicBlock
:
358 MO
.getMBB()->getSymbol()->print(O
, MAI
);
360 case MachineOperand::MO_GlobalAddress
:
361 PrintSymbolOperand(MO
, O
);
363 case MachineOperand::MO_BlockAddress
:
364 O
<< GetBlockAddressSymbol(MO
.getBlockAddress())->getName();
366 case MachineOperand::MO_ExternalSymbol
:
367 O
<< MO
.getSymbolName();
369 case MachineOperand::MO_ConstantPoolIndex
:
370 O
<< DL
.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
373 case MachineOperand::MO_Metadata
:
374 MO
.getMetadata()->printAsOperand(O
, MMI
->getModule());
377 llvm_unreachable("<unknown operand type>");
379 if (CloseParen
) O
<< ")";
382 void SparcAsmPrinter::printMemOperand(const MachineInstr
*MI
, int opNum
,
383 raw_ostream
&O
, const char *Modifier
) {
384 printOperand(MI
, opNum
, O
);
386 // If this is an ADD operand, emit it like normal operands.
387 if (Modifier
&& !strcmp(Modifier
, "arith")) {
389 printOperand(MI
, opNum
+1, O
);
393 if (MI
->getOperand(opNum
+1).isReg() &&
394 MI
->getOperand(opNum
+1).getReg() == SP::G0
)
395 return; // don't print "+%g0"
396 if (MI
->getOperand(opNum
+1).isImm() &&
397 MI
->getOperand(opNum
+1).getImm() == 0)
398 return; // don't print "+0"
401 printOperand(MI
, opNum
+1, O
);
404 /// PrintAsmOperand - Print out an operand for an inline asm expression.
406 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
407 const char *ExtraCode
,
409 if (ExtraCode
&& ExtraCode
[0]) {
410 if (ExtraCode
[1] != 0) return true; // Unknown modifier.
412 switch (ExtraCode
[0]) {
414 // See if this is a generic print operand
415 return AsmPrinter::PrintAsmOperand(MI
, OpNo
, ExtraCode
, O
);
422 printOperand(MI
, OpNo
, O
);
427 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
429 const char *ExtraCode
,
431 if (ExtraCode
&& ExtraCode
[0])
432 return true; // Unknown modifier
435 printMemOperand(MI
, OpNo
, O
);
441 // Force static initialization.
442 extern "C" void LLVMInitializeSparcAsmPrinter() {
443 RegisterAsmPrinter
<SparcAsmPrinter
> X(getTheSparcTarget());
444 RegisterAsmPrinter
<SparcAsmPrinter
> Y(getTheSparcV9Target());
445 RegisterAsmPrinter
<SparcAsmPrinter
> Z(getTheSparcelTarget());