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/Support/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(unsigned RegNo
) {
61 return VEInstPrinter::getRegisterName(RegNo
);
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
;
67 } // end of anonymous namespace
69 static MCOperand
createVEMCOperand(VEMCExpr::VariantKind Kind
, MCSymbol
*Sym
,
70 MCContext
&OutContext
) {
71 const MCSymbolRefExpr
*MCSym
= MCSymbolRefExpr::create(Sym
, OutContext
);
72 const VEMCExpr
*expr
= VEMCExpr::create(Kind
, MCSym
, OutContext
);
73 return MCOperand::createExpr(expr
);
76 static MCOperand
createGOTRelExprOp(VEMCExpr::VariantKind Kind
,
77 MCSymbol
*GOTLabel
, MCContext
&OutContext
) {
78 const MCSymbolRefExpr
*GOT
= MCSymbolRefExpr::create(GOTLabel
, OutContext
);
79 const VEMCExpr
*expr
= VEMCExpr::create(Kind
, GOT
, OutContext
);
80 return MCOperand::createExpr(expr
);
83 static void emitSIC(MCStreamer
&OutStreamer
, MCOperand
&RD
,
84 const MCSubtargetInfo
&STI
) {
86 SICInst
.setOpcode(VE::SIC
);
87 SICInst
.addOperand(RD
);
88 OutStreamer
.emitInstruction(SICInst
, STI
);
91 static void emitBSIC(MCStreamer
&OutStreamer
, MCOperand
&R1
, MCOperand
&R2
,
92 const MCSubtargetInfo
&STI
) {
94 BSICInst
.setOpcode(VE::BSICrii
);
95 BSICInst
.addOperand(R1
);
96 BSICInst
.addOperand(R2
);
97 MCOperand czero
= MCOperand::createImm(0);
98 BSICInst
.addOperand(czero
);
99 BSICInst
.addOperand(czero
);
100 OutStreamer
.emitInstruction(BSICInst
, STI
);
103 static void emitLEAzzi(MCStreamer
&OutStreamer
, MCOperand
&Imm
, MCOperand
&RD
,
104 const MCSubtargetInfo
&STI
) {
106 LEAInst
.setOpcode(VE::LEAzii
);
107 LEAInst
.addOperand(RD
);
108 MCOperand CZero
= MCOperand::createImm(0);
109 LEAInst
.addOperand(CZero
);
110 LEAInst
.addOperand(CZero
);
111 LEAInst
.addOperand(Imm
);
112 OutStreamer
.emitInstruction(LEAInst
, STI
);
115 static void emitLEASLzzi(MCStreamer
&OutStreamer
, MCOperand
&Imm
, MCOperand
&RD
,
116 const MCSubtargetInfo
&STI
) {
118 LEASLInst
.setOpcode(VE::LEASLzii
);
119 LEASLInst
.addOperand(RD
);
120 MCOperand CZero
= MCOperand::createImm(0);
121 LEASLInst
.addOperand(CZero
);
122 LEASLInst
.addOperand(CZero
);
123 LEASLInst
.addOperand(Imm
);
124 OutStreamer
.emitInstruction(LEASLInst
, STI
);
127 static void emitLEAzii(MCStreamer
&OutStreamer
, MCOperand
&RS1
, MCOperand
&Imm
,
128 MCOperand
&RD
, const MCSubtargetInfo
&STI
) {
130 LEAInst
.setOpcode(VE::LEAzii
);
131 LEAInst
.addOperand(RD
);
132 MCOperand CZero
= MCOperand::createImm(0);
133 LEAInst
.addOperand(CZero
);
134 LEAInst
.addOperand(RS1
);
135 LEAInst
.addOperand(Imm
);
136 OutStreamer
.emitInstruction(LEAInst
, STI
);
139 static void emitLEASLrri(MCStreamer
&OutStreamer
, MCOperand
&RS1
,
140 MCOperand
&RS2
, MCOperand
&Imm
, MCOperand
&RD
,
141 const MCSubtargetInfo
&STI
) {
143 LEASLInst
.setOpcode(VE::LEASLrri
);
144 LEASLInst
.addOperand(RD
);
145 LEASLInst
.addOperand(RS1
);
146 LEASLInst
.addOperand(RS2
);
147 LEASLInst
.addOperand(Imm
);
148 OutStreamer
.emitInstruction(LEASLInst
, STI
);
151 static void emitBinary(MCStreamer
&OutStreamer
, unsigned Opcode
, MCOperand
&RS1
,
152 MCOperand
&Src2
, MCOperand
&RD
,
153 const MCSubtargetInfo
&STI
) {
155 Inst
.setOpcode(Opcode
);
157 Inst
.addOperand(RS1
);
158 Inst
.addOperand(Src2
);
159 OutStreamer
.emitInstruction(Inst
, STI
);
162 static void emitANDrm(MCStreamer
&OutStreamer
, MCOperand
&RS1
, MCOperand
&Imm
,
163 MCOperand
&RD
, const MCSubtargetInfo
&STI
) {
164 emitBinary(OutStreamer
, VE::ANDrm
, RS1
, Imm
, RD
, STI
);
167 static void emitHiLo(MCStreamer
&OutStreamer
, MCSymbol
*GOTSym
,
168 VEMCExpr::VariantKind HiKind
, VEMCExpr::VariantKind LoKind
,
169 MCOperand
&RD
, MCContext
&OutContext
,
170 const MCSubtargetInfo
&STI
) {
172 MCOperand hi
= createVEMCOperand(HiKind
, GOTSym
, OutContext
);
173 MCOperand lo
= createVEMCOperand(LoKind
, GOTSym
, OutContext
);
174 emitLEAzzi(OutStreamer
, lo
, RD
, STI
);
175 MCOperand M032
= MCOperand::createImm(M0(32));
176 emitANDrm(OutStreamer
, RD
, M032
, RD
, STI
);
177 emitLEASLzzi(OutStreamer
, hi
, RD
, STI
);
180 void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr
*MI
,
181 const MCSubtargetInfo
&STI
) {
183 OutContext
.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
185 const MachineOperand
&MO
= MI
->getOperand(0);
186 MCOperand MCRegOP
= MCOperand::createReg(MO
.getReg());
188 if (!isPositionIndependent()) {
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 case CodeModel::Medium
:
195 case CodeModel::Large
:
196 emitHiLo(*OutStreamer
, GOTLabel
, VEMCExpr::VK_VE_HI32
,
197 VEMCExpr::VK_VE_LO32
, MCRegOP
, OutContext
, STI
);
203 MCOperand RegGOT
= MCOperand::createReg(VE::SX15
); // GOT
204 MCOperand RegPLT
= MCOperand::createReg(VE::SX16
); // PLT
206 // lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24)
207 // and %got, %got, (32)0
209 // lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%plt, %got)
210 MCOperand cim24
= MCOperand::createImm(-24);
212 createGOTRelExprOp(VEMCExpr::VK_VE_PC_LO32
, GOTLabel
, OutContext
);
213 emitLEAzii(*OutStreamer
, cim24
, loImm
, MCRegOP
, STI
);
214 MCOperand M032
= MCOperand::createImm(M0(32));
215 emitANDrm(*OutStreamer
, MCRegOP
, M032
, MCRegOP
, STI
);
216 emitSIC(*OutStreamer
, RegPLT
, STI
);
218 createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32
, GOTLabel
, OutContext
);
219 emitLEASLrri(*OutStreamer
, RegGOT
, RegPLT
, hiImm
, MCRegOP
, STI
);
222 void VEAsmPrinter::lowerGETFunPLTAndEmitMCInsts(const MachineInstr
*MI
,
223 const MCSubtargetInfo
&STI
) {
224 const MachineOperand
&MO
= MI
->getOperand(0);
225 MCOperand MCRegOP
= MCOperand::createReg(MO
.getReg());
226 const MachineOperand
&Addr
= MI
->getOperand(1);
227 MCSymbol
*AddrSym
= nullptr;
229 switch (Addr
.getType()) {
231 llvm_unreachable("<unknown operand type>");
233 case MachineOperand::MO_MachineBasicBlock
:
234 report_fatal_error("MBB is not supported yet");
236 case MachineOperand::MO_ConstantPoolIndex
:
237 report_fatal_error("ConstantPool is not supported yet");
239 case MachineOperand::MO_ExternalSymbol
:
240 AddrSym
= GetExternalSymbolSymbol(Addr
.getSymbolName());
242 case MachineOperand::MO_GlobalAddress
:
243 AddrSym
= getSymbol(Addr
.getGlobal());
247 if (!isPositionIndependent()) {
248 llvm_unreachable("Unsupported uses of %plt in not PIC code");
252 MCOperand RegPLT
= MCOperand::createReg(VE::SX16
); // PLT
254 // lea %dst, func@plt_lo(-24)
255 // and %dst, %dst, (32)0
256 // sic %plt ; FIXME: is it safe to use %plt here?
257 // lea.sl %dst, func@plt_hi(%plt, %dst)
258 MCOperand cim24
= MCOperand::createImm(-24);
260 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32
, AddrSym
, OutContext
);
261 emitLEAzii(*OutStreamer
, cim24
, loImm
, MCRegOP
, STI
);
262 MCOperand M032
= MCOperand::createImm(M0(32));
263 emitANDrm(*OutStreamer
, MCRegOP
, M032
, MCRegOP
, STI
);
264 emitSIC(*OutStreamer
, RegPLT
, STI
);
266 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32
, AddrSym
, OutContext
);
267 emitLEASLrri(*OutStreamer
, MCRegOP
, RegPLT
, hiImm
, MCRegOP
, STI
);
270 void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr
*MI
,
271 const MCSubtargetInfo
&STI
) {
272 const MachineOperand
&Addr
= MI
->getOperand(0);
273 MCSymbol
*AddrSym
= nullptr;
275 switch (Addr
.getType()) {
277 llvm_unreachable("<unknown operand type>");
279 case MachineOperand::MO_MachineBasicBlock
:
280 report_fatal_error("MBB is not supported yet");
282 case MachineOperand::MO_ConstantPoolIndex
:
283 report_fatal_error("ConstantPool is not supported yet");
285 case MachineOperand::MO_ExternalSymbol
:
286 AddrSym
= GetExternalSymbolSymbol(Addr
.getSymbolName());
288 case MachineOperand::MO_GlobalAddress
:
289 AddrSym
= getSymbol(Addr
.getGlobal());
293 MCOperand RegLR
= MCOperand::createReg(VE::SX10
); // LR
294 MCOperand RegS0
= MCOperand::createReg(VE::SX0
); // S0
295 MCOperand RegS12
= MCOperand::createReg(VE::SX12
); // S12
296 MCSymbol
*GetTLSLabel
= OutContext
.getOrCreateSymbol(Twine("__tls_get_addr"));
298 // lea %s0, sym@tls_gd_lo(-24)
299 // and %s0, %s0, (32)0
301 // lea.sl %s0, sym@tls_gd_hi(%lr, %s0)
302 // lea %s12, __tls_get_addr@plt_lo(8)
303 // and %s12, %s12, (32)0
304 // lea.sl %s12, __tls_get_addr@plt_hi(%s12, %lr)
305 // bsic %lr, (, %s12)
306 MCOperand cim24
= MCOperand::createImm(-24);
308 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_LO32
, AddrSym
, OutContext
);
309 emitLEAzii(*OutStreamer
, cim24
, loImm
, RegS0
, STI
);
310 MCOperand M032
= MCOperand::createImm(M0(32));
311 emitANDrm(*OutStreamer
, RegS0
, M032
, RegS0
, STI
);
312 emitSIC(*OutStreamer
, RegLR
, STI
);
314 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32
, AddrSym
, OutContext
);
315 emitLEASLrri(*OutStreamer
, RegS0
, RegLR
, hiImm
, RegS0
, STI
);
316 MCOperand ci8
= MCOperand::createImm(8);
318 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32
, GetTLSLabel
, OutContext
);
319 emitLEAzii(*OutStreamer
, ci8
, loImm2
, RegS12
, STI
);
320 emitANDrm(*OutStreamer
, RegS12
, M032
, RegS12
, STI
);
322 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32
, GetTLSLabel
, OutContext
);
323 emitLEASLrri(*OutStreamer
, RegS12
, RegLR
, hiImm2
, RegS12
, STI
);
324 emitBSIC(*OutStreamer
, RegLR
, RegS12
, STI
);
327 void VEAsmPrinter::emitInstruction(const MachineInstr
*MI
) {
329 switch (MI
->getOpcode()) {
332 case TargetOpcode::DBG_VALUE
:
333 // FIXME: Debug Value.
336 lowerGETGOTAndEmitMCInsts(MI
, getSubtargetInfo());
339 lowerGETFunPLTAndEmitMCInsts(MI
, getSubtargetInfo());
342 lowerGETTLSAddrAndEmitMCInsts(MI
, getSubtargetInfo());
346 MachineBasicBlock::const_instr_iterator I
= MI
->getIterator();
347 MachineBasicBlock::const_instr_iterator E
= MI
->getParent()->instr_end();
350 LowerVEMachineInstrToMCInst(&*I
, TmpInst
, *this);
351 EmitToStreamer(*OutStreamer
, TmpInst
);
352 } while ((++I
!= E
) && I
->isInsideBundle()); // Delay slot check.
355 void VEAsmPrinter::printOperand(const MachineInstr
*MI
, int OpNum
,
357 const MachineOperand
&MO
= MI
->getOperand(OpNum
);
359 switch (MO
.getType()) {
360 case MachineOperand::MO_Register
:
361 O
<< "%" << StringRef(getRegisterName(MO
.getReg())).lower();
364 llvm_unreachable("<unknown operand type>");
368 // PrintAsmOperand - Print out an operand for an inline asm expression.
369 bool VEAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
370 const char *ExtraCode
, raw_ostream
&O
) {
371 if (ExtraCode
&& ExtraCode
[0]) {
372 if (ExtraCode
[1] != 0)
373 return true; // Unknown modifier.
375 switch (ExtraCode
[0]) {
377 // See if this is a generic print operand
378 return AsmPrinter::PrintAsmOperand(MI
, OpNo
, ExtraCode
, O
);
385 printOperand(MI
, OpNo
, O
);
390 // Force static initialization.
391 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeVEAsmPrinter() {
392 RegisterAsmPrinter
<VEAsmPrinter
> X(getTheVETarget());