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