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