1 //===-- VEAsmPrinter.cpp - VE 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 VE assembly language.
12 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/VEInstPrinter.h"
15 #include "MCTargetDesc/VEMCExpr.h"
16 #include "MCTargetDesc/VETargetStreamer.h"
17 #include "TargetInfo/VETargetInfo.h"
19 #include "VEInstrInfo.h"
20 #include "VETargetMachine.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/MCInstBuilder.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 "ve-asmprinter"
40 class VEAsmPrinter
: public AsmPrinter
{
41 VETargetStreamer
&getTargetStreamer() {
42 return static_cast<VETargetStreamer
&>(*OutStreamer
->getTargetStreamer());
46 explicit VEAsmPrinter(TargetMachine
&TM
, std::unique_ptr
<MCStreamer
> Streamer
)
47 : AsmPrinter(TM
, std::move(Streamer
)) {}
49 StringRef
getPassName() const override
{ return "VE Assembly Printer"; }
51 void lowerGETGOTAndEmitMCInsts(const MachineInstr
*MI
,
52 const MCSubtargetInfo
&STI
);
53 void lowerGETFunPLTAndEmitMCInsts(const MachineInstr
*MI
,
54 const MCSubtargetInfo
&STI
);
55 void lowerGETTLSAddrAndEmitMCInsts(const MachineInstr
*MI
,
56 const MCSubtargetInfo
&STI
);
58 void emitInstruction(const MachineInstr
*MI
) override
;
60 static const char *getRegisterName(MCRegister Reg
) {
61 return VEInstPrinter::getRegisterName(Reg
);
63 void printOperand(const MachineInstr
*MI
, int OpNum
, raw_ostream
&OS
);
64 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
65 const char *ExtraCode
, raw_ostream
&O
) override
;
66 bool PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
67 const char *ExtraCode
, raw_ostream
&O
) override
;
69 } // end of anonymous namespace
71 static MCOperand
createVEMCOperand(VEMCExpr::VariantKind Kind
, MCSymbol
*Sym
,
72 MCContext
&OutContext
) {
73 const MCSymbolRefExpr
*MCSym
= MCSymbolRefExpr::create(Sym
, OutContext
);
74 const VEMCExpr
*expr
= VEMCExpr::create(Kind
, MCSym
, OutContext
);
75 return MCOperand::createExpr(expr
);
78 static MCOperand
createGOTRelExprOp(VEMCExpr::VariantKind Kind
,
79 MCSymbol
*GOTLabel
, MCContext
&OutContext
) {
80 const MCSymbolRefExpr
*GOT
= MCSymbolRefExpr::create(GOTLabel
, OutContext
);
81 const VEMCExpr
*expr
= VEMCExpr::create(Kind
, GOT
, OutContext
);
82 return MCOperand::createExpr(expr
);
85 static void emitSIC(MCStreamer
&OutStreamer
, MCOperand
&RD
,
86 const MCSubtargetInfo
&STI
) {
88 SICInst
.setOpcode(VE::SIC
);
89 SICInst
.addOperand(RD
);
90 OutStreamer
.emitInstruction(SICInst
, STI
);
93 static void emitBSIC(MCStreamer
&OutStreamer
, MCOperand
&R1
, MCOperand
&R2
,
94 const MCSubtargetInfo
&STI
) {
96 BSICInst
.setOpcode(VE::BSICrii
);
97 BSICInst
.addOperand(R1
);
98 BSICInst
.addOperand(R2
);
99 MCOperand czero
= MCOperand::createImm(0);
100 BSICInst
.addOperand(czero
);
101 BSICInst
.addOperand(czero
);
102 OutStreamer
.emitInstruction(BSICInst
, STI
);
105 static void emitLEAzzi(MCStreamer
&OutStreamer
, MCOperand
&Imm
, MCOperand
&RD
,
106 const MCSubtargetInfo
&STI
) {
108 LEAInst
.setOpcode(VE::LEAzii
);
109 LEAInst
.addOperand(RD
);
110 MCOperand CZero
= MCOperand::createImm(0);
111 LEAInst
.addOperand(CZero
);
112 LEAInst
.addOperand(CZero
);
113 LEAInst
.addOperand(Imm
);
114 OutStreamer
.emitInstruction(LEAInst
, STI
);
117 static void emitLEASLzzi(MCStreamer
&OutStreamer
, MCOperand
&Imm
, MCOperand
&RD
,
118 const MCSubtargetInfo
&STI
) {
120 LEASLInst
.setOpcode(VE::LEASLzii
);
121 LEASLInst
.addOperand(RD
);
122 MCOperand CZero
= MCOperand::createImm(0);
123 LEASLInst
.addOperand(CZero
);
124 LEASLInst
.addOperand(CZero
);
125 LEASLInst
.addOperand(Imm
);
126 OutStreamer
.emitInstruction(LEASLInst
, STI
);
129 static void emitLEAzii(MCStreamer
&OutStreamer
, MCOperand
&RS1
, MCOperand
&Imm
,
130 MCOperand
&RD
, const MCSubtargetInfo
&STI
) {
132 LEAInst
.setOpcode(VE::LEAzii
);
133 LEAInst
.addOperand(RD
);
134 MCOperand CZero
= MCOperand::createImm(0);
135 LEAInst
.addOperand(CZero
);
136 LEAInst
.addOperand(RS1
);
137 LEAInst
.addOperand(Imm
);
138 OutStreamer
.emitInstruction(LEAInst
, STI
);
141 static void emitLEASLrri(MCStreamer
&OutStreamer
, MCOperand
&RS1
,
142 MCOperand
&RS2
, MCOperand
&Imm
, MCOperand
&RD
,
143 const MCSubtargetInfo
&STI
) {
145 LEASLInst
.setOpcode(VE::LEASLrri
);
146 LEASLInst
.addOperand(RD
);
147 LEASLInst
.addOperand(RS1
);
148 LEASLInst
.addOperand(RS2
);
149 LEASLInst
.addOperand(Imm
);
150 OutStreamer
.emitInstruction(LEASLInst
, STI
);
153 static void emitBinary(MCStreamer
&OutStreamer
, unsigned Opcode
, MCOperand
&RS1
,
154 MCOperand
&Src2
, MCOperand
&RD
,
155 const MCSubtargetInfo
&STI
) {
157 Inst
.setOpcode(Opcode
);
159 Inst
.addOperand(RS1
);
160 Inst
.addOperand(Src2
);
161 OutStreamer
.emitInstruction(Inst
, STI
);
164 static void emitANDrm(MCStreamer
&OutStreamer
, MCOperand
&RS1
, MCOperand
&Imm
,
165 MCOperand
&RD
, const MCSubtargetInfo
&STI
) {
166 emitBinary(OutStreamer
, VE::ANDrm
, RS1
, Imm
, RD
, STI
);
169 static void emitHiLo(MCStreamer
&OutStreamer
, MCSymbol
*GOTSym
,
170 VEMCExpr::VariantKind HiKind
, VEMCExpr::VariantKind LoKind
,
171 MCOperand
&RD
, MCContext
&OutContext
,
172 const MCSubtargetInfo
&STI
) {
174 MCOperand hi
= createVEMCOperand(HiKind
, GOTSym
, OutContext
);
175 MCOperand lo
= createVEMCOperand(LoKind
, GOTSym
, OutContext
);
176 emitLEAzzi(OutStreamer
, lo
, RD
, STI
);
177 MCOperand M032
= MCOperand::createImm(M0(32));
178 emitANDrm(OutStreamer
, RD
, M032
, RD
, STI
);
179 emitLEASLzzi(OutStreamer
, hi
, RD
, STI
);
182 void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr
*MI
,
183 const MCSubtargetInfo
&STI
) {
185 OutContext
.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
187 const MachineOperand
&MO
= MI
->getOperand(0);
188 MCOperand MCRegOP
= MCOperand::createReg(MO
.getReg());
190 if (!isPositionIndependent()) {
191 // Just load the address of GOT to MCRegOP.
192 switch (TM
.getCodeModel()) {
194 llvm_unreachable("Unsupported absolute code model");
195 case CodeModel::Small
:
196 case CodeModel::Medium
:
197 case CodeModel::Large
:
198 emitHiLo(*OutStreamer
, GOTLabel
, VEMCExpr::VK_VE_HI32
,
199 VEMCExpr::VK_VE_LO32
, MCRegOP
, OutContext
, STI
);
205 MCOperand RegGOT
= MCOperand::createReg(VE::SX15
); // GOT
206 MCOperand RegPLT
= MCOperand::createReg(VE::SX16
); // PLT
208 // lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24)
209 // and %got, %got, (32)0
211 // lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%plt, %got)
212 MCOperand cim24
= MCOperand::createImm(-24);
214 createGOTRelExprOp(VEMCExpr::VK_VE_PC_LO32
, GOTLabel
, OutContext
);
215 emitLEAzii(*OutStreamer
, cim24
, loImm
, MCRegOP
, STI
);
216 MCOperand M032
= MCOperand::createImm(M0(32));
217 emitANDrm(*OutStreamer
, MCRegOP
, M032
, MCRegOP
, STI
);
218 emitSIC(*OutStreamer
, RegPLT
, STI
);
220 createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32
, GOTLabel
, OutContext
);
221 emitLEASLrri(*OutStreamer
, RegGOT
, RegPLT
, hiImm
, MCRegOP
, STI
);
224 void VEAsmPrinter::lowerGETFunPLTAndEmitMCInsts(const MachineInstr
*MI
,
225 const MCSubtargetInfo
&STI
) {
226 const MachineOperand
&MO
= MI
->getOperand(0);
227 MCOperand MCRegOP
= MCOperand::createReg(MO
.getReg());
228 const MachineOperand
&Addr
= MI
->getOperand(1);
229 MCSymbol
*AddrSym
= nullptr;
231 switch (Addr
.getType()) {
233 llvm_unreachable("<unknown operand type>");
235 case MachineOperand::MO_MachineBasicBlock
:
236 report_fatal_error("MBB is not supported yet");
238 case MachineOperand::MO_ConstantPoolIndex
:
239 report_fatal_error("ConstantPool is not supported yet");
241 case MachineOperand::MO_ExternalSymbol
:
242 AddrSym
= GetExternalSymbolSymbol(Addr
.getSymbolName());
244 case MachineOperand::MO_GlobalAddress
:
245 AddrSym
= getSymbol(Addr
.getGlobal());
249 if (!isPositionIndependent()) {
250 llvm_unreachable("Unsupported uses of %plt in not PIC code");
254 MCOperand RegPLT
= MCOperand::createReg(VE::SX16
); // PLT
256 // lea %dst, func@plt_lo(-24)
257 // and %dst, %dst, (32)0
258 // sic %plt ; FIXME: is it safe to use %plt here?
259 // lea.sl %dst, func@plt_hi(%plt, %dst)
260 MCOperand cim24
= MCOperand::createImm(-24);
262 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32
, AddrSym
, OutContext
);
263 emitLEAzii(*OutStreamer
, cim24
, loImm
, MCRegOP
, STI
);
264 MCOperand M032
= MCOperand::createImm(M0(32));
265 emitANDrm(*OutStreamer
, MCRegOP
, M032
, MCRegOP
, STI
);
266 emitSIC(*OutStreamer
, RegPLT
, STI
);
268 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32
, AddrSym
, OutContext
);
269 emitLEASLrri(*OutStreamer
, MCRegOP
, RegPLT
, hiImm
, MCRegOP
, STI
);
272 void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr
*MI
,
273 const MCSubtargetInfo
&STI
) {
274 const MachineOperand
&Addr
= MI
->getOperand(0);
275 MCSymbol
*AddrSym
= nullptr;
277 switch (Addr
.getType()) {
279 llvm_unreachable("<unknown operand type>");
281 case MachineOperand::MO_MachineBasicBlock
:
282 report_fatal_error("MBB is not supported yet");
284 case MachineOperand::MO_ConstantPoolIndex
:
285 report_fatal_error("ConstantPool is not supported yet");
287 case MachineOperand::MO_ExternalSymbol
:
288 AddrSym
= GetExternalSymbolSymbol(Addr
.getSymbolName());
290 case MachineOperand::MO_GlobalAddress
:
291 AddrSym
= getSymbol(Addr
.getGlobal());
295 MCOperand RegLR
= MCOperand::createReg(VE::SX10
); // LR
296 MCOperand RegS0
= MCOperand::createReg(VE::SX0
); // S0
297 MCOperand RegS12
= MCOperand::createReg(VE::SX12
); // S12
298 MCSymbol
*GetTLSLabel
= OutContext
.getOrCreateSymbol(Twine("__tls_get_addr"));
300 // lea %s0, sym@tls_gd_lo(-24)
301 // and %s0, %s0, (32)0
303 // lea.sl %s0, sym@tls_gd_hi(%lr, %s0)
304 // lea %s12, __tls_get_addr@plt_lo(8)
305 // and %s12, %s12, (32)0
306 // lea.sl %s12, __tls_get_addr@plt_hi(%s12, %lr)
307 // bsic %lr, (, %s12)
308 MCOperand cim24
= MCOperand::createImm(-24);
310 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_LO32
, AddrSym
, OutContext
);
311 emitLEAzii(*OutStreamer
, cim24
, loImm
, RegS0
, STI
);
312 MCOperand M032
= MCOperand::createImm(M0(32));
313 emitANDrm(*OutStreamer
, RegS0
, M032
, RegS0
, STI
);
314 emitSIC(*OutStreamer
, RegLR
, STI
);
316 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32
, AddrSym
, OutContext
);
317 emitLEASLrri(*OutStreamer
, RegS0
, RegLR
, hiImm
, RegS0
, STI
);
318 MCOperand ci8
= MCOperand::createImm(8);
320 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32
, GetTLSLabel
, OutContext
);
321 emitLEAzii(*OutStreamer
, ci8
, loImm2
, RegS12
, STI
);
322 emitANDrm(*OutStreamer
, RegS12
, M032
, RegS12
, STI
);
324 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32
, GetTLSLabel
, OutContext
);
325 emitLEASLrri(*OutStreamer
, RegS12
, RegLR
, hiImm2
, RegS12
, STI
);
326 emitBSIC(*OutStreamer
, RegLR
, RegS12
, STI
);
329 void VEAsmPrinter::emitInstruction(const MachineInstr
*MI
) {
330 VE_MC::verifyInstructionPredicates(MI
->getOpcode(),
331 getSubtargetInfo().getFeatureBits());
333 switch (MI
->getOpcode()) {
336 case TargetOpcode::DBG_VALUE
:
337 // FIXME: Debug Value.
340 lowerGETGOTAndEmitMCInsts(MI
, getSubtargetInfo());
343 lowerGETFunPLTAndEmitMCInsts(MI
, getSubtargetInfo());
346 lowerGETTLSAddrAndEmitMCInsts(MI
, getSubtargetInfo());
350 MachineBasicBlock::const_instr_iterator I
= MI
->getIterator();
351 MachineBasicBlock::const_instr_iterator E
= MI
->getParent()->instr_end();
354 LowerVEMachineInstrToMCInst(&*I
, TmpInst
, *this);
355 EmitToStreamer(*OutStreamer
, TmpInst
);
356 } while ((++I
!= E
) && I
->isInsideBundle()); // Delay slot check.
359 void VEAsmPrinter::printOperand(const MachineInstr
*MI
, int OpNum
,
361 const MachineOperand
&MO
= MI
->getOperand(OpNum
);
363 switch (MO
.getType()) {
364 case MachineOperand::MO_Register
:
365 O
<< "%" << StringRef(getRegisterName(MO
.getReg())).lower();
367 case MachineOperand::MO_Immediate
:
368 O
<< (int)MO
.getImm();
371 llvm_unreachable("<unknown operand type>");
375 // PrintAsmOperand - Print out an operand for an inline asm expression.
376 bool VEAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
377 const char *ExtraCode
, raw_ostream
&O
) {
378 if (ExtraCode
&& ExtraCode
[0]) {
379 if (ExtraCode
[1] != 0)
380 return true; // Unknown modifier.
382 switch (ExtraCode
[0]) {
384 // See if this is a generic print operand
385 return AsmPrinter::PrintAsmOperand(MI
, OpNo
, ExtraCode
, O
);
392 printOperand(MI
, OpNo
, O
);
397 bool VEAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
398 const char *ExtraCode
,
400 if (ExtraCode
&& ExtraCode
[0])
401 return true; // Unknown modifier
403 if (MI
->getOperand(OpNo
+1).isImm() &&
404 MI
->getOperand(OpNo
+1).getImm() == 0) {
407 printOperand(MI
, OpNo
+1, O
);
409 if (MI
->getOperand(OpNo
).isImm() &&
410 MI
->getOperand(OpNo
).getImm() == 0) {
411 if (MI
->getOperand(OpNo
+1).isImm() &&
412 MI
->getOperand(OpNo
+1).getImm() == 0) {
419 printOperand(MI
, OpNo
, O
);
425 // Force static initialization.
426 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeVEAsmPrinter() {
427 RegisterAsmPrinter
<VEAsmPrinter
> X(getTheVETarget());