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