AArch64InstPrinter.cpp revision 151dfc7d7ff6406a471058fcd142018a10b0c479
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 25using namespace llvm; 26 27#define GET_INSTRUCTION_NAME 28#define PRINT_ALIAS_INSTR 29#include "AArch64GenAsmWriter.inc" 30 31static 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 39AArch64InstPrinter::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 48void AArch64InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { 49 OS << getRegisterName(RegNo); 50} 51 52void 53AArch64InstPrinter::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 61void 62AArch64InstPrinter::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 91void 92AArch64InstPrinter::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 106void 107AArch64InstPrinter::printAddSubImmLSL12Operand(const MCInst *MI, unsigned OpNum, 108 raw_ostream &O) { 109 110 printAddSubImmLSL0Operand(MI, OpNum, O); 111 112 O << ", lsl #12"; 113} 114 115void 116AArch64InstPrinter::printBareImmOperand(const MCInst *MI, unsigned OpNum, 117 raw_ostream &O) { 118 const MCOperand &MO = MI->getOperand(OpNum); 119 O << MO.getImm(); 120} 121 122template<unsigned RegWidth> void 123AArch64InstPrinter::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 131void 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 139void 140AArch64InstPrinter::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 153void 154AArch64InstPrinter::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 162void 163AArch64InstPrinter::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 171void 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 199void AArch64InstPrinter::printFPZeroOperand(const MCInst *MI, unsigned OpNum, 200 raw_ostream &o) { 201 o << "#0.0"; 202} 203 204void 205AArch64InstPrinter::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 212template <unsigned field_width, unsigned scale> void 213AArch64InstPrinter::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 231template<unsigned RegWidth> void 232AArch64InstPrinter::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 241void 242AArch64InstPrinter::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 255void 256AArch64InstPrinter::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 276void 277AArch64InstPrinter::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 294void 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 307void 308AArch64InstPrinter::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 322void 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 362template<int MemScale> void 363AArch64InstPrinter::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 371void 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 379void 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 405void 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 418template <A64SE::ShiftExtSpecifiers Ext, bool isHalf> 419void 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 460void AArch64InstPrinter::printNeonUImm0Operand(const MCInst *MI, unsigned OpNum, 461 raw_ostream &o) { 462 o << "#0x0"; 463} 464 465void 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 478void 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 490void 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. 515template <A64Layout::VectorLayout Layout, unsigned Count> 516void 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::_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