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 "InstPrinter/SparcInstPrinter.h"
15 #include "MCTargetDesc/SparcMCExpr.h"
16 #include "MCTargetDesc/SparcTargetStreamer.h"
18 #include "SparcInstrInfo.h"
19 #include "SparcTargetMachine.h"
20 #include "llvm/CodeGen/AsmPrinter.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
23 #include "llvm/CodeGen/MachineRegisterInfo.h"
24 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
25 #include "llvm/IR/Mangler.h"
26 #include "llvm/MC/MCAsmInfo.h"
27 #include "llvm/MC/MCContext.h"
28 #include "llvm/MC/MCInst.h"
29 #include "llvm/MC/MCStreamer.h"
30 #include "llvm/MC/MCSymbol.h"
31 #include "llvm/Support/TargetRegistry.h"
32 #include "llvm/Support/raw_ostream.h"
35 #define DEBUG_TYPE "asm-printer"
38 class SparcAsmPrinter
: public AsmPrinter
{
39 SparcTargetStreamer
&getTargetStreamer() {
40 return static_cast<SparcTargetStreamer
&>(
41 *OutStreamer
->getTargetStreamer());
44 explicit SparcAsmPrinter(TargetMachine
&TM
,
45 std::unique_ptr
<MCStreamer
> Streamer
)
46 : AsmPrinter(TM
, std::move(Streamer
)) {}
48 StringRef
getPassName() const override
{ return "Sparc Assembly Printer"; }
50 void printOperand(const MachineInstr
*MI
, int opNum
, raw_ostream
&OS
);
51 void printMemOperand(const MachineInstr
*MI
, int opNum
, raw_ostream
&OS
,
52 const char *Modifier
= nullptr);
54 void EmitFunctionBodyStart() override
;
55 void EmitInstruction(const MachineInstr
*MI
) override
;
57 static const char *getRegisterName(unsigned RegNo
) {
58 return SparcInstPrinter::getRegisterName(RegNo
);
61 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
62 unsigned AsmVariant
, const char *ExtraCode
,
63 raw_ostream
&O
) override
;
64 bool PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
65 unsigned AsmVariant
, const char *ExtraCode
,
66 raw_ostream
&O
) override
;
68 void LowerGETPCXAndEmitMCInsts(const MachineInstr
*MI
,
69 const MCSubtargetInfo
&STI
);
72 } // end of anonymous namespace
74 static MCOperand
createSparcMCOperand(SparcMCExpr::VariantKind Kind
,
75 MCSymbol
*Sym
, MCContext
&OutContext
) {
76 const MCSymbolRefExpr
*MCSym
= MCSymbolRefExpr::create(Sym
,
78 const SparcMCExpr
*expr
= SparcMCExpr::create(Kind
, MCSym
, OutContext
);
79 return MCOperand::createExpr(expr
);
82 static MCOperand
createPCXCallOP(MCSymbol
*Label
,
83 MCContext
&OutContext
) {
84 return createSparcMCOperand(SparcMCExpr::VK_Sparc_None
, Label
, OutContext
);
87 static MCOperand
createPCXRelExprOp(SparcMCExpr::VariantKind Kind
,
88 MCSymbol
*GOTLabel
, MCSymbol
*StartLabel
,
90 MCContext
&OutContext
)
92 const MCSymbolRefExpr
*GOT
= MCSymbolRefExpr::create(GOTLabel
, OutContext
);
93 const MCSymbolRefExpr
*Start
= MCSymbolRefExpr::create(StartLabel
,
95 const MCSymbolRefExpr
*Cur
= MCSymbolRefExpr::create(CurLabel
,
98 const MCBinaryExpr
*Sub
= MCBinaryExpr::createSub(Cur
, Start
, OutContext
);
99 const MCBinaryExpr
*Add
= MCBinaryExpr::createAdd(GOT
, Sub
, OutContext
);
100 const SparcMCExpr
*expr
= SparcMCExpr::create(Kind
,
102 return MCOperand::createExpr(expr
);
105 static void EmitCall(MCStreamer
&OutStreamer
,
107 const MCSubtargetInfo
&STI
)
110 CallInst
.setOpcode(SP::CALL
);
111 CallInst
.addOperand(Callee
);
112 OutStreamer
.EmitInstruction(CallInst
, STI
);
115 static void EmitSETHI(MCStreamer
&OutStreamer
,
116 MCOperand
&Imm
, MCOperand
&RD
,
117 const MCSubtargetInfo
&STI
)
120 SETHIInst
.setOpcode(SP::SETHIi
);
121 SETHIInst
.addOperand(RD
);
122 SETHIInst
.addOperand(Imm
);
123 OutStreamer
.EmitInstruction(SETHIInst
, STI
);
126 static void EmitBinary(MCStreamer
&OutStreamer
, unsigned Opcode
,
127 MCOperand
&RS1
, MCOperand
&Src2
, MCOperand
&RD
,
128 const MCSubtargetInfo
&STI
)
131 Inst
.setOpcode(Opcode
);
133 Inst
.addOperand(RS1
);
134 Inst
.addOperand(Src2
);
135 OutStreamer
.EmitInstruction(Inst
, STI
);
138 static void EmitOR(MCStreamer
&OutStreamer
,
139 MCOperand
&RS1
, MCOperand
&Imm
, MCOperand
&RD
,
140 const MCSubtargetInfo
&STI
) {
141 EmitBinary(OutStreamer
, SP::ORri
, RS1
, Imm
, RD
, STI
);
144 static void EmitADD(MCStreamer
&OutStreamer
,
145 MCOperand
&RS1
, MCOperand
&RS2
, MCOperand
&RD
,
146 const MCSubtargetInfo
&STI
) {
147 EmitBinary(OutStreamer
, SP::ADDrr
, RS1
, RS2
, RD
, STI
);
150 static void EmitSHL(MCStreamer
&OutStreamer
,
151 MCOperand
&RS1
, MCOperand
&Imm
, MCOperand
&RD
,
152 const MCSubtargetInfo
&STI
) {
153 EmitBinary(OutStreamer
, SP::SLLri
, RS1
, Imm
, RD
, STI
);
157 static void EmitHiLo(MCStreamer
&OutStreamer
, MCSymbol
*GOTSym
,
158 SparcMCExpr::VariantKind HiKind
,
159 SparcMCExpr::VariantKind LoKind
,
161 MCContext
&OutContext
,
162 const MCSubtargetInfo
&STI
) {
164 MCOperand hi
= createSparcMCOperand(HiKind
, GOTSym
, OutContext
);
165 MCOperand lo
= createSparcMCOperand(LoKind
, GOTSym
, OutContext
);
166 EmitSETHI(OutStreamer
, hi
, RD
, STI
);
167 EmitOR(OutStreamer
, RD
, lo
, RD
, STI
);
170 void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr
*MI
,
171 const MCSubtargetInfo
&STI
)
174 OutContext
.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
176 const MachineOperand
&MO
= MI
->getOperand(0);
177 assert(MO
.getReg() != SP::O7
&&
178 "%o7 is assigned as destination for getpcx!");
180 MCOperand MCRegOP
= MCOperand::createReg(MO
.getReg());
183 if (!isPositionIndependent()) {
184 // Just load the address of GOT to MCRegOP.
185 switch(TM
.getCodeModel()) {
187 llvm_unreachable("Unsupported absolute code model");
188 case CodeModel::Small
:
189 EmitHiLo(*OutStreamer
, GOTLabel
,
190 SparcMCExpr::VK_Sparc_HI
, SparcMCExpr::VK_Sparc_LO
,
191 MCRegOP
, OutContext
, STI
);
193 case CodeModel::Medium
: {
194 EmitHiLo(*OutStreamer
, GOTLabel
,
195 SparcMCExpr::VK_Sparc_H44
, SparcMCExpr::VK_Sparc_M44
,
196 MCRegOP
, OutContext
, STI
);
197 MCOperand imm
= MCOperand::createExpr(MCConstantExpr::create(12,
199 EmitSHL(*OutStreamer
, MCRegOP
, imm
, MCRegOP
, STI
);
200 MCOperand lo
= createSparcMCOperand(SparcMCExpr::VK_Sparc_L44
,
201 GOTLabel
, OutContext
);
202 EmitOR(*OutStreamer
, MCRegOP
, lo
, MCRegOP
, STI
);
205 case CodeModel::Large
: {
206 EmitHiLo(*OutStreamer
, GOTLabel
,
207 SparcMCExpr::VK_Sparc_HH
, SparcMCExpr::VK_Sparc_HM
,
208 MCRegOP
, OutContext
, STI
);
209 MCOperand imm
= MCOperand::createExpr(MCConstantExpr::create(32,
211 EmitSHL(*OutStreamer
, MCRegOP
, imm
, MCRegOP
, STI
);
212 // Use register %o7 to load the lower 32 bits.
213 MCOperand RegO7
= MCOperand::createReg(SP::O7
);
214 EmitHiLo(*OutStreamer
, GOTLabel
,
215 SparcMCExpr::VK_Sparc_HI
, SparcMCExpr::VK_Sparc_LO
,
216 RegO7
, OutContext
, STI
);
217 EmitADD(*OutStreamer
, MCRegOP
, RegO7
, MCRegOP
, STI
);
223 MCSymbol
*StartLabel
= OutContext
.createTempSymbol();
224 MCSymbol
*EndLabel
= OutContext
.createTempSymbol();
225 MCSymbol
*SethiLabel
= OutContext
.createTempSymbol();
227 MCOperand RegO7
= MCOperand::createReg(SP::O7
);
232 // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
234 // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
235 // add <MO>, %o7, <MO>
237 OutStreamer
->EmitLabel(StartLabel
);
238 MCOperand Callee
= createPCXCallOP(EndLabel
, OutContext
);
239 EmitCall(*OutStreamer
, Callee
, STI
);
240 OutStreamer
->EmitLabel(SethiLabel
);
241 MCOperand hiImm
= createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22
,
242 GOTLabel
, StartLabel
, SethiLabel
,
244 EmitSETHI(*OutStreamer
, hiImm
, MCRegOP
, STI
);
245 OutStreamer
->EmitLabel(EndLabel
);
246 MCOperand loImm
= createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10
,
247 GOTLabel
, StartLabel
, EndLabel
,
249 EmitOR(*OutStreamer
, MCRegOP
, loImm
, MCRegOP
, STI
);
250 EmitADD(*OutStreamer
, MCRegOP
, RegO7
, MCRegOP
, STI
);
253 void SparcAsmPrinter::EmitInstruction(const MachineInstr
*MI
)
256 switch (MI
->getOpcode()) {
258 case TargetOpcode::DBG_VALUE
:
259 // FIXME: Debug Value.
262 LowerGETPCXAndEmitMCInsts(MI
, getSubtargetInfo());
265 MachineBasicBlock::const_instr_iterator I
= MI
->getIterator();
266 MachineBasicBlock::const_instr_iterator E
= MI
->getParent()->instr_end();
269 LowerSparcMachineInstrToMCInst(&*I
, TmpInst
, *this);
270 EmitToStreamer(*OutStreamer
, TmpInst
);
271 } while ((++I
!= E
) && I
->isInsideBundle()); // Delay slot check.
274 void SparcAsmPrinter::EmitFunctionBodyStart() {
275 if (!MF
->getSubtarget
<SparcSubtarget
>().is64Bit())
278 const MachineRegisterInfo
&MRI
= MF
->getRegInfo();
279 const unsigned globalRegs
[] = { SP::G2
, SP::G3
, SP::G6
, SP::G7
, 0 };
280 for (unsigned i
= 0; globalRegs
[i
] != 0; ++i
) {
281 unsigned reg
= globalRegs
[i
];
282 if (MRI
.use_empty(reg
))
285 if (reg
== SP::G6
|| reg
== SP::G7
)
286 getTargetStreamer().emitSparcRegisterIgnore(reg
);
288 getTargetStreamer().emitSparcRegisterScratch(reg
);
292 void SparcAsmPrinter::printOperand(const MachineInstr
*MI
, int opNum
,
294 const DataLayout
&DL
= getDataLayout();
295 const MachineOperand
&MO
= MI
->getOperand (opNum
);
296 SparcMCExpr::VariantKind TF
= (SparcMCExpr::VariantKind
) MO
.getTargetFlags();
299 // Verify the target flags.
300 if (MO
.isGlobal() || MO
.isSymbol() || MO
.isCPI()) {
301 if (MI
->getOpcode() == SP::CALL
)
302 assert(TF
== SparcMCExpr::VK_Sparc_None
&&
303 "Cannot handle target flags on call address");
304 else if (MI
->getOpcode() == SP::SETHIi
|| MI
->getOpcode() == SP::SETHIXi
)
305 assert((TF
== SparcMCExpr::VK_Sparc_HI
306 || TF
== SparcMCExpr::VK_Sparc_H44
307 || TF
== SparcMCExpr::VK_Sparc_HH
308 || TF
== SparcMCExpr::VK_Sparc_TLS_GD_HI22
309 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_HI22
310 || TF
== SparcMCExpr::VK_Sparc_TLS_LDO_HIX22
311 || TF
== SparcMCExpr::VK_Sparc_TLS_IE_HI22
312 || TF
== SparcMCExpr::VK_Sparc_TLS_LE_HIX22
) &&
313 "Invalid target flags for address operand on sethi");
314 else if (MI
->getOpcode() == SP::TLS_CALL
)
315 assert((TF
== SparcMCExpr::VK_Sparc_None
316 || TF
== SparcMCExpr::VK_Sparc_TLS_GD_CALL
317 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_CALL
) &&
318 "Cannot handle target flags on tls call address");
319 else if (MI
->getOpcode() == SP::TLS_ADDrr
)
320 assert((TF
== SparcMCExpr::VK_Sparc_TLS_GD_ADD
321 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_ADD
322 || TF
== SparcMCExpr::VK_Sparc_TLS_LDO_ADD
323 || TF
== SparcMCExpr::VK_Sparc_TLS_IE_ADD
) &&
324 "Cannot handle target flags on add for TLS");
325 else if (MI
->getOpcode() == SP::TLS_LDrr
)
326 assert(TF
== SparcMCExpr::VK_Sparc_TLS_IE_LD
&&
327 "Cannot handle target flags on ld for TLS");
328 else if (MI
->getOpcode() == SP::TLS_LDXrr
)
329 assert(TF
== SparcMCExpr::VK_Sparc_TLS_IE_LDX
&&
330 "Cannot handle target flags on ldx for TLS");
331 else if (MI
->getOpcode() == SP::XORri
|| MI
->getOpcode() == SP::XORXri
)
332 assert((TF
== SparcMCExpr::VK_Sparc_TLS_LDO_LOX10
333 || TF
== SparcMCExpr::VK_Sparc_TLS_LE_LOX10
) &&
334 "Cannot handle target flags on xor for TLS");
336 assert((TF
== SparcMCExpr::VK_Sparc_LO
337 || TF
== SparcMCExpr::VK_Sparc_M44
338 || TF
== SparcMCExpr::VK_Sparc_L44
339 || TF
== SparcMCExpr::VK_Sparc_HM
340 || TF
== SparcMCExpr::VK_Sparc_TLS_GD_LO10
341 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_LO10
342 || TF
== SparcMCExpr::VK_Sparc_TLS_IE_LO10
) &&
343 "Invalid target flags for small address operand");
348 bool CloseParen
= SparcMCExpr::printVariantKind(O
, TF
);
350 switch (MO
.getType()) {
351 case MachineOperand::MO_Register
:
352 O
<< "%" << StringRef(getRegisterName(MO
.getReg())).lower();
355 case MachineOperand::MO_Immediate
:
356 O
<< (int)MO
.getImm();
358 case MachineOperand::MO_MachineBasicBlock
:
359 MO
.getMBB()->getSymbol()->print(O
, MAI
);
361 case MachineOperand::MO_GlobalAddress
:
362 getSymbol(MO
.getGlobal())->print(O
, MAI
);
364 case MachineOperand::MO_BlockAddress
:
365 O
<< GetBlockAddressSymbol(MO
.getBlockAddress())->getName();
367 case MachineOperand::MO_ExternalSymbol
:
368 O
<< MO
.getSymbolName();
370 case MachineOperand::MO_ConstantPoolIndex
:
371 O
<< DL
.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
374 case MachineOperand::MO_Metadata
:
375 MO
.getMetadata()->printAsOperand(O
, MMI
->getModule());
378 llvm_unreachable("<unknown operand type>");
380 if (CloseParen
) O
<< ")";
383 void SparcAsmPrinter::printMemOperand(const MachineInstr
*MI
, int opNum
,
384 raw_ostream
&O
, const char *Modifier
) {
385 printOperand(MI
, opNum
, O
);
387 // If this is an ADD operand, emit it like normal operands.
388 if (Modifier
&& !strcmp(Modifier
, "arith")) {
390 printOperand(MI
, opNum
+1, O
);
394 if (MI
->getOperand(opNum
+1).isReg() &&
395 MI
->getOperand(opNum
+1).getReg() == SP::G0
)
396 return; // don't print "+%g0"
397 if (MI
->getOperand(opNum
+1).isImm() &&
398 MI
->getOperand(opNum
+1).getImm() == 0)
399 return; // don't print "+0"
402 printOperand(MI
, opNum
+1, O
);
405 /// PrintAsmOperand - Print out an operand for an inline asm expression.
407 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
409 const char *ExtraCode
,
411 if (ExtraCode
&& ExtraCode
[0]) {
412 if (ExtraCode
[1] != 0) return true; // Unknown modifier.
414 switch (ExtraCode
[0]) {
416 // See if this is a generic print operand
417 return AsmPrinter::PrintAsmOperand(MI
, OpNo
, AsmVariant
, ExtraCode
, O
);
424 printOperand(MI
, OpNo
, O
);
429 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
430 unsigned OpNo
, unsigned AsmVariant
,
431 const char *ExtraCode
,
433 if (ExtraCode
&& ExtraCode
[0])
434 return true; // Unknown modifier
437 printMemOperand(MI
, OpNo
, O
);
443 // Force static initialization.
444 extern "C" void LLVMInitializeSparcAsmPrinter() {
445 RegisterAsmPrinter
<SparcAsmPrinter
> X(getTheSparcTarget());
446 RegisterAsmPrinter
<SparcAsmPrinter
> Y(getTheSparcV9Target());
447 RegisterAsmPrinter
<SparcAsmPrinter
> Z(getTheSparcelTarget());