1249259Sdim//==-- AArch64InstPrinter.cpp - Convert AArch64 MCInst to assembly syntax --==//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// This class prints an AArch64 MCInst to a .s file.
11249259Sdim//
12249259Sdim//===----------------------------------------------------------------------===//
13249259Sdim
14249259Sdim#define DEBUG_TYPE "asm-printer"
15249259Sdim#include "AArch64InstPrinter.h"
16249259Sdim#include "MCTargetDesc/AArch64MCTargetDesc.h"
17249259Sdim#include "Utils/AArch64BaseInfo.h"
18249259Sdim#include "llvm/MC/MCInst.h"
19249259Sdim#include "llvm/MC/MCExpr.h"
20249259Sdim#include "llvm/MC/MCRegisterInfo.h"
21249259Sdim#include "llvm/Support/ErrorHandling.h"
22249259Sdim#include "llvm/Support/Format.h"
23249259Sdim#include "llvm/Support/raw_ostream.h"
24249259Sdim
25249259Sdimusing namespace llvm;
26249259Sdim
27249259Sdim#define GET_INSTRUCTION_NAME
28249259Sdim#define PRINT_ALIAS_INSTR
29249259Sdim#include "AArch64GenAsmWriter.inc"
30249259Sdim
31249259Sdimstatic int64_t unpackSignedImm(int BitWidth, uint64_t Value) {
32249259Sdim  assert(!(Value & ~((1ULL << BitWidth)-1)) && "immediate not n-bit");
33249259Sdim  if (Value & (1ULL <<  (BitWidth - 1)))
34249259Sdim    return static_cast<int64_t>(Value) - (1LL << BitWidth);
35249259Sdim  else
36249259Sdim    return Value;
37249259Sdim}
38249259Sdim
39249259SdimAArch64InstPrinter::AArch64InstPrinter(const MCAsmInfo &MAI,
40249259Sdim                                       const MCInstrInfo &MII,
41249259Sdim                                       const MCRegisterInfo &MRI,
42249259Sdim                                       const MCSubtargetInfo &STI) :
43249259Sdim  MCInstPrinter(MAI, MII, MRI) {
44249259Sdim  // Initialize the set of available features.
45249259Sdim  setAvailableFeatures(STI.getFeatureBits());
46249259Sdim}
47249259Sdim
48249259Sdimvoid AArch64InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
49249259Sdim  OS << getRegisterName(RegNo);
50249259Sdim}
51249259Sdim
52249259Sdimvoid
53249259SdimAArch64InstPrinter::printOffsetSImm9Operand(const MCInst *MI,
54249259Sdim                                              unsigned OpNum, raw_ostream &O) {
55249259Sdim  const MCOperand &MOImm = MI->getOperand(OpNum);
56249259Sdim  int32_t Imm = unpackSignedImm(9, MOImm.getImm());
57249259Sdim
58249259Sdim  O << '#' << Imm;
59249259Sdim}
60249259Sdim
61249259Sdimvoid
62249259SdimAArch64InstPrinter::printAddrRegExtendOperand(const MCInst *MI, unsigned OpNum,
63249259Sdim                                          raw_ostream &O, unsigned MemSize,
64249259Sdim                                          unsigned RmSize) {
65249259Sdim  unsigned ExtImm = MI->getOperand(OpNum).getImm();
66249259Sdim  unsigned OptionHi = ExtImm >> 1;
67249259Sdim  unsigned S = ExtImm & 1;
68249259Sdim  bool IsLSL = OptionHi == 1 && RmSize == 64;
69249259Sdim
70249259Sdim  const char *Ext;
71249259Sdim  switch (OptionHi) {
72249259Sdim  case 1:
73249259Sdim    Ext = (RmSize == 32) ? "uxtw" : "lsl";
74249259Sdim    break;
75249259Sdim  case 3:
76249259Sdim    Ext = (RmSize == 32) ? "sxtw" : "sxtx";
77249259Sdim    break;
78249259Sdim  default:
79249259Sdim    llvm_unreachable("Incorrect Option on load/store (reg offset)");
80249259Sdim  }
81249259Sdim  O << Ext;
82249259Sdim
83249259Sdim  if (S) {
84249259Sdim    unsigned ShiftAmt = Log2_32(MemSize);
85249259Sdim    O << " #" << ShiftAmt;
86249259Sdim  } else if (IsLSL) {
87249259Sdim    O << " #0";
88249259Sdim  }
89249259Sdim}
90249259Sdim
91249259Sdimvoid
92249259SdimAArch64InstPrinter::printAddSubImmLSL0Operand(const MCInst *MI,
93249259Sdim                                              unsigned OpNum, raw_ostream &O) {
94249259Sdim  const MCOperand &Imm12Op = MI->getOperand(OpNum);
95249259Sdim
96249259Sdim  if (Imm12Op.isImm()) {
97249259Sdim    int64_t Imm12 = Imm12Op.getImm();
98249259Sdim    assert(Imm12 >= 0 && "Invalid immediate for add/sub imm");
99249259Sdim    O << "#" << Imm12;
100249259Sdim  } else {
101249259Sdim    assert(Imm12Op.isExpr() && "Unexpected shift operand type");
102249259Sdim    O << "#" << *Imm12Op.getExpr();
103249259Sdim  }
104249259Sdim}
105249259Sdim
106249259Sdimvoid
107249259SdimAArch64InstPrinter::printAddSubImmLSL12Operand(const MCInst *MI, unsigned OpNum,
108249259Sdim                                               raw_ostream &O) {
109249259Sdim
110249259Sdim  printAddSubImmLSL0Operand(MI, OpNum, O);
111249259Sdim
112249259Sdim  O << ", lsl #12";
113249259Sdim}
114249259Sdim
115249259Sdimvoid
116249259SdimAArch64InstPrinter::printBareImmOperand(const MCInst *MI, unsigned OpNum,
117249259Sdim                                        raw_ostream &O) {
118249259Sdim  const MCOperand &MO = MI->getOperand(OpNum);
119249259Sdim  O << MO.getImm();
120249259Sdim}
121249259Sdim
122249259Sdimtemplate<unsigned RegWidth> void
123249259SdimAArch64InstPrinter::printBFILSBOperand(const MCInst *MI, unsigned OpNum,
124249259Sdim                                       raw_ostream &O) {
125249259Sdim  const MCOperand &ImmROp = MI->getOperand(OpNum);
126249259Sdim  unsigned LSB = ImmROp.getImm() == 0 ? 0 : RegWidth - ImmROp.getImm();
127249259Sdim
128249259Sdim  O << '#' << LSB;
129249259Sdim}
130249259Sdim
131249259Sdimvoid AArch64InstPrinter::printBFIWidthOperand(const MCInst *MI, unsigned OpNum,
132249259Sdim                                              raw_ostream &O) {
133249259Sdim  const MCOperand &ImmSOp = MI->getOperand(OpNum);
134249259Sdim  unsigned Width = ImmSOp.getImm() + 1;
135249259Sdim
136249259Sdim  O << '#' << Width;
137249259Sdim}
138249259Sdim
139249259Sdimvoid
140249259SdimAArch64InstPrinter::printBFXWidthOperand(const MCInst *MI, unsigned OpNum,
141249259Sdim                                         raw_ostream &O) {
142249259Sdim  const MCOperand &ImmSOp = MI->getOperand(OpNum);
143249259Sdim  const MCOperand &ImmROp = MI->getOperand(OpNum - 1);
144249259Sdim
145249259Sdim  unsigned ImmR = ImmROp.getImm();
146249259Sdim  unsigned ImmS = ImmSOp.getImm();
147249259Sdim
148249259Sdim  assert(ImmS >= ImmR && "Invalid ImmR, ImmS combination for bitfield extract");
149249259Sdim
150249259Sdim  O << '#' << (ImmS - ImmR + 1);
151249259Sdim}
152249259Sdim
153249259Sdimvoid
154249259SdimAArch64InstPrinter::printCRxOperand(const MCInst *MI, unsigned OpNum,
155249259Sdim                                    raw_ostream &O) {
156249259Sdim    const MCOperand &CRx = MI->getOperand(OpNum);
157249259Sdim
158249259Sdim    O << 'c' << CRx.getImm();
159249259Sdim}
160249259Sdim
161249259Sdim
162249259Sdimvoid
163249259SdimAArch64InstPrinter::printCVTFixedPosOperand(const MCInst *MI, unsigned OpNum,
164249259Sdim                                            raw_ostream &O) {
165249259Sdim    const MCOperand &ScaleOp = MI->getOperand(OpNum);
166249259Sdim
167249259Sdim    O << '#' << (64 - ScaleOp.getImm());
168249259Sdim}
169249259Sdim
170249259Sdim
171249259Sdimvoid AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum,
172249259Sdim                                           raw_ostream &o) {
173249259Sdim  const MCOperand &MOImm8 = MI->getOperand(OpNum);
174249259Sdim
175249259Sdim  assert(MOImm8.isImm()
176249259Sdim         && "Immediate operand required for floating-point immediate inst");
177249259Sdim
178249259Sdim  uint32_t Imm8 = MOImm8.getImm();
179249259Sdim  uint32_t Fraction = Imm8 & 0xf;
180249259Sdim  uint32_t Exponent = (Imm8 >> 4) & 0x7;
181249259Sdim  uint32_t Negative = (Imm8 >> 7) & 0x1;
182249259Sdim
183249259Sdim  float Val = 1.0f + Fraction / 16.0f;
184249259Sdim
185249259Sdim  // That is:
186249259Sdim  // 000 -> 2^1,  001 -> 2^2,  010 -> 2^3,  011 -> 2^4,
187249259Sdim  // 100 -> 2^-3, 101 -> 2^-2, 110 -> 2^-1, 111 -> 2^0
188249259Sdim  if (Exponent & 0x4) {
189249259Sdim    Val /= 1 << (7 - Exponent);
190249259Sdim  } else {
191249259Sdim    Val *= 1 << (Exponent + 1);
192249259Sdim  }
193249259Sdim
194249259Sdim  Val = Negative ? -Val : Val;
195249259Sdim
196249259Sdim  o << '#' << format("%.8f", Val);
197249259Sdim}
198249259Sdim
199249259Sdimvoid AArch64InstPrinter::printFPZeroOperand(const MCInst *MI, unsigned OpNum,
200249259Sdim                                            raw_ostream &o) {
201249259Sdim  o << "#0.0";
202249259Sdim}
203249259Sdim
204249259Sdimvoid
205249259SdimAArch64InstPrinter::printCondCodeOperand(const MCInst *MI, unsigned OpNum,
206249259Sdim                                         raw_ostream &O) {
207249259Sdim  const MCOperand &MO = MI->getOperand(OpNum);
208249259Sdim
209249259Sdim  O << A64CondCodeToString(static_cast<A64CC::CondCodes>(MO.getImm()));
210249259Sdim}
211249259Sdim
212249259Sdimtemplate <unsigned field_width, unsigned scale> void
213249259SdimAArch64InstPrinter::printLabelOperand(const MCInst *MI, unsigned OpNum,
214249259Sdim                                            raw_ostream &O) {
215249259Sdim  const MCOperand &MO = MI->getOperand(OpNum);
216249259Sdim
217249259Sdim  if (!MO.isImm()) {
218249259Sdim    printOperand(MI, OpNum, O);
219249259Sdim    return;
220249259Sdim  }
221249259Sdim
222249259Sdim  // The immediate of LDR (lit) instructions is a signed 19-bit immediate, which
223249259Sdim  // is multiplied by 4 (because all A64 instructions are 32-bits wide).
224249259Sdim  uint64_t UImm = MO.getImm();
225249259Sdim  uint64_t Sign = UImm & (1LL << (field_width - 1));
226249259Sdim  int64_t SImm = scale * ((UImm & ~Sign) - Sign);
227249259Sdim
228249259Sdim  O << "#" << SImm;
229249259Sdim}
230249259Sdim
231249259Sdimtemplate<unsigned RegWidth> void
232249259SdimAArch64InstPrinter::printLogicalImmOperand(const MCInst *MI, unsigned OpNum,
233249259Sdim                                           raw_ostream &O) {
234249259Sdim  const MCOperand &MO = MI->getOperand(OpNum);
235249259Sdim  uint64_t Val;
236249259Sdim  A64Imms::isLogicalImmBits(RegWidth, MO.getImm(), Val);
237249259Sdim  O << "#0x";
238249259Sdim  O.write_hex(Val);
239249259Sdim}
240249259Sdim
241249259Sdimvoid
242249259SdimAArch64InstPrinter::printOffsetUImm12Operand(const MCInst *MI, unsigned OpNum,
243249259Sdim                                               raw_ostream &O, int MemSize) {
244249259Sdim  const MCOperand &MOImm = MI->getOperand(OpNum);
245249259Sdim
246249259Sdim  if (MOImm.isImm()) {
247249259Sdim    uint32_t Imm = MOImm.getImm() * MemSize;
248249259Sdim
249249259Sdim    O << "#" << Imm;
250249259Sdim  } else {
251249259Sdim    O << "#" << *MOImm.getExpr();
252249259Sdim  }
253249259Sdim}
254249259Sdim
255249259Sdimvoid
256249259SdimAArch64InstPrinter::printShiftOperand(const MCInst *MI,  unsigned OpNum,
257249259Sdim                                      raw_ostream &O,
258249259Sdim                                      A64SE::ShiftExtSpecifiers Shift) {
259249259Sdim    const MCOperand &MO = MI->getOperand(OpNum);
260249259Sdim
261249259Sdim    // LSL #0 is not printed
262249259Sdim    if (Shift == A64SE::LSL && MO.isImm() && MO.getImm() == 0)
263249259Sdim        return;
264249259Sdim
265249259Sdim    switch (Shift) {
266249259Sdim    case A64SE::LSL: O << "lsl"; break;
267249259Sdim    case A64SE::LSR: O << "lsr"; break;
268249259Sdim    case A64SE::ASR: O << "asr"; break;
269249259Sdim    case A64SE::ROR: O << "ror"; break;
270249259Sdim    default: llvm_unreachable("Invalid shift specifier in logical instruction");
271249259Sdim    }
272249259Sdim
273249259Sdim  O << " #" << MO.getImm();
274249259Sdim}
275249259Sdim
276249259Sdimvoid
277249259SdimAArch64InstPrinter::printMoveWideImmOperand(const MCInst *MI,  unsigned OpNum,
278249259Sdim                                            raw_ostream &O) {
279249259Sdim  const MCOperand &UImm16MO = MI->getOperand(OpNum);
280249259Sdim  const MCOperand &ShiftMO = MI->getOperand(OpNum + 1);
281249259Sdim
282249259Sdim  if (UImm16MO.isImm()) {
283249259Sdim    O << '#' << UImm16MO.getImm();
284249259Sdim
285249259Sdim    if (ShiftMO.getImm() != 0)
286249259Sdim      O << ", lsl #" << (ShiftMO.getImm() * 16);
287249259Sdim
288249259Sdim    return;
289249259Sdim  }
290249259Sdim
291249259Sdim  O << "#" << *UImm16MO.getExpr();
292249259Sdim}
293249259Sdim
294249259Sdimvoid AArch64InstPrinter::printNamedImmOperand(const NamedImmMapper &Mapper,
295249259Sdim                                              const MCInst *MI, unsigned OpNum,
296249259Sdim                                              raw_ostream &O) {
297249259Sdim  bool ValidName;
298249259Sdim  const MCOperand &MO = MI->getOperand(OpNum);
299249259Sdim  StringRef Name = Mapper.toString(MO.getImm(), ValidName);
300249259Sdim
301249259Sdim  if (ValidName)
302249259Sdim    O << Name;
303249259Sdim  else
304249259Sdim    O << '#' << MO.getImm();
305249259Sdim}
306249259Sdim
307249259Sdimvoid
308249259SdimAArch64InstPrinter::printSysRegOperand(const A64SysReg::SysRegMapper &Mapper,
309249259Sdim                                       const MCInst *MI, unsigned OpNum,
310249259Sdim                                       raw_ostream &O) {
311249259Sdim  const MCOperand &MO = MI->getOperand(OpNum);
312249259Sdim
313249259Sdim  bool ValidName;
314249259Sdim  std::string Name = Mapper.toString(MO.getImm(), ValidName);
315249259Sdim  if (ValidName) {
316249259Sdim    O << Name;
317249259Sdim    return;
318249259Sdim  }
319249259Sdim}
320249259Sdim
321249259Sdim
322249259Sdimvoid AArch64InstPrinter::printRegExtendOperand(const MCInst *MI,
323249259Sdim                                               unsigned OpNum,
324249259Sdim                                               raw_ostream &O,
325249259Sdim                                               A64SE::ShiftExtSpecifiers Ext) {
326249259Sdim  // FIXME: In principle TableGen should be able to detect this itself far more
327249259Sdim  // easily. We will only accumulate more of these hacks.
328249259Sdim  unsigned Reg0 = MI->getOperand(0).getReg();
329249259Sdim  unsigned Reg1 = MI->getOperand(1).getReg();
330249259Sdim
331249259Sdim  if (isStackReg(Reg0) || isStackReg(Reg1)) {
332249259Sdim    A64SE::ShiftExtSpecifiers LSLEquiv;
333249259Sdim
334249259Sdim    if (Reg0 == AArch64::XSP || Reg1 == AArch64::XSP)
335249259Sdim      LSLEquiv = A64SE::UXTX;
336249259Sdim    else
337249259Sdim      LSLEquiv = A64SE::UXTW;
338249259Sdim
339249259Sdim    if (Ext == LSLEquiv) {
340249259Sdim      O << "lsl #" << MI->getOperand(OpNum).getImm();
341249259Sdim      return;
342249259Sdim    }
343249259Sdim  }
344249259Sdim
345249259Sdim  switch (Ext) {
346249259Sdim  case A64SE::UXTB: O << "uxtb"; break;
347249259Sdim  case A64SE::UXTH: O << "uxth"; break;
348249259Sdim  case A64SE::UXTW: O << "uxtw"; break;
349249259Sdim  case A64SE::UXTX: O << "uxtx"; break;
350249259Sdim  case A64SE::SXTB: O << "sxtb"; break;
351249259Sdim  case A64SE::SXTH: O << "sxth"; break;
352249259Sdim  case A64SE::SXTW: O << "sxtw"; break;
353249259Sdim  case A64SE::SXTX: O << "sxtx"; break;
354249259Sdim  default: llvm_unreachable("Unexpected shift type for printing");
355249259Sdim  }
356249259Sdim
357249259Sdim  const MCOperand &MO = MI->getOperand(OpNum);
358249259Sdim  if (MO.getImm() != 0)
359249259Sdim    O << " #" << MO.getImm();
360249259Sdim}
361249259Sdim
362249259Sdimtemplate<int MemScale> void
363249259SdimAArch64InstPrinter::printSImm7ScaledOperand(const MCInst *MI, unsigned OpNum,
364249259Sdim                                      raw_ostream &O) {
365249259Sdim  const MCOperand &MOImm = MI->getOperand(OpNum);
366249259Sdim  int32_t Imm = unpackSignedImm(7, MOImm.getImm());
367249259Sdim
368249259Sdim  O << "#" << (Imm * MemScale);
369249259Sdim}
370249259Sdim
371263508Sdimvoid AArch64InstPrinter::printVPRRegister(const MCInst *MI, unsigned OpNo,
372263508Sdim                                          raw_ostream &O) {
373263508Sdim  unsigned Reg = MI->getOperand(OpNo).getReg();
374263508Sdim  std::string Name = getRegisterName(Reg);
375263508Sdim  Name[0] = 'v';
376263508Sdim  O << Name;
377263508Sdim}
378263508Sdim
379249259Sdimvoid AArch64InstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
380249259Sdim                                      raw_ostream &O) {
381249259Sdim  const MCOperand &Op = MI->getOperand(OpNo);
382249259Sdim  if (Op.isReg()) {
383249259Sdim    unsigned Reg = Op.getReg();
384249259Sdim    O << getRegisterName(Reg);
385249259Sdim  } else if (Op.isImm()) {
386249259Sdim    O << '#' << Op.getImm();
387249259Sdim  } else {
388249259Sdim    assert(Op.isExpr() && "unknown operand kind in printOperand");
389249259Sdim    // If a symbolic branch target was added as a constant expression then print
390249259Sdim    // that address in hex.
391249259Sdim    const MCConstantExpr *BranchTarget = dyn_cast<MCConstantExpr>(Op.getExpr());
392249259Sdim    int64_t Address;
393249259Sdim    if (BranchTarget && BranchTarget->EvaluateAsAbsolute(Address)) {
394249259Sdim      O << "0x";
395249259Sdim      O.write_hex(Address);
396249259Sdim    }
397249259Sdim    else {
398249259Sdim      // Otherwise, just print the expression.
399249259Sdim      O << *Op.getExpr();
400249259Sdim    }
401249259Sdim  }
402249259Sdim}
403249259Sdim
404249259Sdim
405249259Sdimvoid AArch64InstPrinter::printInst(const MCInst *MI, raw_ostream &O,
406249259Sdim                                   StringRef Annot) {
407249259Sdim  if (MI->getOpcode() == AArch64::TLSDESCCALL) {
408249259Sdim    // This is a special assembler directive which applies an
409249259Sdim    // R_AARCH64_TLSDESC_CALL to the following (BLR) instruction. It has a fixed
410249259Sdim    // form outside the normal TableGenerated scheme.
411249259Sdim    O << "\t.tlsdesccall " << *MI->getOperand(0).getExpr();
412249259Sdim  } else if (!printAliasInstr(MI, O))
413249259Sdim    printInstruction(MI, O);
414249259Sdim
415249259Sdim  printAnnotation(O, Annot);
416249259Sdim}
417263508Sdim
418263508Sdimtemplate <A64SE::ShiftExtSpecifiers Ext, bool isHalf>
419263508Sdimvoid AArch64InstPrinter::printNeonMovImmShiftOperand(const MCInst *MI,
420263508Sdim                                                     unsigned OpNum,
421263508Sdim                                                     raw_ostream &O) {
422263508Sdim  const MCOperand &MO = MI->getOperand(OpNum);
423263508Sdim
424263508Sdim  assert(MO.isImm() &&
425263508Sdim         "Immediate operand required for Neon vector immediate inst.");
426263508Sdim
427263508Sdim  bool IsLSL = false;
428263508Sdim  if (Ext == A64SE::LSL)
429263508Sdim    IsLSL = true;
430263508Sdim  else if (Ext != A64SE::MSL)
431263508Sdim    llvm_unreachable("Invalid shift specifier in movi instruction");
432263508Sdim
433263508Sdim  int64_t Imm = MO.getImm();
434263508Sdim
435263508Sdim  // MSL and LSLH accepts encoded shift amount 0 or 1.
436263508Sdim  if ((!IsLSL || (IsLSL && isHalf)) && Imm != 0 && Imm != 1)
437263508Sdim    llvm_unreachable("Invalid shift amount in movi instruction");
438263508Sdim
439263508Sdim  // LSH accepts encoded shift amount 0, 1, 2 or 3.
440263508Sdim  if (IsLSL && (Imm < 0 || Imm > 3))
441263508Sdim    llvm_unreachable("Invalid shift amount in movi instruction");
442263508Sdim
443263508Sdim  // Print shift amount as multiple of 8 with MSL encoded shift amount
444263508Sdim  // 0 and 1 printed as 8 and 16.
445263508Sdim  if (!IsLSL)
446263508Sdim    Imm++;
447263508Sdim  Imm *= 8;
448263508Sdim
449263508Sdim  // LSL #0 is not printed
450263508Sdim  if (IsLSL) {
451263508Sdim    if (Imm == 0)
452263508Sdim      return;
453263508Sdim    O << ", lsl";
454263508Sdim  } else
455263508Sdim    O << ", msl";
456263508Sdim
457263508Sdim  O << " #" << Imm;
458263508Sdim}
459263508Sdim
460263508Sdimvoid AArch64InstPrinter::printNeonUImm0Operand(const MCInst *MI, unsigned OpNum,
461263508Sdim                                               raw_ostream &o) {
462263508Sdim  o << "#0x0";
463263508Sdim}
464263508Sdim
465263508Sdimvoid AArch64InstPrinter::printUImmHexOperand(const MCInst *MI, unsigned OpNum,
466263508Sdim                                             raw_ostream &O) {
467263508Sdim  const MCOperand &MOUImm = MI->getOperand(OpNum);
468263508Sdim
469263508Sdim  assert(MOUImm.isImm() &&
470263508Sdim         "Immediate operand required for Neon vector immediate inst.");
471263508Sdim
472263508Sdim  unsigned Imm = MOUImm.getImm();
473263508Sdim
474263508Sdim  O << "#0x";
475263508Sdim  O.write_hex(Imm);
476263508Sdim}
477263508Sdim
478263508Sdimvoid AArch64InstPrinter::printUImmBareOperand(const MCInst *MI,
479263508Sdim                                              unsigned OpNum,
480263508Sdim                                              raw_ostream &O) {
481263508Sdim  const MCOperand &MOUImm = MI->getOperand(OpNum);
482263508Sdim
483263508Sdim  assert(MOUImm.isImm()
484263508Sdim         && "Immediate operand required for Neon vector immediate inst.");
485263508Sdim
486263508Sdim  unsigned Imm = MOUImm.getImm();
487263508Sdim  O << Imm;
488263508Sdim}
489263508Sdim
490263508Sdimvoid AArch64InstPrinter::printNeonUImm64MaskOperand(const MCInst *MI,
491263508Sdim                                                    unsigned OpNum,
492263508Sdim                                                    raw_ostream &O) {
493263508Sdim  const MCOperand &MOUImm8 = MI->getOperand(OpNum);
494263508Sdim
495263508Sdim  assert(MOUImm8.isImm() &&
496263508Sdim         "Immediate operand required for Neon vector immediate bytemask inst.");
497263508Sdim
498263508Sdim  uint32_t UImm8 = MOUImm8.getImm();
499263508Sdim  uint64_t Mask = 0;
500263508Sdim
501263508Sdim  // Replicates 0x00 or 0xff byte in a 64-bit vector
502263508Sdim  for (unsigned ByteNum = 0; ByteNum < 8; ++ByteNum) {
503263508Sdim    if ((UImm8 >> ByteNum) & 1)
504263508Sdim      Mask |= (uint64_t)0xff << (8 * ByteNum);
505263508Sdim  }
506263508Sdim
507263508Sdim  O << "#0x";
508263508Sdim  O.write_hex(Mask);
509263508Sdim}
510263508Sdim
511263508Sdim// If Count > 1, there are two valid kinds of vector list:
512263508Sdim//   (1) {Vn.layout, Vn+1.layout, ... , Vm.layout}
513263508Sdim//   (2) {Vn.layout - Vm.layout}
514263508Sdim// We choose the first kind as output.
515263508Sdimtemplate <A64Layout::VectorLayout Layout, unsigned Count>
516263508Sdimvoid AArch64InstPrinter::printVectorList(const MCInst *MI, unsigned OpNum,
517263508Sdim                                         raw_ostream &O) {
518263508Sdim  assert(Count >= 1 && Count <= 4 && "Invalid Number of Vectors");
519263508Sdim
520263508Sdim  unsigned Reg = MI->getOperand(OpNum).getReg();
521263508Sdim  std::string LayoutStr = A64VectorLayoutToString(Layout);
522263508Sdim  O << "{";
523263508Sdim  if (Count > 1) { // Print sub registers separately
524263508Sdim    bool IsVec64 = (Layout < A64Layout::VL_16B);
525263508Sdim    unsigned SubRegIdx = IsVec64 ? AArch64::dsub_0 : AArch64::qsub_0;
526263508Sdim    for (unsigned I = 0; I < Count; I++) {
527263508Sdim      std::string Name = getRegisterName(MRI.getSubReg(Reg, SubRegIdx++));
528263508Sdim      Name[0] = 'v';
529263508Sdim      O << Name << LayoutStr;
530263508Sdim      if (I != Count - 1)
531263508Sdim        O << ", ";
532263508Sdim    }
533263508Sdim  } else { // Print the register directly when NumVecs is 1.
534263508Sdim    std::string Name = getRegisterName(Reg);
535263508Sdim    Name[0] = 'v';
536263508Sdim    O << Name << LayoutStr;
537263508Sdim  }
538263508Sdim  O << "}";
539263508Sdim}
540