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