1 //===-- VEAsmPrinter.cpp - VE LLVM assembly writer ------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains a printer that converts from our internal representation
10 // of machine-dependent LLVM code to GAS-format VE assembly language.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "MCTargetDesc/VEInstPrinter.h"
15 #include "MCTargetDesc/VEMCExpr.h"
16 #include "MCTargetDesc/VETargetStreamer.h"
17 #include "TargetInfo/VETargetInfo.h"
18 #include "VE.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"
35 using namespace llvm;
36
37 #define DEBUG_TYPE "ve-asmprinter"
38
39 namespace {
40 class VEAsmPrinter : public AsmPrinter {
getTargetStreamer()41 VETargetStreamer &getTargetStreamer() {
42 return static_cast<VETargetStreamer &>(*OutStreamer->getTargetStreamer());
43 }
44
45 public:
VEAsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)46 explicit VEAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
47 : AsmPrinter(TM, std::move(Streamer)) {}
48
getPassName() const49 StringRef getPassName() const override { return "VE Assembly Printer"; }
50
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);
57
58 void emitInstruction(const MachineInstr *MI) override;
59
getRegisterName(unsigned RegNo)60 static const char *getRegisterName(unsigned RegNo) {
61 return VEInstPrinter::getRegisterName(RegNo);
62 }
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 };
67 } // end of anonymous namespace
68
createVEMCOperand(VEMCExpr::VariantKind Kind,MCSymbol * Sym,MCContext & OutContext)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);
74 }
75
createGOTRelExprOp(VEMCExpr::VariantKind Kind,MCSymbol * GOTLabel,MCContext & OutContext)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);
81 }
82
emitSIC(MCStreamer & OutStreamer,MCOperand & RD,const MCSubtargetInfo & STI)83 static void emitSIC(MCStreamer &OutStreamer, MCOperand &RD,
84 const MCSubtargetInfo &STI) {
85 MCInst SICInst;
86 SICInst.setOpcode(VE::SIC);
87 SICInst.addOperand(RD);
88 OutStreamer.emitInstruction(SICInst, STI);
89 }
90
emitBSIC(MCStreamer & OutStreamer,MCOperand & R1,MCOperand & R2,const MCSubtargetInfo & STI)91 static void emitBSIC(MCStreamer &OutStreamer, MCOperand &R1, MCOperand &R2,
92 const MCSubtargetInfo &STI) {
93 MCInst BSICInst;
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);
101 }
102
emitLEAzzi(MCStreamer & OutStreamer,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)103 static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
104 const MCSubtargetInfo &STI) {
105 MCInst LEAInst;
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);
113 }
114
emitLEASLzzi(MCStreamer & OutStreamer,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)115 static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
116 const MCSubtargetInfo &STI) {
117 MCInst LEASLInst;
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);
125 }
126
emitLEAzii(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)127 static void emitLEAzii(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
128 MCOperand &RD, const MCSubtargetInfo &STI) {
129 MCInst LEAInst;
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);
137 }
138
emitLEASLrri(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & RS2,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)139 static void emitLEASLrri(MCStreamer &OutStreamer, MCOperand &RS1,
140 MCOperand &RS2, MCOperand &Imm, MCOperand &RD,
141 const MCSubtargetInfo &STI) {
142 MCInst LEASLInst;
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);
149 }
150
emitBinary(MCStreamer & OutStreamer,unsigned Opcode,MCOperand & RS1,MCOperand & Src2,MCOperand & RD,const MCSubtargetInfo & STI)151 static void emitBinary(MCStreamer &OutStreamer, unsigned Opcode, MCOperand &RS1,
152 MCOperand &Src2, MCOperand &RD,
153 const MCSubtargetInfo &STI) {
154 MCInst Inst;
155 Inst.setOpcode(Opcode);
156 Inst.addOperand(RD);
157 Inst.addOperand(RS1);
158 Inst.addOperand(Src2);
159 OutStreamer.emitInstruction(Inst, STI);
160 }
161
emitANDrm(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & 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);
165 }
166
emitHiLo(MCStreamer & OutStreamer,MCSymbol * GOTSym,VEMCExpr::VariantKind HiKind,VEMCExpr::VariantKind LoKind,MCOperand & RD,MCContext & OutContext,const MCSubtargetInfo & 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) {
171
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);
178 }
179
lowerGETGOTAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & STI)180 void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr *MI,
181 const MCSubtargetInfo &STI) {
182 MCSymbol *GOTLabel =
183 OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
184
185 const MachineOperand &MO = MI->getOperand(0);
186 MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
187
188 if (!isPositionIndependent()) {
189 // Just load the address of GOT to MCRegOP.
190 switch (TM.getCodeModel()) {
191 default:
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);
198 break;
199 }
200 return;
201 }
202
203 MCOperand RegGOT = MCOperand::createReg(VE::SX15); // GOT
204 MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
205
206 // lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24)
207 // and %got, %got, (32)0
208 // sic %plt
209 // lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%plt, %got)
210 MCOperand cim24 = MCOperand::createImm(-24);
211 MCOperand loImm =
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);
217 MCOperand hiImm =
218 createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32, GOTLabel, OutContext);
219 emitLEASLrri(*OutStreamer, RegGOT, RegPLT, hiImm, MCRegOP, STI);
220 }
221
lowerGETFunPLTAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & 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;
228
229 switch (Addr.getType()) {
230 default:
231 llvm_unreachable("<unknown operand type>");
232 return;
233 case MachineOperand::MO_MachineBasicBlock:
234 report_fatal_error("MBB is not supported yet");
235 return;
236 case MachineOperand::MO_ConstantPoolIndex:
237 report_fatal_error("ConstantPool is not supported yet");
238 return;
239 case MachineOperand::MO_ExternalSymbol:
240 AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
241 break;
242 case MachineOperand::MO_GlobalAddress:
243 AddrSym = getSymbol(Addr.getGlobal());
244 break;
245 }
246
247 if (!isPositionIndependent()) {
248 llvm_unreachable("Unsupported uses of %plt in not PIC code");
249 return;
250 }
251
252 MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
253
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);
259 MCOperand loImm =
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);
265 MCOperand hiImm =
266 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, AddrSym, OutContext);
267 emitLEASLrri(*OutStreamer, MCRegOP, RegPLT, hiImm, MCRegOP, STI);
268 }
269
lowerGETTLSAddrAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & STI)270 void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI,
271 const MCSubtargetInfo &STI) {
272 const MachineOperand &Addr = MI->getOperand(0);
273 MCSymbol *AddrSym = nullptr;
274
275 switch (Addr.getType()) {
276 default:
277 llvm_unreachable("<unknown operand type>");
278 return;
279 case MachineOperand::MO_MachineBasicBlock:
280 report_fatal_error("MBB is not supported yet");
281 return;
282 case MachineOperand::MO_ConstantPoolIndex:
283 report_fatal_error("ConstantPool is not supported yet");
284 return;
285 case MachineOperand::MO_ExternalSymbol:
286 AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
287 break;
288 case MachineOperand::MO_GlobalAddress:
289 AddrSym = getSymbol(Addr.getGlobal());
290 break;
291 }
292
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"));
297
298 // lea %s0, sym@tls_gd_lo(-24)
299 // and %s0, %s0, (32)0
300 // sic %lr
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);
307 MCOperand loImm =
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);
313 MCOperand hiImm =
314 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32, AddrSym, OutContext);
315 emitLEASLrri(*OutStreamer, RegS0, RegLR, hiImm, RegS0, STI);
316 MCOperand ci8 = MCOperand::createImm(8);
317 MCOperand loImm2 =
318 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, GetTLSLabel, OutContext);
319 emitLEAzii(*OutStreamer, ci8, loImm2, RegS12, STI);
320 emitANDrm(*OutStreamer, RegS12, M032, RegS12, STI);
321 MCOperand hiImm2 =
322 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, GetTLSLabel, OutContext);
323 emitLEASLrri(*OutStreamer, RegS12, RegLR, hiImm2, RegS12, STI);
324 emitBSIC(*OutStreamer, RegLR, RegS12, STI);
325 }
326
emitInstruction(const MachineInstr * MI)327 void VEAsmPrinter::emitInstruction(const MachineInstr *MI) {
328
329 switch (MI->getOpcode()) {
330 default:
331 break;
332 case TargetOpcode::DBG_VALUE:
333 // FIXME: Debug Value.
334 return;
335 case VE::GETGOT:
336 lowerGETGOTAndEmitMCInsts(MI, getSubtargetInfo());
337 return;
338 case VE::GETFUNPLT:
339 lowerGETFunPLTAndEmitMCInsts(MI, getSubtargetInfo());
340 return;
341 case VE::GETTLSADDR:
342 lowerGETTLSAddrAndEmitMCInsts(MI, getSubtargetInfo());
343 return;
344 }
345
346 MachineBasicBlock::const_instr_iterator I = MI->getIterator();
347 MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
348 do {
349 MCInst TmpInst;
350 LowerVEMachineInstrToMCInst(&*I, TmpInst, *this);
351 EmitToStreamer(*OutStreamer, TmpInst);
352 } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
353 }
354
printOperand(const MachineInstr * MI,int OpNum,raw_ostream & O)355 void VEAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
356 raw_ostream &O) {
357 const MachineOperand &MO = MI->getOperand(OpNum);
358
359 switch (MO.getType()) {
360 case MachineOperand::MO_Register:
361 O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
362 break;
363 default:
364 llvm_unreachable("<unknown operand type>");
365 }
366 }
367
368 // PrintAsmOperand - Print out an operand for an inline asm expression.
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)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.
374
375 switch (ExtraCode[0]) {
376 default:
377 // See if this is a generic print operand
378 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
379 case 'r':
380 case 'v':
381 break;
382 }
383 }
384
385 printOperand(MI, OpNo, O);
386
387 return false;
388 }
389
390 // Force static initialization.
LLVMInitializeVEAsmPrinter()391 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeVEAsmPrinter() {
392 RegisterAsmPrinter<VEAsmPrinter> X(getTheVETarget());
393 }
394