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