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