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