xref: /freebsd/contrib/llvm-project/llvm/lib/Target/VE/VEAsmPrinter.cpp (revision 6be3386466ab79a84b48429ae66244f21526d3df)
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 {
41   VETargetStreamer &getTargetStreamer() {
42     return static_cast<VETargetStreamer &>(*OutStreamer->getTargetStreamer());
43   }
44 
45 public:
46   explicit VEAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
47       : AsmPrinter(TM, std::move(Streamer)) {}
48 
49   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 
60   static const char *getRegisterName(unsigned RegNo) {
61     return VEInstPrinter::getRegisterName(RegNo);
62   }
63 };
64 } // end of anonymous namespace
65 
66 static MCOperand createVEMCOperand(VEMCExpr::VariantKind Kind, MCSymbol *Sym,
67                                    MCContext &OutContext) {
68   const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym, OutContext);
69   const VEMCExpr *expr = VEMCExpr::create(Kind, MCSym, OutContext);
70   return MCOperand::createExpr(expr);
71 }
72 
73 static MCOperand createGOTRelExprOp(VEMCExpr::VariantKind Kind,
74                                     MCSymbol *GOTLabel, MCContext &OutContext) {
75   const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);
76   const VEMCExpr *expr = VEMCExpr::create(Kind, GOT, OutContext);
77   return MCOperand::createExpr(expr);
78 }
79 
80 static void emitSIC(MCStreamer &OutStreamer, MCOperand &RD,
81                     const MCSubtargetInfo &STI) {
82   MCInst SICInst;
83   SICInst.setOpcode(VE::SIC);
84   SICInst.addOperand(RD);
85   OutStreamer.emitInstruction(SICInst, STI);
86 }
87 
88 static void emitBSIC(MCStreamer &OutStreamer, MCOperand &R1, MCOperand &R2,
89                      const MCSubtargetInfo &STI) {
90   MCInst BSICInst;
91   BSICInst.setOpcode(VE::BSICrii);
92   BSICInst.addOperand(R1);
93   BSICInst.addOperand(R2);
94   MCOperand czero = MCOperand::createImm(0);
95   BSICInst.addOperand(czero);
96   BSICInst.addOperand(czero);
97   OutStreamer.emitInstruction(BSICInst, STI);
98 }
99 
100 static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
101                        const MCSubtargetInfo &STI) {
102   MCInst LEAInst;
103   LEAInst.setOpcode(VE::LEAzii);
104   LEAInst.addOperand(RD);
105   MCOperand CZero = MCOperand::createImm(0);
106   LEAInst.addOperand(CZero);
107   LEAInst.addOperand(CZero);
108   LEAInst.addOperand(Imm);
109   OutStreamer.emitInstruction(LEAInst, STI);
110 }
111 
112 static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
113                          const MCSubtargetInfo &STI) {
114   MCInst LEASLInst;
115   LEASLInst.setOpcode(VE::LEASLzii);
116   LEASLInst.addOperand(RD);
117   MCOperand CZero = MCOperand::createImm(0);
118   LEASLInst.addOperand(CZero);
119   LEASLInst.addOperand(CZero);
120   LEASLInst.addOperand(Imm);
121   OutStreamer.emitInstruction(LEASLInst, STI);
122 }
123 
124 static void emitLEAzii(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
125                        MCOperand &RD, const MCSubtargetInfo &STI) {
126   MCInst LEAInst;
127   LEAInst.setOpcode(VE::LEAzii);
128   LEAInst.addOperand(RD);
129   MCOperand CZero = MCOperand::createImm(0);
130   LEAInst.addOperand(CZero);
131   LEAInst.addOperand(RS1);
132   LEAInst.addOperand(Imm);
133   OutStreamer.emitInstruction(LEAInst, STI);
134 }
135 
136 static void emitLEASLrri(MCStreamer &OutStreamer, MCOperand &RS1,
137                          MCOperand &RS2, MCOperand &Imm, MCOperand &RD,
138                          const MCSubtargetInfo &STI) {
139   MCInst LEASLInst;
140   LEASLInst.setOpcode(VE::LEASLrri);
141   LEASLInst.addOperand(RD);
142   LEASLInst.addOperand(RS1);
143   LEASLInst.addOperand(RS2);
144   LEASLInst.addOperand(Imm);
145   OutStreamer.emitInstruction(LEASLInst, STI);
146 }
147 
148 static void emitBinary(MCStreamer &OutStreamer, unsigned Opcode, MCOperand &RS1,
149                        MCOperand &Src2, MCOperand &RD,
150                        const MCSubtargetInfo &STI) {
151   MCInst Inst;
152   Inst.setOpcode(Opcode);
153   Inst.addOperand(RD);
154   Inst.addOperand(RS1);
155   Inst.addOperand(Src2);
156   OutStreamer.emitInstruction(Inst, STI);
157 }
158 
159 static void emitANDrm(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
160                       MCOperand &RD, const MCSubtargetInfo &STI) {
161   emitBinary(OutStreamer, VE::ANDrm, RS1, Imm, RD, STI);
162 }
163 
164 static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
165                      VEMCExpr::VariantKind HiKind, VEMCExpr::VariantKind LoKind,
166                      MCOperand &RD, MCContext &OutContext,
167                      const MCSubtargetInfo &STI) {
168 
169   MCOperand hi = createVEMCOperand(HiKind, GOTSym, OutContext);
170   MCOperand lo = createVEMCOperand(LoKind, GOTSym, OutContext);
171   emitLEAzzi(OutStreamer, lo, RD, STI);
172   MCOperand M032 = MCOperand::createImm(M0(32));
173   emitANDrm(OutStreamer, RD, M032, RD, STI);
174   emitLEASLzzi(OutStreamer, hi, RD, STI);
175 }
176 
177 void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr *MI,
178                                              const MCSubtargetInfo &STI) {
179   MCSymbol *GOTLabel =
180       OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
181 
182   const MachineOperand &MO = MI->getOperand(0);
183   MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
184 
185   if (!isPositionIndependent()) {
186     // Just load the address of GOT to MCRegOP.
187     switch (TM.getCodeModel()) {
188     default:
189       llvm_unreachable("Unsupported absolute code model");
190     case CodeModel::Small:
191     case CodeModel::Medium:
192     case CodeModel::Large:
193       emitHiLo(*OutStreamer, GOTLabel, VEMCExpr::VK_VE_HI32,
194                VEMCExpr::VK_VE_LO32, MCRegOP, OutContext, STI);
195       break;
196     }
197     return;
198   }
199 
200   MCOperand RegGOT = MCOperand::createReg(VE::SX15); // GOT
201   MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
202 
203   // lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24)
204   // and %got, %got, (32)0
205   // sic %plt
206   // lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%got, %plt)
207   MCOperand cim24 = MCOperand::createImm(-24);
208   MCOperand loImm =
209       createGOTRelExprOp(VEMCExpr::VK_VE_PC_LO32, GOTLabel, OutContext);
210   emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI);
211   MCOperand M032 = MCOperand::createImm(M0(32));
212   emitANDrm(*OutStreamer, MCRegOP, M032, MCRegOP, STI);
213   emitSIC(*OutStreamer, RegPLT, STI);
214   MCOperand hiImm =
215       createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32, GOTLabel, OutContext);
216   emitLEASLrri(*OutStreamer, RegGOT, RegPLT, hiImm, MCRegOP, STI);
217 }
218 
219 void VEAsmPrinter::lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI,
220                                                 const MCSubtargetInfo &STI) {
221   const MachineOperand &MO = MI->getOperand(0);
222   MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
223   const MachineOperand &Addr = MI->getOperand(1);
224   MCSymbol *AddrSym = nullptr;
225 
226   switch (Addr.getType()) {
227   default:
228     llvm_unreachable("<unknown operand type>");
229     return;
230   case MachineOperand::MO_MachineBasicBlock:
231     report_fatal_error("MBB is not supported yet");
232     return;
233   case MachineOperand::MO_ConstantPoolIndex:
234     report_fatal_error("ConstantPool is not supported yet");
235     return;
236   case MachineOperand::MO_ExternalSymbol:
237     AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
238     break;
239   case MachineOperand::MO_GlobalAddress:
240     AddrSym = getSymbol(Addr.getGlobal());
241     break;
242   }
243 
244   if (!isPositionIndependent()) {
245     llvm_unreachable("Unsupported uses of %plt in not PIC code");
246     return;
247   }
248 
249   MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
250 
251   // lea %dst, %plt_lo(func)(-24)
252   // and %dst, %dst, (32)0
253   // sic %plt                            ; FIXME: is it safe to use %plt here?
254   // lea.sl %dst, %plt_hi(func)(%dst, %plt)
255   MCOperand cim24 = MCOperand::createImm(-24);
256   MCOperand loImm =
257       createGOTRelExprOp(VEMCExpr::VK_VE_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 =
263       createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, AddrSym, OutContext);
264   emitLEASLrri(*OutStreamer, MCRegOP, RegPLT, hiImm, MCRegOP, STI);
265 }
266 
267 void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI,
268                                                  const MCSubtargetInfo &STI) {
269   const MachineOperand &Addr = MI->getOperand(0);
270   MCSymbol *AddrSym = nullptr;
271 
272   switch (Addr.getType()) {
273   default:
274     llvm_unreachable("<unknown operand type>");
275     return;
276   case MachineOperand::MO_MachineBasicBlock:
277     report_fatal_error("MBB is not supported yet");
278     return;
279   case MachineOperand::MO_ConstantPoolIndex:
280     report_fatal_error("ConstantPool is not supported yet");
281     return;
282   case MachineOperand::MO_ExternalSymbol:
283     AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
284     break;
285   case MachineOperand::MO_GlobalAddress:
286     AddrSym = getSymbol(Addr.getGlobal());
287     break;
288   }
289 
290   MCOperand RegLR = MCOperand::createReg(VE::SX10);  // LR
291   MCOperand RegS0 = MCOperand::createReg(VE::SX0);   // S0
292   MCOperand RegS12 = MCOperand::createReg(VE::SX12); // S12
293   MCSymbol *GetTLSLabel = OutContext.getOrCreateSymbol(Twine("__tls_get_addr"));
294 
295   // lea %s0, sym@tls_gd_lo(-24)
296   // and %s0, %s0, (32)0
297   // sic %lr
298   // lea.sl %s0, sym@tls_gd_hi(%s0, %lr)
299   // lea %s12, __tls_get_addr@plt_lo(8)
300   // and %s12, %s12, (32)0
301   // lea.sl %s12, __tls_get_addr@plt_hi(%s12, %lr)
302   // bsic %lr, (, %s12)
303   MCOperand cim24 = MCOperand::createImm(-24);
304   MCOperand loImm =
305       createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_LO32, AddrSym, OutContext);
306   emitLEAzii(*OutStreamer, cim24, loImm, RegS0, STI);
307   MCOperand M032 = MCOperand::createImm(M0(32));
308   emitANDrm(*OutStreamer, RegS0, M032, RegS0, STI);
309   emitSIC(*OutStreamer, RegLR, STI);
310   MCOperand hiImm =
311       createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32, AddrSym, OutContext);
312   emitLEASLrri(*OutStreamer, RegS0, RegLR, hiImm, RegS0, STI);
313   MCOperand ci8 = MCOperand::createImm(8);
314   MCOperand loImm2 =
315       createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, GetTLSLabel, OutContext);
316   emitLEAzii(*OutStreamer, ci8, loImm2, RegS12, STI);
317   emitANDrm(*OutStreamer, RegS12, M032, RegS12, STI);
318   MCOperand hiImm2 =
319       createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, GetTLSLabel, OutContext);
320   emitLEASLrri(*OutStreamer, RegS12, RegLR, hiImm2, RegS12, STI);
321   emitBSIC(*OutStreamer, RegLR, RegS12, STI);
322 }
323 
324 void VEAsmPrinter::emitInstruction(const MachineInstr *MI) {
325 
326   switch (MI->getOpcode()) {
327   default:
328     break;
329   case TargetOpcode::DBG_VALUE:
330     // FIXME: Debug Value.
331     return;
332   case VE::GETGOT:
333     lowerGETGOTAndEmitMCInsts(MI, getSubtargetInfo());
334     return;
335   case VE::GETFUNPLT:
336     lowerGETFunPLTAndEmitMCInsts(MI, getSubtargetInfo());
337     return;
338   case VE::GETTLSADDR:
339     lowerGETTLSAddrAndEmitMCInsts(MI, getSubtargetInfo());
340     return;
341   }
342 
343   MachineBasicBlock::const_instr_iterator I = MI->getIterator();
344   MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
345   do {
346     MCInst TmpInst;
347     LowerVEMachineInstrToMCInst(&*I, TmpInst, *this);
348     EmitToStreamer(*OutStreamer, TmpInst);
349   } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
350 }
351 
352 // Force static initialization.
353 extern "C" void LLVMInitializeVEAsmPrinter() {
354   RegisterAsmPrinter<VEAsmPrinter> X(getTheVETarget());
355 }
356