LLVM API Documentation

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AArch64InstPrinter.cpp
Go to the documentation of this file.
1 //==-- AArch64InstPrinter.cpp - Convert AArch64 MCInst to assembly syntax --==//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This class prints an AArch64 MCInst to a .s file.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #define DEBUG_TYPE "asm-printer"
15 #include "AArch64InstPrinter.h"
17 #include "Utils/AArch64BaseInfo.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCExpr.h"
20 #include "llvm/MC/MCRegisterInfo.h"
22 #include "llvm/Support/Format.h"
24 
25 using namespace llvm;
26 
27 #define GET_INSTRUCTION_NAME
28 #define PRINT_ALIAS_INSTR
29 #include "AArch64GenAsmWriter.inc"
30 
31 static int64_t unpackSignedImm(int BitWidth, uint64_t Value) {
32  assert(!(Value & ~((1ULL << BitWidth)-1)) && "immediate not n-bit");
33  if (Value & (1ULL << (BitWidth - 1)))
34  return static_cast<int64_t>(Value) - (1LL << BitWidth);
35  else
36  return Value;
37 }
38 
40  const MCInstrInfo &MII,
41  const MCRegisterInfo &MRI,
42  const MCSubtargetInfo &STI) :
43  MCInstPrinter(MAI, MII, MRI) {
44  // Initialize the set of available features.
46 }
47 
48 void AArch64InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
49  OS << getRegisterName(RegNo);
50 }
51 
52 void
54  unsigned OpNum, raw_ostream &O) {
55  const MCOperand &MOImm = MI->getOperand(OpNum);
56  int32_t Imm = unpackSignedImm(9, MOImm.getImm());
57 
58  O << '#' << Imm;
59 }
60 
61 void
63  raw_ostream &O, unsigned MemSize,
64  unsigned RmSize) {
65  unsigned ExtImm = MI->getOperand(OpNum).getImm();
66  unsigned OptionHi = ExtImm >> 1;
67  unsigned S = ExtImm & 1;
68  bool IsLSL = OptionHi == 1 && RmSize == 64;
69 
70  const char *Ext;
71  switch (OptionHi) {
72  case 1:
73  Ext = (RmSize == 32) ? "uxtw" : "lsl";
74  break;
75  case 3:
76  Ext = (RmSize == 32) ? "sxtw" : "sxtx";
77  break;
78  default:
79  llvm_unreachable("Incorrect Option on load/store (reg offset)");
80  }
81  O << Ext;
82 
83  if (S) {
84  unsigned ShiftAmt = Log2_32(MemSize);
85  O << " #" << ShiftAmt;
86  } else if (IsLSL) {
87  O << " #0";
88  }
89 }
90 
91 void
93  unsigned OpNum, raw_ostream &O) {
94  const MCOperand &Imm12Op = MI->getOperand(OpNum);
95 
96  if (Imm12Op.isImm()) {
97  int64_t Imm12 = Imm12Op.getImm();
98  assert(Imm12 >= 0 && "Invalid immediate for add/sub imm");
99  O << "#" << Imm12;
100  } else {
101  assert(Imm12Op.isExpr() && "Unexpected shift operand type");
102  O << "#" << *Imm12Op.getExpr();
103  }
104 }
105 
106 void
108  raw_ostream &O) {
109 
110  printAddSubImmLSL0Operand(MI, OpNum, O);
111 
112  O << ", lsl #12";
113 }
114 
115 void
117  raw_ostream &O) {
118  const MCOperand &MO = MI->getOperand(OpNum);
119  O << MO.getImm();
120 }
121 
122 template<unsigned RegWidth> void
124  raw_ostream &O) {
125  const MCOperand &ImmROp = MI->getOperand(OpNum);
126  unsigned LSB = ImmROp.getImm() == 0 ? 0 : RegWidth - ImmROp.getImm();
127 
128  O << '#' << LSB;
129 }
130 
132  raw_ostream &O) {
133  const MCOperand &ImmSOp = MI->getOperand(OpNum);
134  unsigned Width = ImmSOp.getImm() + 1;
135 
136  O << '#' << Width;
137 }
138 
139 void
141  raw_ostream &O) {
142  const MCOperand &ImmSOp = MI->getOperand(OpNum);
143  const MCOperand &ImmROp = MI->getOperand(OpNum - 1);
144 
145  unsigned ImmR = ImmROp.getImm();
146  unsigned ImmS = ImmSOp.getImm();
147 
148  assert(ImmS >= ImmR && "Invalid ImmR, ImmS combination for bitfield extract");
149 
150  O << '#' << (ImmS - ImmR + 1);
151 }
152 
153 void
155  raw_ostream &O) {
156  const MCOperand &CRx = MI->getOperand(OpNum);
157 
158  O << 'c' << CRx.getImm();
159 }
160 
161 
162 void
164  raw_ostream &O) {
165  const MCOperand &ScaleOp = MI->getOperand(OpNum);
166 
167  O << '#' << (64 - ScaleOp.getImm());
168 }
169 
170 
171 void AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum,
172  raw_ostream &o) {
173  const MCOperand &MOImm8 = MI->getOperand(OpNum);
174 
175  assert(MOImm8.isImm()
176  && "Immediate operand required for floating-point immediate inst");
177 
178  uint32_t Imm8 = MOImm8.getImm();
179  uint32_t Fraction = Imm8 & 0xf;
180  uint32_t Exponent = (Imm8 >> 4) & 0x7;
181  uint32_t Negative = (Imm8 >> 7) & 0x1;
182 
183  float Val = 1.0f + Fraction / 16.0f;
184 
185  // That is:
186  // 000 -> 2^1, 001 -> 2^2, 010 -> 2^3, 011 -> 2^4,
187  // 100 -> 2^-3, 101 -> 2^-2, 110 -> 2^-1, 111 -> 2^0
188  if (Exponent & 0x4) {
189  Val /= 1 << (7 - Exponent);
190  } else {
191  Val *= 1 << (Exponent + 1);
192  }
193 
194  Val = Negative ? -Val : Val;
195 
196  o << '#' << format("%.8f", Val);
197 }
198 
200  raw_ostream &o) {
201  o << "#0.0";
202 }
203 
204 void
206  raw_ostream &O) {
207  const MCOperand &MO = MI->getOperand(OpNum);
208 
209  O << A64CondCodeToString(static_cast<A64CC::CondCodes>(MO.getImm()));
210 }
211 
212 template <unsigned field_width, unsigned scale> void
214  raw_ostream &O) {
215  const MCOperand &MO = MI->getOperand(OpNum);
216 
217  if (!MO.isImm()) {
218  printOperand(MI, OpNum, O);
219  return;
220  }
221 
222  // The immediate of LDR (lit) instructions is a signed 19-bit immediate, which
223  // is multiplied by 4 (because all A64 instructions are 32-bits wide).
224  uint64_t UImm = MO.getImm();
225  uint64_t Sign = UImm & (1LL << (field_width - 1));
226  int64_t SImm = scale * ((UImm & ~Sign) - Sign);
227 
228  O << "#" << SImm;
229 }
230 
231 template<unsigned RegWidth> void
233  raw_ostream &O) {
234  const MCOperand &MO = MI->getOperand(OpNum);
235  uint64_t Val;
236  A64Imms::isLogicalImmBits(RegWidth, MO.getImm(), Val);
237  O << "#0x";
238  O.write_hex(Val);
239 }
240 
241 void
243  raw_ostream &O, int MemSize) {
244  const MCOperand &MOImm = MI->getOperand(OpNum);
245 
246  if (MOImm.isImm()) {
247  uint32_t Imm = MOImm.getImm() * MemSize;
248 
249  O << "#" << Imm;
250  } else {
251  O << "#" << *MOImm.getExpr();
252  }
253 }
254 
255 void
257  raw_ostream &O,
259  const MCOperand &MO = MI->getOperand(OpNum);
260 
261  // LSL #0 is not printed
262  if (Shift == A64SE::LSL && MO.isImm() && MO.getImm() == 0)
263  return;
264 
265  switch (Shift) {
266  case A64SE::LSL: O << "lsl"; break;
267  case A64SE::LSR: O << "lsr"; break;
268  case A64SE::ASR: O << "asr"; break;
269  case A64SE::ROR: O << "ror"; break;
270  default: llvm_unreachable("Invalid shift specifier in logical instruction");
271  }
272 
273  O << " #" << MO.getImm();
274 }
275 
276 void
278  raw_ostream &O) {
279  const MCOperand &UImm16MO = MI->getOperand(OpNum);
280  const MCOperand &ShiftMO = MI->getOperand(OpNum + 1);
281 
282  if (UImm16MO.isImm()) {
283  O << '#' << UImm16MO.getImm();
284 
285  if (ShiftMO.getImm() != 0)
286  O << ", lsl #" << (ShiftMO.getImm() * 16);
287 
288  return;
289  }
290 
291  O << "#" << *UImm16MO.getExpr();
292 }
293 
295  const MCInst *MI, unsigned OpNum,
296  raw_ostream &O) {
297  bool ValidName;
298  const MCOperand &MO = MI->getOperand(OpNum);
299  StringRef Name = Mapper.toString(MO.getImm(), ValidName);
300 
301  if (ValidName)
302  O << Name;
303  else
304  O << '#' << MO.getImm();
305 }
306 
307 void
309  const MCInst *MI, unsigned OpNum,
310  raw_ostream &O) {
311  const MCOperand &MO = MI->getOperand(OpNum);
312 
313  bool ValidName;
314  std::string Name = Mapper.toString(MO.getImm(), ValidName);
315  if (ValidName) {
316  O << Name;
317  return;
318  }
319 }
320 
321 
323  unsigned OpNum,
324  raw_ostream &O,
326  // FIXME: In principle TableGen should be able to detect this itself far more
327  // easily. We will only accumulate more of these hacks.
328  unsigned Reg0 = MI->getOperand(0).getReg();
329  unsigned Reg1 = MI->getOperand(1).getReg();
330 
331  if (isStackReg(Reg0) || isStackReg(Reg1)) {
332  A64SE::ShiftExtSpecifiers LSLEquiv;
333 
334  if (Reg0 == AArch64::XSP || Reg1 == AArch64::XSP)
335  LSLEquiv = A64SE::UXTX;
336  else
337  LSLEquiv = A64SE::UXTW;
338 
339  if (Ext == LSLEquiv) {
340  O << "lsl #" << MI->getOperand(OpNum).getImm();
341  return;
342  }
343  }
344 
345  switch (Ext) {
346  case A64SE::UXTB: O << "uxtb"; break;
347  case A64SE::UXTH: O << "uxth"; break;
348  case A64SE::UXTW: O << "uxtw"; break;
349  case A64SE::UXTX: O << "uxtx"; break;
350  case A64SE::SXTB: O << "sxtb"; break;
351  case A64SE::SXTH: O << "sxth"; break;
352  case A64SE::SXTW: O << "sxtw"; break;
353  case A64SE::SXTX: O << "sxtx"; break;
354  default: llvm_unreachable("Unexpected shift type for printing");
355  }
356 
357  const MCOperand &MO = MI->getOperand(OpNum);
358  if (MO.getImm() != 0)
359  O << " #" << MO.getImm();
360 }
361 
362 template<int MemScale> void
364  raw_ostream &O) {
365  const MCOperand &MOImm = MI->getOperand(OpNum);
366  int32_t Imm = unpackSignedImm(7, MOImm.getImm());
367 
368  O << "#" << (Imm * MemScale);
369 }
370 
371 void AArch64InstPrinter::printVPRRegister(const MCInst *MI, unsigned OpNo,
372  raw_ostream &O) {
373  unsigned Reg = MI->getOperand(OpNo).getReg();
374  std::string Name = getRegisterName(Reg);
375  Name[0] = 'v';
376  O << Name;
377 }
378 
379 void AArch64InstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
380  raw_ostream &O) {
381  const MCOperand &Op = MI->getOperand(OpNo);
382  if (Op.isReg()) {
383  unsigned Reg = Op.getReg();
384  O << getRegisterName(Reg);
385  } else if (Op.isImm()) {
386  O << '#' << Op.getImm();
387  } else {
388  assert(Op.isExpr() && "unknown operand kind in printOperand");
389  // If a symbolic branch target was added as a constant expression then print
390  // that address in hex.
391  const MCConstantExpr *BranchTarget = dyn_cast<MCConstantExpr>(Op.getExpr());
392  int64_t Address;
393  if (BranchTarget && BranchTarget->EvaluateAsAbsolute(Address)) {
394  O << "0x";
395  O.write_hex(Address);
396  }
397  else {
398  // Otherwise, just print the expression.
399  O << *Op.getExpr();
400  }
401  }
402 }
403 
404 
406  StringRef Annot) {
407  if (MI->getOpcode() == AArch64::TLSDESCCALL) {
408  // This is a special assembler directive which applies an
409  // R_AARCH64_TLSDESC_CALL to the following (BLR) instruction. It has a fixed
410  // form outside the normal TableGenerated scheme.
411  O << "\t.tlsdesccall " << *MI->getOperand(0).getExpr();
412  } else if (!printAliasInstr(MI, O))
413  printInstruction(MI, O);
414 
415  printAnnotation(O, Annot);
416 }
417 
418 template <A64SE::ShiftExtSpecifiers Ext, bool isHalf>
420  unsigned OpNum,
421  raw_ostream &O) {
422  const MCOperand &MO = MI->getOperand(OpNum);
423 
424  assert(MO.isImm() &&
425  "Immediate operand required for Neon vector immediate inst.");
426 
427  bool IsLSL = false;
428  if (Ext == A64SE::LSL)
429  IsLSL = true;
430  else if (Ext != A64SE::MSL)
431  llvm_unreachable("Invalid shift specifier in movi instruction");
432 
433  int64_t Imm = MO.getImm();
434 
435  // MSL and LSLH accepts encoded shift amount 0 or 1.
436  if ((!IsLSL || (IsLSL && isHalf)) && Imm != 0 && Imm != 1)
437  llvm_unreachable("Invalid shift amount in movi instruction");
438 
439  // LSH accepts encoded shift amount 0, 1, 2 or 3.
440  if (IsLSL && (Imm < 0 || Imm > 3))
441  llvm_unreachable("Invalid shift amount in movi instruction");
442 
443  // Print shift amount as multiple of 8 with MSL encoded shift amount
444  // 0 and 1 printed as 8 and 16.
445  if (!IsLSL)
446  Imm++;
447  Imm *= 8;
448 
449  // LSL #0 is not printed
450  if (IsLSL) {
451  if (Imm == 0)
452  return;
453  O << ", lsl";
454  } else
455  O << ", msl";
456 
457  O << " #" << Imm;
458 }
459 
461  raw_ostream &o) {
462  o << "#0x0";
463 }
464 
466  raw_ostream &O) {
467  const MCOperand &MOUImm = MI->getOperand(OpNum);
468 
469  assert(MOUImm.isImm() &&
470  "Immediate operand required for Neon vector immediate inst.");
471 
472  unsigned Imm = MOUImm.getImm();
473 
474  O << "#0x";
475  O.write_hex(Imm);
476 }
477 
479  unsigned OpNum,
480  raw_ostream &O) {
481  const MCOperand &MOUImm = MI->getOperand(OpNum);
482 
483  assert(MOUImm.isImm()
484  && "Immediate operand required for Neon vector immediate inst.");
485 
486  unsigned Imm = MOUImm.getImm();
487  O << Imm;
488 }
489 
491  unsigned OpNum,
492  raw_ostream &O) {
493  const MCOperand &MOUImm8 = MI->getOperand(OpNum);
494 
495  assert(MOUImm8.isImm() &&
496  "Immediate operand required for Neon vector immediate bytemask inst.");
497 
498  uint32_t UImm8 = MOUImm8.getImm();
499  uint64_t Mask = 0;
500 
501  // Replicates 0x00 or 0xff byte in a 64-bit vector
502  for (unsigned ByteNum = 0; ByteNum < 8; ++ByteNum) {
503  if ((UImm8 >> ByteNum) & 1)
504  Mask |= (uint64_t)0xff << (8 * ByteNum);
505  }
506 
507  O << "#0x";
508  O.write_hex(Mask);
509 }
510 
511 // If Count > 1, there are two valid kinds of vector list:
512 // (1) {Vn.layout, Vn+1.layout, ... , Vm.layout}
513 // (2) {Vn.layout - Vm.layout}
514 // We choose the first kind as output.
515 template <A64Layout::VectorLayout Layout, unsigned Count>
516 void AArch64InstPrinter::printVectorList(const MCInst *MI, unsigned OpNum,
517  raw_ostream &O) {
518  assert(Count >= 1 && Count <= 4 && "Invalid Number of Vectors");
519 
520  unsigned Reg = MI->getOperand(OpNum).getReg();
521  std::string LayoutStr = A64VectorLayoutToString(Layout);
522  O << "{";
523  if (Count > 1) { // Print sub registers separately
524  bool IsVec64 = (Layout < A64Layout::VL_16B);
525  unsigned SubRegIdx = IsVec64 ? AArch64::dsub_0 : AArch64::qsub_0;
526  for (unsigned I = 0; I < Count; I++) {
527  std::string Name = getRegisterName(MRI.getSubReg(Reg, SubRegIdx++));
528  Name[0] = 'v';
529  O << Name << LayoutStr;
530  if (I != Count - 1)
531  O << ", ";
532  }
533  } else { // Print the register directly when NumVecs is 1.
534  std::string Name = getRegisterName(Reg);
535  Name[0] = 'v';
536  O << Name << LayoutStr;
537  }
538  O << "}";
539 }
virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot)
bool isReg() const
Definition: MCInst.h:56
void printBFIWidthOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
enable_if_c<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:266
void printNeonMovImmShiftOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
bool isLogicalImmBits(unsigned RegWidth, uint32_t Bits, uint64_t &Imm)
void printSysRegOperand(const A64SysReg::SysRegMapper &Mapper, const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printInstruction(const MCInst *MI, raw_ostream &O)
void printBFILSBOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printFPImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &o)
bool isStackReg(unsigned RegNo)
void printOffsetSImm9Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
bool printAliasInstr(const MCInst *MI, raw_ostream &O)
#define llvm_unreachable(msg)
void printCVTFixedPosOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printRegName(raw_ostream &O, unsigned RegNum) const
printRegName - Print the assembler register name.
format_object1< T > format(const char *Fmt, const T &Val)
Definition: Format.h:180
void printAddSubImmLSL12Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
unsigned getReg() const
getReg - Returns the register number.
Definition: MCInst.h:63
raw_ostream & write_hex(unsigned long long N)
write_hex - Output N in hexadecimal, without any prefix or padding.
void printRegExtendOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printUImmHexOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printLabelOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
bool isImm() const
Definition: MCInst.h:57
const MCExpr * getExpr() const
Definition: MCInst.h:93
static const char * A64VectorLayoutToString(A64Layout::VectorLayout Layout)
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O)
const MCInstrInfo & MII
unsigned getSubReg(unsigned Reg, unsigned Idx) const
Returns the physical register number of sub-register "Index" for physical register RegNo...
void printNeonUImm0Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
bool isExpr() const
Definition: MCInst.h:59
void printLogicalImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printCRxOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printOffsetUImm12Operand(const MCInst *MI, unsigned OpNum, raw_ostream &o)
AArch64InstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI, const MCSubtargetInfo &STI)
void printVPRRegister(const MCInst *MI, unsigned OpNo, raw_ostream &O)
uint64_t getFeatureBits() const
void printVectorList(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printSImm7ScaledOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
static int64_t unpackSignedImm(int BitWidth, uint64_t Value)
static const char * getRegisterName(unsigned RegNo)
void printShiftOperand(const char *name, const MCInst *MI, unsigned OpIdx, raw_ostream &O)
unsigned Log2_32(uint32_t Value)
Definition: MathExtras.h:443
void printBareImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
unsigned getOpcode() const
Definition: MCInst.h:158
void printBFXWidthOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
std::string toString(uint32_t Bits, bool &Valid) const
int64_t getImm() const
Definition: MCInst.h:74
StringRef toString(uint32_t Value, bool &Valid) const
void printMoveWideImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
#define I(x, y, z)
Definition: MD5.cpp:54
void printAddrRegExtendOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printNeonUImm64MaskOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
LLVM Value Representation.
Definition: Value.h:66
void printAnnotation(raw_ostream &OS, StringRef Annot)
Utility function for printing annotations.
void setAvailableFeatures(uint64_t Value)
Definition: MCInstPrinter.h:81
void printFPZeroOperand(const MCInst *MI, unsigned OpNum, raw_ostream &o)
const MCRegisterInfo & MRI
void printUImmBareOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printCondCodeOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
void printAddSubImmLSL0Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:163
void printNamedImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O)
const MCRegisterInfo & MRI
Definition: MCInstPrinter.h:41