1351278Sdim//===-- LanaiInstPrinter.cpp - Convert Lanai MCInst to asm syntax ---------===//
2351278Sdim//
3351278Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4351278Sdim// See https://llvm.org/LICENSE.txt for license information.
5351278Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6351278Sdim//
7351278Sdim//===----------------------------------------------------------------------===//
8351278Sdim//
9351278Sdim// This class prints an Lanai MCInst to a .s file.
10351278Sdim//
11351278Sdim//===----------------------------------------------------------------------===//
12351278Sdim
13351278Sdim#include "LanaiInstPrinter.h"
14351278Sdim#include "LanaiMCExpr.h"
15351278Sdim#include "LanaiAluCode.h"
16351278Sdim#include "LanaiCondCode.h"
17351278Sdim#include "MCTargetDesc/LanaiMCTargetDesc.h"
18351278Sdim#include "llvm/MC/MCAsmInfo.h"
19351278Sdim#include "llvm/MC/MCExpr.h"
20351278Sdim#include "llvm/MC/MCInst.h"
21351278Sdim#include "llvm/MC/MCRegisterInfo.h"
22351278Sdim#include "llvm/MC/MCSymbol.h"
23351278Sdim#include "llvm/Support/ErrorHandling.h"
24351278Sdim#include "llvm/Support/FormattedStream.h"
25351278Sdim
26351278Sdimusing namespace llvm;
27351278Sdim
28351278Sdim#define DEBUG_TYPE "asm-printer"
29351278Sdim
30351278Sdim// Include the auto-generated portion of the assembly writer.
31351278Sdim#define PRINT_ALIAS_INSTR
32351278Sdim#include "LanaiGenAsmWriter.inc"
33351278Sdim
34351278Sdimvoid LanaiInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
35351278Sdim  OS << StringRef(getRegisterName(RegNo)).lower();
36351278Sdim}
37351278Sdim
38351278Sdimbool LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
39351278Sdim                                 StringRef Alias, unsigned OpNo0,
40351278Sdim                                 unsigned OpNo1) {
41351278Sdim  OS << "\t" << Alias << " ";
42351278Sdim  printOperand(MI, OpNo0, OS);
43351278Sdim  OS << ", ";
44351278Sdim  printOperand(MI, OpNo1, OS);
45351278Sdim  return true;
46351278Sdim}
47351278Sdim
48351278Sdimstatic bool usesGivenOffset(const MCInst *MI, int AddOffset) {
49351278Sdim  unsigned AluCode = MI->getOperand(3).getImm();
50351278Sdim  return LPAC::encodeLanaiAluCode(AluCode) == LPAC::ADD &&
51351278Sdim         (MI->getOperand(2).getImm() == AddOffset ||
52351278Sdim          MI->getOperand(2).getImm() == -AddOffset);
53351278Sdim}
54351278Sdim
55351278Sdimstatic bool isPreIncrementForm(const MCInst *MI, int AddOffset) {
56351278Sdim  unsigned AluCode = MI->getOperand(3).getImm();
57351278Sdim  return LPAC::isPreOp(AluCode) && usesGivenOffset(MI, AddOffset);
58351278Sdim}
59351278Sdim
60351278Sdimstatic bool isPostIncrementForm(const MCInst *MI, int AddOffset) {
61351278Sdim  unsigned AluCode = MI->getOperand(3).getImm();
62351278Sdim  return LPAC::isPostOp(AluCode) && usesGivenOffset(MI, AddOffset);
63351278Sdim}
64351278Sdim
65351278Sdimstatic StringRef decIncOperator(const MCInst *MI) {
66351278Sdim  if (MI->getOperand(2).getImm() < 0)
67351278Sdim    return "--";
68351278Sdim  return "++";
69351278Sdim}
70351278Sdim
71351278Sdimbool LanaiInstPrinter::printMemoryLoadIncrement(const MCInst *MI,
72351278Sdim                                                raw_ostream &OS,
73351278Sdim                                                StringRef Opcode,
74351278Sdim                                                int AddOffset) {
75351278Sdim  if (isPreIncrementForm(MI, AddOffset)) {
76351278Sdim    OS << "\t" << Opcode << "\t[" << decIncOperator(MI) << "%"
77351278Sdim       << getRegisterName(MI->getOperand(1).getReg()) << "], %"
78351278Sdim       << getRegisterName(MI->getOperand(0).getReg());
79351278Sdim    return true;
80351278Sdim  }
81351278Sdim  if (isPostIncrementForm(MI, AddOffset)) {
82351278Sdim    OS << "\t" << Opcode << "\t[%"
83351278Sdim       << getRegisterName(MI->getOperand(1).getReg()) << decIncOperator(MI)
84351278Sdim       << "], %" << getRegisterName(MI->getOperand(0).getReg());
85351278Sdim    return true;
86351278Sdim  }
87351278Sdim  return false;
88351278Sdim}
89351278Sdim
90351278Sdimbool LanaiInstPrinter::printMemoryStoreIncrement(const MCInst *MI,
91351278Sdim                                                 raw_ostream &OS,
92351278Sdim                                                 StringRef Opcode,
93351278Sdim                                                 int AddOffset) {
94351278Sdim  if (isPreIncrementForm(MI, AddOffset)) {
95351278Sdim    OS << "\t" << Opcode << "\t%" << getRegisterName(MI->getOperand(0).getReg())
96351278Sdim       << ", [" << decIncOperator(MI) << "%"
97351278Sdim       << getRegisterName(MI->getOperand(1).getReg()) << "]";
98351278Sdim    return true;
99351278Sdim  }
100351278Sdim  if (isPostIncrementForm(MI, AddOffset)) {
101351278Sdim    OS << "\t" << Opcode << "\t%" << getRegisterName(MI->getOperand(0).getReg())
102351278Sdim       << ", [%" << getRegisterName(MI->getOperand(1).getReg())
103351278Sdim       << decIncOperator(MI) << "]";
104351278Sdim    return true;
105351278Sdim  }
106351278Sdim  return false;
107351278Sdim}
108351278Sdim
109351278Sdimbool LanaiInstPrinter::printAlias(const MCInst *MI, raw_ostream &OS) {
110351278Sdim  switch (MI->getOpcode()) {
111351278Sdim  case Lanai::LDW_RI:
112351278Sdim    // ld 4[*%rN], %rX => ld [++imm], %rX
113351278Sdim    // ld -4[*%rN], %rX => ld [--imm], %rX
114351278Sdim    // ld 4[%rN*], %rX => ld [imm++], %rX
115351278Sdim    // ld -4[%rN*], %rX => ld [imm--], %rX
116351278Sdim    return printMemoryLoadIncrement(MI, OS, "ld", 4);
117351278Sdim  case Lanai::LDHs_RI:
118351278Sdim    return printMemoryLoadIncrement(MI, OS, "ld.h", 2);
119351278Sdim  case Lanai::LDHz_RI:
120351278Sdim    return printMemoryLoadIncrement(MI, OS, "uld.h", 2);
121351278Sdim  case Lanai::LDBs_RI:
122351278Sdim    return printMemoryLoadIncrement(MI, OS, "ld.b", 1);
123351278Sdim  case Lanai::LDBz_RI:
124351278Sdim    return printMemoryLoadIncrement(MI, OS, "uld.b", 1);
125351278Sdim  case Lanai::SW_RI:
126351278Sdim    // st %rX, 4[*%rN] => st %rX, [++imm]
127351278Sdim    // st %rX, -4[*%rN] => st %rX, [--imm]
128351278Sdim    // st %rX, 4[%rN*] => st %rX, [imm++]
129351278Sdim    // st %rX, -4[%rN*] => st %rX, [imm--]
130351278Sdim    return printMemoryStoreIncrement(MI, OS, "st", 4);
131351278Sdim  case Lanai::STH_RI:
132351278Sdim    return printMemoryStoreIncrement(MI, OS, "st.h", 2);
133351278Sdim  case Lanai::STB_RI:
134351278Sdim    return printMemoryStoreIncrement(MI, OS, "st.b", 1);
135351278Sdim  default:
136351278Sdim    return false;
137351278Sdim  }
138351278Sdim}
139351278Sdim
140360784Sdimvoid LanaiInstPrinter::printInst(const MCInst *MI, uint64_t Address,
141351278Sdim                                 StringRef Annotation,
142360784Sdim                                 const MCSubtargetInfo & /*STI*/,
143360784Sdim                                 raw_ostream &OS) {
144351278Sdim  if (!printAlias(MI, OS) && !printAliasInstr(MI, OS))
145360784Sdim    printInstruction(MI, Address, OS);
146351278Sdim  printAnnotation(OS, Annotation);
147351278Sdim}
148351278Sdim
149351278Sdimvoid LanaiInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
150351278Sdim                                    raw_ostream &OS, const char *Modifier) {
151351278Sdim  assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
152351278Sdim  const MCOperand &Op = MI->getOperand(OpNo);
153351278Sdim  if (Op.isReg())
154351278Sdim    OS << "%" << getRegisterName(Op.getReg());
155351278Sdim  else if (Op.isImm())
156351278Sdim    OS << formatHex(Op.getImm());
157351278Sdim  else {
158351278Sdim    assert(Op.isExpr() && "Expected an expression");
159351278Sdim    Op.getExpr()->print(OS, &MAI);
160351278Sdim  }
161351278Sdim}
162351278Sdim
163351278Sdimvoid LanaiInstPrinter::printMemImmOperand(const MCInst *MI, unsigned OpNo,
164351278Sdim                                          raw_ostream &OS) {
165351278Sdim  const MCOperand &Op = MI->getOperand(OpNo);
166351278Sdim  if (Op.isImm()) {
167351278Sdim    OS << '[' << formatHex(Op.getImm()) << ']';
168351278Sdim  } else {
169351278Sdim    // Symbolic operand will be lowered to immediate value by linker
170351278Sdim    assert(Op.isExpr() && "Expected an expression");
171351278Sdim    OS << '[';
172351278Sdim    Op.getExpr()->print(OS, &MAI);
173351278Sdim    OS << ']';
174351278Sdim  }
175351278Sdim}
176351278Sdim
177351278Sdimvoid LanaiInstPrinter::printHi16ImmOperand(const MCInst *MI, unsigned OpNo,
178351278Sdim                                           raw_ostream &OS) {
179351278Sdim  const MCOperand &Op = MI->getOperand(OpNo);
180351278Sdim  if (Op.isImm()) {
181351278Sdim    OS << formatHex(Op.getImm() << 16);
182351278Sdim  } else {
183351278Sdim    // Symbolic operand will be lowered to immediate value by linker
184351278Sdim    assert(Op.isExpr() && "Expected an expression");
185351278Sdim    Op.getExpr()->print(OS, &MAI);
186351278Sdim  }
187351278Sdim}
188351278Sdim
189351278Sdimvoid LanaiInstPrinter::printHi16AndImmOperand(const MCInst *MI, unsigned OpNo,
190351278Sdim                                              raw_ostream &OS) {
191351278Sdim  const MCOperand &Op = MI->getOperand(OpNo);
192351278Sdim  if (Op.isImm()) {
193351278Sdim    OS << formatHex((Op.getImm() << 16) | 0xffff);
194351278Sdim  } else {
195351278Sdim    // Symbolic operand will be lowered to immediate value by linker
196351278Sdim    assert(Op.isExpr() && "Expected an expression");
197351278Sdim    Op.getExpr()->print(OS, &MAI);
198351278Sdim  }
199351278Sdim}
200351278Sdim
201351278Sdimvoid LanaiInstPrinter::printLo16AndImmOperand(const MCInst *MI, unsigned OpNo,
202351278Sdim                                              raw_ostream &OS) {
203351278Sdim  const MCOperand &Op = MI->getOperand(OpNo);
204351278Sdim  if (Op.isImm()) {
205351278Sdim    OS << formatHex(0xffff0000 | Op.getImm());
206351278Sdim  } else {
207351278Sdim    // Symbolic operand will be lowered to immediate value by linker
208351278Sdim    assert(Op.isExpr() && "Expected an expression");
209351278Sdim    Op.getExpr()->print(OS, &MAI);
210351278Sdim  }
211351278Sdim}
212351278Sdim
213351278Sdimstatic void printMemoryBaseRegister(raw_ostream &OS, const unsigned AluCode,
214351278Sdim                                    const MCOperand &RegOp) {
215351278Sdim  assert(RegOp.isReg() && "Register operand expected");
216351278Sdim  OS << "[";
217351278Sdim  if (LPAC::isPreOp(AluCode))
218351278Sdim    OS << "*";
219351278Sdim  OS << "%" << LanaiInstPrinter::getRegisterName(RegOp.getReg());
220351278Sdim  if (LPAC::isPostOp(AluCode))
221351278Sdim    OS << "*";
222351278Sdim  OS << "]";
223351278Sdim}
224351278Sdim
225351278Sdimtemplate <unsigned SizeInBits>
226351278Sdimstatic void printMemoryImmediateOffset(const MCAsmInfo &MAI,
227351278Sdim                                       const MCOperand &OffsetOp,
228351278Sdim                                       raw_ostream &OS) {
229351278Sdim  assert((OffsetOp.isImm() || OffsetOp.isExpr()) && "Immediate expected");
230351278Sdim  if (OffsetOp.isImm()) {
231351278Sdim    assert(isInt<SizeInBits>(OffsetOp.getImm()) && "Constant value truncated");
232351278Sdim    OS << OffsetOp.getImm();
233351278Sdim  } else
234351278Sdim    OffsetOp.getExpr()->print(OS, &MAI);
235351278Sdim}
236351278Sdim
237351278Sdimvoid LanaiInstPrinter::printMemRiOperand(const MCInst *MI, int OpNo,
238351278Sdim                                         raw_ostream &OS,
239351278Sdim                                         const char * /*Modifier*/) {
240351278Sdim  const MCOperand &RegOp = MI->getOperand(OpNo);
241351278Sdim  const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
242351278Sdim  const MCOperand &AluOp = MI->getOperand(OpNo + 2);
243351278Sdim  const unsigned AluCode = AluOp.getImm();
244351278Sdim
245351278Sdim  // Offset
246351278Sdim  printMemoryImmediateOffset<16>(MAI, OffsetOp, OS);
247351278Sdim
248351278Sdim  // Register
249351278Sdim  printMemoryBaseRegister(OS, AluCode, RegOp);
250351278Sdim}
251351278Sdim
252351278Sdimvoid LanaiInstPrinter::printMemRrOperand(const MCInst *MI, int OpNo,
253351278Sdim                                         raw_ostream &OS,
254351278Sdim                                         const char * /*Modifier*/) {
255351278Sdim  const MCOperand &RegOp = MI->getOperand(OpNo);
256351278Sdim  const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
257351278Sdim  const MCOperand &AluOp = MI->getOperand(OpNo + 2);
258351278Sdim  const unsigned AluCode = AluOp.getImm();
259351278Sdim  assert(OffsetOp.isReg() && RegOp.isReg() && "Registers expected.");
260351278Sdim
261351278Sdim  // [ Base OP Offset ]
262351278Sdim  OS << "[";
263351278Sdim  if (LPAC::isPreOp(AluCode))
264351278Sdim    OS << "*";
265351278Sdim  OS << "%" << getRegisterName(RegOp.getReg());
266351278Sdim  if (LPAC::isPostOp(AluCode))
267351278Sdim    OS << "*";
268351278Sdim  OS << " " << LPAC::lanaiAluCodeToString(AluCode) << " ";
269351278Sdim  OS << "%" << getRegisterName(OffsetOp.getReg());
270351278Sdim  OS << "]";
271351278Sdim}
272351278Sdim
273351278Sdimvoid LanaiInstPrinter::printMemSplsOperand(const MCInst *MI, int OpNo,
274351278Sdim                                           raw_ostream &OS,
275351278Sdim                                           const char * /*Modifier*/) {
276351278Sdim  const MCOperand &RegOp = MI->getOperand(OpNo);
277351278Sdim  const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
278351278Sdim  const MCOperand &AluOp = MI->getOperand(OpNo + 2);
279351278Sdim  const unsigned AluCode = AluOp.getImm();
280351278Sdim
281351278Sdim  // Offset
282351278Sdim  printMemoryImmediateOffset<10>(MAI, OffsetOp, OS);
283351278Sdim
284351278Sdim  // Register
285351278Sdim  printMemoryBaseRegister(OS, AluCode, RegOp);
286351278Sdim}
287351278Sdim
288351278Sdimvoid LanaiInstPrinter::printCCOperand(const MCInst *MI, int OpNo,
289351278Sdim                                      raw_ostream &OS) {
290351278Sdim  LPCC::CondCode CC =
291351278Sdim      static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm());
292351278Sdim  // Handle the undefined value here for printing so we don't abort().
293351278Sdim  if (CC >= LPCC::UNKNOWN)
294351278Sdim    OS << "<und>";
295351278Sdim  else
296351278Sdim    OS << lanaiCondCodeToString(CC);
297351278Sdim}
298351278Sdim
299351278Sdimvoid LanaiInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
300351278Sdim                                             raw_ostream &OS) {
301351278Sdim  LPCC::CondCode CC =
302351278Sdim      static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm());
303351278Sdim  // Handle the undefined value here for printing so we don't abort().
304351278Sdim  if (CC >= LPCC::UNKNOWN)
305351278Sdim    OS << "<und>";
306351278Sdim  else if (CC != LPCC::ICC_T)
307351278Sdim    OS << "." << lanaiCondCodeToString(CC);
308351278Sdim}
309