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