xref: /freebsd/contrib/llvm-project/llvm/lib/Target/VE/VEAsmPrinter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/VEMCAsmInfo.h"
16 #include "MCTargetDesc/VETargetStreamer.h"
17 #include "TargetInfo/VETargetInfo.h"
18 #include "VE.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/Compiler.h"
32 #include "llvm/Support/raw_ostream.h"
33 using namespace llvm;
34 
35 #define DEBUG_TYPE "ve-asmprinter"
36 
37 namespace {
38 class VEAsmPrinter : public AsmPrinter {
getTargetStreamer()39   VETargetStreamer &getTargetStreamer() {
40     return static_cast<VETargetStreamer &>(*OutStreamer->getTargetStreamer());
41   }
42 
43 public:
VEAsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)44   explicit VEAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
45       : AsmPrinter(TM, std::move(Streamer), ID) {}
46 
getPassName() const47   StringRef getPassName() const override { return "VE Assembly Printer"; }
48 
49   void lowerGETGOTAndEmitMCInsts(const MachineInstr *MI,
50                                  const MCSubtargetInfo &STI);
51   void lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI,
52                                     const MCSubtargetInfo &STI);
53   void lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI,
54                                      const MCSubtargetInfo &STI);
55 
56   void emitInstruction(const MachineInstr *MI) override;
57 
getRegisterName(MCRegister Reg)58   static const char *getRegisterName(MCRegister Reg) {
59     return VEInstPrinter::getRegisterName(Reg);
60   }
61   void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS);
62   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
63                        const char *ExtraCode, raw_ostream &O) override;
64   bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
65                              const char *ExtraCode, raw_ostream &O) override;
66 
67   static char ID;
68 };
69 } // end of anonymous namespace
70 
createVEMCOperand(VE::Specifier Kind,MCSymbol * Sym,MCContext & OutContext)71 static MCOperand createVEMCOperand(VE::Specifier Kind, MCSymbol *Sym,
72                                    MCContext &OutContext) {
73   const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym, OutContext);
74   return MCOperand::createExpr(
75       MCSpecifierExpr::create(MCSym, Kind, OutContext));
76 }
77 
createGOTRelExprOp(VE::Specifier Kind,MCSymbol * GOTLabel,MCContext & OutContext)78 static MCOperand createGOTRelExprOp(VE::Specifier Kind, MCSymbol *GOTLabel,
79                                     MCContext &OutContext) {
80   const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);
81   return MCOperand::createExpr(MCSpecifierExpr::create(GOT, Kind, OutContext));
82 }
83 
emitSIC(MCStreamer & OutStreamer,MCOperand & RD,const MCSubtargetInfo & STI)84 static void emitSIC(MCStreamer &OutStreamer, MCOperand &RD,
85                     const MCSubtargetInfo &STI) {
86   MCInst SICInst;
87   SICInst.setOpcode(VE::SIC);
88   SICInst.addOperand(RD);
89   OutStreamer.emitInstruction(SICInst, STI);
90 }
91 
emitBSIC(MCStreamer & OutStreamer,MCOperand & R1,MCOperand & R2,const MCSubtargetInfo & STI)92 static void emitBSIC(MCStreamer &OutStreamer, MCOperand &R1, MCOperand &R2,
93                      const MCSubtargetInfo &STI) {
94   MCInst BSICInst;
95   BSICInst.setOpcode(VE::BSICrii);
96   BSICInst.addOperand(R1);
97   BSICInst.addOperand(R2);
98   MCOperand czero = MCOperand::createImm(0);
99   BSICInst.addOperand(czero);
100   BSICInst.addOperand(czero);
101   OutStreamer.emitInstruction(BSICInst, STI);
102 }
103 
emitLEAzzi(MCStreamer & OutStreamer,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)104 static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
105                        const MCSubtargetInfo &STI) {
106   MCInst LEAInst;
107   LEAInst.setOpcode(VE::LEAzii);
108   LEAInst.addOperand(RD);
109   MCOperand CZero = MCOperand::createImm(0);
110   LEAInst.addOperand(CZero);
111   LEAInst.addOperand(CZero);
112   LEAInst.addOperand(Imm);
113   OutStreamer.emitInstruction(LEAInst, STI);
114 }
115 
emitLEASLzzi(MCStreamer & OutStreamer,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)116 static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
117                          const MCSubtargetInfo &STI) {
118   MCInst LEASLInst;
119   LEASLInst.setOpcode(VE::LEASLzii);
120   LEASLInst.addOperand(RD);
121   MCOperand CZero = MCOperand::createImm(0);
122   LEASLInst.addOperand(CZero);
123   LEASLInst.addOperand(CZero);
124   LEASLInst.addOperand(Imm);
125   OutStreamer.emitInstruction(LEASLInst, STI);
126 }
127 
emitLEAzii(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)128 static void emitLEAzii(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
129                        MCOperand &RD, const MCSubtargetInfo &STI) {
130   MCInst LEAInst;
131   LEAInst.setOpcode(VE::LEAzii);
132   LEAInst.addOperand(RD);
133   MCOperand CZero = MCOperand::createImm(0);
134   LEAInst.addOperand(CZero);
135   LEAInst.addOperand(RS1);
136   LEAInst.addOperand(Imm);
137   OutStreamer.emitInstruction(LEAInst, STI);
138 }
139 
emitLEASLrri(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & RS2,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)140 static void emitLEASLrri(MCStreamer &OutStreamer, MCOperand &RS1,
141                          MCOperand &RS2, MCOperand &Imm, MCOperand &RD,
142                          const MCSubtargetInfo &STI) {
143   MCInst LEASLInst;
144   LEASLInst.setOpcode(VE::LEASLrri);
145   LEASLInst.addOperand(RD);
146   LEASLInst.addOperand(RS1);
147   LEASLInst.addOperand(RS2);
148   LEASLInst.addOperand(Imm);
149   OutStreamer.emitInstruction(LEASLInst, STI);
150 }
151 
emitBinary(MCStreamer & OutStreamer,unsigned Opcode,MCOperand & RS1,MCOperand & Src2,MCOperand & RD,const MCSubtargetInfo & STI)152 static void emitBinary(MCStreamer &OutStreamer, unsigned Opcode, MCOperand &RS1,
153                        MCOperand &Src2, MCOperand &RD,
154                        const MCSubtargetInfo &STI) {
155   MCInst Inst;
156   Inst.setOpcode(Opcode);
157   Inst.addOperand(RD);
158   Inst.addOperand(RS1);
159   Inst.addOperand(Src2);
160   OutStreamer.emitInstruction(Inst, STI);
161 }
162 
emitANDrm(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)163 static void emitANDrm(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
164                       MCOperand &RD, const MCSubtargetInfo &STI) {
165   emitBinary(OutStreamer, VE::ANDrm, RS1, Imm, RD, STI);
166 }
167 
emitHiLo(MCStreamer & OutStreamer,MCSymbol * GOTSym,VE::Specifier HiKind,VE::Specifier LoKind,MCOperand & RD,MCContext & OutContext,const MCSubtargetInfo & STI)168 static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
169                      VE::Specifier HiKind, VE::Specifier LoKind, MCOperand &RD,
170                      MCContext &OutContext, 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, VE::S_HI32, VE::S_LO32, MCRegOP,
197                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 = createGOTRelExprOp(VE::S_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);
216   MCOperand hiImm = createGOTRelExprOp(VE::S_PC_HI32, GOTLabel, OutContext);
217   emitLEASLrri(*OutStreamer, RegGOT, RegPLT, hiImm, MCRegOP, STI);
218 }
219 
lowerGETFunPLTAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & STI)220 void VEAsmPrinter::lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI,
221                                                 const MCSubtargetInfo &STI) {
222   const MachineOperand &MO = MI->getOperand(0);
223   MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
224   const MachineOperand &Addr = MI->getOperand(1);
225   MCSymbol *AddrSym = nullptr;
226 
227   switch (Addr.getType()) {
228   default:
229     llvm_unreachable("<unknown operand type>");
230     return;
231   case MachineOperand::MO_MachineBasicBlock:
232     report_fatal_error("MBB is not supported yet");
233     return;
234   case MachineOperand::MO_ConstantPoolIndex:
235     report_fatal_error("ConstantPool is not supported yet");
236     return;
237   case MachineOperand::MO_ExternalSymbol:
238     AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
239     break;
240   case MachineOperand::MO_GlobalAddress:
241     AddrSym = getSymbol(Addr.getGlobal());
242     break;
243   }
244 
245   if (!isPositionIndependent()) {
246     llvm_unreachable("Unsupported uses of %plt in not PIC code");
247     return;
248   }
249 
250   MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
251 
252   // lea %dst, func@plt_lo(-24)
253   // and %dst, %dst, (32)0
254   // sic %plt                            ; FIXME: is it safe to use %plt here?
255   // lea.sl %dst, func@plt_hi(%plt, %dst)
256   MCOperand cim24 = MCOperand::createImm(-24);
257   MCOperand loImm = createGOTRelExprOp(VE::S_PLT_LO32, AddrSym, OutContext);
258   emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI);
259   MCOperand M032 = MCOperand::createImm(M0(32));
260   emitANDrm(*OutStreamer, MCRegOP, M032, MCRegOP, STI);
261   emitSIC(*OutStreamer, RegPLT, STI);
262   MCOperand hiImm = createGOTRelExprOp(VE::S_PLT_HI32, AddrSym, OutContext);
263   emitLEASLrri(*OutStreamer, MCRegOP, RegPLT, hiImm, MCRegOP, STI);
264 }
265 
lowerGETTLSAddrAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & STI)266 void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI,
267                                                  const MCSubtargetInfo &STI) {
268   const MachineOperand &Addr = MI->getOperand(0);
269   MCSymbol *AddrSym = nullptr;
270 
271   switch (Addr.getType()) {
272   default:
273     llvm_unreachable("<unknown operand type>");
274     return;
275   case MachineOperand::MO_MachineBasicBlock:
276     report_fatal_error("MBB is not supported yet");
277     return;
278   case MachineOperand::MO_ConstantPoolIndex:
279     report_fatal_error("ConstantPool is not supported yet");
280     return;
281   case MachineOperand::MO_ExternalSymbol:
282     AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
283     break;
284   case MachineOperand::MO_GlobalAddress:
285     AddrSym = getSymbol(Addr.getGlobal());
286     break;
287   }
288 
289   MCOperand RegLR = MCOperand::createReg(VE::SX10);  // LR
290   MCOperand RegS0 = MCOperand::createReg(VE::SX0);   // S0
291   MCOperand RegS12 = MCOperand::createReg(VE::SX12); // S12
292   MCSymbol *GetTLSLabel = OutContext.getOrCreateSymbol(Twine("__tls_get_addr"));
293 
294   // lea %s0, sym@tls_gd_lo(-24)
295   // and %s0, %s0, (32)0
296   // sic %lr
297   // lea.sl %s0, sym@tls_gd_hi(%lr, %s0)
298   // lea %s12, __tls_get_addr@plt_lo(8)
299   // and %s12, %s12, (32)0
300   // lea.sl %s12, __tls_get_addr@plt_hi(%s12, %lr)
301   // bsic %lr, (, %s12)
302   MCOperand cim24 = MCOperand::createImm(-24);
303   MCOperand loImm = createGOTRelExprOp(VE::S_TLS_GD_LO32, AddrSym, OutContext);
304   emitLEAzii(*OutStreamer, cim24, loImm, RegS0, STI);
305   MCOperand M032 = MCOperand::createImm(M0(32));
306   emitANDrm(*OutStreamer, RegS0, M032, RegS0, STI);
307   emitSIC(*OutStreamer, RegLR, STI);
308   MCOperand hiImm = createGOTRelExprOp(VE::S_TLS_GD_HI32, AddrSym, OutContext);
309   emitLEASLrri(*OutStreamer, RegS0, RegLR, hiImm, RegS0, STI);
310   MCOperand ci8 = MCOperand::createImm(8);
311   MCOperand loImm2 =
312       createGOTRelExprOp(VE::S_PLT_LO32, GetTLSLabel, OutContext);
313   emitLEAzii(*OutStreamer, ci8, loImm2, RegS12, STI);
314   emitANDrm(*OutStreamer, RegS12, M032, RegS12, STI);
315   MCOperand hiImm2 =
316       createGOTRelExprOp(VE::S_PLT_HI32, GetTLSLabel, OutContext);
317   emitLEASLrri(*OutStreamer, RegS12, RegLR, hiImm2, RegS12, STI);
318   emitBSIC(*OutStreamer, RegLR, RegS12, STI);
319 }
320 
emitInstruction(const MachineInstr * MI)321 void VEAsmPrinter::emitInstruction(const MachineInstr *MI) {
322   VE_MC::verifyInstructionPredicates(MI->getOpcode(),
323                                      getSubtargetInfo().getFeatureBits());
324 
325   switch (MI->getOpcode()) {
326   default:
327     break;
328   case TargetOpcode::DBG_VALUE:
329     // FIXME: Debug Value.
330     return;
331   case VE::GETGOT:
332     lowerGETGOTAndEmitMCInsts(MI, getSubtargetInfo());
333     return;
334   case VE::GETFUNPLT:
335     lowerGETFunPLTAndEmitMCInsts(MI, getSubtargetInfo());
336     return;
337   case VE::GETTLSADDR:
338     lowerGETTLSAddrAndEmitMCInsts(MI, getSubtargetInfo());
339     return;
340   }
341 
342   MachineBasicBlock::const_instr_iterator I = MI->getIterator();
343   MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
344   do {
345     MCInst TmpInst;
346     LowerVEMachineInstrToMCInst(&*I, TmpInst, *this);
347     EmitToStreamer(*OutStreamer, TmpInst);
348   } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
349 }
350 
printOperand(const MachineInstr * MI,int OpNum,raw_ostream & O)351 void VEAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
352                                 raw_ostream &O) {
353   const MachineOperand &MO = MI->getOperand(OpNum);
354 
355   switch (MO.getType()) {
356   case MachineOperand::MO_Register:
357     O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
358     break;
359   case MachineOperand::MO_Immediate:
360     O << (int)MO.getImm();
361     break;
362   default:
363     llvm_unreachable("<unknown operand type>");
364   }
365 }
366 
367 // PrintAsmOperand - Print out an operand for an inline asm expression.
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)368 bool VEAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
369                                    const char *ExtraCode, raw_ostream &O) {
370   if (ExtraCode && ExtraCode[0]) {
371     if (ExtraCode[1] != 0)
372       return true; // Unknown modifier.
373 
374     switch (ExtraCode[0]) {
375     default:
376       // See if this is a generic print operand
377       return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
378     case 'r':
379     case 'v':
380       break;
381     }
382   }
383 
384   printOperand(MI, OpNo, O);
385 
386   return false;
387 }
388 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)389 bool VEAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
390                                          const char *ExtraCode,
391                                          raw_ostream &O) {
392   if (ExtraCode && ExtraCode[0])
393     return true;  // Unknown modifier
394 
395   if (MI->getOperand(OpNo+1).isImm() &&
396       MI->getOperand(OpNo+1).getImm() == 0) {
397     // don't print "+0"
398   } else {
399     printOperand(MI, OpNo+1, O);
400   }
401   if (MI->getOperand(OpNo).isImm() &&
402       MI->getOperand(OpNo).getImm() == 0) {
403     if (MI->getOperand(OpNo+1).isImm() &&
404         MI->getOperand(OpNo+1).getImm() == 0) {
405       O << "0";
406     } else {
407       // don't print "(0)"
408     }
409   } else {
410     O << "(";
411     printOperand(MI, OpNo, O);
412     O << ")";
413   }
414   return false;
415 }
416 
417 char VEAsmPrinter::ID = 0;
418 
419 INITIALIZE_PASS(VEAsmPrinter, "ve-asm-printer", "VE Assembly Printer", false,
420                 false)
421 
422 // Force static initialization.
LLVMInitializeVEAsmPrinter()423 extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeVEAsmPrinter() {
424   RegisterAsmPrinter<VEAsmPrinter> X(getTheVETarget());
425 }
426