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"
16 #include "MCTargetDesc/AArch64MCTargetDesc.h"
17 #include "Utils/AArch64BaseInfo.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCExpr.h"
20 #include "llvm/MC/MCRegisterInfo.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/Format.h"
23 #include "llvm/Support/raw_ostream.h"
24
25 using namespace llvm;
26
27 #define GET_INSTRUCTION_NAME
28 #define PRINT_ALIAS_INSTR
29 #include "AArch64GenAsmWriter.inc"
30
unpackSignedImm(int BitWidth,uint64_t Value)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
AArch64InstPrinter(const MCAsmInfo & MAI,const MCInstrInfo & MII,const MCRegisterInfo & MRI,const MCSubtargetInfo & STI)39 AArch64InstPrinter::AArch64InstPrinter(const MCAsmInfo &MAI,
40 const MCInstrInfo &MII,
41 const MCRegisterInfo &MRI,
42 const MCSubtargetInfo &STI) :
43 MCInstPrinter(MAI, MII, MRI) {
44 // Initialize the set of available features.
45 setAvailableFeatures(STI.getFeatureBits());
46 }
47
printRegName(raw_ostream & OS,unsigned RegNo) const48 void AArch64InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
49 OS << getRegisterName(RegNo);
50 }
51
52 void
printOffsetSImm9Operand(const MCInst * MI,unsigned OpNum,raw_ostream & O)53 AArch64InstPrinter::printOffsetSImm9Operand(const MCInst *MI,
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
printAddrRegExtendOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O,unsigned MemSize,unsigned RmSize)62 AArch64InstPrinter::printAddrRegExtendOperand(const MCInst *MI, unsigned OpNum,
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
printAddSubImmLSL0Operand(const MCInst * MI,unsigned OpNum,raw_ostream & O)92 AArch64InstPrinter::printAddSubImmLSL0Operand(const MCInst *MI,
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
printAddSubImmLSL12Operand(const MCInst * MI,unsigned OpNum,raw_ostream & O)107 AArch64InstPrinter::printAddSubImmLSL12Operand(const MCInst *MI, unsigned OpNum,
108 raw_ostream &O) {
109
110 printAddSubImmLSL0Operand(MI, OpNum, O);
111
112 O << ", lsl #12";
113 }
114
115 void
printBareImmOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)116 AArch64InstPrinter::printBareImmOperand(const MCInst *MI, unsigned OpNum,
117 raw_ostream &O) {
118 const MCOperand &MO = MI->getOperand(OpNum);
119 O << MO.getImm();
120 }
121
122 template<unsigned RegWidth> void
printBFILSBOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)123 AArch64InstPrinter::printBFILSBOperand(const MCInst *MI, unsigned OpNum,
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
printBFIWidthOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)131 void AArch64InstPrinter::printBFIWidthOperand(const MCInst *MI, unsigned OpNum,
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
printBFXWidthOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)140 AArch64InstPrinter::printBFXWidthOperand(const MCInst *MI, unsigned OpNum,
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
printCRxOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)154 AArch64InstPrinter::printCRxOperand(const MCInst *MI, unsigned OpNum,
155 raw_ostream &O) {
156 const MCOperand &CRx = MI->getOperand(OpNum);
157
158 O << 'c' << CRx.getImm();
159 }
160
161
162 void
printCVTFixedPosOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)163 AArch64InstPrinter::printCVTFixedPosOperand(const MCInst *MI, unsigned OpNum,
164 raw_ostream &O) {
165 const MCOperand &ScaleOp = MI->getOperand(OpNum);
166
167 O << '#' << (64 - ScaleOp.getImm());
168 }
169
170
printFPImmOperand(const MCInst * MI,unsigned OpNum,raw_ostream & o)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
printFPZeroOperand(const MCInst * MI,unsigned OpNum,raw_ostream & o)199 void AArch64InstPrinter::printFPZeroOperand(const MCInst *MI, unsigned OpNum,
200 raw_ostream &o) {
201 o << "#0.0";
202 }
203
204 void
printCondCodeOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)205 AArch64InstPrinter::printCondCodeOperand(const MCInst *MI, unsigned OpNum,
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
printLabelOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)213 AArch64InstPrinter::printLabelOperand(const MCInst *MI, unsigned OpNum,
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
printLogicalImmOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)232 AArch64InstPrinter::printLogicalImmOperand(const MCInst *MI, unsigned OpNum,
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
printOffsetUImm12Operand(const MCInst * MI,unsigned OpNum,raw_ostream & O,int MemSize)242 AArch64InstPrinter::printOffsetUImm12Operand(const MCInst *MI, unsigned OpNum,
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
printShiftOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O,A64SE::ShiftExtSpecifiers Shift)256 AArch64InstPrinter::printShiftOperand(const MCInst *MI, unsigned OpNum,
257 raw_ostream &O,
258 A64SE::ShiftExtSpecifiers Shift) {
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
printMoveWideImmOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)277 AArch64InstPrinter::printMoveWideImmOperand(const MCInst *MI, unsigned OpNum,
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
printNamedImmOperand(const NamedImmMapper & Mapper,const MCInst * MI,unsigned OpNum,raw_ostream & O)294 void AArch64InstPrinter::printNamedImmOperand(const NamedImmMapper &Mapper,
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
printSysRegOperand(const A64SysReg::SysRegMapper & Mapper,const MCInst * MI,unsigned OpNum,raw_ostream & O)308 AArch64InstPrinter::printSysRegOperand(const A64SysReg::SysRegMapper &Mapper,
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
printRegExtendOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O,A64SE::ShiftExtSpecifiers Ext)322 void AArch64InstPrinter::printRegExtendOperand(const MCInst *MI,
323 unsigned OpNum,
324 raw_ostream &O,
325 A64SE::ShiftExtSpecifiers Ext) {
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
printSImm7ScaledOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)363 AArch64InstPrinter::printSImm7ScaledOperand(const MCInst *MI, unsigned OpNum,
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
printVPRRegister(const MCInst * MI,unsigned OpNo,raw_ostream & O)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
printOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)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
printInst(const MCInst * MI,raw_ostream & O,StringRef Annot)405 void AArch64InstPrinter::printInst(const MCInst *MI, raw_ostream &O,
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>
printNeonMovImmShiftOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)419 void AArch64InstPrinter::printNeonMovImmShiftOperand(const MCInst *MI,
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
printNeonUImm0Operand(const MCInst * MI,unsigned OpNum,raw_ostream & o)460 void AArch64InstPrinter::printNeonUImm0Operand(const MCInst *MI, unsigned OpNum,
461 raw_ostream &o) {
462 o << "#0x0";
463 }
464
printUImmHexOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)465 void AArch64InstPrinter::printUImmHexOperand(const MCInst *MI, unsigned OpNum,
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
printUImmBareOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)478 void AArch64InstPrinter::printUImmBareOperand(const MCInst *MI,
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
printNeonUImm64MaskOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)490 void AArch64InstPrinter::printNeonUImm64MaskOperand(const MCInst *MI,
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>
printVectorList(const MCInst * MI,unsigned OpNum,raw_ostream & O)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 }
540