LanaiInstPrinter.cpp revision 360660
1//===-- LanaiInstPrinter.cpp - Convert Lanai MCInst to asm syntax ---------===//
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 class prints an Lanai MCInst to a .s file.
10//
11//===----------------------------------------------------------------------===//
12
13#include "LanaiInstPrinter.h"
14#include "LanaiMCExpr.h"
15#include "LanaiAluCode.h"
16#include "LanaiCondCode.h"
17#include "MCTargetDesc/LanaiMCTargetDesc.h"
18#include "llvm/MC/MCAsmInfo.h"
19#include "llvm/MC/MCExpr.h"
20#include "llvm/MC/MCInst.h"
21#include "llvm/MC/MCRegisterInfo.h"
22#include "llvm/MC/MCSymbol.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Support/FormattedStream.h"
25
26using namespace llvm;
27
28#define DEBUG_TYPE "asm-printer"
29
30// Include the auto-generated portion of the assembly writer.
31#define PRINT_ALIAS_INSTR
32#include "LanaiGenAsmWriter.inc"
33
34void LanaiInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
35  OS << StringRef(getRegisterName(RegNo)).lower();
36}
37
38bool LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
39                                 StringRef Alias, unsigned OpNo0,
40                                 unsigned OpNo1) {
41  OS << "\t" << Alias << " ";
42  printOperand(MI, OpNo0, OS);
43  OS << ", ";
44  printOperand(MI, OpNo1, OS);
45  return true;
46}
47
48static bool usesGivenOffset(const MCInst *MI, int AddOffset) {
49  unsigned AluCode = MI->getOperand(3).getImm();
50  return LPAC::encodeLanaiAluCode(AluCode) == LPAC::ADD &&
51         (MI->getOperand(2).getImm() == AddOffset ||
52          MI->getOperand(2).getImm() == -AddOffset);
53}
54
55static bool isPreIncrementForm(const MCInst *MI, int AddOffset) {
56  unsigned AluCode = MI->getOperand(3).getImm();
57  return LPAC::isPreOp(AluCode) && usesGivenOffset(MI, AddOffset);
58}
59
60static bool isPostIncrementForm(const MCInst *MI, int AddOffset) {
61  unsigned AluCode = MI->getOperand(3).getImm();
62  return LPAC::isPostOp(AluCode) && usesGivenOffset(MI, AddOffset);
63}
64
65static StringRef decIncOperator(const MCInst *MI) {
66  if (MI->getOperand(2).getImm() < 0)
67    return "--";
68  return "++";
69}
70
71bool LanaiInstPrinter::printMemoryLoadIncrement(const MCInst *MI,
72                                                raw_ostream &OS,
73                                                StringRef Opcode,
74                                                int AddOffset) {
75  if (isPreIncrementForm(MI, AddOffset)) {
76    OS << "\t" << Opcode << "\t[" << decIncOperator(MI) << "%"
77       << getRegisterName(MI->getOperand(1).getReg()) << "], %"
78       << getRegisterName(MI->getOperand(0).getReg());
79    return true;
80  }
81  if (isPostIncrementForm(MI, AddOffset)) {
82    OS << "\t" << Opcode << "\t[%"
83       << getRegisterName(MI->getOperand(1).getReg()) << decIncOperator(MI)
84       << "], %" << getRegisterName(MI->getOperand(0).getReg());
85    return true;
86  }
87  return false;
88}
89
90bool LanaiInstPrinter::printMemoryStoreIncrement(const MCInst *MI,
91                                                 raw_ostream &OS,
92                                                 StringRef Opcode,
93                                                 int AddOffset) {
94  if (isPreIncrementForm(MI, AddOffset)) {
95    OS << "\t" << Opcode << "\t%" << getRegisterName(MI->getOperand(0).getReg())
96       << ", [" << decIncOperator(MI) << "%"
97       << getRegisterName(MI->getOperand(1).getReg()) << "]";
98    return true;
99  }
100  if (isPostIncrementForm(MI, AddOffset)) {
101    OS << "\t" << Opcode << "\t%" << getRegisterName(MI->getOperand(0).getReg())
102       << ", [%" << getRegisterName(MI->getOperand(1).getReg())
103       << decIncOperator(MI) << "]";
104    return true;
105  }
106  return false;
107}
108
109bool LanaiInstPrinter::printAlias(const MCInst *MI, raw_ostream &OS) {
110  switch (MI->getOpcode()) {
111  case Lanai::LDW_RI:
112    // ld 4[*%rN], %rX => ld [++imm], %rX
113    // ld -4[*%rN], %rX => ld [--imm], %rX
114    // ld 4[%rN*], %rX => ld [imm++], %rX
115    // ld -4[%rN*], %rX => ld [imm--], %rX
116    return printMemoryLoadIncrement(MI, OS, "ld", 4);
117  case Lanai::LDHs_RI:
118    return printMemoryLoadIncrement(MI, OS, "ld.h", 2);
119  case Lanai::LDHz_RI:
120    return printMemoryLoadIncrement(MI, OS, "uld.h", 2);
121  case Lanai::LDBs_RI:
122    return printMemoryLoadIncrement(MI, OS, "ld.b", 1);
123  case Lanai::LDBz_RI:
124    return printMemoryLoadIncrement(MI, OS, "uld.b", 1);
125  case Lanai::SW_RI:
126    // st %rX, 4[*%rN] => st %rX, [++imm]
127    // st %rX, -4[*%rN] => st %rX, [--imm]
128    // st %rX, 4[%rN*] => st %rX, [imm++]
129    // st %rX, -4[%rN*] => st %rX, [imm--]
130    return printMemoryStoreIncrement(MI, OS, "st", 4);
131  case Lanai::STH_RI:
132    return printMemoryStoreIncrement(MI, OS, "st.h", 2);
133  case Lanai::STB_RI:
134    return printMemoryStoreIncrement(MI, OS, "st.b", 1);
135  default:
136    return false;
137  }
138}
139
140void LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
141                                 StringRef Annotation,
142                                 const MCSubtargetInfo & /*STI*/) {
143  if (!printAlias(MI, OS) && !printAliasInstr(MI, OS))
144    printInstruction(MI, OS);
145  printAnnotation(OS, Annotation);
146}
147
148void LanaiInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
149                                    raw_ostream &OS, const char *Modifier) {
150  assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
151  const MCOperand &Op = MI->getOperand(OpNo);
152  if (Op.isReg())
153    OS << "%" << getRegisterName(Op.getReg());
154  else if (Op.isImm())
155    OS << formatHex(Op.getImm());
156  else {
157    assert(Op.isExpr() && "Expected an expression");
158    Op.getExpr()->print(OS, &MAI);
159  }
160}
161
162void LanaiInstPrinter::printMemImmOperand(const MCInst *MI, unsigned OpNo,
163                                          raw_ostream &OS) {
164  const MCOperand &Op = MI->getOperand(OpNo);
165  if (Op.isImm()) {
166    OS << '[' << formatHex(Op.getImm()) << ']';
167  } else {
168    // Symbolic operand will be lowered to immediate value by linker
169    assert(Op.isExpr() && "Expected an expression");
170    OS << '[';
171    Op.getExpr()->print(OS, &MAI);
172    OS << ']';
173  }
174}
175
176void LanaiInstPrinter::printHi16ImmOperand(const MCInst *MI, unsigned OpNo,
177                                           raw_ostream &OS) {
178  const MCOperand &Op = MI->getOperand(OpNo);
179  if (Op.isImm()) {
180    OS << formatHex(Op.getImm() << 16);
181  } else {
182    // Symbolic operand will be lowered to immediate value by linker
183    assert(Op.isExpr() && "Expected an expression");
184    Op.getExpr()->print(OS, &MAI);
185  }
186}
187
188void LanaiInstPrinter::printHi16AndImmOperand(const MCInst *MI, unsigned OpNo,
189                                              raw_ostream &OS) {
190  const MCOperand &Op = MI->getOperand(OpNo);
191  if (Op.isImm()) {
192    OS << formatHex((Op.getImm() << 16) | 0xffff);
193  } else {
194    // Symbolic operand will be lowered to immediate value by linker
195    assert(Op.isExpr() && "Expected an expression");
196    Op.getExpr()->print(OS, &MAI);
197  }
198}
199
200void LanaiInstPrinter::printLo16AndImmOperand(const MCInst *MI, unsigned OpNo,
201                                              raw_ostream &OS) {
202  const MCOperand &Op = MI->getOperand(OpNo);
203  if (Op.isImm()) {
204    OS << formatHex(0xffff0000 | Op.getImm());
205  } else {
206    // Symbolic operand will be lowered to immediate value by linker
207    assert(Op.isExpr() && "Expected an expression");
208    Op.getExpr()->print(OS, &MAI);
209  }
210}
211
212static void printMemoryBaseRegister(raw_ostream &OS, const unsigned AluCode,
213                                    const MCOperand &RegOp) {
214  assert(RegOp.isReg() && "Register operand expected");
215  OS << "[";
216  if (LPAC::isPreOp(AluCode))
217    OS << "*";
218  OS << "%" << LanaiInstPrinter::getRegisterName(RegOp.getReg());
219  if (LPAC::isPostOp(AluCode))
220    OS << "*";
221  OS << "]";
222}
223
224template <unsigned SizeInBits>
225static void printMemoryImmediateOffset(const MCAsmInfo &MAI,
226                                       const MCOperand &OffsetOp,
227                                       raw_ostream &OS) {
228  assert((OffsetOp.isImm() || OffsetOp.isExpr()) && "Immediate expected");
229  if (OffsetOp.isImm()) {
230    assert(isInt<SizeInBits>(OffsetOp.getImm()) && "Constant value truncated");
231    OS << OffsetOp.getImm();
232  } else
233    OffsetOp.getExpr()->print(OS, &MAI);
234}
235
236void LanaiInstPrinter::printMemRiOperand(const MCInst *MI, int OpNo,
237                                         raw_ostream &OS,
238                                         const char * /*Modifier*/) {
239  const MCOperand &RegOp = MI->getOperand(OpNo);
240  const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
241  const MCOperand &AluOp = MI->getOperand(OpNo + 2);
242  const unsigned AluCode = AluOp.getImm();
243
244  // Offset
245  printMemoryImmediateOffset<16>(MAI, OffsetOp, OS);
246
247  // Register
248  printMemoryBaseRegister(OS, AluCode, RegOp);
249}
250
251void LanaiInstPrinter::printMemRrOperand(const MCInst *MI, int OpNo,
252                                         raw_ostream &OS,
253                                         const char * /*Modifier*/) {
254  const MCOperand &RegOp = MI->getOperand(OpNo);
255  const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
256  const MCOperand &AluOp = MI->getOperand(OpNo + 2);
257  const unsigned AluCode = AluOp.getImm();
258  assert(OffsetOp.isReg() && RegOp.isReg() && "Registers expected.");
259
260  // [ Base OP Offset ]
261  OS << "[";
262  if (LPAC::isPreOp(AluCode))
263    OS << "*";
264  OS << "%" << getRegisterName(RegOp.getReg());
265  if (LPAC::isPostOp(AluCode))
266    OS << "*";
267  OS << " " << LPAC::lanaiAluCodeToString(AluCode) << " ";
268  OS << "%" << getRegisterName(OffsetOp.getReg());
269  OS << "]";
270}
271
272void LanaiInstPrinter::printMemSplsOperand(const MCInst *MI, int OpNo,
273                                           raw_ostream &OS,
274                                           const char * /*Modifier*/) {
275  const MCOperand &RegOp = MI->getOperand(OpNo);
276  const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
277  const MCOperand &AluOp = MI->getOperand(OpNo + 2);
278  const unsigned AluCode = AluOp.getImm();
279
280  // Offset
281  printMemoryImmediateOffset<10>(MAI, OffsetOp, OS);
282
283  // Register
284  printMemoryBaseRegister(OS, AluCode, RegOp);
285}
286
287void LanaiInstPrinter::printCCOperand(const MCInst *MI, int OpNo,
288                                      raw_ostream &OS) {
289  LPCC::CondCode CC =
290      static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm());
291  // Handle the undefined value here for printing so we don't abort().
292  if (CC >= LPCC::UNKNOWN)
293    OS << "<und>";
294  else
295    OS << lanaiCondCodeToString(CC);
296}
297
298void LanaiInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
299                                             raw_ostream &OS) {
300  LPCC::CondCode CC =
301      static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm());
302  // Handle the undefined value here for printing so we don't abort().
303  if (CC >= LPCC::UNKNOWN)
304    OS << "<und>";
305  else if (CC != LPCC::ICC_T)
306    OS << "." << lanaiCondCodeToString(CC);
307}
308