1 //===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains a printer that converts from our internal representation
11 // of machine-dependent LLVM code to GAS-format SPARC assembly language.
13 //===----------------------------------------------------------------------===//
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/ADT/SmallString.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/Support/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
, MCStreamer
&Streamer
)
47 : AsmPrinter(TM
, Streamer
) {}
49 const char *getPassName() const override
{
50 return "Sparc Assembly Printer";
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 void printCCOperand(const MachineInstr
*MI
, int opNum
, raw_ostream
&OS
);
58 void EmitFunctionBodyStart() override
;
59 void EmitInstruction(const MachineInstr
*MI
) override
;
60 void EmitEndOfAsmFile(Module
&M
) override
;
62 static const char *getRegisterName(unsigned RegNo
) {
63 return SparcInstPrinter::getRegisterName(RegNo
);
66 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
67 unsigned AsmVariant
, const char *ExtraCode
,
68 raw_ostream
&O
) override
;
69 bool PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
70 unsigned AsmVariant
, const char *ExtraCode
,
71 raw_ostream
&O
) override
;
73 void LowerGETPCXAndEmitMCInsts(const MachineInstr
*MI
,
74 const MCSubtargetInfo
&STI
);
77 } // end of anonymous namespace
79 static MCOperand
createSparcMCOperand(SparcMCExpr::VariantKind Kind
,
80 MCSymbol
*Sym
, MCContext
&OutContext
) {
81 const MCSymbolRefExpr
*MCSym
= MCSymbolRefExpr::Create(Sym
,
83 const SparcMCExpr
*expr
= SparcMCExpr::Create(Kind
, MCSym
, OutContext
);
84 return MCOperand::CreateExpr(expr
);
87 static MCOperand
createPCXCallOP(MCSymbol
*Label
,
88 MCContext
&OutContext
) {
89 return createSparcMCOperand(SparcMCExpr::VK_Sparc_None
, Label
, OutContext
);
92 static MCOperand
createPCXRelExprOp(SparcMCExpr::VariantKind Kind
,
93 MCSymbol
*GOTLabel
, MCSymbol
*StartLabel
,
95 MCContext
&OutContext
)
97 const MCSymbolRefExpr
*GOT
= MCSymbolRefExpr::Create(GOTLabel
, OutContext
);
98 const MCSymbolRefExpr
*Start
= MCSymbolRefExpr::Create(StartLabel
,
100 const MCSymbolRefExpr
*Cur
= MCSymbolRefExpr::Create(CurLabel
,
103 const MCBinaryExpr
*Sub
= MCBinaryExpr::CreateSub(Cur
, Start
, OutContext
);
104 const MCBinaryExpr
*Add
= MCBinaryExpr::CreateAdd(GOT
, Sub
, OutContext
);
105 const SparcMCExpr
*expr
= SparcMCExpr::Create(Kind
,
107 return MCOperand::CreateExpr(expr
);
110 static void EmitCall(MCStreamer
&OutStreamer
,
112 const MCSubtargetInfo
&STI
)
115 CallInst
.setOpcode(SP::CALL
);
116 CallInst
.addOperand(Callee
);
117 OutStreamer
.EmitInstruction(CallInst
, STI
);
120 static void EmitSETHI(MCStreamer
&OutStreamer
,
121 MCOperand
&Imm
, MCOperand
&RD
,
122 const MCSubtargetInfo
&STI
)
125 SETHIInst
.setOpcode(SP::SETHIi
);
126 SETHIInst
.addOperand(RD
);
127 SETHIInst
.addOperand(Imm
);
128 OutStreamer
.EmitInstruction(SETHIInst
, STI
);
131 static void EmitBinary(MCStreamer
&OutStreamer
, unsigned Opcode
,
132 MCOperand
&RS1
, MCOperand
&Src2
, MCOperand
&RD
,
133 const MCSubtargetInfo
&STI
)
136 Inst
.setOpcode(Opcode
);
138 Inst
.addOperand(RS1
);
139 Inst
.addOperand(Src2
);
140 OutStreamer
.EmitInstruction(Inst
, STI
);
143 static void EmitOR(MCStreamer
&OutStreamer
,
144 MCOperand
&RS1
, MCOperand
&Imm
, MCOperand
&RD
,
145 const MCSubtargetInfo
&STI
) {
146 EmitBinary(OutStreamer
, SP::ORri
, RS1
, Imm
, RD
, STI
);
149 static void EmitADD(MCStreamer
&OutStreamer
,
150 MCOperand
&RS1
, MCOperand
&RS2
, MCOperand
&RD
,
151 const MCSubtargetInfo
&STI
) {
152 EmitBinary(OutStreamer
, SP::ADDrr
, RS1
, RS2
, RD
, STI
);
155 static void EmitSHL(MCStreamer
&OutStreamer
,
156 MCOperand
&RS1
, MCOperand
&Imm
, MCOperand
&RD
,
157 const MCSubtargetInfo
&STI
) {
158 EmitBinary(OutStreamer
, SP::SLLri
, RS1
, Imm
, RD
, STI
);
162 static void EmitHiLo(MCStreamer
&OutStreamer
, MCSymbol
*GOTSym
,
163 SparcMCExpr::VariantKind HiKind
,
164 SparcMCExpr::VariantKind LoKind
,
166 MCContext
&OutContext
,
167 const MCSubtargetInfo
&STI
) {
169 MCOperand hi
= createSparcMCOperand(HiKind
, GOTSym
, OutContext
);
170 MCOperand lo
= createSparcMCOperand(LoKind
, GOTSym
, OutContext
);
171 EmitSETHI(OutStreamer
, hi
, RD
, STI
);
172 EmitOR(OutStreamer
, RD
, lo
, RD
, STI
);
175 void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr
*MI
,
176 const MCSubtargetInfo
&STI
)
179 OutContext
.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
181 const MachineOperand
&MO
= MI
->getOperand(0);
182 assert(MO
.getReg() != SP::O7
&&
183 "%o7 is assigned as destination for getpcx!");
185 MCOperand MCRegOP
= MCOperand::CreateReg(MO
.getReg());
188 if (TM
.getRelocationModel() != Reloc::PIC_
) {
189 // Just load the address of GOT to MCRegOP.
190 switch(TM
.getCodeModel()) {
192 llvm_unreachable("Unsupported absolute code model");
193 case CodeModel::Small
:
194 EmitHiLo(OutStreamer
, GOTLabel
,
195 SparcMCExpr::VK_Sparc_HI
, SparcMCExpr::VK_Sparc_LO
,
196 MCRegOP
, OutContext
, STI
);
198 case CodeModel::Medium
: {
199 EmitHiLo(OutStreamer
, GOTLabel
,
200 SparcMCExpr::VK_Sparc_H44
, SparcMCExpr::VK_Sparc_M44
,
201 MCRegOP
, OutContext
, STI
);
202 MCOperand imm
= MCOperand::CreateExpr(MCConstantExpr::Create(12,
204 EmitSHL(OutStreamer
, MCRegOP
, imm
, MCRegOP
, STI
);
205 MCOperand lo
= createSparcMCOperand(SparcMCExpr::VK_Sparc_L44
,
206 GOTLabel
, OutContext
);
207 EmitOR(OutStreamer
, MCRegOP
, lo
, MCRegOP
, STI
);
210 case CodeModel::Large
: {
211 EmitHiLo(OutStreamer
, GOTLabel
,
212 SparcMCExpr::VK_Sparc_HH
, SparcMCExpr::VK_Sparc_HM
,
213 MCRegOP
, OutContext
, STI
);
214 MCOperand imm
= MCOperand::CreateExpr(MCConstantExpr::Create(32,
216 EmitSHL(OutStreamer
, MCRegOP
, imm
, MCRegOP
, STI
);
217 // Use register %o7 to load the lower 32 bits.
218 MCOperand RegO7
= MCOperand::CreateReg(SP::O7
);
219 EmitHiLo(OutStreamer
, GOTLabel
,
220 SparcMCExpr::VK_Sparc_HI
, SparcMCExpr::VK_Sparc_LO
,
221 RegO7
, OutContext
, STI
);
222 EmitADD(OutStreamer
, MCRegOP
, RegO7
, MCRegOP
, STI
);
228 MCSymbol
*StartLabel
= OutContext
.CreateTempSymbol();
229 MCSymbol
*EndLabel
= OutContext
.CreateTempSymbol();
230 MCSymbol
*SethiLabel
= OutContext
.CreateTempSymbol();
232 MCOperand RegO7
= MCOperand::CreateReg(SP::O7
);
237 // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
239 // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
240 // add <MO>, %o7, <MO>
242 OutStreamer
.EmitLabel(StartLabel
);
243 MCOperand Callee
= createPCXCallOP(EndLabel
, OutContext
);
244 EmitCall(OutStreamer
, Callee
, STI
);
245 OutStreamer
.EmitLabel(SethiLabel
);
246 MCOperand hiImm
= createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22
,
247 GOTLabel
, StartLabel
, SethiLabel
,
249 EmitSETHI(OutStreamer
, hiImm
, MCRegOP
, STI
);
250 OutStreamer
.EmitLabel(EndLabel
);
251 MCOperand loImm
= createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10
,
252 GOTLabel
, StartLabel
, EndLabel
,
254 EmitOR(OutStreamer
, MCRegOP
, loImm
, MCRegOP
, STI
);
255 EmitADD(OutStreamer
, MCRegOP
, RegO7
, MCRegOP
, STI
);
258 void SparcAsmPrinter::EmitInstruction(const MachineInstr
*MI
)
261 switch (MI
->getOpcode()) {
263 case TargetOpcode::DBG_VALUE
:
264 // FIXME: Debug Value.
267 LowerGETPCXAndEmitMCInsts(MI
, getSubtargetInfo());
270 MachineBasicBlock::const_instr_iterator I
= MI
;
271 MachineBasicBlock::const_instr_iterator E
= MI
->getParent()->instr_end();
274 LowerSparcMachineInstrToMCInst(I
, TmpInst
, *this);
275 EmitToStreamer(OutStreamer
, TmpInst
);
276 } while ((++I
!= E
) && I
->isInsideBundle()); // Delay slot check.
279 void SparcAsmPrinter::EmitFunctionBodyStart() {
280 if (!TM
.getSubtarget
<SparcSubtarget
>().is64Bit())
283 const MachineRegisterInfo
&MRI
= MF
->getRegInfo();
284 const unsigned globalRegs
[] = { SP::G2
, SP::G3
, SP::G6
, SP::G7
, 0 };
285 for (unsigned i
= 0; globalRegs
[i
] != 0; ++i
) {
286 unsigned reg
= globalRegs
[i
];
287 if (MRI
.use_empty(reg
))
290 if (reg
== SP::G6
|| reg
== SP::G7
)
291 getTargetStreamer().emitSparcRegisterIgnore(reg
);
293 getTargetStreamer().emitSparcRegisterScratch(reg
);
297 void SparcAsmPrinter::printOperand(const MachineInstr
*MI
, int opNum
,
299 const DataLayout
*DL
= TM
.getSubtargetImpl()->getDataLayout();
300 const MachineOperand
&MO
= MI
->getOperand (opNum
);
301 SparcMCExpr::VariantKind TF
= (SparcMCExpr::VariantKind
) MO
.getTargetFlags();
304 // Verify the target flags.
305 if (MO
.isGlobal() || MO
.isSymbol() || MO
.isCPI()) {
306 if (MI
->getOpcode() == SP::CALL
)
307 assert(TF
== SparcMCExpr::VK_Sparc_None
&&
308 "Cannot handle target flags on call address");
309 else if (MI
->getOpcode() == SP::SETHIi
|| MI
->getOpcode() == SP::SETHIXi
)
310 assert((TF
== SparcMCExpr::VK_Sparc_HI
311 || TF
== SparcMCExpr::VK_Sparc_H44
312 || TF
== SparcMCExpr::VK_Sparc_HH
313 || TF
== SparcMCExpr::VK_Sparc_TLS_GD_HI22
314 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_HI22
315 || TF
== SparcMCExpr::VK_Sparc_TLS_LDO_HIX22
316 || TF
== SparcMCExpr::VK_Sparc_TLS_IE_HI22
317 || TF
== SparcMCExpr::VK_Sparc_TLS_LE_HIX22
) &&
318 "Invalid target flags for address operand on sethi");
319 else if (MI
->getOpcode() == SP::TLS_CALL
)
320 assert((TF
== SparcMCExpr::VK_Sparc_None
321 || TF
== SparcMCExpr::VK_Sparc_TLS_GD_CALL
322 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_CALL
) &&
323 "Cannot handle target flags on tls call address");
324 else if (MI
->getOpcode() == SP::TLS_ADDrr
)
325 assert((TF
== SparcMCExpr::VK_Sparc_TLS_GD_ADD
326 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_ADD
327 || TF
== SparcMCExpr::VK_Sparc_TLS_LDO_ADD
328 || TF
== SparcMCExpr::VK_Sparc_TLS_IE_ADD
) &&
329 "Cannot handle target flags on add for TLS");
330 else if (MI
->getOpcode() == SP::TLS_LDrr
)
331 assert(TF
== SparcMCExpr::VK_Sparc_TLS_IE_LD
&&
332 "Cannot handle target flags on ld for TLS");
333 else if (MI
->getOpcode() == SP::TLS_LDXrr
)
334 assert(TF
== SparcMCExpr::VK_Sparc_TLS_IE_LDX
&&
335 "Cannot handle target flags on ldx for TLS");
336 else if (MI
->getOpcode() == SP::XORri
|| MI
->getOpcode() == SP::XORXri
)
337 assert((TF
== SparcMCExpr::VK_Sparc_TLS_LDO_LOX10
338 || TF
== SparcMCExpr::VK_Sparc_TLS_LE_LOX10
) &&
339 "Cannot handle target flags on xor for TLS");
341 assert((TF
== SparcMCExpr::VK_Sparc_LO
342 || TF
== SparcMCExpr::VK_Sparc_M44
343 || TF
== SparcMCExpr::VK_Sparc_L44
344 || TF
== SparcMCExpr::VK_Sparc_HM
345 || TF
== SparcMCExpr::VK_Sparc_TLS_GD_LO10
346 || TF
== SparcMCExpr::VK_Sparc_TLS_LDM_LO10
347 || TF
== SparcMCExpr::VK_Sparc_TLS_IE_LO10
) &&
348 "Invalid target flags for small address operand");
353 bool CloseParen
= SparcMCExpr::printVariantKind(O
, TF
);
355 switch (MO
.getType()) {
356 case MachineOperand::MO_Register
:
357 O
<< "%" << StringRef(getRegisterName(MO
.getReg())).lower();
360 case MachineOperand::MO_Immediate
:
361 O
<< (int)MO
.getImm();
363 case MachineOperand::MO_MachineBasicBlock
:
364 O
<< *MO
.getMBB()->getSymbol();
366 case MachineOperand::MO_GlobalAddress
:
367 O
<< *getSymbol(MO
.getGlobal());
369 case MachineOperand::MO_BlockAddress
:
370 O
<< GetBlockAddressSymbol(MO
.getBlockAddress())->getName();
372 case MachineOperand::MO_ExternalSymbol
:
373 O
<< MO
.getSymbolName();
375 case MachineOperand::MO_ConstantPoolIndex
:
376 O
<< DL
->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
380 llvm_unreachable("<unknown operand type>");
382 if (CloseParen
) O
<< ")";
385 void SparcAsmPrinter::printMemOperand(const MachineInstr
*MI
, int opNum
,
386 raw_ostream
&O
, const char *Modifier
) {
387 printOperand(MI
, opNum
, O
);
389 // If this is an ADD operand, emit it like normal operands.
390 if (Modifier
&& !strcmp(Modifier
, "arith")) {
392 printOperand(MI
, opNum
+1, O
);
396 if (MI
->getOperand(opNum
+1).isReg() &&
397 MI
->getOperand(opNum
+1).getReg() == SP::G0
)
398 return; // don't print "+%g0"
399 if (MI
->getOperand(opNum
+1).isImm() &&
400 MI
->getOperand(opNum
+1).getImm() == 0)
401 return; // don't print "+0"
404 printOperand(MI
, opNum
+1, O
);
407 /// PrintAsmOperand - Print out an operand for an inline asm expression.
409 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
411 const char *ExtraCode
,
413 if (ExtraCode
&& ExtraCode
[0]) {
414 if (ExtraCode
[1] != 0) return true; // Unknown modifier.
416 switch (ExtraCode
[0]) {
418 // See if this is a generic print operand
419 return AsmPrinter::PrintAsmOperand(MI
, OpNo
, AsmVariant
, ExtraCode
, O
);
425 printOperand(MI
, OpNo
, O
);
430 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
431 unsigned OpNo
, unsigned AsmVariant
,
432 const char *ExtraCode
,
434 if (ExtraCode
&& ExtraCode
[0])
435 return true; // Unknown modifier
438 printMemOperand(MI
, OpNo
, O
);
444 void SparcAsmPrinter::EmitEndOfAsmFile(Module
&M
) {
445 const TargetLoweringObjectFileELF
&TLOFELF
=
446 static_cast<const TargetLoweringObjectFileELF
&>(getObjFileLowering());
447 MachineModuleInfoELF
&MMIELF
= MMI
->getObjFileInfo
<MachineModuleInfoELF
>();
449 // Generate stubs for global variables.
450 MachineModuleInfoELF::SymbolListTy Stubs
= MMIELF
.GetGVStubList();
451 if (!Stubs
.empty()) {
452 OutStreamer
.SwitchSection(TLOFELF
.getDataSection());
454 TM
.getSubtargetImpl()->getDataLayout()->getPointerSize(0);
455 for (unsigned i
= 0, e
= Stubs
.size(); i
!= e
; ++i
) {
456 OutStreamer
.EmitLabel(Stubs
[i
].first
);
457 OutStreamer
.EmitSymbolValue(Stubs
[i
].second
.getPointer(), PtrSize
);
462 // Force static initialization.
463 extern "C" void LLVMInitializeSparcAsmPrinter() {
464 RegisterAsmPrinter
<SparcAsmPrinter
> X(TheSparcTarget
);
465 RegisterAsmPrinter
<SparcAsmPrinter
> Y(TheSparcV9Target
);