1 | //===-- ARMInstPrinter.cpp - Convert ARM MCInst to assembly 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 ARM MCInst to a .s file. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "ARMInstPrinter.h" |
14 | #include "MCTargetDesc/ARMAddressingModes.h" |
15 | #include "MCTargetDesc/ARMBaseInfo.h" |
16 | #include "Utils/ARMBaseInfo.h" |
17 | #include "llvm/MC/MCAsmInfo.h" |
18 | #include "llvm/MC/MCExpr.h" |
19 | #include "llvm/MC/MCInst.h" |
20 | #include "llvm/MC/MCInstrAnalysis.h" |
21 | #include "llvm/MC/MCInstrInfo.h" |
22 | #include "llvm/MC/MCRegisterInfo.h" |
23 | #include "llvm/MC/MCSubtargetInfo.h" |
24 | #include "llvm/Support/Casting.h" |
25 | #include "llvm/Support/ErrorHandling.h" |
26 | #include "llvm/Support/raw_ostream.h" |
27 | #include "llvm/TargetParser/SubtargetFeature.h" |
28 | #include <cassert> |
29 | #include <cstdint> |
30 | |
31 | using namespace llvm; |
32 | |
33 | #define DEBUG_TYPE "asm-printer" |
34 | |
35 | #define PRINT_ALIAS_INSTR |
36 | #include "ARMGenAsmWriter.inc" |
37 | |
38 | /// translateShiftImm - Convert shift immediate from 0-31 to 1-32 for printing. |
39 | /// |
40 | /// getSORegOffset returns an integer from 0-31, representing '32' as 0. |
41 | static unsigned translateShiftImm(unsigned imm) { |
42 | // lsr #32 and asr #32 exist, but should be encoded as a 0. |
43 | assert((imm & ~0x1f) == 0 && "Invalid shift encoding" ); |
44 | |
45 | if (imm == 0) |
46 | return 32; |
47 | return imm; |
48 | } |
49 | |
50 | static void printRegImmShift(raw_ostream &O, ARM_AM::ShiftOpc ShOpc, |
51 | unsigned ShImm, ARMInstPrinter &printer) { |
52 | if (ShOpc == ARM_AM::no_shift || (ShOpc == ARM_AM::lsl && !ShImm)) |
53 | return; |
54 | O << ", " ; |
55 | |
56 | assert(!(ShOpc == ARM_AM::ror && !ShImm) && "Cannot have ror #0" ); |
57 | O << getShiftOpcStr(Op: ShOpc); |
58 | |
59 | if (ShOpc != ARM_AM::rrx) { |
60 | O << " " ; |
61 | printer.markup(OS&: O, M: llvm::MCInstPrinter::Markup::Immediate) |
62 | << "#" << translateShiftImm(imm: ShImm); |
63 | } |
64 | } |
65 | |
66 | ARMInstPrinter::ARMInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, |
67 | const MCRegisterInfo &MRI) |
68 | : MCInstPrinter(MAI, MII, MRI) {} |
69 | |
70 | bool ARMInstPrinter::applyTargetSpecificCLOption(StringRef Opt) { |
71 | if (Opt == "reg-names-std" ) { |
72 | DefaultAltIdx = ARM::NoRegAltName; |
73 | return true; |
74 | } |
75 | if (Opt == "reg-names-raw" ) { |
76 | DefaultAltIdx = ARM::RegNamesRaw; |
77 | return true; |
78 | } |
79 | return false; |
80 | } |
81 | |
82 | void ARMInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) { |
83 | markup(OS, M: Markup::Register) << getRegisterName(Reg, AltIdx: DefaultAltIdx); |
84 | } |
85 | |
86 | void ARMInstPrinter::printInst(const MCInst *MI, uint64_t Address, |
87 | StringRef Annot, const MCSubtargetInfo &STI, |
88 | raw_ostream &O) { |
89 | unsigned Opcode = MI->getOpcode(); |
90 | |
91 | switch (Opcode) { |
92 | case ARM::VLLDM: { |
93 | const MCOperand &Reg = MI->getOperand(i: 0); |
94 | O << '\t' << "vlldm" << '\t'; |
95 | printRegName(OS&: O, Reg: Reg.getReg()); |
96 | O << ", " |
97 | << "{d0 - d15}" ; |
98 | return; |
99 | } |
100 | case ARM::VLLDM_T2: { |
101 | const MCOperand &Reg = MI->getOperand(i: 0); |
102 | O << '\t' << "vlldm" << '\t'; |
103 | printRegName(OS&: O, Reg: Reg.getReg()); |
104 | O << ", " |
105 | << "{d0 - d31}" ; |
106 | return; |
107 | } |
108 | case ARM::VLSTM: { |
109 | const MCOperand &Reg = MI->getOperand(i: 0); |
110 | O << '\t' << "vlstm" << '\t'; |
111 | printRegName(OS&: O, Reg: Reg.getReg()); |
112 | O << ", " |
113 | << "{d0 - d15}" ; |
114 | return; |
115 | } |
116 | case ARM::VLSTM_T2: { |
117 | const MCOperand &Reg = MI->getOperand(i: 0); |
118 | O << '\t' << "vlstm" << '\t'; |
119 | printRegName(OS&: O, Reg: Reg.getReg()); |
120 | O << ", " |
121 | << "{d0 - d31}" ; |
122 | return; |
123 | } |
124 | // Check for MOVs and print canonical forms, instead. |
125 | case ARM::MOVsr: { |
126 | // FIXME: Thumb variants? |
127 | const MCOperand &Dst = MI->getOperand(i: 0); |
128 | const MCOperand &MO1 = MI->getOperand(i: 1); |
129 | const MCOperand &MO2 = MI->getOperand(i: 2); |
130 | const MCOperand &MO3 = MI->getOperand(i: 3); |
131 | |
132 | O << '\t' << ARM_AM::getShiftOpcStr(Op: ARM_AM::getSORegShOp(Op: MO3.getImm())); |
133 | printSBitModifierOperand(MI, OpNum: 6, STI, O); |
134 | printPredicateOperand(MI, OpNum: 4, STI, O); |
135 | |
136 | O << '\t'; |
137 | printRegName(OS&: O, Reg: Dst.getReg()); |
138 | O << ", " ; |
139 | printRegName(OS&: O, Reg: MO1.getReg()); |
140 | |
141 | O << ", " ; |
142 | printRegName(OS&: O, Reg: MO2.getReg()); |
143 | assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); |
144 | printAnnotation(OS&: O, Annot); |
145 | return; |
146 | } |
147 | |
148 | case ARM::MOVsi: { |
149 | // FIXME: Thumb variants? |
150 | const MCOperand &Dst = MI->getOperand(i: 0); |
151 | const MCOperand &MO1 = MI->getOperand(i: 1); |
152 | const MCOperand &MO2 = MI->getOperand(i: 2); |
153 | |
154 | O << '\t' << ARM_AM::getShiftOpcStr(Op: ARM_AM::getSORegShOp(Op: MO2.getImm())); |
155 | printSBitModifierOperand(MI, OpNum: 5, STI, O); |
156 | printPredicateOperand(MI, OpNum: 3, STI, O); |
157 | |
158 | O << '\t'; |
159 | printRegName(OS&: O, Reg: Dst.getReg()); |
160 | O << ", " ; |
161 | printRegName(OS&: O, Reg: MO1.getReg()); |
162 | |
163 | if (ARM_AM::getSORegShOp(Op: MO2.getImm()) == ARM_AM::rrx) { |
164 | printAnnotation(OS&: O, Annot); |
165 | return; |
166 | } |
167 | |
168 | O << ", " ; |
169 | markup(OS&: O, M: Markup::Immediate) |
170 | << "#" << translateShiftImm(imm: ARM_AM::getSORegOffset(Op: MO2.getImm())); |
171 | printAnnotation(OS&: O, Annot); |
172 | return; |
173 | } |
174 | |
175 | // A8.6.123 PUSH |
176 | case ARM::STMDB_UPD: |
177 | case ARM::t2STMDB_UPD: |
178 | if (MI->getOperand(i: 0).getReg() == ARM::SP && MI->getNumOperands() > 5) { |
179 | // Should only print PUSH if there are at least two registers in the list. |
180 | O << '\t' << "push" ; |
181 | printPredicateOperand(MI, OpNum: 2, STI, O); |
182 | if (Opcode == ARM::t2STMDB_UPD) |
183 | O << ".w" ; |
184 | O << '\t'; |
185 | printRegisterList(MI, OpNum: 4, STI, O); |
186 | printAnnotation(OS&: O, Annot); |
187 | return; |
188 | } else |
189 | break; |
190 | |
191 | case ARM::STR_PRE_IMM: |
192 | if (MI->getOperand(i: 2).getReg() == ARM::SP && |
193 | MI->getOperand(i: 3).getImm() == -4) { |
194 | O << '\t' << "push" ; |
195 | printPredicateOperand(MI, OpNum: 4, STI, O); |
196 | O << "\t{" ; |
197 | printRegName(OS&: O, Reg: MI->getOperand(i: 1).getReg()); |
198 | O << "}" ; |
199 | printAnnotation(OS&: O, Annot); |
200 | return; |
201 | } else |
202 | break; |
203 | |
204 | // A8.6.122 POP |
205 | case ARM::LDMIA_UPD: |
206 | case ARM::t2LDMIA_UPD: |
207 | if (MI->getOperand(i: 0).getReg() == ARM::SP && MI->getNumOperands() > 5) { |
208 | // Should only print POP if there are at least two registers in the list. |
209 | O << '\t' << "pop" ; |
210 | printPredicateOperand(MI, OpNum: 2, STI, O); |
211 | if (Opcode == ARM::t2LDMIA_UPD) |
212 | O << ".w" ; |
213 | O << '\t'; |
214 | printRegisterList(MI, OpNum: 4, STI, O); |
215 | printAnnotation(OS&: O, Annot); |
216 | return; |
217 | } else |
218 | break; |
219 | |
220 | case ARM::LDR_POST_IMM: |
221 | if (MI->getOperand(i: 2).getReg() == ARM::SP && |
222 | MI->getOperand(i: 4).getImm() == 4) { |
223 | O << '\t' << "pop" ; |
224 | printPredicateOperand(MI, OpNum: 5, STI, O); |
225 | O << "\t{" ; |
226 | printRegName(OS&: O, Reg: MI->getOperand(i: 0).getReg()); |
227 | O << "}" ; |
228 | printAnnotation(OS&: O, Annot); |
229 | return; |
230 | } else |
231 | break; |
232 | |
233 | // A8.6.355 VPUSH |
234 | case ARM::VSTMSDB_UPD: |
235 | case ARM::VSTMDDB_UPD: |
236 | if (MI->getOperand(i: 0).getReg() == ARM::SP) { |
237 | O << '\t' << "vpush" ; |
238 | printPredicateOperand(MI, OpNum: 2, STI, O); |
239 | O << '\t'; |
240 | printRegisterList(MI, OpNum: 4, STI, O); |
241 | printAnnotation(OS&: O, Annot); |
242 | return; |
243 | } else |
244 | break; |
245 | |
246 | // A8.6.354 VPOP |
247 | case ARM::VLDMSIA_UPD: |
248 | case ARM::VLDMDIA_UPD: |
249 | if (MI->getOperand(i: 0).getReg() == ARM::SP) { |
250 | O << '\t' << "vpop" ; |
251 | printPredicateOperand(MI, OpNum: 2, STI, O); |
252 | O << '\t'; |
253 | printRegisterList(MI, OpNum: 4, STI, O); |
254 | printAnnotation(OS&: O, Annot); |
255 | return; |
256 | } else |
257 | break; |
258 | |
259 | case ARM::tLDMIA: { |
260 | bool Writeback = true; |
261 | MCRegister BaseReg = MI->getOperand(i: 0).getReg(); |
262 | for (unsigned i = 3; i < MI->getNumOperands(); ++i) { |
263 | if (MI->getOperand(i).getReg() == BaseReg) |
264 | Writeback = false; |
265 | } |
266 | |
267 | O << "\tldm" ; |
268 | |
269 | printPredicateOperand(MI, OpNum: 1, STI, O); |
270 | O << '\t'; |
271 | printRegName(OS&: O, Reg: BaseReg); |
272 | if (Writeback) |
273 | O << "!" ; |
274 | O << ", " ; |
275 | printRegisterList(MI, OpNum: 3, STI, O); |
276 | printAnnotation(OS&: O, Annot); |
277 | return; |
278 | } |
279 | |
280 | // Combine 2 GPRs from disassember into a GPRPair to match with instr def. |
281 | // ldrexd/strexd require even/odd GPR pair. To enforce this constraint, |
282 | // a single GPRPair reg operand is used in the .td file to replace the two |
283 | // GPRs. However, when decoding them, the two GRPs cannot be automatically |
284 | // expressed as a GPRPair, so we have to manually merge them. |
285 | // FIXME: We would really like to be able to tablegen'erate this. |
286 | case ARM::LDREXD: |
287 | case ARM::STREXD: |
288 | case ARM::LDAEXD: |
289 | case ARM::STLEXD: { |
290 | const MCRegisterClass &MRC = MRI.getRegClass(i: ARM::GPRRegClassID); |
291 | bool isStore = Opcode == ARM::STREXD || Opcode == ARM::STLEXD; |
292 | MCRegister Reg = MI->getOperand(i: isStore ? 1 : 0).getReg(); |
293 | if (MRC.contains(Reg)) { |
294 | MCInst NewMI; |
295 | MCOperand NewReg; |
296 | NewMI.setOpcode(Opcode); |
297 | |
298 | if (isStore) |
299 | NewMI.addOperand(Op: MI->getOperand(i: 0)); |
300 | NewReg = MCOperand::createReg(Reg: MRI.getMatchingSuperReg( |
301 | Reg, SubIdx: ARM::gsub_0, RC: &MRI.getRegClass(i: ARM::GPRPairRegClassID))); |
302 | NewMI.addOperand(Op: NewReg); |
303 | |
304 | // Copy the rest operands into NewMI. |
305 | for (unsigned i = isStore ? 3 : 2; i < MI->getNumOperands(); ++i) |
306 | NewMI.addOperand(Op: MI->getOperand(i)); |
307 | printInstruction(MI: &NewMI, Address, STI, O); |
308 | return; |
309 | } |
310 | break; |
311 | } |
312 | case ARM::TSB: |
313 | case ARM::t2TSB: |
314 | O << "\ttsb\tcsync" ; |
315 | return; |
316 | case ARM::t2DSB: |
317 | switch (MI->getOperand(i: 0).getImm()) { |
318 | default: |
319 | if (!printAliasInstr(MI, Address, STI, OS&: O)) |
320 | printInstruction(MI, Address, STI, O); |
321 | break; |
322 | case 0: |
323 | O << "\tssbb" ; |
324 | break; |
325 | case 4: |
326 | O << "\tpssbb" ; |
327 | break; |
328 | } |
329 | printAnnotation(OS&: O, Annot); |
330 | return; |
331 | } |
332 | |
333 | if (!printAliasInstr(MI, Address, STI, OS&: O)) |
334 | printInstruction(MI, Address, STI, O); |
335 | |
336 | printAnnotation(OS&: O, Annot); |
337 | } |
338 | |
339 | void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, |
340 | const MCSubtargetInfo &STI, raw_ostream &O) { |
341 | const MCOperand &Op = MI->getOperand(i: OpNo); |
342 | if (Op.isReg()) { |
343 | MCRegister Reg = Op.getReg(); |
344 | printRegName(OS&: O, Reg); |
345 | } else if (Op.isImm()) { |
346 | markup(OS&: O, M: Markup::Immediate) << '#' << formatImm(Value: Op.getImm()); |
347 | } else { |
348 | assert(Op.isExpr() && "unknown operand kind in printOperand" ); |
349 | const MCExpr *Expr = Op.getExpr(); |
350 | switch (Expr->getKind()) { |
351 | case MCExpr::Binary: |
352 | O << '#'; |
353 | MAI.printExpr(O, *Expr); |
354 | break; |
355 | case MCExpr::Constant: { |
356 | // If a symbolic branch target was added as a constant expression then |
357 | // print that address in hex. And only print 32 unsigned bits for the |
358 | // address. |
359 | const MCConstantExpr *Constant = cast<MCConstantExpr>(Val: Expr); |
360 | int64_t TargetAddress; |
361 | if (!Constant->evaluateAsAbsolute(Res&: TargetAddress)) { |
362 | O << '#'; |
363 | MAI.printExpr(O, *Expr); |
364 | } else { |
365 | O << "0x" ; |
366 | O.write_hex(N: static_cast<uint32_t>(TargetAddress)); |
367 | } |
368 | break; |
369 | } |
370 | default: |
371 | // FIXME: Should we always treat this as if it is a constant literal and |
372 | // prefix it with '#'? |
373 | MAI.printExpr(O, *Expr); |
374 | break; |
375 | } |
376 | } |
377 | } |
378 | |
379 | void ARMInstPrinter::printOperand(const MCInst *MI, uint64_t Address, |
380 | unsigned OpNum, const MCSubtargetInfo &STI, |
381 | raw_ostream &O) { |
382 | const MCOperand &Op = MI->getOperand(i: OpNum); |
383 | if (!Op.isImm() || !PrintBranchImmAsAddress || getUseMarkup()) |
384 | return printOperand(MI, OpNo: OpNum, STI, O); |
385 | uint64_t Target = ARM_MC::evaluateBranchTarget(InstDesc: MII.get(Opcode: MI->getOpcode()), |
386 | Addr: Address, Imm: Op.getImm()); |
387 | Target &= 0xffffffff; |
388 | O << formatHex(Value: Target); |
389 | if (CommentStream) |
390 | *CommentStream << "imm = #" << formatImm(Value: Op.getImm()) << '\n'; |
391 | } |
392 | |
393 | void ARMInstPrinter::printThumbLdrLabelOperand(const MCInst *MI, unsigned OpNum, |
394 | const MCSubtargetInfo &STI, |
395 | raw_ostream &O) { |
396 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
397 | if (MO1.isExpr()) { |
398 | MAI.printExpr(O, *MO1.getExpr()); |
399 | return; |
400 | } |
401 | |
402 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
403 | O << "[pc, " ; |
404 | |
405 | int32_t OffImm = (int32_t)MO1.getImm(); |
406 | bool isSub = OffImm < 0; |
407 | |
408 | // Special value for #-0. All others are normal. |
409 | if (OffImm == INT32_MIN) |
410 | OffImm = 0; |
411 | if (isSub) { |
412 | markup(OS&: O, M: Markup::Immediate) << "#-" << formatImm(Value: -OffImm); |
413 | } else { |
414 | markup(OS&: O, M: Markup::Immediate) << "#" << formatImm(Value: OffImm); |
415 | } |
416 | O << "]" ; |
417 | } |
418 | |
419 | // so_reg is a 4-operand unit corresponding to register forms of the A5.1 |
420 | // "Addressing Mode 1 - Data-processing operands" forms. This includes: |
421 | // REG 0 0 - e.g. R5 |
422 | // REG REG 0,SH_OPC - e.g. R5, ROR R3 |
423 | // REG 0 IMM,SH_OPC - e.g. R5, LSL #3 |
424 | void ARMInstPrinter::printSORegRegOperand(const MCInst *MI, unsigned OpNum, |
425 | const MCSubtargetInfo &STI, |
426 | raw_ostream &O) { |
427 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
428 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
429 | const MCOperand &MO3 = MI->getOperand(i: OpNum + 2); |
430 | |
431 | printRegName(OS&: O, Reg: MO1.getReg()); |
432 | |
433 | // Print the shift opc. |
434 | ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(Op: MO3.getImm()); |
435 | O << ", " << ARM_AM::getShiftOpcStr(Op: ShOpc); |
436 | if (ShOpc == ARM_AM::rrx) |
437 | return; |
438 | |
439 | O << ' '; |
440 | printRegName(OS&: O, Reg: MO2.getReg()); |
441 | assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); |
442 | } |
443 | |
444 | void ARMInstPrinter::printSORegImmOperand(const MCInst *MI, unsigned OpNum, |
445 | const MCSubtargetInfo &STI, |
446 | raw_ostream &O) { |
447 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
448 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
449 | |
450 | printRegName(OS&: O, Reg: MO1.getReg()); |
451 | |
452 | // Print the shift opc. |
453 | printRegImmShift(O, ShOpc: ARM_AM::getSORegShOp(Op: MO2.getImm()), |
454 | ShImm: ARM_AM::getSORegOffset(Op: MO2.getImm()), printer&: *this); |
455 | } |
456 | |
457 | //===--------------------------------------------------------------------===// |
458 | // Addressing Mode #2 |
459 | //===--------------------------------------------------------------------===// |
460 | |
461 | void ARMInstPrinter::printAM2PreOrOffsetIndexOp(const MCInst *MI, unsigned Op, |
462 | const MCSubtargetInfo &STI, |
463 | raw_ostream &O) { |
464 | const MCOperand &MO1 = MI->getOperand(i: Op); |
465 | const MCOperand &MO2 = MI->getOperand(i: Op + 1); |
466 | const MCOperand &MO3 = MI->getOperand(i: Op + 2); |
467 | |
468 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
469 | O << "[" ; |
470 | printRegName(OS&: O, Reg: MO1.getReg()); |
471 | |
472 | if (!MO2.getReg()) { |
473 | if (ARM_AM::getAM2Offset(AM2Opc: MO3.getImm())) { // Don't print +0. |
474 | O << ", " ; |
475 | markup(OS&: O, M: Markup::Immediate) |
476 | << "#" << ARM_AM::getAddrOpcStr(Op: ARM_AM::getAM2Op(AM2Opc: MO3.getImm())) |
477 | << ARM_AM::getAM2Offset(AM2Opc: MO3.getImm()); |
478 | } |
479 | O << "]" ; |
480 | return; |
481 | } |
482 | |
483 | O << ", " ; |
484 | O << ARM_AM::getAddrOpcStr(Op: ARM_AM::getAM2Op(AM2Opc: MO3.getImm())); |
485 | printRegName(OS&: O, Reg: MO2.getReg()); |
486 | |
487 | printRegImmShift(O, ShOpc: ARM_AM::getAM2ShiftOpc(AM2Opc: MO3.getImm()), |
488 | ShImm: ARM_AM::getAM2Offset(AM2Opc: MO3.getImm()), printer&: *this); |
489 | O << "]" ; |
490 | } |
491 | |
492 | void ARMInstPrinter::printAddrModeTBB(const MCInst *MI, unsigned Op, |
493 | const MCSubtargetInfo &STI, |
494 | raw_ostream &O) { |
495 | const MCOperand &MO1 = MI->getOperand(i: Op); |
496 | const MCOperand &MO2 = MI->getOperand(i: Op + 1); |
497 | |
498 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
499 | O << "[" ; |
500 | printRegName(OS&: O, Reg: MO1.getReg()); |
501 | O << ", " ; |
502 | printRegName(OS&: O, Reg: MO2.getReg()); |
503 | O << "]" ; |
504 | } |
505 | |
506 | void ARMInstPrinter::printAddrModeTBH(const MCInst *MI, unsigned Op, |
507 | const MCSubtargetInfo &STI, |
508 | raw_ostream &O) { |
509 | const MCOperand &MO1 = MI->getOperand(i: Op); |
510 | const MCOperand &MO2 = MI->getOperand(i: Op + 1); |
511 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
512 | O << "[" ; |
513 | printRegName(OS&: O, Reg: MO1.getReg()); |
514 | O << ", " ; |
515 | printRegName(OS&: O, Reg: MO2.getReg()); |
516 | O << ", lsl " ; |
517 | markup(OS&: O, M: Markup::Immediate) << "#1" ; |
518 | O << "]" ; |
519 | } |
520 | |
521 | void ARMInstPrinter::printAddrMode2Operand(const MCInst *MI, unsigned Op, |
522 | const MCSubtargetInfo &STI, |
523 | raw_ostream &O) { |
524 | const MCOperand &MO1 = MI->getOperand(i: Op); |
525 | |
526 | if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. |
527 | printOperand(MI, OpNo: Op, STI, O); |
528 | return; |
529 | } |
530 | |
531 | #ifndef NDEBUG |
532 | const MCOperand &MO3 = MI->getOperand(Op + 2); |
533 | unsigned IdxMode = ARM_AM::getAM2IdxMode(MO3.getImm()); |
534 | assert(IdxMode != ARMII::IndexModePost && "Should be pre or offset index op" ); |
535 | #endif |
536 | |
537 | printAM2PreOrOffsetIndexOp(MI, Op, STI, O); |
538 | } |
539 | |
540 | void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI, |
541 | unsigned OpNum, |
542 | const MCSubtargetInfo &STI, |
543 | raw_ostream &O) { |
544 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
545 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
546 | |
547 | if (!MO1.getReg()) { |
548 | unsigned ImmOffs = ARM_AM::getAM2Offset(AM2Opc: MO2.getImm()); |
549 | markup(OS&: O, M: Markup::Immediate) |
550 | << '#' << ARM_AM::getAddrOpcStr(Op: ARM_AM::getAM2Op(AM2Opc: MO2.getImm())) |
551 | << ImmOffs; |
552 | return; |
553 | } |
554 | |
555 | O << ARM_AM::getAddrOpcStr(Op: ARM_AM::getAM2Op(AM2Opc: MO2.getImm())); |
556 | printRegName(OS&: O, Reg: MO1.getReg()); |
557 | |
558 | printRegImmShift(O, ShOpc: ARM_AM::getAM2ShiftOpc(AM2Opc: MO2.getImm()), |
559 | ShImm: ARM_AM::getAM2Offset(AM2Opc: MO2.getImm()), printer&: *this); |
560 | } |
561 | |
562 | //===--------------------------------------------------------------------===// |
563 | // Addressing Mode #3 |
564 | //===--------------------------------------------------------------------===// |
565 | |
566 | void ARMInstPrinter::printAM3PreOrOffsetIndexOp(const MCInst *MI, unsigned Op, |
567 | raw_ostream &O, |
568 | bool AlwaysPrintImm0) { |
569 | const MCOperand &MO1 = MI->getOperand(i: Op); |
570 | const MCOperand &MO2 = MI->getOperand(i: Op + 1); |
571 | const MCOperand &MO3 = MI->getOperand(i: Op + 2); |
572 | |
573 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
574 | O << '['; |
575 | printRegName(OS&: O, Reg: MO1.getReg()); |
576 | |
577 | if (MO2.getReg()) { |
578 | O << ", " << getAddrOpcStr(Op: ARM_AM::getAM3Op(AM3Opc: MO3.getImm())); |
579 | printRegName(OS&: O, Reg: MO2.getReg()); |
580 | O << ']'; |
581 | return; |
582 | } |
583 | |
584 | // If the op is sub we have to print the immediate even if it is 0 |
585 | unsigned ImmOffs = ARM_AM::getAM3Offset(AM3Opc: MO3.getImm()); |
586 | ARM_AM::AddrOpc op = ARM_AM::getAM3Op(AM3Opc: MO3.getImm()); |
587 | |
588 | if (AlwaysPrintImm0 || ImmOffs || (op == ARM_AM::sub)) { |
589 | O << ", " ; |
590 | markup(OS&: O, M: Markup::Immediate) << "#" << ARM_AM::getAddrOpcStr(Op: op) << ImmOffs; |
591 | } |
592 | O << ']'; |
593 | } |
594 | |
595 | template <bool AlwaysPrintImm0> |
596 | void ARMInstPrinter::printAddrMode3Operand(const MCInst *MI, unsigned Op, |
597 | const MCSubtargetInfo &STI, |
598 | raw_ostream &O) { |
599 | const MCOperand &MO1 = MI->getOperand(i: Op); |
600 | if (!MO1.isReg()) { // For label symbolic references. |
601 | printOperand(MI, OpNo: Op, STI, O); |
602 | return; |
603 | } |
604 | |
605 | assert(ARM_AM::getAM3IdxMode(MI->getOperand(Op + 2).getImm()) != |
606 | ARMII::IndexModePost && |
607 | "unexpected idxmode" ); |
608 | printAM3PreOrOffsetIndexOp(MI, Op, O, AlwaysPrintImm0); |
609 | } |
610 | |
611 | void ARMInstPrinter::printAddrMode3OffsetOperand(const MCInst *MI, |
612 | unsigned OpNum, |
613 | const MCSubtargetInfo &STI, |
614 | raw_ostream &O) { |
615 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
616 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
617 | |
618 | if (MO1.getReg()) { |
619 | O << getAddrOpcStr(Op: ARM_AM::getAM3Op(AM3Opc: MO2.getImm())); |
620 | printRegName(OS&: O, Reg: MO1.getReg()); |
621 | return; |
622 | } |
623 | |
624 | unsigned ImmOffs = ARM_AM::getAM3Offset(AM3Opc: MO2.getImm()); |
625 | markup(OS&: O, M: Markup::Immediate) |
626 | << '#' << ARM_AM::getAddrOpcStr(Op: ARM_AM::getAM3Op(AM3Opc: MO2.getImm())) |
627 | << ImmOffs; |
628 | } |
629 | |
630 | void ARMInstPrinter::printPostIdxImm8Operand(const MCInst *MI, unsigned OpNum, |
631 | const MCSubtargetInfo &STI, |
632 | raw_ostream &O) { |
633 | const MCOperand &MO = MI->getOperand(i: OpNum); |
634 | unsigned Imm = MO.getImm(); |
635 | markup(OS&: O, M: Markup::Immediate) |
636 | << '#' << ((Imm & 256) ? "" : "-" ) << (Imm & 0xff); |
637 | } |
638 | |
639 | void ARMInstPrinter::printPostIdxRegOperand(const MCInst *MI, unsigned OpNum, |
640 | const MCSubtargetInfo &STI, |
641 | raw_ostream &O) { |
642 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
643 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
644 | |
645 | O << (MO2.getImm() ? "" : "-" ); |
646 | printRegName(OS&: O, Reg: MO1.getReg()); |
647 | } |
648 | |
649 | void ARMInstPrinter::printPostIdxImm8s4Operand(const MCInst *MI, unsigned OpNum, |
650 | const MCSubtargetInfo &STI, |
651 | raw_ostream &O) { |
652 | const MCOperand &MO = MI->getOperand(i: OpNum); |
653 | unsigned Imm = MO.getImm(); |
654 | markup(OS&: O, M: Markup::Immediate) |
655 | << '#' << ((Imm & 256) ? "" : "-" ) << ((Imm & 0xff) << 2); |
656 | } |
657 | |
658 | template<int shift> |
659 | void ARMInstPrinter::printMveAddrModeRQOperand(const MCInst *MI, unsigned OpNum, |
660 | const MCSubtargetInfo &STI, |
661 | raw_ostream &O) { |
662 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
663 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
664 | |
665 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
666 | O << "[" ; |
667 | printRegName(OS&: O, Reg: MO1.getReg()); |
668 | O << ", " ; |
669 | printRegName(OS&: O, Reg: MO2.getReg()); |
670 | |
671 | if (shift > 0) |
672 | printRegImmShift(O, ShOpc: ARM_AM::uxtw, ShImm: shift, printer&: *this); |
673 | |
674 | O << "]" ; |
675 | } |
676 | |
677 | void ARMInstPrinter::printLdStmModeOperand(const MCInst *MI, unsigned OpNum, |
678 | const MCSubtargetInfo &STI, |
679 | raw_ostream &O) { |
680 | ARM_AM::AMSubMode Mode = |
681 | ARM_AM::getAM4SubMode(Mode: MI->getOperand(i: OpNum).getImm()); |
682 | O << ARM_AM::getAMSubModeStr(Mode); |
683 | } |
684 | |
685 | template <bool AlwaysPrintImm0> |
686 | void ARMInstPrinter::printAddrMode5Operand(const MCInst *MI, unsigned OpNum, |
687 | const MCSubtargetInfo &STI, |
688 | raw_ostream &O) { |
689 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
690 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
691 | |
692 | if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. |
693 | printOperand(MI, OpNo: OpNum, STI, O); |
694 | return; |
695 | } |
696 | |
697 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
698 | O << "[" ; |
699 | printRegName(OS&: O, Reg: MO1.getReg()); |
700 | |
701 | unsigned ImmOffs = ARM_AM::getAM5Offset(AM5Opc: MO2.getImm()); |
702 | ARM_AM::AddrOpc Op = ARM_AM::getAM5Op(AM5Opc: MO2.getImm()); |
703 | if (AlwaysPrintImm0 || ImmOffs || Op == ARM_AM::sub) { |
704 | O << ", " ; |
705 | markup(OS&: O, M: Markup::Immediate) |
706 | << "#" << ARM_AM::getAddrOpcStr(Op) << ImmOffs * 4; |
707 | } |
708 | O << "]" ; |
709 | } |
710 | |
711 | template <bool AlwaysPrintImm0> |
712 | void ARMInstPrinter::printAddrMode5FP16Operand(const MCInst *MI, unsigned OpNum, |
713 | const MCSubtargetInfo &STI, |
714 | raw_ostream &O) { |
715 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
716 | const MCOperand &MO2 = MI->getOperand(i: OpNum+1); |
717 | |
718 | if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. |
719 | printOperand(MI, OpNo: OpNum, STI, O); |
720 | return; |
721 | } |
722 | |
723 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
724 | O << "[" ; |
725 | printRegName(OS&: O, Reg: MO1.getReg()); |
726 | |
727 | unsigned ImmOffs = ARM_AM::getAM5FP16Offset(AM5Opc: MO2.getImm()); |
728 | unsigned Op = ARM_AM::getAM5FP16Op(AM5Opc: MO2.getImm()); |
729 | if (AlwaysPrintImm0 || ImmOffs || Op == ARM_AM::sub) { |
730 | O << ", " ; |
731 | markup(OS&: O, M: Markup::Immediate) |
732 | << "#" << ARM_AM::getAddrOpcStr(Op: ARM_AM::getAM5FP16Op(AM5Opc: MO2.getImm())) |
733 | << ImmOffs * 2; |
734 | } |
735 | O << "]" ; |
736 | } |
737 | |
738 | void ARMInstPrinter::printAddrMode6Operand(const MCInst *MI, unsigned OpNum, |
739 | const MCSubtargetInfo &STI, |
740 | raw_ostream &O) { |
741 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
742 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
743 | |
744 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
745 | O << "[" ; |
746 | printRegName(OS&: O, Reg: MO1.getReg()); |
747 | if (MO2.getImm()) { |
748 | O << ":" << (MO2.getImm() << 3); |
749 | } |
750 | O << "]" ; |
751 | } |
752 | |
753 | void ARMInstPrinter::printAddrMode7Operand(const MCInst *MI, unsigned OpNum, |
754 | const MCSubtargetInfo &STI, |
755 | raw_ostream &O) { |
756 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
757 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
758 | O << "[" ; |
759 | printRegName(OS&: O, Reg: MO1.getReg()); |
760 | O << "]" ; |
761 | } |
762 | |
763 | void ARMInstPrinter::printAddrMode6OffsetOperand(const MCInst *MI, |
764 | unsigned OpNum, |
765 | const MCSubtargetInfo &STI, |
766 | raw_ostream &O) { |
767 | const MCOperand &MO = MI->getOperand(i: OpNum); |
768 | if (!MO.getReg()) |
769 | O << "!" ; |
770 | else { |
771 | O << ", " ; |
772 | printRegName(OS&: O, Reg: MO.getReg()); |
773 | } |
774 | } |
775 | |
776 | void ARMInstPrinter::printBitfieldInvMaskImmOperand(const MCInst *MI, |
777 | unsigned OpNum, |
778 | const MCSubtargetInfo &STI, |
779 | raw_ostream &O) { |
780 | const MCOperand &MO = MI->getOperand(i: OpNum); |
781 | uint32_t v = ~MO.getImm(); |
782 | int32_t lsb = llvm::countr_zero(Val: v); |
783 | int32_t width = llvm::bit_width(Value: v) - lsb; |
784 | assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!" ); |
785 | markup(OS&: O, M: Markup::Immediate) << '#' << lsb; |
786 | O << ", " ; |
787 | markup(OS&: O, M: Markup::Immediate) << '#' << width; |
788 | } |
789 | |
790 | void ARMInstPrinter::printMemBOption(const MCInst *MI, unsigned OpNum, |
791 | const MCSubtargetInfo &STI, |
792 | raw_ostream &O) { |
793 | unsigned val = MI->getOperand(i: OpNum).getImm(); |
794 | O << ARM_MB::MemBOptToString(val, HasV8: STI.hasFeature(Feature: ARM::HasV8Ops)); |
795 | } |
796 | |
797 | void ARMInstPrinter::printInstSyncBOption(const MCInst *MI, unsigned OpNum, |
798 | const MCSubtargetInfo &STI, |
799 | raw_ostream &O) { |
800 | unsigned val = MI->getOperand(i: OpNum).getImm(); |
801 | O << ARM_ISB::InstSyncBOptToString(val); |
802 | } |
803 | |
804 | void ARMInstPrinter::printTraceSyncBOption(const MCInst *MI, unsigned OpNum, |
805 | const MCSubtargetInfo &STI, |
806 | raw_ostream &O) { |
807 | unsigned val = MI->getOperand(i: OpNum).getImm(); |
808 | O << ARM_TSB::TraceSyncBOptToString(val); |
809 | } |
810 | |
811 | void ARMInstPrinter::printShiftImmOperand(const MCInst *MI, unsigned OpNum, |
812 | const MCSubtargetInfo &STI, |
813 | raw_ostream &O) { |
814 | unsigned ShiftOp = MI->getOperand(i: OpNum).getImm(); |
815 | bool isASR = (ShiftOp & (1 << 5)) != 0; |
816 | unsigned Amt = ShiftOp & 0x1f; |
817 | if (isASR) { |
818 | O << ", asr " ; |
819 | markup(OS&: O, M: Markup::Immediate) << "#" << (Amt == 0 ? 32 : Amt); |
820 | } else if (Amt) { |
821 | O << ", lsl " ; |
822 | markup(OS&: O, M: Markup::Immediate) << "#" << Amt; |
823 | } |
824 | } |
825 | |
826 | void ARMInstPrinter::printPKHLSLShiftImm(const MCInst *MI, unsigned OpNum, |
827 | const MCSubtargetInfo &STI, |
828 | raw_ostream &O) { |
829 | unsigned Imm = MI->getOperand(i: OpNum).getImm(); |
830 | if (Imm == 0) |
831 | return; |
832 | assert(Imm > 0 && Imm < 32 && "Invalid PKH shift immediate value!" ); |
833 | O << ", lsl " ; |
834 | markup(OS&: O, M: Markup::Immediate) << "#" << Imm; |
835 | } |
836 | |
837 | void ARMInstPrinter::printPKHASRShiftImm(const MCInst *MI, unsigned OpNum, |
838 | const MCSubtargetInfo &STI, |
839 | raw_ostream &O) { |
840 | unsigned Imm = MI->getOperand(i: OpNum).getImm(); |
841 | // A shift amount of 32 is encoded as 0. |
842 | if (Imm == 0) |
843 | Imm = 32; |
844 | assert(Imm > 0 && Imm <= 32 && "Invalid PKH shift immediate value!" ); |
845 | O << ", asr " ; |
846 | markup(OS&: O, M: Markup::Immediate) << "#" << Imm; |
847 | } |
848 | |
849 | void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum, |
850 | const MCSubtargetInfo &STI, |
851 | raw_ostream &O) { |
852 | if (MI->getOpcode() != ARM::t2CLRM && MI->getOpcode() != ARM::VSCCLRMS) { |
853 | assert(is_sorted(drop_begin(*MI, OpNum), |
854 | [&](const MCOperand &LHS, const MCOperand &RHS) { |
855 | return MRI.getEncodingValue(LHS.getReg()) < |
856 | MRI.getEncodingValue(RHS.getReg()); |
857 | })); |
858 | } |
859 | |
860 | O << "{" ; |
861 | for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { |
862 | if (i != OpNum) |
863 | O << ", " ; |
864 | printRegName(OS&: O, Reg: MI->getOperand(i).getReg()); |
865 | } |
866 | O << "}" ; |
867 | } |
868 | |
869 | void ARMInstPrinter::printGPRPairOperand(const MCInst *MI, unsigned OpNum, |
870 | const MCSubtargetInfo &STI, |
871 | raw_ostream &O) { |
872 | MCRegister Reg = MI->getOperand(i: OpNum).getReg(); |
873 | printRegName(OS&: O, Reg: MRI.getSubReg(Reg, Idx: ARM::gsub_0)); |
874 | O << ", " ; |
875 | printRegName(OS&: O, Reg: MRI.getSubReg(Reg, Idx: ARM::gsub_1)); |
876 | } |
877 | |
878 | void ARMInstPrinter::printSetendOperand(const MCInst *MI, unsigned OpNum, |
879 | const MCSubtargetInfo &STI, |
880 | raw_ostream &O) { |
881 | const MCOperand &Op = MI->getOperand(i: OpNum); |
882 | if (Op.getImm()) |
883 | O << "be" ; |
884 | else |
885 | O << "le" ; |
886 | } |
887 | |
888 | void ARMInstPrinter::printCPSIMod(const MCInst *MI, unsigned OpNum, |
889 | const MCSubtargetInfo &STI, raw_ostream &O) { |
890 | const MCOperand &Op = MI->getOperand(i: OpNum); |
891 | O << ARM_PROC::IModToString(val: Op.getImm()); |
892 | } |
893 | |
894 | void ARMInstPrinter::printCPSIFlag(const MCInst *MI, unsigned OpNum, |
895 | const MCSubtargetInfo &STI, raw_ostream &O) { |
896 | const MCOperand &Op = MI->getOperand(i: OpNum); |
897 | unsigned IFlags = Op.getImm(); |
898 | for (int i = 2; i >= 0; --i) |
899 | if (IFlags & (1 << i)) |
900 | O << ARM_PROC::IFlagsToString(val: 1 << i); |
901 | |
902 | if (IFlags == 0) |
903 | O << "none" ; |
904 | } |
905 | |
906 | void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum, |
907 | const MCSubtargetInfo &STI, |
908 | raw_ostream &O) { |
909 | const MCOperand &Op = MI->getOperand(i: OpNum); |
910 | const FeatureBitset &FeatureBits = STI.getFeatureBits(); |
911 | if (FeatureBits[ARM::FeatureMClass]) { |
912 | |
913 | unsigned SYSm = Op.getImm() & 0xFFF; // 12-bit SYSm |
914 | unsigned Opcode = MI->getOpcode(); |
915 | |
916 | // For writes, handle extended mask bits if the DSP extension is present. |
917 | if (Opcode == ARM::t2MSR_M && FeatureBits[ARM::FeatureDSP]) { |
918 | auto TheReg =ARMSysReg::lookupMClassSysRegBy12bitSYSmValue(SYSm); |
919 | if (TheReg && TheReg->isInRequiredFeatures(TestFeatures: {ARM::FeatureDSP})) { |
920 | O << TheReg->Name; |
921 | return; |
922 | } |
923 | } |
924 | |
925 | // Handle the basic 8-bit mask. |
926 | SYSm &= 0xff; |
927 | if (Opcode == ARM::t2MSR_M && FeatureBits [ARM::HasV7Ops]) { |
928 | // ARMv7-M deprecates using MSR APSR without a _<bits> qualifier as an |
929 | // alias for MSR APSR_nzcvq. |
930 | auto TheReg = ARMSysReg::lookupMClassSysRegAPSRNonDeprecated(SYSm); |
931 | if (TheReg) { |
932 | O << TheReg->Name; |
933 | return; |
934 | } |
935 | } |
936 | |
937 | auto TheReg = ARMSysReg::lookupMClassSysRegBy8bitSYSmValue(SYSm); |
938 | if (TheReg) { |
939 | O << TheReg->Name; |
940 | return; |
941 | } |
942 | |
943 | O << SYSm; |
944 | |
945 | return; |
946 | } |
947 | |
948 | // As special cases, CPSR_f, CPSR_s and CPSR_fs prefer printing as |
949 | // APSR_nzcvq, APSR_g and APSRnzcvqg, respectively. |
950 | unsigned SpecRegRBit = Op.getImm() >> 4; |
951 | unsigned Mask = Op.getImm() & 0xf; |
952 | |
953 | if (!SpecRegRBit && (Mask == 8 || Mask == 4 || Mask == 12)) { |
954 | O << "APSR_" ; |
955 | switch (Mask) { |
956 | default: |
957 | llvm_unreachable("Unexpected mask value!" ); |
958 | case 4: |
959 | O << "g" ; |
960 | return; |
961 | case 8: |
962 | O << "nzcvq" ; |
963 | return; |
964 | case 12: |
965 | O << "nzcvqg" ; |
966 | return; |
967 | } |
968 | } |
969 | |
970 | if (SpecRegRBit) |
971 | O << "SPSR" ; |
972 | else |
973 | O << "CPSR" ; |
974 | |
975 | if (Mask) { |
976 | O << '_'; |
977 | if (Mask & 8) |
978 | O << 'f'; |
979 | if (Mask & 4) |
980 | O << 's'; |
981 | if (Mask & 2) |
982 | O << 'x'; |
983 | if (Mask & 1) |
984 | O << 'c'; |
985 | } |
986 | } |
987 | |
988 | void ARMInstPrinter::printBankedRegOperand(const MCInst *MI, unsigned OpNum, |
989 | const MCSubtargetInfo &STI, |
990 | raw_ostream &O) { |
991 | uint32_t Banked = MI->getOperand(i: OpNum).getImm(); |
992 | auto TheReg = ARMBankedReg::lookupBankedRegByEncoding(Encoding: Banked); |
993 | assert(TheReg && "invalid banked register operand" ); |
994 | std::string Name = TheReg->Name; |
995 | |
996 | uint32_t isSPSR = (Banked & 0x20) >> 5; |
997 | if (isSPSR) |
998 | Name.replace(pos: 0, n1: 4, s: "SPSR" ); // convert 'spsr_' to 'SPSR_' |
999 | O << Name; |
1000 | } |
1001 | |
1002 | void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum, |
1003 | const MCSubtargetInfo &STI, |
1004 | raw_ostream &O) { |
1005 | ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(i: OpNum).getImm(); |
1006 | // Handle the undefined 15 CC value here for printing so we don't abort(). |
1007 | if ((unsigned)CC == 15) |
1008 | O << "<und>" ; |
1009 | else if (CC != ARMCC::AL) |
1010 | O << ARMCondCodeToString(CC); |
1011 | } |
1012 | |
1013 | void ARMInstPrinter::printMandatoryRestrictedPredicateOperand( |
1014 | const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, |
1015 | raw_ostream &O) { |
1016 | if ((ARMCC::CondCodes)MI->getOperand(i: OpNum).getImm() == ARMCC::HS) |
1017 | O << "cs" ; |
1018 | else |
1019 | printMandatoryPredicateOperand(MI, OpNum, STI, O); |
1020 | } |
1021 | |
1022 | void ARMInstPrinter::printMandatoryPredicateOperand(const MCInst *MI, |
1023 | unsigned OpNum, |
1024 | const MCSubtargetInfo &STI, |
1025 | raw_ostream &O) { |
1026 | ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(i: OpNum).getImm(); |
1027 | O << ARMCondCodeToString(CC); |
1028 | } |
1029 | |
1030 | void ARMInstPrinter::printMandatoryInvertedPredicateOperand(const MCInst *MI, |
1031 | unsigned OpNum, |
1032 | const MCSubtargetInfo &STI, |
1033 | raw_ostream &O) { |
1034 | ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(i: OpNum).getImm(); |
1035 | O << ARMCondCodeToString(CC: ARMCC::getOppositeCondition(CC)); |
1036 | } |
1037 | |
1038 | void ARMInstPrinter::printSBitModifierOperand(const MCInst *MI, unsigned OpNum, |
1039 | const MCSubtargetInfo &STI, |
1040 | raw_ostream &O) { |
1041 | if (MI->getOperand(i: OpNum).getReg()) { |
1042 | assert(MI->getOperand(OpNum).getReg() == ARM::CPSR && |
1043 | "Expect ARM CPSR register!" ); |
1044 | O << 's'; |
1045 | } |
1046 | } |
1047 | |
1048 | void ARMInstPrinter::printNoHashImmediate(const MCInst *MI, unsigned OpNum, |
1049 | const MCSubtargetInfo &STI, |
1050 | raw_ostream &O) { |
1051 | O << MI->getOperand(i: OpNum).getImm(); |
1052 | } |
1053 | |
1054 | void ARMInstPrinter::printPImmediate(const MCInst *MI, unsigned OpNum, |
1055 | const MCSubtargetInfo &STI, |
1056 | raw_ostream &O) { |
1057 | O << "p" << MI->getOperand(i: OpNum).getImm(); |
1058 | } |
1059 | |
1060 | void ARMInstPrinter::printCImmediate(const MCInst *MI, unsigned OpNum, |
1061 | const MCSubtargetInfo &STI, |
1062 | raw_ostream &O) { |
1063 | O << "c" << MI->getOperand(i: OpNum).getImm(); |
1064 | } |
1065 | |
1066 | void ARMInstPrinter::printCoprocOptionImm(const MCInst *MI, unsigned OpNum, |
1067 | const MCSubtargetInfo &STI, |
1068 | raw_ostream &O) { |
1069 | O << "{" << MI->getOperand(i: OpNum).getImm() << "}" ; |
1070 | } |
1071 | |
1072 | void ARMInstPrinter::printPCLabel(const MCInst *MI, unsigned OpNum, |
1073 | const MCSubtargetInfo &STI, raw_ostream &O) { |
1074 | llvm_unreachable("Unhandled PC-relative pseudo-instruction!" ); |
1075 | } |
1076 | |
1077 | template <unsigned scale> |
1078 | void ARMInstPrinter::printAdrLabelOperand(const MCInst *MI, unsigned OpNum, |
1079 | const MCSubtargetInfo &STI, |
1080 | raw_ostream &O) { |
1081 | const MCOperand &MO = MI->getOperand(i: OpNum); |
1082 | |
1083 | if (MO.isExpr()) { |
1084 | MAI.printExpr(O, *MO.getExpr()); |
1085 | return; |
1086 | } |
1087 | |
1088 | int32_t OffImm = (int32_t)MO.getImm() << scale; |
1089 | |
1090 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Immediate); |
1091 | if (OffImm == INT32_MIN) |
1092 | O << "#-0" ; |
1093 | else if (OffImm < 0) |
1094 | O << "#-" << -OffImm; |
1095 | else |
1096 | O << "#" << OffImm; |
1097 | } |
1098 | |
1099 | void ARMInstPrinter::printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum, |
1100 | const MCSubtargetInfo &STI, |
1101 | raw_ostream &O) { |
1102 | markup(OS&: O, M: Markup::Immediate) |
1103 | << "#" << formatImm(Value: MI->getOperand(i: OpNum).getImm() * 4); |
1104 | } |
1105 | |
1106 | void ARMInstPrinter::printThumbSRImm(const MCInst *MI, unsigned OpNum, |
1107 | const MCSubtargetInfo &STI, |
1108 | raw_ostream &O) { |
1109 | unsigned Imm = MI->getOperand(i: OpNum).getImm(); |
1110 | markup(OS&: O, M: Markup::Immediate) << "#" << formatImm(Value: (Imm == 0 ? 32 : Imm)); |
1111 | } |
1112 | |
1113 | void ARMInstPrinter::printThumbITMask(const MCInst *MI, unsigned OpNum, |
1114 | const MCSubtargetInfo &STI, |
1115 | raw_ostream &O) { |
1116 | // (3 - the number of trailing zeros) is the number of then / else. |
1117 | unsigned Mask = MI->getOperand(i: OpNum).getImm(); |
1118 | unsigned NumTZ = llvm::countr_zero(Val: Mask); |
1119 | assert(NumTZ <= 3 && "Invalid IT mask!" ); |
1120 | for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { |
1121 | if ((Mask >> Pos) & 1) |
1122 | O << 'e'; |
1123 | else |
1124 | O << 't'; |
1125 | } |
1126 | } |
1127 | |
1128 | void ARMInstPrinter::printThumbAddrModeRROperand(const MCInst *MI, unsigned Op, |
1129 | const MCSubtargetInfo &STI, |
1130 | raw_ostream &O) { |
1131 | const MCOperand &MO1 = MI->getOperand(i: Op); |
1132 | const MCOperand &MO2 = MI->getOperand(i: Op + 1); |
1133 | |
1134 | if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. |
1135 | printOperand(MI, OpNo: Op, STI, O); |
1136 | return; |
1137 | } |
1138 | |
1139 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
1140 | O << "[" ; |
1141 | printRegName(OS&: O, Reg: MO1.getReg()); |
1142 | if (MCRegister RegNum = MO2.getReg()) { |
1143 | O << ", " ; |
1144 | printRegName(OS&: O, Reg: RegNum); |
1145 | } |
1146 | O << "]" ; |
1147 | } |
1148 | |
1149 | void ARMInstPrinter::printThumbAddrModeImm5SOperand(const MCInst *MI, |
1150 | unsigned Op, |
1151 | const MCSubtargetInfo &STI, |
1152 | raw_ostream &O, |
1153 | unsigned Scale) { |
1154 | const MCOperand &MO1 = MI->getOperand(i: Op); |
1155 | const MCOperand &MO2 = MI->getOperand(i: Op + 1); |
1156 | |
1157 | if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. |
1158 | printOperand(MI, OpNo: Op, STI, O); |
1159 | return; |
1160 | } |
1161 | |
1162 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
1163 | O << "[" ; |
1164 | printRegName(OS&: O, Reg: MO1.getReg()); |
1165 | if (unsigned ImmOffs = MO2.getImm()) { |
1166 | O << ", " ; |
1167 | markup(OS&: O, M: Markup::Immediate) << "#" << formatImm(Value: ImmOffs * Scale); |
1168 | } |
1169 | O << "]" ; |
1170 | } |
1171 | |
1172 | void ARMInstPrinter::printThumbAddrModeImm5S1Operand(const MCInst *MI, |
1173 | unsigned Op, |
1174 | const MCSubtargetInfo &STI, |
1175 | raw_ostream &O) { |
1176 | printThumbAddrModeImm5SOperand(MI, Op, STI, O, Scale: 1); |
1177 | } |
1178 | |
1179 | void ARMInstPrinter::printThumbAddrModeImm5S2Operand(const MCInst *MI, |
1180 | unsigned Op, |
1181 | const MCSubtargetInfo &STI, |
1182 | raw_ostream &O) { |
1183 | printThumbAddrModeImm5SOperand(MI, Op, STI, O, Scale: 2); |
1184 | } |
1185 | |
1186 | void ARMInstPrinter::printThumbAddrModeImm5S4Operand(const MCInst *MI, |
1187 | unsigned Op, |
1188 | const MCSubtargetInfo &STI, |
1189 | raw_ostream &O) { |
1190 | printThumbAddrModeImm5SOperand(MI, Op, STI, O, Scale: 4); |
1191 | } |
1192 | |
1193 | void ARMInstPrinter::printThumbAddrModeSPOperand(const MCInst *MI, unsigned Op, |
1194 | const MCSubtargetInfo &STI, |
1195 | raw_ostream &O) { |
1196 | printThumbAddrModeImm5SOperand(MI, Op, STI, O, Scale: 4); |
1197 | } |
1198 | |
1199 | // Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 |
1200 | // register with shift forms. |
1201 | // REG 0 0 - e.g. R5 |
1202 | // REG IMM, SH_OPC - e.g. R5, LSL #3 |
1203 | void ARMInstPrinter::printT2SOOperand(const MCInst *MI, unsigned OpNum, |
1204 | const MCSubtargetInfo &STI, |
1205 | raw_ostream &O) { |
1206 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
1207 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
1208 | |
1209 | MCRegister Reg = MO1.getReg(); |
1210 | printRegName(OS&: O, Reg); |
1211 | |
1212 | // Print the shift opc. |
1213 | assert(MO2.isImm() && "Not a valid t2_so_reg value!" ); |
1214 | printRegImmShift(O, ShOpc: ARM_AM::getSORegShOp(Op: MO2.getImm()), |
1215 | ShImm: ARM_AM::getSORegOffset(Op: MO2.getImm()), printer&: *this); |
1216 | } |
1217 | |
1218 | template <bool AlwaysPrintImm0> |
1219 | void ARMInstPrinter::printAddrModeImm12Operand(const MCInst *MI, unsigned OpNum, |
1220 | const MCSubtargetInfo &STI, |
1221 | raw_ostream &O) { |
1222 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
1223 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
1224 | |
1225 | if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. |
1226 | printOperand(MI, OpNo: OpNum, STI, O); |
1227 | return; |
1228 | } |
1229 | |
1230 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
1231 | O << "[" ; |
1232 | printRegName(OS&: O, Reg: MO1.getReg()); |
1233 | |
1234 | int32_t OffImm = (int32_t)MO2.getImm(); |
1235 | bool isSub = OffImm < 0; |
1236 | // Special value for #-0. All others are normal. |
1237 | if (OffImm == INT32_MIN) |
1238 | OffImm = 0; |
1239 | if (isSub) { |
1240 | O << ", " ; |
1241 | markup(OS&: O, M: Markup::Immediate) << "#-" << formatImm(Value: -OffImm); |
1242 | } else if (AlwaysPrintImm0 || OffImm > 0) { |
1243 | O << ", " ; |
1244 | markup(OS&: O, M: Markup::Immediate) << "#" << formatImm(Value: OffImm); |
1245 | } |
1246 | O << "]" ; |
1247 | } |
1248 | |
1249 | template <bool AlwaysPrintImm0> |
1250 | void ARMInstPrinter::printT2AddrModeImm8Operand(const MCInst *MI, |
1251 | unsigned OpNum, |
1252 | const MCSubtargetInfo &STI, |
1253 | raw_ostream &O) { |
1254 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
1255 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
1256 | |
1257 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
1258 | O << "[" ; |
1259 | printRegName(OS&: O, Reg: MO1.getReg()); |
1260 | |
1261 | int32_t OffImm = (int32_t)MO2.getImm(); |
1262 | bool isSub = OffImm < 0; |
1263 | // Don't print +0. |
1264 | if (OffImm == INT32_MIN) |
1265 | OffImm = 0; |
1266 | if (isSub) { |
1267 | O << ", " ; |
1268 | markup(OS&: O, M: Markup::Immediate) << "#-" << -OffImm; |
1269 | } else if (AlwaysPrintImm0 || OffImm > 0) { |
1270 | O << ", " ; |
1271 | markup(OS&: O, M: Markup::Immediate) << "#" << OffImm; |
1272 | } |
1273 | O << "]" ; |
1274 | } |
1275 | |
1276 | template <bool AlwaysPrintImm0> |
1277 | void ARMInstPrinter::printT2AddrModeImm8s4Operand(const MCInst *MI, |
1278 | unsigned OpNum, |
1279 | const MCSubtargetInfo &STI, |
1280 | raw_ostream &O) { |
1281 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
1282 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
1283 | |
1284 | if (!MO1.isReg()) { // For label symbolic references. |
1285 | printOperand(MI, OpNo: OpNum, STI, O); |
1286 | return; |
1287 | } |
1288 | |
1289 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
1290 | O << "[" ; |
1291 | printRegName(OS&: O, Reg: MO1.getReg()); |
1292 | |
1293 | int32_t OffImm = (int32_t)MO2.getImm(); |
1294 | bool isSub = OffImm < 0; |
1295 | |
1296 | assert(((OffImm & 0x3) == 0) && "Not a valid immediate!" ); |
1297 | |
1298 | // Don't print +0. |
1299 | if (OffImm == INT32_MIN) |
1300 | OffImm = 0; |
1301 | if (isSub) { |
1302 | O << ", " ; |
1303 | markup(OS&: O, M: Markup::Immediate) << "#-" << -OffImm; |
1304 | } else if (AlwaysPrintImm0 || OffImm > 0) { |
1305 | O << ", " ; |
1306 | markup(OS&: O, M: Markup::Immediate) << "#" << OffImm; |
1307 | } |
1308 | O << "]" ; |
1309 | } |
1310 | |
1311 | void ARMInstPrinter::printT2AddrModeImm0_1020s4Operand( |
1312 | const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, |
1313 | raw_ostream &O) { |
1314 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
1315 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
1316 | |
1317 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
1318 | O << "[" ; |
1319 | printRegName(OS&: O, Reg: MO1.getReg()); |
1320 | if (MO2.getImm()) { |
1321 | O << ", " ; |
1322 | markup(OS&: O, M: Markup::Immediate) << "#" << formatImm(Value: MO2.getImm() * 4); |
1323 | } |
1324 | O << "]" ; |
1325 | } |
1326 | |
1327 | void ARMInstPrinter::printT2AddrModeImm8OffsetOperand( |
1328 | const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, |
1329 | raw_ostream &O) { |
1330 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
1331 | int32_t OffImm = (int32_t)MO1.getImm(); |
1332 | O << ", " ; |
1333 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Immediate); |
1334 | if (OffImm == INT32_MIN) |
1335 | O << "#-0" ; |
1336 | else if (OffImm < 0) |
1337 | O << "#-" << -OffImm; |
1338 | else |
1339 | O << "#" << OffImm; |
1340 | } |
1341 | |
1342 | void ARMInstPrinter::printT2AddrModeImm8s4OffsetOperand( |
1343 | const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, |
1344 | raw_ostream &O) { |
1345 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
1346 | int32_t OffImm = (int32_t)MO1.getImm(); |
1347 | |
1348 | assert(((OffImm & 0x3) == 0) && "Not a valid immediate!" ); |
1349 | |
1350 | O << ", " ; |
1351 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Immediate); |
1352 | if (OffImm == INT32_MIN) |
1353 | O << "#-0" ; |
1354 | else if (OffImm < 0) |
1355 | O << "#-" << -OffImm; |
1356 | else |
1357 | O << "#" << OffImm; |
1358 | } |
1359 | |
1360 | void ARMInstPrinter::printT2AddrModeSoRegOperand(const MCInst *MI, |
1361 | unsigned OpNum, |
1362 | const MCSubtargetInfo &STI, |
1363 | raw_ostream &O) { |
1364 | const MCOperand &MO1 = MI->getOperand(i: OpNum); |
1365 | const MCOperand &MO2 = MI->getOperand(i: OpNum + 1); |
1366 | const MCOperand &MO3 = MI->getOperand(i: OpNum + 2); |
1367 | |
1368 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Memory); |
1369 | O << "[" ; |
1370 | printRegName(OS&: O, Reg: MO1.getReg()); |
1371 | |
1372 | assert(MO2.getReg() && "Invalid so_reg load / store address!" ); |
1373 | O << ", " ; |
1374 | printRegName(OS&: O, Reg: MO2.getReg()); |
1375 | |
1376 | unsigned ShAmt = MO3.getImm(); |
1377 | if (ShAmt) { |
1378 | assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!" ); |
1379 | O << ", lsl " ; |
1380 | markup(OS&: O, M: Markup::Immediate) << "#" << ShAmt; |
1381 | } |
1382 | O << "]" ; |
1383 | } |
1384 | |
1385 | void ARMInstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum, |
1386 | const MCSubtargetInfo &STI, |
1387 | raw_ostream &O) { |
1388 | const MCOperand &MO = MI->getOperand(i: OpNum); |
1389 | markup(OS&: O, M: Markup::Immediate) << '#' << ARM_AM::getFPImmFloat(Imm: MO.getImm()); |
1390 | } |
1391 | |
1392 | void ARMInstPrinter::printVMOVModImmOperand(const MCInst *MI, unsigned OpNum, |
1393 | const MCSubtargetInfo &STI, |
1394 | raw_ostream &O) { |
1395 | unsigned EncodedImm = MI->getOperand(i: OpNum).getImm(); |
1396 | unsigned EltBits; |
1397 | uint64_t Val = ARM_AM::decodeVMOVModImm(ModImm: EncodedImm, EltBits); |
1398 | |
1399 | WithMarkup ScopedMarkup = markup(OS&: O, M: Markup::Immediate); |
1400 | O << "#0x" ; |
1401 | O.write_hex(N: Val); |
1402 | } |
1403 | |
1404 | void ARMInstPrinter::printImmPlusOneOperand(const MCInst *MI, unsigned OpNum, |
1405 | const MCSubtargetInfo &STI, |
1406 | raw_ostream &O) { |
1407 | unsigned Imm = MI->getOperand(i: OpNum).getImm(); |
1408 | markup(OS&: O, M: Markup::Immediate) << "#" << formatImm(Value: Imm + 1); |
1409 | } |
1410 | |
1411 | void ARMInstPrinter::printRotImmOperand(const MCInst *MI, unsigned OpNum, |
1412 | const MCSubtargetInfo &STI, |
1413 | raw_ostream &O) { |
1414 | unsigned Imm = MI->getOperand(i: OpNum).getImm(); |
1415 | if (Imm == 0) |
1416 | return; |
1417 | assert(Imm <= 3 && "illegal ror immediate!" ); |
1418 | O << ", ror " ; |
1419 | markup(OS&: O, M: Markup::Immediate) << "#" << 8 * Imm; |
1420 | } |
1421 | |
1422 | void ARMInstPrinter::printModImmOperand(const MCInst *MI, unsigned OpNum, |
1423 | const MCSubtargetInfo &STI, |
1424 | raw_ostream &O) { |
1425 | MCOperand Op = MI->getOperand(i: OpNum); |
1426 | |
1427 | // Support for fixups (MCFixup) |
1428 | if (Op.isExpr()) |
1429 | return printOperand(MI, OpNo: OpNum, STI, O); |
1430 | |
1431 | unsigned Bits = Op.getImm() & 0xFF; |
1432 | unsigned Rot = (Op.getImm() & 0xF00) >> 7; |
1433 | |
1434 | bool PrintUnsigned = false; |
1435 | switch (MI->getOpcode()) { |
1436 | case ARM::MOVi: |
1437 | // Movs to PC should be treated unsigned |
1438 | PrintUnsigned = (MI->getOperand(i: OpNum - 1).getReg() == ARM::PC); |
1439 | break; |
1440 | case ARM::MSRi: |
1441 | // Movs to special registers should be treated unsigned |
1442 | PrintUnsigned = true; |
1443 | break; |
1444 | } |
1445 | |
1446 | int32_t Rotated = llvm::rotr<uint32_t>(V: Bits, R: Rot); |
1447 | if (ARM_AM::getSOImmVal(Arg: Rotated) == Op.getImm()) { |
1448 | // #rot has the least possible value |
1449 | O << "#" ; |
1450 | if (PrintUnsigned) |
1451 | markup(OS&: O, M: Markup::Immediate) << static_cast<uint32_t>(Rotated); |
1452 | else |
1453 | markup(OS&: O, M: Markup::Immediate) << Rotated; |
1454 | return; |
1455 | } |
1456 | |
1457 | // Explicit #bits, #rot implied |
1458 | O << "#" ; |
1459 | markup(OS&: O, M: Markup::Immediate) << Bits; |
1460 | O << ", #" ; |
1461 | markup(OS&: O, M: Markup::Immediate) << Rot; |
1462 | } |
1463 | |
1464 | void ARMInstPrinter::printFBits16(const MCInst *MI, unsigned OpNum, |
1465 | const MCSubtargetInfo &STI, raw_ostream &O) { |
1466 | markup(OS&: O, M: Markup::Immediate) << "#" << 16 - MI->getOperand(i: OpNum).getImm(); |
1467 | } |
1468 | |
1469 | void ARMInstPrinter::printFBits32(const MCInst *MI, unsigned OpNum, |
1470 | const MCSubtargetInfo &STI, raw_ostream &O) { |
1471 | markup(OS&: O, M: Markup::Immediate) << "#" << 32 - MI->getOperand(i: OpNum).getImm(); |
1472 | } |
1473 | |
1474 | void ARMInstPrinter::printVectorIndex(const MCInst *MI, unsigned OpNum, |
1475 | const MCSubtargetInfo &STI, |
1476 | raw_ostream &O) { |
1477 | O << "[" << MI->getOperand(i: OpNum).getImm() << "]" ; |
1478 | } |
1479 | |
1480 | void ARMInstPrinter::printVectorListOne(const MCInst *MI, unsigned OpNum, |
1481 | const MCSubtargetInfo &STI, |
1482 | raw_ostream &O) { |
1483 | O << "{" ; |
1484 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1485 | O << "}" ; |
1486 | } |
1487 | |
1488 | void ARMInstPrinter::printVectorListTwo(const MCInst *MI, unsigned OpNum, |
1489 | const MCSubtargetInfo &STI, |
1490 | raw_ostream &O) { |
1491 | MCRegister Reg = MI->getOperand(i: OpNum).getReg(); |
1492 | MCRegister Reg0 = MRI.getSubReg(Reg, Idx: ARM::dsub_0); |
1493 | MCRegister Reg1 = MRI.getSubReg(Reg, Idx: ARM::dsub_1); |
1494 | O << "{" ; |
1495 | printRegName(OS&: O, Reg: Reg0); |
1496 | O << ", " ; |
1497 | printRegName(OS&: O, Reg: Reg1); |
1498 | O << "}" ; |
1499 | } |
1500 | |
1501 | void ARMInstPrinter::printVectorListTwoSpaced(const MCInst *MI, unsigned OpNum, |
1502 | const MCSubtargetInfo &STI, |
1503 | raw_ostream &O) { |
1504 | MCRegister Reg = MI->getOperand(i: OpNum).getReg(); |
1505 | MCRegister Reg0 = MRI.getSubReg(Reg, Idx: ARM::dsub_0); |
1506 | MCRegister Reg1 = MRI.getSubReg(Reg, Idx: ARM::dsub_2); |
1507 | O << "{" ; |
1508 | printRegName(OS&: O, Reg: Reg0); |
1509 | O << ", " ; |
1510 | printRegName(OS&: O, Reg: Reg1); |
1511 | O << "}" ; |
1512 | } |
1513 | |
1514 | void ARMInstPrinter::printVectorListThree(const MCInst *MI, unsigned OpNum, |
1515 | const MCSubtargetInfo &STI, |
1516 | raw_ostream &O) { |
1517 | // Normally, it's not safe to use register enum values directly with |
1518 | // addition to get the next register, but for VFP registers, the |
1519 | // sort order is guaranteed because they're all of the form D<n>. |
1520 | O << "{" ; |
1521 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1522 | O << ", " ; |
1523 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 1); |
1524 | O << ", " ; |
1525 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 2); |
1526 | O << "}" ; |
1527 | } |
1528 | |
1529 | void ARMInstPrinter::printVectorListFour(const MCInst *MI, unsigned OpNum, |
1530 | const MCSubtargetInfo &STI, |
1531 | raw_ostream &O) { |
1532 | // Normally, it's not safe to use register enum values directly with |
1533 | // addition to get the next register, but for VFP registers, the |
1534 | // sort order is guaranteed because they're all of the form D<n>. |
1535 | O << "{" ; |
1536 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1537 | O << ", " ; |
1538 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 1); |
1539 | O << ", " ; |
1540 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 2); |
1541 | O << ", " ; |
1542 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 3); |
1543 | O << "}" ; |
1544 | } |
1545 | |
1546 | void ARMInstPrinter::printVectorListOneAllLanes(const MCInst *MI, |
1547 | unsigned OpNum, |
1548 | const MCSubtargetInfo &STI, |
1549 | raw_ostream &O) { |
1550 | O << "{" ; |
1551 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1552 | O << "[]}" ; |
1553 | } |
1554 | |
1555 | void ARMInstPrinter::printVectorListTwoAllLanes(const MCInst *MI, |
1556 | unsigned OpNum, |
1557 | const MCSubtargetInfo &STI, |
1558 | raw_ostream &O) { |
1559 | MCRegister Reg = MI->getOperand(i: OpNum).getReg(); |
1560 | MCRegister Reg0 = MRI.getSubReg(Reg, Idx: ARM::dsub_0); |
1561 | MCRegister Reg1 = MRI.getSubReg(Reg, Idx: ARM::dsub_1); |
1562 | O << "{" ; |
1563 | printRegName(OS&: O, Reg: Reg0); |
1564 | O << "[], " ; |
1565 | printRegName(OS&: O, Reg: Reg1); |
1566 | O << "[]}" ; |
1567 | } |
1568 | |
1569 | void ARMInstPrinter::printVectorListThreeAllLanes(const MCInst *MI, |
1570 | unsigned OpNum, |
1571 | const MCSubtargetInfo &STI, |
1572 | raw_ostream &O) { |
1573 | // Normally, it's not safe to use register enum values directly with |
1574 | // addition to get the next register, but for VFP registers, the |
1575 | // sort order is guaranteed because they're all of the form D<n>. |
1576 | O << "{" ; |
1577 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1578 | O << "[], " ; |
1579 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 1); |
1580 | O << "[], " ; |
1581 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 2); |
1582 | O << "[]}" ; |
1583 | } |
1584 | |
1585 | void ARMInstPrinter::printVectorListFourAllLanes(const MCInst *MI, |
1586 | unsigned OpNum, |
1587 | const MCSubtargetInfo &STI, |
1588 | raw_ostream &O) { |
1589 | // Normally, it's not safe to use register enum values directly with |
1590 | // addition to get the next register, but for VFP registers, the |
1591 | // sort order is guaranteed because they're all of the form D<n>. |
1592 | O << "{" ; |
1593 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1594 | O << "[], " ; |
1595 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 1); |
1596 | O << "[], " ; |
1597 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 2); |
1598 | O << "[], " ; |
1599 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 3); |
1600 | O << "[]}" ; |
1601 | } |
1602 | |
1603 | void ARMInstPrinter::printVectorListTwoSpacedAllLanes( |
1604 | const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, |
1605 | raw_ostream &O) { |
1606 | MCRegister Reg = MI->getOperand(i: OpNum).getReg(); |
1607 | MCRegister Reg0 = MRI.getSubReg(Reg, Idx: ARM::dsub_0); |
1608 | MCRegister Reg1 = MRI.getSubReg(Reg, Idx: ARM::dsub_2); |
1609 | O << "{" ; |
1610 | printRegName(OS&: O, Reg: Reg0); |
1611 | O << "[], " ; |
1612 | printRegName(OS&: O, Reg: Reg1); |
1613 | O << "[]}" ; |
1614 | } |
1615 | |
1616 | void ARMInstPrinter::printVectorListThreeSpacedAllLanes( |
1617 | const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, |
1618 | raw_ostream &O) { |
1619 | // Normally, it's not safe to use register enum values directly with |
1620 | // addition to get the next register, but for VFP registers, the |
1621 | // sort order is guaranteed because they're all of the form D<n>. |
1622 | O << "{" ; |
1623 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1624 | O << "[], " ; |
1625 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 2); |
1626 | O << "[], " ; |
1627 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 4); |
1628 | O << "[]}" ; |
1629 | } |
1630 | |
1631 | void ARMInstPrinter::printVectorListFourSpacedAllLanes( |
1632 | const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, |
1633 | raw_ostream &O) { |
1634 | // Normally, it's not safe to use register enum values directly with |
1635 | // addition to get the next register, but for VFP registers, the |
1636 | // sort order is guaranteed because they're all of the form D<n>. |
1637 | O << "{" ; |
1638 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1639 | O << "[], " ; |
1640 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 2); |
1641 | O << "[], " ; |
1642 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 4); |
1643 | O << "[], " ; |
1644 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 6); |
1645 | O << "[]}" ; |
1646 | } |
1647 | |
1648 | void ARMInstPrinter::printVectorListThreeSpaced(const MCInst *MI, |
1649 | unsigned OpNum, |
1650 | const MCSubtargetInfo &STI, |
1651 | raw_ostream &O) { |
1652 | // Normally, it's not safe to use register enum values directly with |
1653 | // addition to get the next register, but for VFP registers, the |
1654 | // sort order is guaranteed because they're all of the form D<n>. |
1655 | O << "{" ; |
1656 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1657 | O << ", " ; |
1658 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 2); |
1659 | O << ", " ; |
1660 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 4); |
1661 | O << "}" ; |
1662 | } |
1663 | |
1664 | void ARMInstPrinter::printVectorListFourSpaced(const MCInst *MI, unsigned OpNum, |
1665 | const MCSubtargetInfo &STI, |
1666 | raw_ostream &O) { |
1667 | // Normally, it's not safe to use register enum values directly with |
1668 | // addition to get the next register, but for VFP registers, the |
1669 | // sort order is guaranteed because they're all of the form D<n>. |
1670 | O << "{" ; |
1671 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg()); |
1672 | O << ", " ; |
1673 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 2); |
1674 | O << ", " ; |
1675 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 4); |
1676 | O << ", " ; |
1677 | printRegName(OS&: O, Reg: MI->getOperand(i: OpNum).getReg() + 6); |
1678 | O << "}" ; |
1679 | } |
1680 | |
1681 | template<unsigned NumRegs> |
1682 | void ARMInstPrinter::printMVEVectorList(const MCInst *MI, unsigned OpNum, |
1683 | const MCSubtargetInfo &STI, |
1684 | raw_ostream &O) { |
1685 | MCRegister Reg = MI->getOperand(i: OpNum).getReg(); |
1686 | const char *Prefix = "{" ; |
1687 | for (unsigned i = 0; i < NumRegs; i++) { |
1688 | O << Prefix; |
1689 | printRegName(OS&: O, Reg: MRI.getSubReg(Reg, Idx: ARM::qsub_0 + i)); |
1690 | Prefix = ", " ; |
1691 | } |
1692 | O << "}" ; |
1693 | } |
1694 | |
1695 | template<int64_t Angle, int64_t Remainder> |
1696 | void ARMInstPrinter::printComplexRotationOp(const MCInst *MI, unsigned OpNo, |
1697 | const MCSubtargetInfo &STI, |
1698 | raw_ostream &O) { |
1699 | unsigned Val = MI->getOperand(i: OpNo).getImm(); |
1700 | O << "#" << (Val * Angle) + Remainder; |
1701 | } |
1702 | |
1703 | void ARMInstPrinter::printVPTPredicateOperand(const MCInst *MI, unsigned OpNum, |
1704 | const MCSubtargetInfo &STI, |
1705 | raw_ostream &O) { |
1706 | ARMVCC::VPTCodes CC = (ARMVCC::VPTCodes)MI->getOperand(i: OpNum).getImm(); |
1707 | if (CC != ARMVCC::None) |
1708 | O << ARMVPTPredToString(CC); |
1709 | } |
1710 | |
1711 | void ARMInstPrinter::printVPTMask(const MCInst *MI, unsigned OpNum, |
1712 | const MCSubtargetInfo &STI, |
1713 | raw_ostream &O) { |
1714 | // (3 - the number of trailing zeroes) is the number of them / else. |
1715 | unsigned Mask = MI->getOperand(i: OpNum).getImm(); |
1716 | unsigned NumTZ = llvm::countr_zero(Val: Mask); |
1717 | assert(NumTZ <= 3 && "Invalid VPT mask!" ); |
1718 | for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { |
1719 | bool T = ((Mask >> Pos) & 1) == 0; |
1720 | if (T) |
1721 | O << 't'; |
1722 | else |
1723 | O << 'e'; |
1724 | } |
1725 | } |
1726 | |
1727 | void ARMInstPrinter::printMveSaturateOp(const MCInst *MI, unsigned OpNum, |
1728 | const MCSubtargetInfo &STI, |
1729 | raw_ostream &O) { |
1730 | uint32_t Val = MI->getOperand(i: OpNum).getImm(); |
1731 | assert(Val <= 1 && "Invalid MVE saturate operand" ); |
1732 | O << "#" << (Val == 1 ? 48 : 64); |
1733 | } |
1734 | |