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 "llvm/CodeGen/AsmPrinter.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
23 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
24 #include "llvm/IR/Mangler.h"
25 #include "llvm/MC/MCAsmInfo.h"
26 #include "llvm/MC/MCContext.h"
27 #include "llvm/MC/MCInst.h"
28 #include "llvm/MC/MCStreamer.h"
29 #include "llvm/MC/MCSymbol.h"
30 #include "llvm/MC/TargetRegistry.h"
31 #include "llvm/Support/raw_ostream.h"
34 #define DEBUG_TYPE "ve-asmprinter"
37 class VEAsmPrinter
: public AsmPrinter
{
38 VETargetStreamer
&getTargetStreamer() {
39 return static_cast<VETargetStreamer
&>(*OutStreamer
->getTargetStreamer());
43 explicit VEAsmPrinter(TargetMachine
&TM
, std::unique_ptr
<MCStreamer
> Streamer
)
44 : AsmPrinter(TM
, std::move(Streamer
)) {}
46 StringRef
getPassName() const override
{ return "VE Assembly Printer"; }
48 void lowerGETGOTAndEmitMCInsts(const MachineInstr
*MI
,
49 const MCSubtargetInfo
&STI
);
50 void lowerGETFunPLTAndEmitMCInsts(const MachineInstr
*MI
,
51 const MCSubtargetInfo
&STI
);
52 void lowerGETTLSAddrAndEmitMCInsts(const MachineInstr
*MI
,
53 const MCSubtargetInfo
&STI
);
55 void emitInstruction(const MachineInstr
*MI
) override
;
57 static const char *getRegisterName(MCRegister Reg
) {
58 return VEInstPrinter::getRegisterName(Reg
);
60 void printOperand(const MachineInstr
*MI
, int OpNum
, raw_ostream
&OS
);
61 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
62 const char *ExtraCode
, raw_ostream
&O
) override
;
63 bool PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
64 const char *ExtraCode
, raw_ostream
&O
) override
;
66 } // end of anonymous namespace
68 static MCOperand
createVEMCOperand(VEMCExpr::VariantKind Kind
, MCSymbol
*Sym
,
69 MCContext
&OutContext
) {
70 const MCSymbolRefExpr
*MCSym
= MCSymbolRefExpr::create(Sym
, OutContext
);
71 const VEMCExpr
*expr
= VEMCExpr::create(Kind
, MCSym
, OutContext
);
72 return MCOperand::createExpr(expr
);
75 static MCOperand
createGOTRelExprOp(VEMCExpr::VariantKind Kind
,
76 MCSymbol
*GOTLabel
, MCContext
&OutContext
) {
77 const MCSymbolRefExpr
*GOT
= MCSymbolRefExpr::create(GOTLabel
, OutContext
);
78 const VEMCExpr
*expr
= VEMCExpr::create(Kind
, GOT
, OutContext
);
79 return MCOperand::createExpr(expr
);
82 static void emitSIC(MCStreamer
&OutStreamer
, MCOperand
&RD
,
83 const MCSubtargetInfo
&STI
) {
85 SICInst
.setOpcode(VE::SIC
);
86 SICInst
.addOperand(RD
);
87 OutStreamer
.emitInstruction(SICInst
, STI
);
90 static void emitBSIC(MCStreamer
&OutStreamer
, MCOperand
&R1
, MCOperand
&R2
,
91 const MCSubtargetInfo
&STI
) {
93 BSICInst
.setOpcode(VE::BSICrii
);
94 BSICInst
.addOperand(R1
);
95 BSICInst
.addOperand(R2
);
96 MCOperand czero
= MCOperand::createImm(0);
97 BSICInst
.addOperand(czero
);
98 BSICInst
.addOperand(czero
);
99 OutStreamer
.emitInstruction(BSICInst
, STI
);
102 static void emitLEAzzi(MCStreamer
&OutStreamer
, MCOperand
&Imm
, MCOperand
&RD
,
103 const MCSubtargetInfo
&STI
) {
105 LEAInst
.setOpcode(VE::LEAzii
);
106 LEAInst
.addOperand(RD
);
107 MCOperand CZero
= MCOperand::createImm(0);
108 LEAInst
.addOperand(CZero
);
109 LEAInst
.addOperand(CZero
);
110 LEAInst
.addOperand(Imm
);
111 OutStreamer
.emitInstruction(LEAInst
, STI
);
114 static void emitLEASLzzi(MCStreamer
&OutStreamer
, MCOperand
&Imm
, MCOperand
&RD
,
115 const MCSubtargetInfo
&STI
) {
117 LEASLInst
.setOpcode(VE::LEASLzii
);
118 LEASLInst
.addOperand(RD
);
119 MCOperand CZero
= MCOperand::createImm(0);
120 LEASLInst
.addOperand(CZero
);
121 LEASLInst
.addOperand(CZero
);
122 LEASLInst
.addOperand(Imm
);
123 OutStreamer
.emitInstruction(LEASLInst
, STI
);
126 static void emitLEAzii(MCStreamer
&OutStreamer
, MCOperand
&RS1
, MCOperand
&Imm
,
127 MCOperand
&RD
, const MCSubtargetInfo
&STI
) {
129 LEAInst
.setOpcode(VE::LEAzii
);
130 LEAInst
.addOperand(RD
);
131 MCOperand CZero
= MCOperand::createImm(0);
132 LEAInst
.addOperand(CZero
);
133 LEAInst
.addOperand(RS1
);
134 LEAInst
.addOperand(Imm
);
135 OutStreamer
.emitInstruction(LEAInst
, STI
);
138 static void emitLEASLrri(MCStreamer
&OutStreamer
, MCOperand
&RS1
,
139 MCOperand
&RS2
, MCOperand
&Imm
, MCOperand
&RD
,
140 const MCSubtargetInfo
&STI
) {
142 LEASLInst
.setOpcode(VE::LEASLrri
);
143 LEASLInst
.addOperand(RD
);
144 LEASLInst
.addOperand(RS1
);
145 LEASLInst
.addOperand(RS2
);
146 LEASLInst
.addOperand(Imm
);
147 OutStreamer
.emitInstruction(LEASLInst
, STI
);
150 static void emitBinary(MCStreamer
&OutStreamer
, unsigned Opcode
, MCOperand
&RS1
,
151 MCOperand
&Src2
, MCOperand
&RD
,
152 const MCSubtargetInfo
&STI
) {
154 Inst
.setOpcode(Opcode
);
156 Inst
.addOperand(RS1
);
157 Inst
.addOperand(Src2
);
158 OutStreamer
.emitInstruction(Inst
, STI
);
161 static void emitANDrm(MCStreamer
&OutStreamer
, MCOperand
&RS1
, MCOperand
&Imm
,
162 MCOperand
&RD
, const MCSubtargetInfo
&STI
) {
163 emitBinary(OutStreamer
, VE::ANDrm
, RS1
, Imm
, RD
, STI
);
166 static void emitHiLo(MCStreamer
&OutStreamer
, MCSymbol
*GOTSym
,
167 VEMCExpr::VariantKind HiKind
, VEMCExpr::VariantKind LoKind
,
168 MCOperand
&RD
, MCContext
&OutContext
,
169 const MCSubtargetInfo
&STI
) {
171 MCOperand hi
= createVEMCOperand(HiKind
, GOTSym
, OutContext
);
172 MCOperand lo
= createVEMCOperand(LoKind
, GOTSym
, OutContext
);
173 emitLEAzzi(OutStreamer
, lo
, RD
, STI
);
174 MCOperand M032
= MCOperand::createImm(M0(32));
175 emitANDrm(OutStreamer
, RD
, M032
, RD
, STI
);
176 emitLEASLzzi(OutStreamer
, hi
, RD
, STI
);
179 void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr
*MI
,
180 const MCSubtargetInfo
&STI
) {
182 OutContext
.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
184 const MachineOperand
&MO
= MI
->getOperand(0);
185 MCOperand MCRegOP
= MCOperand::createReg(MO
.getReg());
187 if (!isPositionIndependent()) {
188 // Just load the address of GOT to MCRegOP.
189 switch (TM
.getCodeModel()) {
191 llvm_unreachable("Unsupported absolute code model");
192 case CodeModel::Small
:
193 case CodeModel::Medium
:
194 case CodeModel::Large
:
195 emitHiLo(*OutStreamer
, GOTLabel
, VEMCExpr::VK_VE_HI32
,
196 VEMCExpr::VK_VE_LO32
, MCRegOP
, OutContext
, STI
);
202 MCOperand RegGOT
= MCOperand::createReg(VE::SX15
); // GOT
203 MCOperand RegPLT
= MCOperand::createReg(VE::SX16
); // PLT
205 // lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24)
206 // and %got, %got, (32)0
208 // lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%plt, %got)
209 MCOperand cim24
= MCOperand::createImm(-24);
211 createGOTRelExprOp(VEMCExpr::VK_VE_PC_LO32
, GOTLabel
, OutContext
);
212 emitLEAzii(*OutStreamer
, cim24
, loImm
, MCRegOP
, STI
);
213 MCOperand M032
= MCOperand::createImm(M0(32));
214 emitANDrm(*OutStreamer
, MCRegOP
, M032
, MCRegOP
, STI
);
215 emitSIC(*OutStreamer
, RegPLT
, STI
);
217 createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32
, GOTLabel
, OutContext
);
218 emitLEASLrri(*OutStreamer
, RegGOT
, RegPLT
, hiImm
, MCRegOP
, STI
);
221 void VEAsmPrinter::lowerGETFunPLTAndEmitMCInsts(const MachineInstr
*MI
,
222 const MCSubtargetInfo
&STI
) {
223 const MachineOperand
&MO
= MI
->getOperand(0);
224 MCOperand MCRegOP
= MCOperand::createReg(MO
.getReg());
225 const MachineOperand
&Addr
= MI
->getOperand(1);
226 MCSymbol
*AddrSym
= nullptr;
228 switch (Addr
.getType()) {
230 llvm_unreachable("<unknown operand type>");
232 case MachineOperand::MO_MachineBasicBlock
:
233 report_fatal_error("MBB is not supported yet");
235 case MachineOperand::MO_ConstantPoolIndex
:
236 report_fatal_error("ConstantPool is not supported yet");
238 case MachineOperand::MO_ExternalSymbol
:
239 AddrSym
= GetExternalSymbolSymbol(Addr
.getSymbolName());
241 case MachineOperand::MO_GlobalAddress
:
242 AddrSym
= getSymbol(Addr
.getGlobal());
246 if (!isPositionIndependent()) {
247 llvm_unreachable("Unsupported uses of %plt in not PIC code");
251 MCOperand RegPLT
= MCOperand::createReg(VE::SX16
); // PLT
253 // lea %dst, func@plt_lo(-24)
254 // and %dst, %dst, (32)0
255 // sic %plt ; FIXME: is it safe to use %plt here?
256 // lea.sl %dst, func@plt_hi(%plt, %dst)
257 MCOperand cim24
= MCOperand::createImm(-24);
259 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32
, AddrSym
, OutContext
);
260 emitLEAzii(*OutStreamer
, cim24
, loImm
, MCRegOP
, STI
);
261 MCOperand M032
= MCOperand::createImm(M0(32));
262 emitANDrm(*OutStreamer
, MCRegOP
, M032
, MCRegOP
, STI
);
263 emitSIC(*OutStreamer
, RegPLT
, STI
);
265 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32
, AddrSym
, OutContext
);
266 emitLEASLrri(*OutStreamer
, MCRegOP
, RegPLT
, hiImm
, MCRegOP
, STI
);
269 void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr
*MI
,
270 const MCSubtargetInfo
&STI
) {
271 const MachineOperand
&Addr
= MI
->getOperand(0);
272 MCSymbol
*AddrSym
= nullptr;
274 switch (Addr
.getType()) {
276 llvm_unreachable("<unknown operand type>");
278 case MachineOperand::MO_MachineBasicBlock
:
279 report_fatal_error("MBB is not supported yet");
281 case MachineOperand::MO_ConstantPoolIndex
:
282 report_fatal_error("ConstantPool is not supported yet");
284 case MachineOperand::MO_ExternalSymbol
:
285 AddrSym
= GetExternalSymbolSymbol(Addr
.getSymbolName());
287 case MachineOperand::MO_GlobalAddress
:
288 AddrSym
= getSymbol(Addr
.getGlobal());
292 MCOperand RegLR
= MCOperand::createReg(VE::SX10
); // LR
293 MCOperand RegS0
= MCOperand::createReg(VE::SX0
); // S0
294 MCOperand RegS12
= MCOperand::createReg(VE::SX12
); // S12
295 MCSymbol
*GetTLSLabel
= OutContext
.getOrCreateSymbol(Twine("__tls_get_addr"));
297 // lea %s0, sym@tls_gd_lo(-24)
298 // and %s0, %s0, (32)0
300 // lea.sl %s0, sym@tls_gd_hi(%lr, %s0)
301 // lea %s12, __tls_get_addr@plt_lo(8)
302 // and %s12, %s12, (32)0
303 // lea.sl %s12, __tls_get_addr@plt_hi(%s12, %lr)
304 // bsic %lr, (, %s12)
305 MCOperand cim24
= MCOperand::createImm(-24);
307 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_LO32
, AddrSym
, OutContext
);
308 emitLEAzii(*OutStreamer
, cim24
, loImm
, RegS0
, STI
);
309 MCOperand M032
= MCOperand::createImm(M0(32));
310 emitANDrm(*OutStreamer
, RegS0
, M032
, RegS0
, STI
);
311 emitSIC(*OutStreamer
, RegLR
, STI
);
313 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32
, AddrSym
, OutContext
);
314 emitLEASLrri(*OutStreamer
, RegS0
, RegLR
, hiImm
, RegS0
, STI
);
315 MCOperand ci8
= MCOperand::createImm(8);
317 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32
, GetTLSLabel
, OutContext
);
318 emitLEAzii(*OutStreamer
, ci8
, loImm2
, RegS12
, STI
);
319 emitANDrm(*OutStreamer
, RegS12
, M032
, RegS12
, STI
);
321 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32
, GetTLSLabel
, OutContext
);
322 emitLEASLrri(*OutStreamer
, RegS12
, RegLR
, hiImm2
, RegS12
, STI
);
323 emitBSIC(*OutStreamer
, RegLR
, RegS12
, STI
);
326 void VEAsmPrinter::emitInstruction(const MachineInstr
*MI
) {
327 VE_MC::verifyInstructionPredicates(MI
->getOpcode(),
328 getSubtargetInfo().getFeatureBits());
330 switch (MI
->getOpcode()) {
333 case TargetOpcode::DBG_VALUE
:
334 // FIXME: Debug Value.
337 lowerGETGOTAndEmitMCInsts(MI
, getSubtargetInfo());
340 lowerGETFunPLTAndEmitMCInsts(MI
, getSubtargetInfo());
343 lowerGETTLSAddrAndEmitMCInsts(MI
, getSubtargetInfo());
347 MachineBasicBlock::const_instr_iterator I
= MI
->getIterator();
348 MachineBasicBlock::const_instr_iterator E
= MI
->getParent()->instr_end();
351 LowerVEMachineInstrToMCInst(&*I
, TmpInst
, *this);
352 EmitToStreamer(*OutStreamer
, TmpInst
);
353 } while ((++I
!= E
) && I
->isInsideBundle()); // Delay slot check.
356 void VEAsmPrinter::printOperand(const MachineInstr
*MI
, int OpNum
,
358 const MachineOperand
&MO
= MI
->getOperand(OpNum
);
360 switch (MO
.getType()) {
361 case MachineOperand::MO_Register
:
362 O
<< "%" << StringRef(getRegisterName(MO
.getReg())).lower();
364 case MachineOperand::MO_Immediate
:
365 O
<< (int)MO
.getImm();
368 llvm_unreachable("<unknown operand type>");
372 // PrintAsmOperand - Print out an operand for an inline asm expression.
373 bool VEAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
374 const char *ExtraCode
, raw_ostream
&O
) {
375 if (ExtraCode
&& ExtraCode
[0]) {
376 if (ExtraCode
[1] != 0)
377 return true; // Unknown modifier.
379 switch (ExtraCode
[0]) {
381 // See if this is a generic print operand
382 return AsmPrinter::PrintAsmOperand(MI
, OpNo
, ExtraCode
, O
);
389 printOperand(MI
, OpNo
, O
);
394 bool VEAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
395 const char *ExtraCode
,
397 if (ExtraCode
&& ExtraCode
[0])
398 return true; // Unknown modifier
400 if (MI
->getOperand(OpNo
+1).isImm() &&
401 MI
->getOperand(OpNo
+1).getImm() == 0) {
404 printOperand(MI
, OpNo
+1, O
);
406 if (MI
->getOperand(OpNo
).isImm() &&
407 MI
->getOperand(OpNo
).getImm() == 0) {
408 if (MI
->getOperand(OpNo
+1).isImm() &&
409 MI
->getOperand(OpNo
+1).getImm() == 0) {
416 printOperand(MI
, OpNo
, O
);
422 // Force static initialization.
423 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeVEAsmPrinter() {
424 RegisterAsmPrinter
<VEAsmPrinter
> X(getTheVETarget());