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/MC/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(MCRegister Reg)60 static const char *getRegisterName(MCRegister Reg) {
61 return VEInstPrinter::getRegisterName(Reg);
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 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
67 const char *ExtraCode, raw_ostream &O) override;
68 };
69 } // end of anonymous namespace
70
createVEMCOperand(VEMCExpr::VariantKind Kind,MCSymbol * Sym,MCContext & OutContext)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);
76 }
77
createGOTRelExprOp(VEMCExpr::VariantKind Kind,MCSymbol * GOTLabel,MCContext & OutContext)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);
83 }
84
emitSIC(MCStreamer & OutStreamer,MCOperand & RD,const MCSubtargetInfo & STI)85 static void emitSIC(MCStreamer &OutStreamer, MCOperand &RD,
86 const MCSubtargetInfo &STI) {
87 MCInst SICInst;
88 SICInst.setOpcode(VE::SIC);
89 SICInst.addOperand(RD);
90 OutStreamer.emitInstruction(SICInst, STI);
91 }
92
emitBSIC(MCStreamer & OutStreamer,MCOperand & R1,MCOperand & R2,const MCSubtargetInfo & STI)93 static void emitBSIC(MCStreamer &OutStreamer, MCOperand &R1, MCOperand &R2,
94 const MCSubtargetInfo &STI) {
95 MCInst BSICInst;
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);
103 }
104
emitLEAzzi(MCStreamer & OutStreamer,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)105 static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
106 const MCSubtargetInfo &STI) {
107 MCInst LEAInst;
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);
115 }
116
emitLEASLzzi(MCStreamer & OutStreamer,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)117 static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
118 const MCSubtargetInfo &STI) {
119 MCInst LEASLInst;
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);
127 }
128
emitLEAzii(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)129 static void emitLEAzii(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
130 MCOperand &RD, const MCSubtargetInfo &STI) {
131 MCInst LEAInst;
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);
139 }
140
emitLEASLrri(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & RS2,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)141 static void emitLEASLrri(MCStreamer &OutStreamer, MCOperand &RS1,
142 MCOperand &RS2, MCOperand &Imm, MCOperand &RD,
143 const MCSubtargetInfo &STI) {
144 MCInst LEASLInst;
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);
151 }
152
emitBinary(MCStreamer & OutStreamer,unsigned Opcode,MCOperand & RS1,MCOperand & Src2,MCOperand & RD,const MCSubtargetInfo & STI)153 static void emitBinary(MCStreamer &OutStreamer, unsigned Opcode, MCOperand &RS1,
154 MCOperand &Src2, MCOperand &RD,
155 const MCSubtargetInfo &STI) {
156 MCInst Inst;
157 Inst.setOpcode(Opcode);
158 Inst.addOperand(RD);
159 Inst.addOperand(RS1);
160 Inst.addOperand(Src2);
161 OutStreamer.emitInstruction(Inst, STI);
162 }
163
emitANDrm(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & 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);
167 }
168
emitHiLo(MCStreamer & OutStreamer,MCSymbol * GOTSym,VEMCExpr::VariantKind HiKind,VEMCExpr::VariantKind LoKind,MCOperand & RD,MCContext & OutContext,const MCSubtargetInfo & 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) {
173
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);
180 }
181
lowerGETGOTAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & STI)182 void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr *MI,
183 const MCSubtargetInfo &STI) {
184 MCSymbol *GOTLabel =
185 OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
186
187 const MachineOperand &MO = MI->getOperand(0);
188 MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
189
190 if (!isPositionIndependent()) {
191 // Just load the address of GOT to MCRegOP.
192 switch (TM.getCodeModel()) {
193 default:
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);
200 break;
201 }
202 return;
203 }
204
205 MCOperand RegGOT = MCOperand::createReg(VE::SX15); // GOT
206 MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
207
208 // lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24)
209 // and %got, %got, (32)0
210 // sic %plt
211 // lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%plt, %got)
212 MCOperand cim24 = MCOperand::createImm(-24);
213 MCOperand loImm =
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);
219 MCOperand hiImm =
220 createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32, GOTLabel, OutContext);
221 emitLEASLrri(*OutStreamer, RegGOT, RegPLT, hiImm, MCRegOP, STI);
222 }
223
lowerGETFunPLTAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & 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;
230
231 switch (Addr.getType()) {
232 default:
233 llvm_unreachable("<unknown operand type>");
234 return;
235 case MachineOperand::MO_MachineBasicBlock:
236 report_fatal_error("MBB is not supported yet");
237 return;
238 case MachineOperand::MO_ConstantPoolIndex:
239 report_fatal_error("ConstantPool is not supported yet");
240 return;
241 case MachineOperand::MO_ExternalSymbol:
242 AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
243 break;
244 case MachineOperand::MO_GlobalAddress:
245 AddrSym = getSymbol(Addr.getGlobal());
246 break;
247 }
248
249 if (!isPositionIndependent()) {
250 llvm_unreachable("Unsupported uses of %plt in not PIC code");
251 return;
252 }
253
254 MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
255
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);
261 MCOperand loImm =
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);
267 MCOperand hiImm =
268 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, AddrSym, OutContext);
269 emitLEASLrri(*OutStreamer, MCRegOP, RegPLT, hiImm, MCRegOP, STI);
270 }
271
lowerGETTLSAddrAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & STI)272 void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI,
273 const MCSubtargetInfo &STI) {
274 const MachineOperand &Addr = MI->getOperand(0);
275 MCSymbol *AddrSym = nullptr;
276
277 switch (Addr.getType()) {
278 default:
279 llvm_unreachable("<unknown operand type>");
280 return;
281 case MachineOperand::MO_MachineBasicBlock:
282 report_fatal_error("MBB is not supported yet");
283 return;
284 case MachineOperand::MO_ConstantPoolIndex:
285 report_fatal_error("ConstantPool is not supported yet");
286 return;
287 case MachineOperand::MO_ExternalSymbol:
288 AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
289 break;
290 case MachineOperand::MO_GlobalAddress:
291 AddrSym = getSymbol(Addr.getGlobal());
292 break;
293 }
294
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"));
299
300 // lea %s0, sym@tls_gd_lo(-24)
301 // and %s0, %s0, (32)0
302 // sic %lr
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);
309 MCOperand loImm =
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);
315 MCOperand hiImm =
316 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32, AddrSym, OutContext);
317 emitLEASLrri(*OutStreamer, RegS0, RegLR, hiImm, RegS0, STI);
318 MCOperand ci8 = MCOperand::createImm(8);
319 MCOperand loImm2 =
320 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, GetTLSLabel, OutContext);
321 emitLEAzii(*OutStreamer, ci8, loImm2, RegS12, STI);
322 emitANDrm(*OutStreamer, RegS12, M032, RegS12, STI);
323 MCOperand hiImm2 =
324 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, GetTLSLabel, OutContext);
325 emitLEASLrri(*OutStreamer, RegS12, RegLR, hiImm2, RegS12, STI);
326 emitBSIC(*OutStreamer, RegLR, RegS12, STI);
327 }
328
emitInstruction(const MachineInstr * MI)329 void VEAsmPrinter::emitInstruction(const MachineInstr *MI) {
330 VE_MC::verifyInstructionPredicates(MI->getOpcode(),
331 getSubtargetInfo().getFeatureBits());
332
333 switch (MI->getOpcode()) {
334 default:
335 break;
336 case TargetOpcode::DBG_VALUE:
337 // FIXME: Debug Value.
338 return;
339 case VE::GETGOT:
340 lowerGETGOTAndEmitMCInsts(MI, getSubtargetInfo());
341 return;
342 case VE::GETFUNPLT:
343 lowerGETFunPLTAndEmitMCInsts(MI, getSubtargetInfo());
344 return;
345 case VE::GETTLSADDR:
346 lowerGETTLSAddrAndEmitMCInsts(MI, getSubtargetInfo());
347 return;
348 }
349
350 MachineBasicBlock::const_instr_iterator I = MI->getIterator();
351 MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
352 do {
353 MCInst TmpInst;
354 LowerVEMachineInstrToMCInst(&*I, TmpInst, *this);
355 EmitToStreamer(*OutStreamer, TmpInst);
356 } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
357 }
358
printOperand(const MachineInstr * MI,int OpNum,raw_ostream & O)359 void VEAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
360 raw_ostream &O) {
361 const MachineOperand &MO = MI->getOperand(OpNum);
362
363 switch (MO.getType()) {
364 case MachineOperand::MO_Register:
365 O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
366 break;
367 case MachineOperand::MO_Immediate:
368 O << (int)MO.getImm();
369 break;
370 default:
371 llvm_unreachable("<unknown operand type>");
372 }
373 }
374
375 // PrintAsmOperand - Print out an operand for an inline asm expression.
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)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.
381
382 switch (ExtraCode[0]) {
383 default:
384 // See if this is a generic print operand
385 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
386 case 'r':
387 case 'v':
388 break;
389 }
390 }
391
392 printOperand(MI, OpNo, O);
393
394 return false;
395 }
396
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)397 bool VEAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
398 const char *ExtraCode,
399 raw_ostream &O) {
400 if (ExtraCode && ExtraCode[0])
401 return true; // Unknown modifier
402
403 if (MI->getOperand(OpNo+1).isImm() &&
404 MI->getOperand(OpNo+1).getImm() == 0) {
405 // don't print "+0"
406 } else {
407 printOperand(MI, OpNo+1, O);
408 }
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) {
413 O << "0";
414 } else {
415 // don't print "(0)"
416 }
417 } else {
418 O << "(";
419 printOperand(MI, OpNo, O);
420 O << ")";
421 }
422 return false;
423 }
424
425 // Force static initialization.
LLVMInitializeVEAsmPrinter()426 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeVEAsmPrinter() {
427 RegisterAsmPrinter<VEAsmPrinter> X(getTheVETarget());
428 }
429