xref: /llvm-project/llvm/lib/Target/VE/VEAsmPrinter.cpp (revision ed8019d9fbed2e6a6b08f8f73e9fa54a24f3ed52)
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 "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"
32 using namespace llvm;
33 
34 #define DEBUG_TYPE "ve-asmprinter"
35 
36 namespace {
37 class VEAsmPrinter : public AsmPrinter {
38   VETargetStreamer &getTargetStreamer() {
39     return static_cast<VETargetStreamer &>(*OutStreamer->getTargetStreamer());
40   }
41 
42 public:
43   explicit VEAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
44       : AsmPrinter(TM, std::move(Streamer)) {}
45 
46   StringRef getPassName() const override { return "VE Assembly Printer"; }
47 
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);
54 
55   void emitInstruction(const MachineInstr *MI) override;
56 
57   static const char *getRegisterName(MCRegister Reg) {
58     return VEInstPrinter::getRegisterName(Reg);
59   }
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;
65 };
66 } // end of anonymous namespace
67 
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);
73 }
74 
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);
80 }
81 
82 static void emitSIC(MCStreamer &OutStreamer, MCOperand &RD,
83                     const MCSubtargetInfo &STI) {
84   MCInst SICInst;
85   SICInst.setOpcode(VE::SIC);
86   SICInst.addOperand(RD);
87   OutStreamer.emitInstruction(SICInst, STI);
88 }
89 
90 static void emitBSIC(MCStreamer &OutStreamer, MCOperand &R1, MCOperand &R2,
91                      const MCSubtargetInfo &STI) {
92   MCInst BSICInst;
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);
100 }
101 
102 static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
103                        const MCSubtargetInfo &STI) {
104   MCInst LEAInst;
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);
112 }
113 
114 static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
115                          const MCSubtargetInfo &STI) {
116   MCInst LEASLInst;
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);
124 }
125 
126 static void emitLEAzii(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
127                        MCOperand &RD, const MCSubtargetInfo &STI) {
128   MCInst LEAInst;
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);
136 }
137 
138 static void emitLEASLrri(MCStreamer &OutStreamer, MCOperand &RS1,
139                          MCOperand &RS2, MCOperand &Imm, MCOperand &RD,
140                          const MCSubtargetInfo &STI) {
141   MCInst LEASLInst;
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);
148 }
149 
150 static void emitBinary(MCStreamer &OutStreamer, unsigned Opcode, MCOperand &RS1,
151                        MCOperand &Src2, MCOperand &RD,
152                        const MCSubtargetInfo &STI) {
153   MCInst Inst;
154   Inst.setOpcode(Opcode);
155   Inst.addOperand(RD);
156   Inst.addOperand(RS1);
157   Inst.addOperand(Src2);
158   OutStreamer.emitInstruction(Inst, STI);
159 }
160 
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);
164 }
165 
166 static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
167                      VEMCExpr::VariantKind HiKind, VEMCExpr::VariantKind LoKind,
168                      MCOperand &RD, MCContext &OutContext,
169                      const MCSubtargetInfo &STI) {
170 
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);
177 }
178 
179 void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr *MI,
180                                              const MCSubtargetInfo &STI) {
181   MCSymbol *GOTLabel =
182       OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
183 
184   const MachineOperand &MO = MI->getOperand(0);
185   MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
186 
187   if (!isPositionIndependent()) {
188     // Just load the address of GOT to MCRegOP.
189     switch (TM.getCodeModel()) {
190     default:
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);
197       break;
198     }
199     return;
200   }
201 
202   MCOperand RegGOT = MCOperand::createReg(VE::SX15); // GOT
203   MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
204 
205   // lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24)
206   // and %got, %got, (32)0
207   // sic %plt
208   // lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%plt, %got)
209   MCOperand cim24 = MCOperand::createImm(-24);
210   MCOperand loImm =
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);
216   MCOperand hiImm =
217       createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32, GOTLabel, OutContext);
218   emitLEASLrri(*OutStreamer, RegGOT, RegPLT, hiImm, MCRegOP, STI);
219 }
220 
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;
227 
228   switch (Addr.getType()) {
229   default:
230     llvm_unreachable("<unknown operand type>");
231     return;
232   case MachineOperand::MO_MachineBasicBlock:
233     report_fatal_error("MBB is not supported yet");
234     return;
235   case MachineOperand::MO_ConstantPoolIndex:
236     report_fatal_error("ConstantPool is not supported yet");
237     return;
238   case MachineOperand::MO_ExternalSymbol:
239     AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
240     break;
241   case MachineOperand::MO_GlobalAddress:
242     AddrSym = getSymbol(Addr.getGlobal());
243     break;
244   }
245 
246   if (!isPositionIndependent()) {
247     llvm_unreachable("Unsupported uses of %plt in not PIC code");
248     return;
249   }
250 
251   MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
252 
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);
258   MCOperand loImm =
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);
264   MCOperand hiImm =
265       createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, AddrSym, OutContext);
266   emitLEASLrri(*OutStreamer, MCRegOP, RegPLT, hiImm, MCRegOP, STI);
267 }
268 
269 void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI,
270                                                  const MCSubtargetInfo &STI) {
271   const MachineOperand &Addr = MI->getOperand(0);
272   MCSymbol *AddrSym = nullptr;
273 
274   switch (Addr.getType()) {
275   default:
276     llvm_unreachable("<unknown operand type>");
277     return;
278   case MachineOperand::MO_MachineBasicBlock:
279     report_fatal_error("MBB is not supported yet");
280     return;
281   case MachineOperand::MO_ConstantPoolIndex:
282     report_fatal_error("ConstantPool is not supported yet");
283     return;
284   case MachineOperand::MO_ExternalSymbol:
285     AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
286     break;
287   case MachineOperand::MO_GlobalAddress:
288     AddrSym = getSymbol(Addr.getGlobal());
289     break;
290   }
291 
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"));
296 
297   // lea %s0, sym@tls_gd_lo(-24)
298   // and %s0, %s0, (32)0
299   // sic %lr
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);
306   MCOperand loImm =
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);
312   MCOperand hiImm =
313       createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32, AddrSym, OutContext);
314   emitLEASLrri(*OutStreamer, RegS0, RegLR, hiImm, RegS0, STI);
315   MCOperand ci8 = MCOperand::createImm(8);
316   MCOperand loImm2 =
317       createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, GetTLSLabel, OutContext);
318   emitLEAzii(*OutStreamer, ci8, loImm2, RegS12, STI);
319   emitANDrm(*OutStreamer, RegS12, M032, RegS12, STI);
320   MCOperand hiImm2 =
321       createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, GetTLSLabel, OutContext);
322   emitLEASLrri(*OutStreamer, RegS12, RegLR, hiImm2, RegS12, STI);
323   emitBSIC(*OutStreamer, RegLR, RegS12, STI);
324 }
325 
326 void VEAsmPrinter::emitInstruction(const MachineInstr *MI) {
327   VE_MC::verifyInstructionPredicates(MI->getOpcode(),
328                                      getSubtargetInfo().getFeatureBits());
329 
330   switch (MI->getOpcode()) {
331   default:
332     break;
333   case TargetOpcode::DBG_VALUE:
334     // FIXME: Debug Value.
335     return;
336   case VE::GETGOT:
337     lowerGETGOTAndEmitMCInsts(MI, getSubtargetInfo());
338     return;
339   case VE::GETFUNPLT:
340     lowerGETFunPLTAndEmitMCInsts(MI, getSubtargetInfo());
341     return;
342   case VE::GETTLSADDR:
343     lowerGETTLSAddrAndEmitMCInsts(MI, getSubtargetInfo());
344     return;
345   }
346 
347   MachineBasicBlock::const_instr_iterator I = MI->getIterator();
348   MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
349   do {
350     MCInst TmpInst;
351     LowerVEMachineInstrToMCInst(&*I, TmpInst, *this);
352     EmitToStreamer(*OutStreamer, TmpInst);
353   } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
354 }
355 
356 void VEAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
357                                 raw_ostream &O) {
358   const MachineOperand &MO = MI->getOperand(OpNum);
359 
360   switch (MO.getType()) {
361   case MachineOperand::MO_Register:
362     O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
363     break;
364   case MachineOperand::MO_Immediate:
365     O << (int)MO.getImm();
366     break;
367   default:
368     llvm_unreachable("<unknown operand type>");
369   }
370 }
371 
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.
378 
379     switch (ExtraCode[0]) {
380     default:
381       // See if this is a generic print operand
382       return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
383     case 'r':
384     case 'v':
385       break;
386     }
387   }
388 
389   printOperand(MI, OpNo, O);
390 
391   return false;
392 }
393 
394 bool VEAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
395                                          const char *ExtraCode,
396                                          raw_ostream &O) {
397   if (ExtraCode && ExtraCode[0])
398     return true;  // Unknown modifier
399 
400   if (MI->getOperand(OpNo+1).isImm() &&
401       MI->getOperand(OpNo+1).getImm() == 0) {
402     // don't print "+0"
403   } else {
404     printOperand(MI, OpNo+1, O);
405   }
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) {
410       O << "0";
411     } else {
412       // don't print "(0)"
413     }
414   } else {
415     O << "(";
416     printOperand(MI, OpNo, O);
417     O << ")";
418   }
419   return false;
420 }
421 
422 // Force static initialization.
423 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeVEAsmPrinter() {
424   RegisterAsmPrinter<VEAsmPrinter> X(getTheVETarget());
425 }
426