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