1 //==-- AArch64InstPrinter.cpp - Convert AArch64 MCInst to assembly syntax --==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This class prints an AArch64 MCInst to a .s file.
12 //===----------------------------------------------------------------------===//
14 #include "AArch64InstPrinter.h"
15 #include "MCTargetDesc/AArch64MCTargetDesc.h"
16 #include "Utils/AArch64BaseInfo.h"
17 #include "llvm/MC/MCExpr.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCRegisterInfo.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include "llvm/Support/Format.h"
22 #include "llvm/Support/raw_ostream.h"
26 #define DEBUG_TYPE "asm-printer"
28 #define GET_INSTRUCTION_NAME
29 #define PRINT_ALIAS_INSTR
30 #include "AArch64GenAsmWriter.inc"
32 static int64_t unpackSignedImm(int BitWidth, uint64_t Value) {
33 assert(!(Value & ~((1ULL << BitWidth)-1)) && "immediate not n-bit");
34 if (Value & (1ULL << (BitWidth - 1)))
35 return static_cast<int64_t>(Value) - (1LL << BitWidth);
40 AArch64InstPrinter::AArch64InstPrinter(const MCAsmInfo &MAI,
41 const MCInstrInfo &MII,
42 const MCRegisterInfo &MRI,
43 const MCSubtargetInfo &STI) :
44 MCInstPrinter(MAI, MII, MRI) {
45 // Initialize the set of available features.
46 setAvailableFeatures(STI.getFeatureBits());
49 void AArch64InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
50 OS << getRegisterName(RegNo);
54 AArch64InstPrinter::printOffsetSImm9Operand(const MCInst *MI,
55 unsigned OpNum, raw_ostream &O) {
56 const MCOperand &MOImm = MI->getOperand(OpNum);
57 int32_t Imm = unpackSignedImm(9, MOImm.getImm());
63 AArch64InstPrinter::printAddrRegExtendOperand(const MCInst *MI, unsigned OpNum,
64 raw_ostream &O, unsigned MemSize,
66 unsigned ExtImm = MI->getOperand(OpNum).getImm();
67 unsigned OptionHi = ExtImm >> 1;
68 unsigned S = ExtImm & 1;
69 bool IsLSL = OptionHi == 1 && RmSize == 64;
74 Ext = (RmSize == 32) ? "uxtw" : "lsl";
77 Ext = (RmSize == 32) ? "sxtw" : "sxtx";
80 llvm_unreachable("Incorrect Option on load/store (reg offset)");
85 unsigned ShiftAmt = Log2_32(MemSize);
86 O << " #" << ShiftAmt;
93 AArch64InstPrinter::printAddSubImmLSL0Operand(const MCInst *MI,
94 unsigned OpNum, raw_ostream &O) {
95 const MCOperand &Imm12Op = MI->getOperand(OpNum);
97 if (Imm12Op.isImm()) {
98 int64_t Imm12 = Imm12Op.getImm();
99 assert(Imm12 >= 0 && "Invalid immediate for add/sub imm");
102 assert(Imm12Op.isExpr() && "Unexpected shift operand type");
103 O << "#" << *Imm12Op.getExpr();
108 AArch64InstPrinter::printAddSubImmLSL12Operand(const MCInst *MI, unsigned OpNum,
111 printAddSubImmLSL0Operand(MI, OpNum, O);
117 AArch64InstPrinter::printBareImmOperand(const MCInst *MI, unsigned OpNum,
119 const MCOperand &MO = MI->getOperand(OpNum);
123 template<unsigned RegWidth> void
124 AArch64InstPrinter::printBFILSBOperand(const MCInst *MI, unsigned OpNum,
126 const MCOperand &ImmROp = MI->getOperand(OpNum);
127 unsigned LSB = ImmROp.getImm() == 0 ? 0 : RegWidth - ImmROp.getImm();
132 void AArch64InstPrinter::printBFIWidthOperand(const MCInst *MI, unsigned OpNum,
134 const MCOperand &ImmSOp = MI->getOperand(OpNum);
135 unsigned Width = ImmSOp.getImm() + 1;
141 AArch64InstPrinter::printBFXWidthOperand(const MCInst *MI, unsigned OpNum,
143 const MCOperand &ImmSOp = MI->getOperand(OpNum);
144 const MCOperand &ImmROp = MI->getOperand(OpNum - 1);
146 unsigned ImmR = ImmROp.getImm();
147 unsigned ImmS = ImmSOp.getImm();
149 assert(ImmS >= ImmR && "Invalid ImmR, ImmS combination for bitfield extract");
151 O << '#' << (ImmS - ImmR + 1);
155 AArch64InstPrinter::printCRxOperand(const MCInst *MI, unsigned OpNum,
157 const MCOperand &CRx = MI->getOperand(OpNum);
159 O << 'c' << CRx.getImm();
164 AArch64InstPrinter::printCVTFixedPosOperand(const MCInst *MI, unsigned OpNum,
166 const MCOperand &ScaleOp = MI->getOperand(OpNum);
168 O << '#' << (64 - ScaleOp.getImm());
172 void AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum,
174 const MCOperand &MOImm8 = MI->getOperand(OpNum);
176 assert(MOImm8.isImm()
177 && "Immediate operand required for floating-point immediate inst");
179 uint32_t Imm8 = MOImm8.getImm();
180 uint32_t Fraction = Imm8 & 0xf;
181 uint32_t Exponent = (Imm8 >> 4) & 0x7;
182 uint32_t Negative = (Imm8 >> 7) & 0x1;
184 float Val = 1.0f + Fraction / 16.0f;
187 // 000 -> 2^1, 001 -> 2^2, 010 -> 2^3, 011 -> 2^4,
188 // 100 -> 2^-3, 101 -> 2^-2, 110 -> 2^-1, 111 -> 2^0
189 if (Exponent & 0x4) {
190 Val /= 1 << (7 - Exponent);
192 Val *= 1 << (Exponent + 1);
195 Val = Negative ? -Val : Val;
197 o << '#' << format("%.8f", Val);
200 void AArch64InstPrinter::printFPZeroOperand(const MCInst *MI, unsigned OpNum,
206 AArch64InstPrinter::printCondCodeOperand(const MCInst *MI, unsigned OpNum,
208 const MCOperand &MO = MI->getOperand(OpNum);
210 O << A64CondCodeToString(static_cast<A64CC::CondCodes>(MO.getImm()));
213 template <unsigned field_width, unsigned scale> void
214 AArch64InstPrinter::printLabelOperand(const MCInst *MI, unsigned OpNum,
216 const MCOperand &MO = MI->getOperand(OpNum);
219 printOperand(MI, OpNum, O);
223 // The immediate of LDR (lit) instructions is a signed 19-bit immediate, which
224 // is multiplied by 4 (because all A64 instructions are 32-bits wide).
225 uint64_t UImm = MO.getImm();
226 uint64_t Sign = UImm & (1LL << (field_width - 1));
227 int64_t SImm = scale * ((UImm & ~Sign) - Sign);
232 template<unsigned RegWidth> void
233 AArch64InstPrinter::printLogicalImmOperand(const MCInst *MI, unsigned OpNum,
235 const MCOperand &MO = MI->getOperand(OpNum);
237 A64Imms::isLogicalImmBits(RegWidth, MO.getImm(), Val);
243 AArch64InstPrinter::printOffsetUImm12Operand(const MCInst *MI, unsigned OpNum,
244 raw_ostream &O, int MemSize) {
245 const MCOperand &MOImm = MI->getOperand(OpNum);
248 uint32_t Imm = MOImm.getImm() * MemSize;
252 O << "#" << *MOImm.getExpr();
257 AArch64InstPrinter::printShiftOperand(const MCInst *MI, unsigned OpNum,
259 A64SE::ShiftExtSpecifiers Shift) {
260 const MCOperand &MO = MI->getOperand(OpNum);
262 // LSL #0 is not printed
263 if (Shift == A64SE::LSL && MO.isImm() && MO.getImm() == 0)
267 case A64SE::LSL: O << "lsl"; break;
268 case A64SE::LSR: O << "lsr"; break;
269 case A64SE::ASR: O << "asr"; break;
270 case A64SE::ROR: O << "ror"; break;
271 default: llvm_unreachable("Invalid shift specifier in logical instruction");
274 O << " #" << MO.getImm();
278 AArch64InstPrinter::printMoveWideImmOperand(const MCInst *MI, unsigned OpNum,
280 const MCOperand &UImm16MO = MI->getOperand(OpNum);
281 const MCOperand &ShiftMO = MI->getOperand(OpNum + 1);
283 if (UImm16MO.isImm()) {
284 O << '#' << UImm16MO.getImm();
286 if (ShiftMO.getImm() != 0)
287 O << ", lsl #" << (ShiftMO.getImm() * 16);
292 O << "#" << *UImm16MO.getExpr();
295 void AArch64InstPrinter::printNamedImmOperand(const NamedImmMapper &Mapper,
296 const MCInst *MI, unsigned OpNum,
299 const MCOperand &MO = MI->getOperand(OpNum);
300 StringRef Name = Mapper.toString(MO.getImm(), ValidName);
305 O << '#' << MO.getImm();
309 AArch64InstPrinter::printSysRegOperand(const A64SysReg::SysRegMapper &Mapper,
310 const MCInst *MI, unsigned OpNum,
312 const MCOperand &MO = MI->getOperand(OpNum);
315 std::string Name = Mapper.toString(MO.getImm(), ValidName);
323 void AArch64InstPrinter::printRegExtendOperand(const MCInst *MI,
326 A64SE::ShiftExtSpecifiers Ext) {
327 // FIXME: In principle TableGen should be able to detect this itself far more
328 // easily. We will only accumulate more of these hacks.
329 unsigned Reg0 = MI->getOperand(0).getReg();
330 unsigned Reg1 = MI->getOperand(1).getReg();
332 if (isStackReg(Reg0) || isStackReg(Reg1)) {
333 A64SE::ShiftExtSpecifiers LSLEquiv;
335 if (Reg0 == AArch64::XSP || Reg1 == AArch64::XSP)
336 LSLEquiv = A64SE::UXTX;
338 LSLEquiv = A64SE::UXTW;
340 if (Ext == LSLEquiv) {
341 O << "lsl #" << MI->getOperand(OpNum).getImm();
347 case A64SE::UXTB: O << "uxtb"; break;
348 case A64SE::UXTH: O << "uxth"; break;
349 case A64SE::UXTW: O << "uxtw"; break;
350 case A64SE::UXTX: O << "uxtx"; break;
351 case A64SE::SXTB: O << "sxtb"; break;
352 case A64SE::SXTH: O << "sxth"; break;
353 case A64SE::SXTW: O << "sxtw"; break;
354 case A64SE::SXTX: O << "sxtx"; break;
355 default: llvm_unreachable("Unexpected shift type for printing");
358 const MCOperand &MO = MI->getOperand(OpNum);
359 if (MO.getImm() != 0)
360 O << " #" << MO.getImm();
363 template<int MemScale> void
364 AArch64InstPrinter::printSImm7ScaledOperand(const MCInst *MI, unsigned OpNum,
366 const MCOperand &MOImm = MI->getOperand(OpNum);
367 int32_t Imm = unpackSignedImm(7, MOImm.getImm());
369 O << "#" << (Imm * MemScale);
372 void AArch64InstPrinter::printVPRRegister(const MCInst *MI, unsigned OpNo,
374 unsigned Reg = MI->getOperand(OpNo).getReg();
375 std::string Name = getRegisterName(Reg);
380 void AArch64InstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
382 const MCOperand &Op = MI->getOperand(OpNo);
384 unsigned Reg = Op.getReg();
385 O << getRegisterName(Reg);
386 } else if (Op.isImm()) {
387 O << '#' << Op.getImm();
389 assert(Op.isExpr() && "unknown operand kind in printOperand");
390 // If a symbolic branch target was added as a constant expression then print
391 // that address in hex.
392 const MCConstantExpr *BranchTarget = dyn_cast<MCConstantExpr>(Op.getExpr());
394 if (BranchTarget && BranchTarget->EvaluateAsAbsolute(Address)) {
396 O.write_hex(Address);
399 // Otherwise, just print the expression.
406 void AArch64InstPrinter::printInst(const MCInst *MI, raw_ostream &O,
408 if (MI->getOpcode() == AArch64::TLSDESCCALL) {
409 // This is a special assembler directive which applies an
410 // R_AARCH64_TLSDESC_CALL to the following (BLR) instruction. It has a fixed
411 // form outside the normal TableGenerated scheme.
412 O << "\t.tlsdesccall " << *MI->getOperand(0).getExpr();
413 } else if (!printAliasInstr(MI, O))
414 printInstruction(MI, O);
416 printAnnotation(O, Annot);
419 template <A64SE::ShiftExtSpecifiers Ext, bool isHalf>
420 void AArch64InstPrinter::printNeonMovImmShiftOperand(const MCInst *MI,
423 const MCOperand &MO = MI->getOperand(OpNum);
426 "Immediate operand required for Neon vector immediate inst.");
429 if (Ext == A64SE::LSL)
431 else if (Ext != A64SE::MSL)
432 llvm_unreachable("Invalid shift specifier in movi instruction");
434 int64_t Imm = MO.getImm();
436 // MSL and LSLH accepts encoded shift amount 0 or 1.
437 if ((!IsLSL || (IsLSL && isHalf)) && Imm != 0 && Imm != 1)
438 llvm_unreachable("Invalid shift amount in movi instruction");
440 // LSH accepts encoded shift amount 0, 1, 2 or 3.
441 if (IsLSL && (Imm < 0 || Imm > 3))
442 llvm_unreachable("Invalid shift amount in movi instruction");
444 // Print shift amount as multiple of 8 with MSL encoded shift amount
445 // 0 and 1 printed as 8 and 16.
450 // LSL #0 is not printed
461 void AArch64InstPrinter::printNeonUImm0Operand(const MCInst *MI, unsigned OpNum,
466 void AArch64InstPrinter::printUImmHexOperand(const MCInst *MI, unsigned OpNum,
468 const MCOperand &MOUImm = MI->getOperand(OpNum);
470 assert(MOUImm.isImm() &&
471 "Immediate operand required for Neon vector immediate inst.");
473 unsigned Imm = MOUImm.getImm();
479 void AArch64InstPrinter::printUImmBareOperand(const MCInst *MI,
482 const MCOperand &MOUImm = MI->getOperand(OpNum);
484 assert(MOUImm.isImm()
485 && "Immediate operand required for Neon vector immediate inst.");
487 unsigned Imm = MOUImm.getImm();
491 void AArch64InstPrinter::printNeonUImm64MaskOperand(const MCInst *MI,
494 const MCOperand &MOUImm8 = MI->getOperand(OpNum);
496 assert(MOUImm8.isImm() &&
497 "Immediate operand required for Neon vector immediate bytemask inst.");
499 uint32_t UImm8 = MOUImm8.getImm();
502 // Replicates 0x00 or 0xff byte in a 64-bit vector
503 for (unsigned ByteNum = 0; ByteNum < 8; ++ByteNum) {
504 if ((UImm8 >> ByteNum) & 1)
505 Mask |= (uint64_t)0xff << (8 * ByteNum);
512 // If Count > 1, there are two valid kinds of vector list:
513 // (1) {Vn.layout, Vn+1.layout, ... , Vm.layout}
514 // (2) {Vn.layout - Vm.layout}
515 // We choose the first kind as output.
516 template <A64Layout::VectorLayout Layout, unsigned Count>
517 void AArch64InstPrinter::printVectorList(const MCInst *MI, unsigned OpNum,
519 assert(Count >= 1 && Count <= 4 && "Invalid Number of Vectors");
521 unsigned Reg = MI->getOperand(OpNum).getReg();
522 std::string LayoutStr = A64VectorLayoutToString(Layout);
524 if (Count > 1) { // Print sub registers separately
525 bool IsVec64 = (Layout < A64Layout::VL_16B);
526 unsigned SubRegIdx = IsVec64 ? AArch64::dsub_0 : AArch64::qsub_0;
527 for (unsigned I = 0; I < Count; I++) {
528 std::string Name = getRegisterName(MRI.getSubReg(Reg, SubRegIdx++));
530 O << Name << LayoutStr;
534 } else { // Print the register directly when NumVecs is 1.
535 std::string Name = getRegisterName(Reg);
537 O << Name << LayoutStr;