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"
35using namespace llvm;
36
37#define DEBUG_TYPE "ve-asmprinter"
38
39namespace {
40class VEAsmPrinter : public AsmPrinter {
41  VETargetStreamer &getTargetStreamer() {
42    return static_cast<VETargetStreamer &>(*OutStreamer->getTargetStreamer());
43  }
44
45public:
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
71static 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
78static 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
85static 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
93static 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
105static 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
117static 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
129static 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
141static 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
153static 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
164static 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
169static 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
182void 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
224void 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
272void 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
329void 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
359void 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.
376bool 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
397bool 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.
426extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeVEAsmPrinter() {
427  RegisterAsmPrinter<VEAsmPrinter> X(getTheVETarget());
428}
429