2292 lines · cpp
1//==-- AArch64InstPrinter.cpp - Convert AArch64 MCInst to assembly syntax --==//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This class prints an AArch64 MCInst to a .s file.10//11//===----------------------------------------------------------------------===//12 13#include "AArch64InstPrinter.h"14#include "MCTargetDesc/AArch64AddressingModes.h"15#include "Utils/AArch64BaseInfo.h"16#include "llvm/ADT/StringExtras.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/MC/MCAsmInfo.h"19#include "llvm/MC/MCExpr.h"20#include "llvm/MC/MCInst.h"21#include "llvm/MC/MCRegisterInfo.h"22#include "llvm/MC/MCSubtargetInfo.h"23#include "llvm/Support/Casting.h"24#include "llvm/Support/ErrorHandling.h"25#include "llvm/Support/Format.h"26#include "llvm/Support/MathExtras.h"27#include "llvm/Support/raw_ostream.h"28#include <cassert>29#include <cstdint>30#include <string>31 32using namespace llvm;33 34#define DEBUG_TYPE "asm-printer"35 36#define GET_INSTRUCTION_NAME37#define PRINT_ALIAS_INSTR38#include "AArch64GenAsmWriter.inc"39#define GET_INSTRUCTION_NAME40#define PRINT_ALIAS_INSTR41#include "AArch64GenAsmWriter1.inc"42 43AArch64InstPrinter::AArch64InstPrinter(const MCAsmInfo &MAI,44 const MCInstrInfo &MII,45 const MCRegisterInfo &MRI)46 : MCInstPrinter(MAI, MII, MRI) {}47 48AArch64AppleInstPrinter::AArch64AppleInstPrinter(const MCAsmInfo &MAI,49 const MCInstrInfo &MII,50 const MCRegisterInfo &MRI)51 : AArch64InstPrinter(MAI, MII, MRI) {}52 53bool AArch64InstPrinter::applyTargetSpecificCLOption(StringRef Opt) {54 if (Opt == "no-aliases") {55 PrintAliases = false;56 return true;57 }58 return false;59}60 61void AArch64InstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) {62 markup(OS, Markup::Register) << getRegisterName(Reg);63}64 65void AArch64InstPrinter::printRegName(raw_ostream &OS, MCRegister Reg,66 unsigned AltIdx) {67 markup(OS, Markup::Register) << getRegisterName(Reg, AltIdx);68}69 70StringRef AArch64InstPrinter::getRegName(MCRegister Reg) const {71 return getRegisterName(Reg);72}73 74void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,75 StringRef Annot, const MCSubtargetInfo &STI,76 raw_ostream &O) {77 // Check for special encodings and print the canonical alias instead.78 79 unsigned Opcode = MI->getOpcode();80 81 if (Opcode == AArch64::SYSxt)82 if (printSysAlias(MI, STI, O)) {83 printAnnotation(O, Annot);84 return;85 }86 87 if (Opcode == AArch64::SYSLxt)88 if (printSyslAlias(MI, STI, O)) {89 printAnnotation(O, Annot);90 return;91 }92 93 if (Opcode == AArch64::SYSPxt || Opcode == AArch64::SYSPxt_XZR)94 if (printSyspAlias(MI, STI, O)) {95 printAnnotation(O, Annot);96 return;97 }98 99 // RPRFM overlaps PRFM (reg), so try to print it as RPRFM here.100 if ((Opcode == AArch64::PRFMroX) || (Opcode == AArch64::PRFMroW)) {101 if (printRangePrefetchAlias(MI, STI, O, Annot))102 return;103 }104 105 // SBFM/UBFM should print to a nicer aliased form if possible.106 if (Opcode == AArch64::SBFMXri || Opcode == AArch64::SBFMWri ||107 Opcode == AArch64::UBFMXri || Opcode == AArch64::UBFMWri) {108 const MCOperand &Op0 = MI->getOperand(0);109 const MCOperand &Op1 = MI->getOperand(1);110 const MCOperand &Op2 = MI->getOperand(2);111 const MCOperand &Op3 = MI->getOperand(3);112 113 bool IsSigned = (Opcode == AArch64::SBFMXri || Opcode == AArch64::SBFMWri);114 bool Is64Bit = (Opcode == AArch64::SBFMXri || Opcode == AArch64::UBFMXri);115 if (Op2.isImm() && Op2.getImm() == 0 && Op3.isImm()) {116 const char *AsmMnemonic = nullptr;117 118 switch (Op3.getImm()) {119 default:120 break;121 case 7:122 if (IsSigned)123 AsmMnemonic = "sxtb";124 else if (!Is64Bit)125 AsmMnemonic = "uxtb";126 break;127 case 15:128 if (IsSigned)129 AsmMnemonic = "sxth";130 else if (!Is64Bit)131 AsmMnemonic = "uxth";132 break;133 case 31:134 // *xtw is only valid for signed 64-bit operations.135 if (Is64Bit && IsSigned)136 AsmMnemonic = "sxtw";137 break;138 }139 140 if (AsmMnemonic) {141 O << '\t' << AsmMnemonic << '\t';142 printRegName(O, Op0.getReg());143 O << ", ";144 printRegName(O, getWRegFromXReg(Op1.getReg()));145 printAnnotation(O, Annot);146 return;147 }148 }149 150 // All immediate shifts are aliases, implemented using the Bitfield151 // instruction. In all cases the immediate shift amount shift must be in152 // the range 0 to (reg.size -1).153 if (Op2.isImm() && Op3.isImm()) {154 const char *AsmMnemonic = nullptr;155 int shift = 0;156 int64_t immr = Op2.getImm();157 int64_t imms = Op3.getImm();158 if (Opcode == AArch64::UBFMWri && imms != 0x1F && ((imms + 1) == immr)) {159 AsmMnemonic = "lsl";160 shift = 31 - imms;161 } else if (Opcode == AArch64::UBFMXri && imms != 0x3f &&162 ((imms + 1 == immr))) {163 AsmMnemonic = "lsl";164 shift = 63 - imms;165 } else if (Opcode == AArch64::UBFMWri && imms == 0x1f) {166 AsmMnemonic = "lsr";167 shift = immr;168 } else if (Opcode == AArch64::UBFMXri && imms == 0x3f) {169 AsmMnemonic = "lsr";170 shift = immr;171 } else if (Opcode == AArch64::SBFMWri && imms == 0x1f) {172 AsmMnemonic = "asr";173 shift = immr;174 } else if (Opcode == AArch64::SBFMXri && imms == 0x3f) {175 AsmMnemonic = "asr";176 shift = immr;177 }178 if (AsmMnemonic) {179 O << '\t' << AsmMnemonic << '\t';180 printRegName(O, Op0.getReg());181 O << ", ";182 printRegName(O, Op1.getReg());183 O << ", ";184 markup(O, Markup::Immediate) << "#" << shift;185 printAnnotation(O, Annot);186 return;187 }188 }189 190 // SBFIZ/UBFIZ aliases191 if (Op2.getImm() > Op3.getImm()) {192 O << '\t' << (IsSigned ? "sbfiz" : "ubfiz") << '\t';193 printRegName(O, Op0.getReg());194 O << ", ";195 printRegName(O, Op1.getReg());196 O << ", ";197 markup(O, Markup::Immediate) << "#" << (Is64Bit ? 64 : 32) - Op2.getImm();198 O << ", ";199 markup(O, Markup::Immediate) << "#" << Op3.getImm() + 1;200 printAnnotation(O, Annot);201 return;202 }203 204 // Otherwise SBFX/UBFX is the preferred form205 O << '\t' << (IsSigned ? "sbfx" : "ubfx") << '\t';206 printRegName(O, Op0.getReg());207 O << ", ";208 printRegName(O, Op1.getReg());209 O << ", ";210 markup(O, Markup::Immediate) << "#" << Op2.getImm();211 O << ", ";212 markup(O, Markup::Immediate) << "#" << Op3.getImm() - Op2.getImm() + 1;213 printAnnotation(O, Annot);214 return;215 }216 217 if (Opcode == AArch64::BFMXri || Opcode == AArch64::BFMWri) {218 const MCOperand &Op0 = MI->getOperand(0); // Op1 == Op0219 const MCOperand &Op2 = MI->getOperand(2);220 int ImmR = MI->getOperand(3).getImm();221 int ImmS = MI->getOperand(4).getImm();222 223 if ((Op2.getReg() == AArch64::WZR || Op2.getReg() == AArch64::XZR) &&224 (ImmR == 0 || ImmS < ImmR) && STI.hasFeature(AArch64::HasV8_2aOps)) {225 // BFC takes precedence over its entire range, slightly differently to BFI.226 int BitWidth = Opcode == AArch64::BFMXri ? 64 : 32;227 int LSB = (BitWidth - ImmR) % BitWidth;228 int Width = ImmS + 1;229 230 O << "\tbfc\t";231 printRegName(O, Op0.getReg());232 O << ", ";233 markup(O, Markup::Immediate) << "#" << LSB;234 O << ", ";235 markup(O, Markup::Immediate) << "#" << Width;236 printAnnotation(O, Annot);237 return;238 } else if (ImmS < ImmR) {239 // BFI alias240 int BitWidth = Opcode == AArch64::BFMXri ? 64 : 32;241 int LSB = (BitWidth - ImmR) % BitWidth;242 int Width = ImmS + 1;243 244 O << "\tbfi\t";245 printRegName(O, Op0.getReg());246 O << ", ";247 printRegName(O, Op2.getReg());248 O << ", ";249 markup(O, Markup::Immediate) << "#" << LSB;250 O << ", ";251 markup(O, Markup::Immediate) << "#" << Width;252 printAnnotation(O, Annot);253 return;254 }255 256 int LSB = ImmR;257 int Width = ImmS - ImmR + 1;258 // Otherwise BFXIL the preferred form259 O << "\tbfxil\t";260 printRegName(O, Op0.getReg());261 O << ", ";262 printRegName(O, Op2.getReg());263 O << ", ";264 markup(O, Markup::Immediate) << "#" << LSB;265 O << ", ";266 markup(O, Markup::Immediate) << "#" << Width;267 printAnnotation(O, Annot);268 return;269 }270 271 // Symbolic operands for MOVZ, MOVN and MOVK already imply a shift272 // (e.g. :gottprel_g1: is always going to be "lsl #16") so it should not be273 // printed.274 if ((Opcode == AArch64::MOVZXi || Opcode == AArch64::MOVZWi ||275 Opcode == AArch64::MOVNXi || Opcode == AArch64::MOVNWi) &&276 MI->getOperand(1).isExpr()) {277 if (Opcode == AArch64::MOVZXi || Opcode == AArch64::MOVZWi)278 O << "\tmovz\t";279 else280 O << "\tmovn\t";281 282 printRegName(O, MI->getOperand(0).getReg());283 O << ", ";284 {285 WithMarkup M = markup(O, Markup::Immediate);286 O << "#";287 MAI.printExpr(O, *MI->getOperand(1).getExpr());288 }289 return;290 }291 292 if ((Opcode == AArch64::MOVKXi || Opcode == AArch64::MOVKWi) &&293 MI->getOperand(2).isExpr()) {294 O << "\tmovk\t";295 printRegName(O, MI->getOperand(0).getReg());296 O << ", ";297 {298 WithMarkup M = markup(O, Markup::Immediate);299 O << "#";300 MAI.printExpr(O, *MI->getOperand(2).getExpr());301 }302 return;303 }304 305 auto PrintMovImm = [&](uint64_t Value, int RegWidth) {306 int64_t SExtVal = SignExtend64(Value, RegWidth);307 O << "\tmov\t";308 printRegName(O, MI->getOperand(0).getReg());309 O << ", ";310 markup(O, Markup::Immediate) << "#" << formatImm(SExtVal);311 if (CommentStream) {312 // Do the opposite to that used for instruction operands.313 if (getPrintImmHex())314 *CommentStream << '=' << formatDec(SExtVal) << '\n';315 else {316 uint64_t Mask = maskTrailingOnes<uint64_t>(RegWidth);317 *CommentStream << '=' << formatHex(SExtVal & Mask) << '\n';318 }319 }320 };321 322 // MOVZ, MOVN and "ORR wzr, #imm" instructions are aliases for MOV, but their323 // domains overlap so they need to be prioritized. The chain is "MOVZ lsl #0 >324 // MOVZ lsl #N > MOVN lsl #0 > MOVN lsl #N > ORR". The highest instruction325 // that can represent the move is the MOV alias, and the rest get printed326 // normally.327 if ((Opcode == AArch64::MOVZXi || Opcode == AArch64::MOVZWi) &&328 MI->getOperand(1).isImm() && MI->getOperand(2).isImm()) {329 int RegWidth = Opcode == AArch64::MOVZXi ? 64 : 32;330 int Shift = MI->getOperand(2).getImm();331 uint64_t Value = (uint64_t)MI->getOperand(1).getImm() << Shift;332 333 if (AArch64_AM::isMOVZMovAlias(Value, Shift,334 Opcode == AArch64::MOVZXi ? 64 : 32)) {335 PrintMovImm(Value, RegWidth);336 return;337 }338 }339 340 if ((Opcode == AArch64::MOVNXi || Opcode == AArch64::MOVNWi) &&341 MI->getOperand(1).isImm() && MI->getOperand(2).isImm()) {342 int RegWidth = Opcode == AArch64::MOVNXi ? 64 : 32;343 int Shift = MI->getOperand(2).getImm();344 uint64_t Value = ~((uint64_t)MI->getOperand(1).getImm() << Shift);345 if (RegWidth == 32)346 Value = Value & 0xffffffff;347 348 if (AArch64_AM::isMOVNMovAlias(Value, Shift, RegWidth)) {349 PrintMovImm(Value, RegWidth);350 return;351 }352 }353 354 if ((Opcode == AArch64::ORRXri || Opcode == AArch64::ORRWri) &&355 (MI->getOperand(1).getReg() == AArch64::XZR ||356 MI->getOperand(1).getReg() == AArch64::WZR) &&357 MI->getOperand(2).isImm()) {358 int RegWidth = Opcode == AArch64::ORRXri ? 64 : 32;359 uint64_t Value = AArch64_AM::decodeLogicalImmediate(360 MI->getOperand(2).getImm(), RegWidth);361 if (!AArch64_AM::isAnyMOVWMovAlias(Value, RegWidth)) {362 PrintMovImm(Value, RegWidth);363 return;364 }365 }366 367 if (Opcode == AArch64::SPACE) {368 O << '\t' << MAI.getCommentString() << " SPACE "369 << MI->getOperand(1).getImm();370 printAnnotation(O, Annot);371 return;372 }373 374 if (!PrintAliases || !printAliasInstr(MI, Address, STI, O))375 printInstruction(MI, Address, STI, O);376 377 printAnnotation(O, Annot);378 379 if (atomicBarrierDroppedOnZero(Opcode) &&380 (MI->getOperand(0).getReg() == AArch64::XZR ||381 MI->getOperand(0).getReg() == AArch64::WZR)) {382 printAnnotation(O, "acquire semantics dropped since destination is zero");383 }384}385 386static bool isTblTbxInstruction(unsigned Opcode, StringRef &Layout,387 bool &IsTbx) {388 switch (Opcode) {389 case AArch64::TBXv8i8One:390 case AArch64::TBXv8i8Two:391 case AArch64::TBXv8i8Three:392 case AArch64::TBXv8i8Four:393 IsTbx = true;394 Layout = ".8b";395 return true;396 case AArch64::TBLv8i8One:397 case AArch64::TBLv8i8Two:398 case AArch64::TBLv8i8Three:399 case AArch64::TBLv8i8Four:400 IsTbx = false;401 Layout = ".8b";402 return true;403 case AArch64::TBXv16i8One:404 case AArch64::TBXv16i8Two:405 case AArch64::TBXv16i8Three:406 case AArch64::TBXv16i8Four:407 IsTbx = true;408 Layout = ".16b";409 return true;410 case AArch64::TBLv16i8One:411 case AArch64::TBLv16i8Two:412 case AArch64::TBLv16i8Three:413 case AArch64::TBLv16i8Four:414 IsTbx = false;415 Layout = ".16b";416 return true;417 default:418 return false;419 }420}421 422struct LdStNInstrDesc {423 unsigned Opcode;424 const char *Mnemonic;425 const char *Layout;426 int ListOperand;427 bool HasLane;428 int NaturalOffset;429};430 431static const LdStNInstrDesc LdStNInstInfo[] = {432 { AArch64::LD1i8, "ld1", ".b", 1, true, 0 },433 { AArch64::LD1i16, "ld1", ".h", 1, true, 0 },434 { AArch64::LD1i32, "ld1", ".s", 1, true, 0 },435 { AArch64::LD1i64, "ld1", ".d", 1, true, 0 },436 { AArch64::LD1i8_POST, "ld1", ".b", 2, true, 1 },437 { AArch64::LD1i16_POST, "ld1", ".h", 2, true, 2 },438 { AArch64::LD1i32_POST, "ld1", ".s", 2, true, 4 },439 { AArch64::LD1i64_POST, "ld1", ".d", 2, true, 8 },440 { AArch64::LD1Rv16b, "ld1r", ".16b", 0, false, 0 },441 { AArch64::LD1Rv8h, "ld1r", ".8h", 0, false, 0 },442 { AArch64::LD1Rv4s, "ld1r", ".4s", 0, false, 0 },443 { AArch64::LD1Rv2d, "ld1r", ".2d", 0, false, 0 },444 { AArch64::LD1Rv8b, "ld1r", ".8b", 0, false, 0 },445 { AArch64::LD1Rv4h, "ld1r", ".4h", 0, false, 0 },446 { AArch64::LD1Rv2s, "ld1r", ".2s", 0, false, 0 },447 { AArch64::LD1Rv1d, "ld1r", ".1d", 0, false, 0 },448 { AArch64::LD1Rv16b_POST, "ld1r", ".16b", 1, false, 1 },449 { AArch64::LD1Rv8h_POST, "ld1r", ".8h", 1, false, 2 },450 { AArch64::LD1Rv4s_POST, "ld1r", ".4s", 1, false, 4 },451 { AArch64::LD1Rv2d_POST, "ld1r", ".2d", 1, false, 8 },452 { AArch64::LD1Rv8b_POST, "ld1r", ".8b", 1, false, 1 },453 { AArch64::LD1Rv4h_POST, "ld1r", ".4h", 1, false, 2 },454 { AArch64::LD1Rv2s_POST, "ld1r", ".2s", 1, false, 4 },455 { AArch64::LD1Rv1d_POST, "ld1r", ".1d", 1, false, 8 },456 { AArch64::LD1Onev16b, "ld1", ".16b", 0, false, 0 },457 { AArch64::LD1Onev8h, "ld1", ".8h", 0, false, 0 },458 { AArch64::LD1Onev4s, "ld1", ".4s", 0, false, 0 },459 { AArch64::LD1Onev2d, "ld1", ".2d", 0, false, 0 },460 { AArch64::LD1Onev8b, "ld1", ".8b", 0, false, 0 },461 { AArch64::LD1Onev4h, "ld1", ".4h", 0, false, 0 },462 { AArch64::LD1Onev2s, "ld1", ".2s", 0, false, 0 },463 { AArch64::LD1Onev1d, "ld1", ".1d", 0, false, 0 },464 { AArch64::LD1Onev16b_POST, "ld1", ".16b", 1, false, 16 },465 { AArch64::LD1Onev8h_POST, "ld1", ".8h", 1, false, 16 },466 { AArch64::LD1Onev4s_POST, "ld1", ".4s", 1, false, 16 },467 { AArch64::LD1Onev2d_POST, "ld1", ".2d", 1, false, 16 },468 { AArch64::LD1Onev8b_POST, "ld1", ".8b", 1, false, 8 },469 { AArch64::LD1Onev4h_POST, "ld1", ".4h", 1, false, 8 },470 { AArch64::LD1Onev2s_POST, "ld1", ".2s", 1, false, 8 },471 { AArch64::LD1Onev1d_POST, "ld1", ".1d", 1, false, 8 },472 { AArch64::LD1Twov16b, "ld1", ".16b", 0, false, 0 },473 { AArch64::LD1Twov8h, "ld1", ".8h", 0, false, 0 },474 { AArch64::LD1Twov4s, "ld1", ".4s", 0, false, 0 },475 { AArch64::LD1Twov2d, "ld1", ".2d", 0, false, 0 },476 { AArch64::LD1Twov8b, "ld1", ".8b", 0, false, 0 },477 { AArch64::LD1Twov4h, "ld1", ".4h", 0, false, 0 },478 { AArch64::LD1Twov2s, "ld1", ".2s", 0, false, 0 },479 { AArch64::LD1Twov1d, "ld1", ".1d", 0, false, 0 },480 { AArch64::LD1Twov16b_POST, "ld1", ".16b", 1, false, 32 },481 { AArch64::LD1Twov8h_POST, "ld1", ".8h", 1, false, 32 },482 { AArch64::LD1Twov4s_POST, "ld1", ".4s", 1, false, 32 },483 { AArch64::LD1Twov2d_POST, "ld1", ".2d", 1, false, 32 },484 { AArch64::LD1Twov8b_POST, "ld1", ".8b", 1, false, 16 },485 { AArch64::LD1Twov4h_POST, "ld1", ".4h", 1, false, 16 },486 { AArch64::LD1Twov2s_POST, "ld1", ".2s", 1, false, 16 },487 { AArch64::LD1Twov1d_POST, "ld1", ".1d", 1, false, 16 },488 { AArch64::LD1Threev16b, "ld1", ".16b", 0, false, 0 },489 { AArch64::LD1Threev8h, "ld1", ".8h", 0, false, 0 },490 { AArch64::LD1Threev4s, "ld1", ".4s", 0, false, 0 },491 { AArch64::LD1Threev2d, "ld1", ".2d", 0, false, 0 },492 { AArch64::LD1Threev8b, "ld1", ".8b", 0, false, 0 },493 { AArch64::LD1Threev4h, "ld1", ".4h", 0, false, 0 },494 { AArch64::LD1Threev2s, "ld1", ".2s", 0, false, 0 },495 { AArch64::LD1Threev1d, "ld1", ".1d", 0, false, 0 },496 { AArch64::LD1Threev16b_POST, "ld1", ".16b", 1, false, 48 },497 { AArch64::LD1Threev8h_POST, "ld1", ".8h", 1, false, 48 },498 { AArch64::LD1Threev4s_POST, "ld1", ".4s", 1, false, 48 },499 { AArch64::LD1Threev2d_POST, "ld1", ".2d", 1, false, 48 },500 { AArch64::LD1Threev8b_POST, "ld1", ".8b", 1, false, 24 },501 { AArch64::LD1Threev4h_POST, "ld1", ".4h", 1, false, 24 },502 { AArch64::LD1Threev2s_POST, "ld1", ".2s", 1, false, 24 },503 { AArch64::LD1Threev1d_POST, "ld1", ".1d", 1, false, 24 },504 { AArch64::LD1Fourv16b, "ld1", ".16b", 0, false, 0 },505 { AArch64::LD1Fourv8h, "ld1", ".8h", 0, false, 0 },506 { AArch64::LD1Fourv4s, "ld1", ".4s", 0, false, 0 },507 { AArch64::LD1Fourv2d, "ld1", ".2d", 0, false, 0 },508 { AArch64::LD1Fourv8b, "ld1", ".8b", 0, false, 0 },509 { AArch64::LD1Fourv4h, "ld1", ".4h", 0, false, 0 },510 { AArch64::LD1Fourv2s, "ld1", ".2s", 0, false, 0 },511 { AArch64::LD1Fourv1d, "ld1", ".1d", 0, false, 0 },512 { AArch64::LD1Fourv16b_POST, "ld1", ".16b", 1, false, 64 },513 { AArch64::LD1Fourv8h_POST, "ld1", ".8h", 1, false, 64 },514 { AArch64::LD1Fourv4s_POST, "ld1", ".4s", 1, false, 64 },515 { AArch64::LD1Fourv2d_POST, "ld1", ".2d", 1, false, 64 },516 { AArch64::LD1Fourv8b_POST, "ld1", ".8b", 1, false, 32 },517 { AArch64::LD1Fourv4h_POST, "ld1", ".4h", 1, false, 32 },518 { AArch64::LD1Fourv2s_POST, "ld1", ".2s", 1, false, 32 },519 { AArch64::LD1Fourv1d_POST, "ld1", ".1d", 1, false, 32 },520 { AArch64::LD2i8, "ld2", ".b", 1, true, 0 },521 { AArch64::LD2i16, "ld2", ".h", 1, true, 0 },522 { AArch64::LD2i32, "ld2", ".s", 1, true, 0 },523 { AArch64::LD2i64, "ld2", ".d", 1, true, 0 },524 { AArch64::LD2i8_POST, "ld2", ".b", 2, true, 2 },525 { AArch64::LD2i16_POST, "ld2", ".h", 2, true, 4 },526 { AArch64::LD2i32_POST, "ld2", ".s", 2, true, 8 },527 { AArch64::LD2i64_POST, "ld2", ".d", 2, true, 16 },528 { AArch64::LD2Rv16b, "ld2r", ".16b", 0, false, 0 },529 { AArch64::LD2Rv8h, "ld2r", ".8h", 0, false, 0 },530 { AArch64::LD2Rv4s, "ld2r", ".4s", 0, false, 0 },531 { AArch64::LD2Rv2d, "ld2r", ".2d", 0, false, 0 },532 { AArch64::LD2Rv8b, "ld2r", ".8b", 0, false, 0 },533 { AArch64::LD2Rv4h, "ld2r", ".4h", 0, false, 0 },534 { AArch64::LD2Rv2s, "ld2r", ".2s", 0, false, 0 },535 { AArch64::LD2Rv1d, "ld2r", ".1d", 0, false, 0 },536 { AArch64::LD2Rv16b_POST, "ld2r", ".16b", 1, false, 2 },537 { AArch64::LD2Rv8h_POST, "ld2r", ".8h", 1, false, 4 },538 { AArch64::LD2Rv4s_POST, "ld2r", ".4s", 1, false, 8 },539 { AArch64::LD2Rv2d_POST, "ld2r", ".2d", 1, false, 16 },540 { AArch64::LD2Rv8b_POST, "ld2r", ".8b", 1, false, 2 },541 { AArch64::LD2Rv4h_POST, "ld2r", ".4h", 1, false, 4 },542 { AArch64::LD2Rv2s_POST, "ld2r", ".2s", 1, false, 8 },543 { AArch64::LD2Rv1d_POST, "ld2r", ".1d", 1, false, 16 },544 { AArch64::LD2Twov16b, "ld2", ".16b", 0, false, 0 },545 { AArch64::LD2Twov8h, "ld2", ".8h", 0, false, 0 },546 { AArch64::LD2Twov4s, "ld2", ".4s", 0, false, 0 },547 { AArch64::LD2Twov2d, "ld2", ".2d", 0, false, 0 },548 { AArch64::LD2Twov8b, "ld2", ".8b", 0, false, 0 },549 { AArch64::LD2Twov4h, "ld2", ".4h", 0, false, 0 },550 { AArch64::LD2Twov2s, "ld2", ".2s", 0, false, 0 },551 { AArch64::LD2Twov16b_POST, "ld2", ".16b", 1, false, 32 },552 { AArch64::LD2Twov8h_POST, "ld2", ".8h", 1, false, 32 },553 { AArch64::LD2Twov4s_POST, "ld2", ".4s", 1, false, 32 },554 { AArch64::LD2Twov2d_POST, "ld2", ".2d", 1, false, 32 },555 { AArch64::LD2Twov8b_POST, "ld2", ".8b", 1, false, 16 },556 { AArch64::LD2Twov4h_POST, "ld2", ".4h", 1, false, 16 },557 { AArch64::LD2Twov2s_POST, "ld2", ".2s", 1, false, 16 },558 { AArch64::LD3i8, "ld3", ".b", 1, true, 0 },559 { AArch64::LD3i16, "ld3", ".h", 1, true, 0 },560 { AArch64::LD3i32, "ld3", ".s", 1, true, 0 },561 { AArch64::LD3i64, "ld3", ".d", 1, true, 0 },562 { AArch64::LD3i8_POST, "ld3", ".b", 2, true, 3 },563 { AArch64::LD3i16_POST, "ld3", ".h", 2, true, 6 },564 { AArch64::LD3i32_POST, "ld3", ".s", 2, true, 12 },565 { AArch64::LD3i64_POST, "ld3", ".d", 2, true, 24 },566 { AArch64::LD3Rv16b, "ld3r", ".16b", 0, false, 0 },567 { AArch64::LD3Rv8h, "ld3r", ".8h", 0, false, 0 },568 { AArch64::LD3Rv4s, "ld3r", ".4s", 0, false, 0 },569 { AArch64::LD3Rv2d, "ld3r", ".2d", 0, false, 0 },570 { AArch64::LD3Rv8b, "ld3r", ".8b", 0, false, 0 },571 { AArch64::LD3Rv4h, "ld3r", ".4h", 0, false, 0 },572 { AArch64::LD3Rv2s, "ld3r", ".2s", 0, false, 0 },573 { AArch64::LD3Rv1d, "ld3r", ".1d", 0, false, 0 },574 { AArch64::LD3Rv16b_POST, "ld3r", ".16b", 1, false, 3 },575 { AArch64::LD3Rv8h_POST, "ld3r", ".8h", 1, false, 6 },576 { AArch64::LD3Rv4s_POST, "ld3r", ".4s", 1, false, 12 },577 { AArch64::LD3Rv2d_POST, "ld3r", ".2d", 1, false, 24 },578 { AArch64::LD3Rv8b_POST, "ld3r", ".8b", 1, false, 3 },579 { AArch64::LD3Rv4h_POST, "ld3r", ".4h", 1, false, 6 },580 { AArch64::LD3Rv2s_POST, "ld3r", ".2s", 1, false, 12 },581 { AArch64::LD3Rv1d_POST, "ld3r", ".1d", 1, false, 24 },582 { AArch64::LD3Threev16b, "ld3", ".16b", 0, false, 0 },583 { AArch64::LD3Threev8h, "ld3", ".8h", 0, false, 0 },584 { AArch64::LD3Threev4s, "ld3", ".4s", 0, false, 0 },585 { AArch64::LD3Threev2d, "ld3", ".2d", 0, false, 0 },586 { AArch64::LD3Threev8b, "ld3", ".8b", 0, false, 0 },587 { AArch64::LD3Threev4h, "ld3", ".4h", 0, false, 0 },588 { AArch64::LD3Threev2s, "ld3", ".2s", 0, false, 0 },589 { AArch64::LD3Threev16b_POST, "ld3", ".16b", 1, false, 48 },590 { AArch64::LD3Threev8h_POST, "ld3", ".8h", 1, false, 48 },591 { AArch64::LD3Threev4s_POST, "ld3", ".4s", 1, false, 48 },592 { AArch64::LD3Threev2d_POST, "ld3", ".2d", 1, false, 48 },593 { AArch64::LD3Threev8b_POST, "ld3", ".8b", 1, false, 24 },594 { AArch64::LD3Threev4h_POST, "ld3", ".4h", 1, false, 24 },595 { AArch64::LD3Threev2s_POST, "ld3", ".2s", 1, false, 24 },596 { AArch64::LD4i8, "ld4", ".b", 1, true, 0 },597 { AArch64::LD4i16, "ld4", ".h", 1, true, 0 },598 { AArch64::LD4i32, "ld4", ".s", 1, true, 0 },599 { AArch64::LD4i64, "ld4", ".d", 1, true, 0 },600 { AArch64::LD4i8_POST, "ld4", ".b", 2, true, 4 },601 { AArch64::LD4i16_POST, "ld4", ".h", 2, true, 8 },602 { AArch64::LD4i32_POST, "ld4", ".s", 2, true, 16 },603 { AArch64::LD4i64_POST, "ld4", ".d", 2, true, 32 },604 { AArch64::LD4Rv16b, "ld4r", ".16b", 0, false, 0 },605 { AArch64::LD4Rv8h, "ld4r", ".8h", 0, false, 0 },606 { AArch64::LD4Rv4s, "ld4r", ".4s", 0, false, 0 },607 { AArch64::LD4Rv2d, "ld4r", ".2d", 0, false, 0 },608 { AArch64::LD4Rv8b, "ld4r", ".8b", 0, false, 0 },609 { AArch64::LD4Rv4h, "ld4r", ".4h", 0, false, 0 },610 { AArch64::LD4Rv2s, "ld4r", ".2s", 0, false, 0 },611 { AArch64::LD4Rv1d, "ld4r", ".1d", 0, false, 0 },612 { AArch64::LD4Rv16b_POST, "ld4r", ".16b", 1, false, 4 },613 { AArch64::LD4Rv8h_POST, "ld4r", ".8h", 1, false, 8 },614 { AArch64::LD4Rv4s_POST, "ld4r", ".4s", 1, false, 16 },615 { AArch64::LD4Rv2d_POST, "ld4r", ".2d", 1, false, 32 },616 { AArch64::LD4Rv8b_POST, "ld4r", ".8b", 1, false, 4 },617 { AArch64::LD4Rv4h_POST, "ld4r", ".4h", 1, false, 8 },618 { AArch64::LD4Rv2s_POST, "ld4r", ".2s", 1, false, 16 },619 { AArch64::LD4Rv1d_POST, "ld4r", ".1d", 1, false, 32 },620 { AArch64::LD4Fourv16b, "ld4", ".16b", 0, false, 0 },621 { AArch64::LD4Fourv8h, "ld4", ".8h", 0, false, 0 },622 { AArch64::LD4Fourv4s, "ld4", ".4s", 0, false, 0 },623 { AArch64::LD4Fourv2d, "ld4", ".2d", 0, false, 0 },624 { AArch64::LD4Fourv8b, "ld4", ".8b", 0, false, 0 },625 { AArch64::LD4Fourv4h, "ld4", ".4h", 0, false, 0 },626 { AArch64::LD4Fourv2s, "ld4", ".2s", 0, false, 0 },627 { AArch64::LD4Fourv16b_POST, "ld4", ".16b", 1, false, 64 },628 { AArch64::LD4Fourv8h_POST, "ld4", ".8h", 1, false, 64 },629 { AArch64::LD4Fourv4s_POST, "ld4", ".4s", 1, false, 64 },630 { AArch64::LD4Fourv2d_POST, "ld4", ".2d", 1, false, 64 },631 { AArch64::LD4Fourv8b_POST, "ld4", ".8b", 1, false, 32 },632 { AArch64::LD4Fourv4h_POST, "ld4", ".4h", 1, false, 32 },633 { AArch64::LD4Fourv2s_POST, "ld4", ".2s", 1, false, 32 },634 { AArch64::ST1i8, "st1", ".b", 0, true, 0 },635 { AArch64::ST1i16, "st1", ".h", 0, true, 0 },636 { AArch64::ST1i32, "st1", ".s", 0, true, 0 },637 { AArch64::ST1i64, "st1", ".d", 0, true, 0 },638 { AArch64::ST1i8_POST, "st1", ".b", 1, true, 1 },639 { AArch64::ST1i16_POST, "st1", ".h", 1, true, 2 },640 { AArch64::ST1i32_POST, "st1", ".s", 1, true, 4 },641 { AArch64::ST1i64_POST, "st1", ".d", 1, true, 8 },642 { AArch64::ST1Onev16b, "st1", ".16b", 0, false, 0 },643 { AArch64::ST1Onev8h, "st1", ".8h", 0, false, 0 },644 { AArch64::ST1Onev4s, "st1", ".4s", 0, false, 0 },645 { AArch64::ST1Onev2d, "st1", ".2d", 0, false, 0 },646 { AArch64::ST1Onev8b, "st1", ".8b", 0, false, 0 },647 { AArch64::ST1Onev4h, "st1", ".4h", 0, false, 0 },648 { AArch64::ST1Onev2s, "st1", ".2s", 0, false, 0 },649 { AArch64::ST1Onev1d, "st1", ".1d", 0, false, 0 },650 { AArch64::ST1Onev16b_POST, "st1", ".16b", 1, false, 16 },651 { AArch64::ST1Onev8h_POST, "st1", ".8h", 1, false, 16 },652 { AArch64::ST1Onev4s_POST, "st1", ".4s", 1, false, 16 },653 { AArch64::ST1Onev2d_POST, "st1", ".2d", 1, false, 16 },654 { AArch64::ST1Onev8b_POST, "st1", ".8b", 1, false, 8 },655 { AArch64::ST1Onev4h_POST, "st1", ".4h", 1, false, 8 },656 { AArch64::ST1Onev2s_POST, "st1", ".2s", 1, false, 8 },657 { AArch64::ST1Onev1d_POST, "st1", ".1d", 1, false, 8 },658 { AArch64::ST1Twov16b, "st1", ".16b", 0, false, 0 },659 { AArch64::ST1Twov8h, "st1", ".8h", 0, false, 0 },660 { AArch64::ST1Twov4s, "st1", ".4s", 0, false, 0 },661 { AArch64::ST1Twov2d, "st1", ".2d", 0, false, 0 },662 { AArch64::ST1Twov8b, "st1", ".8b", 0, false, 0 },663 { AArch64::ST1Twov4h, "st1", ".4h", 0, false, 0 },664 { AArch64::ST1Twov2s, "st1", ".2s", 0, false, 0 },665 { AArch64::ST1Twov1d, "st1", ".1d", 0, false, 0 },666 { AArch64::ST1Twov16b_POST, "st1", ".16b", 1, false, 32 },667 { AArch64::ST1Twov8h_POST, "st1", ".8h", 1, false, 32 },668 { AArch64::ST1Twov4s_POST, "st1", ".4s", 1, false, 32 },669 { AArch64::ST1Twov2d_POST, "st1", ".2d", 1, false, 32 },670 { AArch64::ST1Twov8b_POST, "st1", ".8b", 1, false, 16 },671 { AArch64::ST1Twov4h_POST, "st1", ".4h", 1, false, 16 },672 { AArch64::ST1Twov2s_POST, "st1", ".2s", 1, false, 16 },673 { AArch64::ST1Twov1d_POST, "st1", ".1d", 1, false, 16 },674 { AArch64::ST1Threev16b, "st1", ".16b", 0, false, 0 },675 { AArch64::ST1Threev8h, "st1", ".8h", 0, false, 0 },676 { AArch64::ST1Threev4s, "st1", ".4s", 0, false, 0 },677 { AArch64::ST1Threev2d, "st1", ".2d", 0, false, 0 },678 { AArch64::ST1Threev8b, "st1", ".8b", 0, false, 0 },679 { AArch64::ST1Threev4h, "st1", ".4h", 0, false, 0 },680 { AArch64::ST1Threev2s, "st1", ".2s", 0, false, 0 },681 { AArch64::ST1Threev1d, "st1", ".1d", 0, false, 0 },682 { AArch64::ST1Threev16b_POST, "st1", ".16b", 1, false, 48 },683 { AArch64::ST1Threev8h_POST, "st1", ".8h", 1, false, 48 },684 { AArch64::ST1Threev4s_POST, "st1", ".4s", 1, false, 48 },685 { AArch64::ST1Threev2d_POST, "st1", ".2d", 1, false, 48 },686 { AArch64::ST1Threev8b_POST, "st1", ".8b", 1, false, 24 },687 { AArch64::ST1Threev4h_POST, "st1", ".4h", 1, false, 24 },688 { AArch64::ST1Threev2s_POST, "st1", ".2s", 1, false, 24 },689 { AArch64::ST1Threev1d_POST, "st1", ".1d", 1, false, 24 },690 { AArch64::ST1Fourv16b, "st1", ".16b", 0, false, 0 },691 { AArch64::ST1Fourv8h, "st1", ".8h", 0, false, 0 },692 { AArch64::ST1Fourv4s, "st1", ".4s", 0, false, 0 },693 { AArch64::ST1Fourv2d, "st1", ".2d", 0, false, 0 },694 { AArch64::ST1Fourv8b, "st1", ".8b", 0, false, 0 },695 { AArch64::ST1Fourv4h, "st1", ".4h", 0, false, 0 },696 { AArch64::ST1Fourv2s, "st1", ".2s", 0, false, 0 },697 { AArch64::ST1Fourv1d, "st1", ".1d", 0, false, 0 },698 { AArch64::ST1Fourv16b_POST, "st1", ".16b", 1, false, 64 },699 { AArch64::ST1Fourv8h_POST, "st1", ".8h", 1, false, 64 },700 { AArch64::ST1Fourv4s_POST, "st1", ".4s", 1, false, 64 },701 { AArch64::ST1Fourv2d_POST, "st1", ".2d", 1, false, 64 },702 { AArch64::ST1Fourv8b_POST, "st1", ".8b", 1, false, 32 },703 { AArch64::ST1Fourv4h_POST, "st1", ".4h", 1, false, 32 },704 { AArch64::ST1Fourv2s_POST, "st1", ".2s", 1, false, 32 },705 { AArch64::ST1Fourv1d_POST, "st1", ".1d", 1, false, 32 },706 { AArch64::ST2i8, "st2", ".b", 0, true, 0 },707 { AArch64::ST2i16, "st2", ".h", 0, true, 0 },708 { AArch64::ST2i32, "st2", ".s", 0, true, 0 },709 { AArch64::ST2i64, "st2", ".d", 0, true, 0 },710 { AArch64::ST2i8_POST, "st2", ".b", 1, true, 2 },711 { AArch64::ST2i16_POST, "st2", ".h", 1, true, 4 },712 { AArch64::ST2i32_POST, "st2", ".s", 1, true, 8 },713 { AArch64::ST2i64_POST, "st2", ".d", 1, true, 16 },714 { AArch64::ST2Twov16b, "st2", ".16b", 0, false, 0 },715 { AArch64::ST2Twov8h, "st2", ".8h", 0, false, 0 },716 { AArch64::ST2Twov4s, "st2", ".4s", 0, false, 0 },717 { AArch64::ST2Twov2d, "st2", ".2d", 0, false, 0 },718 { AArch64::ST2Twov8b, "st2", ".8b", 0, false, 0 },719 { AArch64::ST2Twov4h, "st2", ".4h", 0, false, 0 },720 { AArch64::ST2Twov2s, "st2", ".2s", 0, false, 0 },721 { AArch64::ST2Twov16b_POST, "st2", ".16b", 1, false, 32 },722 { AArch64::ST2Twov8h_POST, "st2", ".8h", 1, false, 32 },723 { AArch64::ST2Twov4s_POST, "st2", ".4s", 1, false, 32 },724 { AArch64::ST2Twov2d_POST, "st2", ".2d", 1, false, 32 },725 { AArch64::ST2Twov8b_POST, "st2", ".8b", 1, false, 16 },726 { AArch64::ST2Twov4h_POST, "st2", ".4h", 1, false, 16 },727 { AArch64::ST2Twov2s_POST, "st2", ".2s", 1, false, 16 },728 { AArch64::ST3i8, "st3", ".b", 0, true, 0 },729 { AArch64::ST3i16, "st3", ".h", 0, true, 0 },730 { AArch64::ST3i32, "st3", ".s", 0, true, 0 },731 { AArch64::ST3i64, "st3", ".d", 0, true, 0 },732 { AArch64::ST3i8_POST, "st3", ".b", 1, true, 3 },733 { AArch64::ST3i16_POST, "st3", ".h", 1, true, 6 },734 { AArch64::ST3i32_POST, "st3", ".s", 1, true, 12 },735 { AArch64::ST3i64_POST, "st3", ".d", 1, true, 24 },736 { AArch64::ST3Threev16b, "st3", ".16b", 0, false, 0 },737 { AArch64::ST3Threev8h, "st3", ".8h", 0, false, 0 },738 { AArch64::ST3Threev4s, "st3", ".4s", 0, false, 0 },739 { AArch64::ST3Threev2d, "st3", ".2d", 0, false, 0 },740 { AArch64::ST3Threev8b, "st3", ".8b", 0, false, 0 },741 { AArch64::ST3Threev4h, "st3", ".4h", 0, false, 0 },742 { AArch64::ST3Threev2s, "st3", ".2s", 0, false, 0 },743 { AArch64::ST3Threev16b_POST, "st3", ".16b", 1, false, 48 },744 { AArch64::ST3Threev8h_POST, "st3", ".8h", 1, false, 48 },745 { AArch64::ST3Threev4s_POST, "st3", ".4s", 1, false, 48 },746 { AArch64::ST3Threev2d_POST, "st3", ".2d", 1, false, 48 },747 { AArch64::ST3Threev8b_POST, "st3", ".8b", 1, false, 24 },748 { AArch64::ST3Threev4h_POST, "st3", ".4h", 1, false, 24 },749 { AArch64::ST3Threev2s_POST, "st3", ".2s", 1, false, 24 },750 { AArch64::ST4i8, "st4", ".b", 0, true, 0 },751 { AArch64::ST4i16, "st4", ".h", 0, true, 0 },752 { AArch64::ST4i32, "st4", ".s", 0, true, 0 },753 { AArch64::ST4i64, "st4", ".d", 0, true, 0 },754 { AArch64::ST4i8_POST, "st4", ".b", 1, true, 4 },755 { AArch64::ST4i16_POST, "st4", ".h", 1, true, 8 },756 { AArch64::ST4i32_POST, "st4", ".s", 1, true, 16 },757 { AArch64::ST4i64_POST, "st4", ".d", 1, true, 32 },758 { AArch64::ST4Fourv16b, "st4", ".16b", 0, false, 0 },759 { AArch64::ST4Fourv8h, "st4", ".8h", 0, false, 0 },760 { AArch64::ST4Fourv4s, "st4", ".4s", 0, false, 0 },761 { AArch64::ST4Fourv2d, "st4", ".2d", 0, false, 0 },762 { AArch64::ST4Fourv8b, "st4", ".8b", 0, false, 0 },763 { AArch64::ST4Fourv4h, "st4", ".4h", 0, false, 0 },764 { AArch64::ST4Fourv2s, "st4", ".2s", 0, false, 0 },765 { AArch64::ST4Fourv16b_POST, "st4", ".16b", 1, false, 64 },766 { AArch64::ST4Fourv8h_POST, "st4", ".8h", 1, false, 64 },767 { AArch64::ST4Fourv4s_POST, "st4", ".4s", 1, false, 64 },768 { AArch64::ST4Fourv2d_POST, "st4", ".2d", 1, false, 64 },769 { AArch64::ST4Fourv8b_POST, "st4", ".8b", 1, false, 32 },770 { AArch64::ST4Fourv4h_POST, "st4", ".4h", 1, false, 32 },771 { AArch64::ST4Fourv2s_POST, "st4", ".2s", 1, false, 32 },772};773 774static const LdStNInstrDesc *getLdStNInstrDesc(unsigned Opcode) {775 for (const auto &Info : LdStNInstInfo)776 if (Info.Opcode == Opcode)777 return &Info;778 779 return nullptr;780}781 782void AArch64AppleInstPrinter::printInst(const MCInst *MI, uint64_t Address,783 StringRef Annot,784 const MCSubtargetInfo &STI,785 raw_ostream &O) {786 unsigned Opcode = MI->getOpcode();787 StringRef Layout;788 789 bool IsTbx;790 if (isTblTbxInstruction(MI->getOpcode(), Layout, IsTbx)) {791 O << "\t" << (IsTbx ? "tbx" : "tbl") << Layout << '\t';792 printRegName(O, MI->getOperand(0).getReg(), AArch64::vreg);793 O << ", ";794 795 unsigned ListOpNum = IsTbx ? 2 : 1;796 printVectorList(MI, ListOpNum, STI, O, "");797 798 O << ", ";799 printRegName(O, MI->getOperand(ListOpNum + 1).getReg(), AArch64::vreg);800 printAnnotation(O, Annot);801 return;802 }803 804 if (const LdStNInstrDesc *LdStDesc = getLdStNInstrDesc(Opcode)) {805 O << "\t" << LdStDesc->Mnemonic << LdStDesc->Layout << '\t';806 807 // Now onto the operands: first a vector list with possible lane808 // specifier. E.g. { v0 }[2]809 int OpNum = LdStDesc->ListOperand;810 printVectorList(MI, OpNum++, STI, O, "");811 812 if (LdStDesc->HasLane)813 O << '[' << MI->getOperand(OpNum++).getImm() << ']';814 815 // Next the address: [xN]816 MCRegister AddrReg = MI->getOperand(OpNum++).getReg();817 O << ", [";818 printRegName(O, AddrReg);819 O << ']';820 821 // Finally, there might be a post-indexed offset.822 if (LdStDesc->NaturalOffset != 0) {823 MCRegister Reg = MI->getOperand(OpNum++).getReg();824 if (Reg != AArch64::XZR) {825 O << ", ";826 printRegName(O, Reg);827 } else {828 assert(LdStDesc->NaturalOffset && "no offset on post-inc instruction?");829 O << ", ";830 markup(O, Markup::Immediate) << "#" << LdStDesc->NaturalOffset;831 }832 }833 834 printAnnotation(O, Annot);835 return;836 }837 838 AArch64InstPrinter::printInst(MI, Address, Annot, STI, O);839}840 841StringRef AArch64AppleInstPrinter::getRegName(MCRegister Reg) const {842 return getRegisterName(Reg);843}844 845bool AArch64InstPrinter::printRangePrefetchAlias(const MCInst *MI,846 const MCSubtargetInfo &STI,847 raw_ostream &O,848 StringRef Annot) {849 unsigned Opcode = MI->getOpcode();850 851#ifndef NDEBUG852 assert(((Opcode == AArch64::PRFMroX) || (Opcode == AArch64::PRFMroW)) &&853 "Invalid opcode for RPRFM alias!");854#endif855 856 unsigned PRFOp = MI->getOperand(0).getImm();857 unsigned Mask = 0x18; // 0b11000858 if ((PRFOp & Mask) != Mask)859 return false; // Rt != '11xxx', it's a PRFM instruction.860 861 MCRegister Rm = MI->getOperand(2).getReg();862 863 // "Rm" must be a 64-bit GPR for RPRFM.864 if (MRI.getRegClass(AArch64::GPR32RegClassID).contains(Rm))865 Rm = MRI.getMatchingSuperReg(Rm, AArch64::sub_32,866 &MRI.getRegClass(AArch64::GPR64RegClassID));867 868 unsigned SignExtend = MI->getOperand(3).getImm(); // encoded in "option<2>".869 unsigned Shift = MI->getOperand(4).getImm(); // encoded in "S".870 871 assert((SignExtend <= 1) && "sign extend should be a single bit!");872 assert((Shift <= 1) && "Shift should be a single bit!");873 874 unsigned Option0 = (Opcode == AArch64::PRFMroX) ? 1 : 0;875 876 // encoded in "option<2>:option<0>:S:Rt<2:0>".877 unsigned RPRFOp =878 (SignExtend << 5) | (Option0 << 4) | (Shift << 3) | (PRFOp & 0x7);879 880 O << "\trprfm ";881 if (auto RPRFM = AArch64RPRFM::lookupRPRFMByEncoding(RPRFOp))882 O << RPRFM->Name << ", ";883 else884 O << "#" << formatImm(RPRFOp) << ", ";885 O << getRegisterName(Rm);886 O << ", [";887 printOperand(MI, 1, STI, O); // "Rn".888 O << "]";889 890 printAnnotation(O, Annot);891 892 return true;893}894 895bool AArch64InstPrinter::printSysAlias(const MCInst *MI,896 const MCSubtargetInfo &STI,897 raw_ostream &O) {898#ifndef NDEBUG899 unsigned Opcode = MI->getOpcode();900 assert(Opcode == AArch64::SYSxt && "Invalid opcode for SYS alias!");901#endif902 903 const MCOperand &Op1 = MI->getOperand(0);904 const MCOperand &Cn = MI->getOperand(1);905 const MCOperand &Cm = MI->getOperand(2);906 const MCOperand &Op2 = MI->getOperand(3);907 908 unsigned Op1Val = Op1.getImm();909 unsigned CnVal = Cn.getImm();910 unsigned CmVal = Cm.getImm();911 unsigned Op2Val = Op2.getImm();912 913 uint16_t Encoding = Op2Val;914 Encoding |= CmVal << 3;915 Encoding |= CnVal << 7;916 Encoding |= Op1Val << 11;917 918 bool NeedsReg = false;919 bool OptionalReg = false;920 std::string Ins;921 std::string Name;922 923 if (CnVal == 7) {924 switch (CmVal) {925 default: return false;926 // MLBI aliases927 case 0: {928 const AArch64MLBI::MLBI *MLBI =929 AArch64MLBI::lookupMLBIByEncoding(Encoding);930 if (!MLBI || !MLBI->haveFeatures(STI.getFeatureBits()))931 return false;932 933 NeedsReg = MLBI->NeedsReg;934 Ins = "mlbi\t";935 Name = std::string(MLBI->Name);936 } break;937 // Maybe IC, maybe Prediction Restriction938 case 1:939 switch (Op1Val) {940 default: return false;941 case 0: goto Search_IC;942 case 3: goto Search_PRCTX;943 }944 // Prediction Restriction aliases945 case 3: {946 Search_PRCTX:947 if (Op1Val != 3 || CnVal != 7 || CmVal != 3)948 return false;949 950 const auto Requires =951 Op2Val == 6 ? AArch64::FeatureSPECRES2 : AArch64::FeaturePredRes;952 if (!(STI.hasFeature(AArch64::FeatureAll) || STI.hasFeature(Requires)))953 return false;954 955 NeedsReg = true;956 switch (Op2Val) {957 default: return false;958 case 4: Ins = "cfp\t"; break;959 case 5: Ins = "dvp\t"; break;960 case 6: Ins = "cosp\t"; break;961 case 7: Ins = "cpp\t"; break;962 }963 Name = "RCTX";964 }965 break;966 // IC aliases967 case 5: {968 Search_IC:969 const AArch64IC::IC *IC = AArch64IC::lookupICByEncoding(Encoding);970 if (!IC || !IC->haveFeatures(STI.getFeatureBits()))971 return false;972 973 NeedsReg = IC->NeedsReg;974 Ins = "ic\t";975 Name = std::string(IC->Name);976 }977 break;978 // DC aliases979 case 4: case 6: case 10: case 11: case 12: case 13: case 14:980 {981 const AArch64DC::DC *DC = AArch64DC::lookupDCByEncoding(Encoding);982 if (!DC || !DC->haveFeatures(STI.getFeatureBits()))983 return false;984 985 NeedsReg = true;986 Ins = "dc\t";987 Name = std::string(DC->Name);988 }989 break;990 // AT aliases991 case 8: case 9: {992 const AArch64AT::AT *AT = AArch64AT::lookupATByEncoding(Encoding);993 if (!AT || !AT->haveFeatures(STI.getFeatureBits()))994 return false;995 996 NeedsReg = true;997 Ins = "at\t";998 Name = std::string(AT->Name);999 }1000 break;1001 // Overlaps with AT and DC1002 case 15: {1003 const AArch64AT::AT *AT = AArch64AT::lookupATByEncoding(Encoding);1004 const AArch64DC::DC *DC = AArch64DC::lookupDCByEncoding(Encoding);1005 if (AT && AT->haveFeatures(STI.getFeatureBits())) {1006 NeedsReg = true;1007 Ins = "at\t";1008 Name = std::string(AT->Name);1009 } else if (DC && DC->haveFeatures(STI.getFeatureBits())) {1010 NeedsReg = true;1011 Ins = "dc\t";1012 Name = std::string(DC->Name);1013 } else {1014 return false;1015 }1016 } break;1017 }1018 } else if (CnVal == 8 || CnVal == 9) {1019 // TLBI aliases1020 const AArch64TLBI::TLBI *TLBI = AArch64TLBI::lookupTLBIByEncoding(Encoding);1021 if (!TLBI || !TLBI->haveFeatures(STI.getFeatureBits()))1022 return false;1023 1024 NeedsReg = TLBI->NeedsReg;1025 if (STI.hasFeature(AArch64::FeatureAll) ||1026 STI.hasFeature(AArch64::FeatureTLBID))1027 OptionalReg = TLBI->OptionalReg;1028 Ins = "tlbi\t";1029 Name = std::string(TLBI->Name);1030 } else if (CnVal == 12) {1031 if (CmVal != 0) {1032 // GIC aliases1033 const AArch64GIC::GIC *GIC = AArch64GIC::lookupGICByEncoding(Encoding);1034 if (!GIC || !GIC->haveFeatures(STI.getFeatureBits()))1035 return false;1036 1037 NeedsReg = GIC->NeedsReg;1038 Ins = "gic\t";1039 Name = std::string(GIC->Name);1040 } else {1041 // GSB aliases1042 const AArch64GSB::GSB *GSB = AArch64GSB::lookupGSBByEncoding(Encoding);1043 if (!GSB || !GSB->haveFeatures(STI.getFeatureBits()))1044 return false;1045 1046 NeedsReg = false;1047 Ins = "gsb\t";1048 Name = std::string(GSB->Name);1049 }1050 } else if (CnVal == 10) {1051 // PLBI aliases1052 const AArch64PLBI::PLBI *PLBI = AArch64PLBI::lookupPLBIByEncoding(Encoding);1053 if (!PLBI || !PLBI->haveFeatures(STI.getFeatureBits()))1054 return false;1055 1056 NeedsReg = PLBI->NeedsReg;1057 if (STI.hasFeature(AArch64::FeatureAll) ||1058 STI.hasFeature(AArch64::FeatureTLBID))1059 OptionalReg = PLBI->OptionalReg;1060 Ins = "plbi\t";1061 Name = std::string(PLBI->Name);1062 } else1063 return false;1064 1065 StringRef Reg = getRegisterName(MI->getOperand(4).getReg());1066 bool NotXZR = Reg != "xzr";1067 1068 // If a mandatory or optional register is not specified in the TableGen1069 // (i.e. no register operand should be present), and the register value1070 // is not xzr/x31, then disassemble to a SYS alias instead.1071 if (NotXZR && !NeedsReg && !OptionalReg)1072 return false;1073 1074 std::string Str = Ins + Name;1075 llvm::transform(Str, Str.begin(), ::tolower);1076 1077 O << '\t' << Str;1078 1079 // For optional registers, don't print the value if it's xzr/x311080 // since this defaults to xzr/x31 if register is not specified.1081 if (NeedsReg || (OptionalReg && NotXZR))1082 O << ", " << Reg;1083 1084 return true;1085}1086 1087bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,1088 const MCSubtargetInfo &STI,1089 raw_ostream &O) {1090#ifndef NDEBUG1091 unsigned Opcode = MI->getOpcode();1092 assert(Opcode == AArch64::SYSLxt && "Invalid opcode for SYSL alias!");1093#endif1094 1095 StringRef Reg = getRegisterName(MI->getOperand(0).getReg());1096 const MCOperand &Op1 = MI->getOperand(1);1097 const MCOperand &Cn = MI->getOperand(2);1098 const MCOperand &Cm = MI->getOperand(3);1099 const MCOperand &Op2 = MI->getOperand(4);1100 1101 unsigned Op1Val = Op1.getImm();1102 unsigned CnVal = Cn.getImm();1103 unsigned CmVal = Cm.getImm();1104 unsigned Op2Val = Op2.getImm();1105 1106 uint16_t Encoding = Op2Val;1107 Encoding |= CmVal << 3;1108 Encoding |= CnVal << 7;1109 Encoding |= Op1Val << 11;1110 1111 std::string Ins;1112 std::string Name;1113 1114 if (CnVal == 12) {1115 if (CmVal == 3) {1116 // GICR aliases1117 const AArch64GICR::GICR *GICR =1118 AArch64GICR::lookupGICRByEncoding(Encoding);1119 if (!GICR || !GICR->haveFeatures(STI.getFeatureBits()))1120 return false;1121 1122 Ins = "gicr";1123 Name = std::string(GICR->Name);1124 } else1125 return false;1126 } else1127 return false;1128 1129 llvm::transform(Name, Name.begin(), ::tolower);1130 1131 O << '\t' << Ins << '\t' << Reg.str() << ", " << Name;1132 1133 return true;1134}1135 1136bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,1137 const MCSubtargetInfo &STI,1138 raw_ostream &O) {1139#ifndef NDEBUG1140 unsigned Opcode = MI->getOpcode();1141 assert((Opcode == AArch64::SYSPxt || Opcode == AArch64::SYSPxt_XZR) &&1142 "Invalid opcode for SYSP alias!");1143#endif1144 1145 const MCOperand &Op1 = MI->getOperand(0);1146 const MCOperand &Cn = MI->getOperand(1);1147 const MCOperand &Cm = MI->getOperand(2);1148 const MCOperand &Op2 = MI->getOperand(3);1149 1150 unsigned Op1Val = Op1.getImm();1151 unsigned CnVal = Cn.getImm();1152 unsigned CmVal = Cm.getImm();1153 unsigned Op2Val = Op2.getImm();1154 1155 uint16_t Encoding = Op2Val;1156 Encoding |= CmVal << 3;1157 Encoding |= CnVal << 7;1158 Encoding |= Op1Val << 11;1159 1160 std::string Ins;1161 std::string Name;1162 1163 if (CnVal == 8 || CnVal == 9) {1164 // TLBIP aliases1165 1166 if (CnVal == 9) {1167 if (!STI.hasFeature(AArch64::FeatureXS))1168 return false;1169 Encoding &= ~(1 << 7);1170 }1171 1172 const AArch64TLBIP::TLBIP *TLBIP =1173 AArch64TLBIP::lookupTLBIPByEncoding(Encoding);1174 if (!TLBIP || !TLBIP->haveFeatures(STI.getFeatureBits()))1175 return false;1176 1177 Ins = "tlbip\t";1178 Name = std::string(TLBIP->Name);1179 if (CnVal == 9)1180 Name += "nXS";1181 } else1182 return false;1183 1184 std::string Str = Ins + Name;1185 llvm::transform(Str, Str.begin(), ::tolower);1186 1187 O << '\t' << Str;1188 O << ", ";1189 if (MI->getOperand(4).getReg() == AArch64::XZR)1190 printSyspXzrPair(MI, 4, STI, O);1191 else1192 printGPRSeqPairsClassOperand<64>(MI, 4, STI, O);1193 1194 return true;1195}1196 1197template <int EltSize>1198void AArch64InstPrinter::printMatrix(const MCInst *MI, unsigned OpNum,1199 const MCSubtargetInfo &STI,1200 raw_ostream &O) {1201 const MCOperand &RegOp = MI->getOperand(OpNum);1202 assert(RegOp.isReg() && "Unexpected operand type!");1203 1204 printRegName(O, RegOp.getReg());1205 switch (EltSize) {1206 case 0:1207 break;1208 case 8:1209 O << ".b";1210 break;1211 case 16:1212 O << ".h";1213 break;1214 case 32:1215 O << ".s";1216 break;1217 case 64:1218 O << ".d";1219 break;1220 case 128:1221 O << ".q";1222 break;1223 default:1224 llvm_unreachable("Unsupported element size");1225 }1226}1227 1228template <bool IsVertical>1229void AArch64InstPrinter::printMatrixTileVector(const MCInst *MI, unsigned OpNum,1230 const MCSubtargetInfo &STI,1231 raw_ostream &O) {1232 const MCOperand &RegOp = MI->getOperand(OpNum);1233 assert(RegOp.isReg() && "Unexpected operand type!");1234 StringRef RegName = getRegisterName(RegOp.getReg());1235 1236 // Insert the horizontal/vertical flag before the suffix.1237 StringRef Base, Suffix;1238 std::tie(Base, Suffix) = RegName.split('.');1239 O << Base << (IsVertical ? "v" : "h") << '.' << Suffix;1240}1241 1242void AArch64InstPrinter::printMatrixTile(const MCInst *MI, unsigned OpNum,1243 const MCSubtargetInfo &STI,1244 raw_ostream &O) {1245 const MCOperand &RegOp = MI->getOperand(OpNum);1246 assert(RegOp.isReg() && "Unexpected operand type!");1247 printRegName(O, RegOp.getReg());1248}1249 1250void AArch64InstPrinter::printSVCROp(const MCInst *MI, unsigned OpNum,1251 const MCSubtargetInfo &STI,1252 raw_ostream &O) {1253 const MCOperand &MO = MI->getOperand(OpNum);1254 assert(MO.isImm() && "Unexpected operand type!");1255 unsigned svcrop = MO.getImm();1256 const auto *SVCR = AArch64SVCR::lookupSVCRByEncoding(svcrop);1257 assert(SVCR && "Unexpected SVCR operand!");1258 O << SVCR->Name;1259}1260 1261void AArch64InstPrinter::printOperand(const MCInst *MI, unsigned OpNo,1262 const MCSubtargetInfo &STI,1263 raw_ostream &O) {1264 const MCOperand &Op = MI->getOperand(OpNo);1265 if (Op.isReg()) {1266 printRegName(O, Op.getReg());1267 } else if (Op.isImm()) {1268 printImm(MI, OpNo, STI, O);1269 } else {1270 assert(Op.isExpr() && "unknown operand kind in printOperand");1271 MAI.printExpr(O, *Op.getExpr());1272 }1273}1274 1275void AArch64InstPrinter::printImm(const MCInst *MI, unsigned OpNo,1276 const MCSubtargetInfo &STI,1277 raw_ostream &O) {1278 const MCOperand &Op = MI->getOperand(OpNo);1279 markup(O, Markup::Immediate) << "#" << formatImm(Op.getImm());1280}1281 1282void AArch64InstPrinter::printImmHex(const MCInst *MI, unsigned OpNo,1283 const MCSubtargetInfo &STI,1284 raw_ostream &O) {1285 const MCOperand &Op = MI->getOperand(OpNo);1286 markup(O, Markup::Immediate) << format("#%#llx", Op.getImm());1287}1288 1289template<int Size>1290void AArch64InstPrinter::printSImm(const MCInst *MI, unsigned OpNo,1291 const MCSubtargetInfo &STI,1292 raw_ostream &O) {1293 const MCOperand &Op = MI->getOperand(OpNo);1294 if (Size == 8)1295 markup(O, Markup::Immediate) << "#" << formatImm((signed char)Op.getImm());1296 else if (Size == 16)1297 markup(O, Markup::Immediate) << "#" << formatImm((signed short)Op.getImm());1298 else1299 markup(O, Markup::Immediate) << "#" << formatImm(Op.getImm());1300}1301 1302void AArch64InstPrinter::printPostIncOperand(const MCInst *MI, unsigned OpNo,1303 unsigned Imm, raw_ostream &O) {1304 const MCOperand &Op = MI->getOperand(OpNo);1305 if (Op.isReg()) {1306 MCRegister Reg = Op.getReg();1307 if (Reg == AArch64::XZR)1308 markup(O, Markup::Immediate) << "#" << Imm;1309 else1310 printRegName(O, Reg);1311 } else1312 llvm_unreachable("unknown operand kind in printPostIncOperand64");1313}1314 1315void AArch64InstPrinter::printVRegOperand(const MCInst *MI, unsigned OpNo,1316 const MCSubtargetInfo &STI,1317 raw_ostream &O) {1318 const MCOperand &Op = MI->getOperand(OpNo);1319 assert(Op.isReg() && "Non-register vreg operand!");1320 printRegName(O, Op.getReg(), AArch64::vreg);1321}1322 1323void AArch64InstPrinter::printSysCROperand(const MCInst *MI, unsigned OpNo,1324 const MCSubtargetInfo &STI,1325 raw_ostream &O) {1326 const MCOperand &Op = MI->getOperand(OpNo);1327 assert(Op.isImm() && "System instruction C[nm] operands must be immediates!");1328 O << "c" << Op.getImm();1329}1330 1331void AArch64InstPrinter::printAddSubImm(const MCInst *MI, unsigned OpNum,1332 const MCSubtargetInfo &STI,1333 raw_ostream &O) {1334 const MCOperand &MO = MI->getOperand(OpNum);1335 if (MO.isImm()) {1336 unsigned Val = (MO.getImm() & 0xfff);1337 assert(Val == MO.getImm() && "Add/sub immediate out of range!");1338 unsigned Shift =1339 AArch64_AM::getShiftValue(MI->getOperand(OpNum + 1).getImm());1340 markup(O, Markup::Immediate) << '#' << formatImm(Val);1341 if (Shift != 0) {1342 printShifter(MI, OpNum + 1, STI, O);1343 if (CommentStream)1344 *CommentStream << '=' << formatImm(Val << Shift) << '\n';1345 }1346 } else {1347 assert(MO.isExpr() && "Unexpected operand type!");1348 MAI.printExpr(O, *MO.getExpr());1349 printShifter(MI, OpNum + 1, STI, O);1350 }1351}1352 1353template <typename T>1354void AArch64InstPrinter::printLogicalImm(const MCInst *MI, unsigned OpNum,1355 const MCSubtargetInfo &STI,1356 raw_ostream &O) {1357 uint64_t Val = MI->getOperand(OpNum).getImm();1358 WithMarkup M = markup(O, Markup::Immediate);1359 O << "#0x";1360 O.write_hex(AArch64_AM::decodeLogicalImmediate(Val, 8 * sizeof(T)));1361}1362 1363void AArch64InstPrinter::printShifter(const MCInst *MI, unsigned OpNum,1364 const MCSubtargetInfo &STI,1365 raw_ostream &O) {1366 unsigned Val = MI->getOperand(OpNum).getImm();1367 // LSL #0 should not be printed.1368 if (AArch64_AM::getShiftType(Val) == AArch64_AM::LSL &&1369 AArch64_AM::getShiftValue(Val) == 0)1370 return;1371 O << ", " << AArch64_AM::getShiftExtendName(AArch64_AM::getShiftType(Val))1372 << " ";1373 markup(O, Markup::Immediate) << "#" << AArch64_AM::getShiftValue(Val);1374}1375 1376void AArch64InstPrinter::printShiftedRegister(const MCInst *MI, unsigned OpNum,1377 const MCSubtargetInfo &STI,1378 raw_ostream &O) {1379 printRegName(O, MI->getOperand(OpNum).getReg());1380 printShifter(MI, OpNum + 1, STI, O);1381}1382 1383void AArch64InstPrinter::printExtendedRegister(const MCInst *MI, unsigned OpNum,1384 const MCSubtargetInfo &STI,1385 raw_ostream &O) {1386 printRegName(O, MI->getOperand(OpNum).getReg());1387 printArithExtend(MI, OpNum + 1, STI, O);1388}1389 1390void AArch64InstPrinter::printArithExtend(const MCInst *MI, unsigned OpNum,1391 const MCSubtargetInfo &STI,1392 raw_ostream &O) {1393 unsigned Val = MI->getOperand(OpNum).getImm();1394 AArch64_AM::ShiftExtendType ExtType = AArch64_AM::getArithExtendType(Val);1395 unsigned ShiftVal = AArch64_AM::getArithShiftValue(Val);1396 1397 // If the destination or first source register operand is [W]SP, print1398 // UXTW/UXTX as LSL, and if the shift amount is also zero, print nothing at1399 // all.1400 if (ExtType == AArch64_AM::UXTW || ExtType == AArch64_AM::UXTX) {1401 MCRegister Dest = MI->getOperand(0).getReg();1402 MCRegister Src1 = MI->getOperand(1).getReg();1403 if ( ((Dest == AArch64::SP || Src1 == AArch64::SP) &&1404 ExtType == AArch64_AM::UXTX) ||1405 ((Dest == AArch64::WSP || Src1 == AArch64::WSP) &&1406 ExtType == AArch64_AM::UXTW) ) {1407 if (ShiftVal != 0) {1408 O << ", lsl ";1409 markup(O, Markup::Immediate) << "#" << ShiftVal;1410 }1411 return;1412 }1413 }1414 O << ", " << AArch64_AM::getShiftExtendName(ExtType);1415 if (ShiftVal != 0) {1416 O << " ";1417 markup(O, Markup::Immediate) << "#" << ShiftVal;1418 }1419}1420 1421void AArch64InstPrinter::printMemExtendImpl(bool SignExtend, bool DoShift,1422 unsigned Width, char SrcRegKind,1423 raw_ostream &O) {1424 // sxtw, sxtx, uxtw or lsl (== uxtx)1425 bool IsLSL = !SignExtend && SrcRegKind == 'x';1426 if (IsLSL)1427 O << "lsl";1428 else1429 O << (SignExtend ? 's' : 'u') << "xt" << SrcRegKind;1430 1431 if (DoShift || IsLSL) {1432 O << " ";1433 markup(O, Markup::Immediate) << "#" << Log2_32(Width / 8);1434 }1435}1436 1437void AArch64InstPrinter::printMemExtend(const MCInst *MI, unsigned OpNum,1438 raw_ostream &O, char SrcRegKind,1439 unsigned Width) {1440 bool SignExtend = MI->getOperand(OpNum).getImm();1441 bool DoShift = MI->getOperand(OpNum + 1).getImm();1442 printMemExtendImpl(SignExtend, DoShift, Width, SrcRegKind, O);1443}1444 1445template <bool SignExtend, int ExtWidth, char SrcRegKind, char Suffix>1446void AArch64InstPrinter::printRegWithShiftExtend(const MCInst *MI,1447 unsigned OpNum,1448 const MCSubtargetInfo &STI,1449 raw_ostream &O) {1450 printOperand(MI, OpNum, STI, O);1451 if (Suffix == 's' || Suffix == 'd')1452 O << '.' << Suffix;1453 else1454 assert(Suffix == 0 && "Unsupported suffix size");1455 1456 bool DoShift = ExtWidth != 8;1457 if (SignExtend || DoShift || SrcRegKind == 'w') {1458 O << ", ";1459 printMemExtendImpl(SignExtend, DoShift, ExtWidth, SrcRegKind, O);1460 }1461}1462 1463template <int EltSize>1464void AArch64InstPrinter::printPredicateAsCounter(const MCInst *MI,1465 unsigned OpNum,1466 const MCSubtargetInfo &STI,1467 raw_ostream &O) {1468 MCRegister Reg = MI->getOperand(OpNum).getReg();1469 if (Reg < AArch64::PN0 || Reg > AArch64::PN15)1470 llvm_unreachable("Unsupported predicate-as-counter register");1471 O << "pn" << Reg - AArch64::PN0;1472 1473 switch (EltSize) {1474 case 0:1475 break;1476 case 8:1477 O << ".b";1478 break;1479 case 16:1480 O << ".h";1481 break;1482 case 32:1483 O << ".s";1484 break;1485 case 64:1486 O << ".d";1487 break;1488 default:1489 llvm_unreachable("Unsupported element size");1490 }1491}1492 1493void AArch64InstPrinter::printCondCode(const MCInst *MI, unsigned OpNum,1494 const MCSubtargetInfo &STI,1495 raw_ostream &O) {1496 AArch64CC::CondCode CC = (AArch64CC::CondCode)MI->getOperand(OpNum).getImm();1497 O << AArch64CC::getCondCodeName(CC);1498}1499 1500void AArch64InstPrinter::printInverseCondCode(const MCInst *MI, unsigned OpNum,1501 const MCSubtargetInfo &STI,1502 raw_ostream &O) {1503 AArch64CC::CondCode CC = (AArch64CC::CondCode)MI->getOperand(OpNum).getImm();1504 O << AArch64CC::getCondCodeName(AArch64CC::getInvertedCondCode(CC));1505}1506 1507void AArch64InstPrinter::printAMNoIndex(const MCInst *MI, unsigned OpNum,1508 const MCSubtargetInfo &STI,1509 raw_ostream &O) {1510 O << '[';1511 printRegName(O, MI->getOperand(OpNum).getReg());1512 O << ']';1513}1514 1515template <int Scale>1516void AArch64InstPrinter::printImmScale(const MCInst *MI, unsigned OpNum,1517 const MCSubtargetInfo &STI,1518 raw_ostream &O) {1519 markup(O, Markup::Immediate)1520 << '#' << formatImm(Scale * MI->getOperand(OpNum).getImm());1521}1522 1523template <int Scale, int Offset>1524void AArch64InstPrinter::printImmRangeScale(const MCInst *MI, unsigned OpNum,1525 const MCSubtargetInfo &STI,1526 raw_ostream &O) {1527 unsigned FirstImm = Scale * MI->getOperand(OpNum).getImm();1528 O << formatImm(FirstImm);1529 O << ":" << formatImm(FirstImm + Offset);1530}1531 1532void AArch64InstPrinter::printUImm12Offset(const MCInst *MI, unsigned OpNum,1533 unsigned Scale, raw_ostream &O) {1534 const MCOperand MO = MI->getOperand(OpNum);1535 if (MO.isImm()) {1536 markup(O, Markup::Immediate) << '#' << formatImm(MO.getImm() * Scale);1537 } else {1538 assert(MO.isExpr() && "Unexpected operand type!");1539 MAI.printExpr(O, *MO.getExpr());1540 }1541}1542 1543void AArch64InstPrinter::printAMIndexedWB(const MCInst *MI, unsigned OpNum,1544 unsigned Scale, raw_ostream &O) {1545 const MCOperand MO1 = MI->getOperand(OpNum + 1);1546 O << '[';1547 printRegName(O, MI->getOperand(OpNum).getReg());1548 if (MO1.isImm()) {1549 O << ", ";1550 markup(O, Markup::Immediate) << "#" << formatImm(MO1.getImm() * Scale);1551 } else {1552 assert(MO1.isExpr() && "Unexpected operand type!");1553 O << ", ";1554 MAI.printExpr(O, *MO1.getExpr());1555 }1556 O << ']';1557}1558 1559void AArch64InstPrinter::printRPRFMOperand(const MCInst *MI, unsigned OpNum,1560 const MCSubtargetInfo &STI,1561 raw_ostream &O) {1562 unsigned prfop = MI->getOperand(OpNum).getImm();1563 if (auto PRFM = AArch64RPRFM::lookupRPRFMByEncoding(prfop)) {1564 O << PRFM->Name;1565 return;1566 }1567 1568 O << '#' << formatImm(prfop);1569}1570 1571template <bool IsSVEPrefetch>1572void AArch64InstPrinter::printPrefetchOp(const MCInst *MI, unsigned OpNum,1573 const MCSubtargetInfo &STI,1574 raw_ostream &O) {1575 unsigned prfop = MI->getOperand(OpNum).getImm();1576 if (IsSVEPrefetch) {1577 if (auto PRFM = AArch64SVEPRFM::lookupSVEPRFMByEncoding(prfop)) {1578 O << PRFM->Name;1579 return;1580 }1581 } else {1582 auto PRFM = AArch64PRFM::lookupPRFMByEncoding(prfop);1583 if (PRFM && PRFM->haveFeatures(STI.getFeatureBits())) {1584 O << PRFM->Name;1585 return;1586 }1587 }1588 1589 markup(O, Markup::Immediate) << '#' << formatImm(prfop);1590}1591 1592void AArch64InstPrinter::printPSBHintOp(const MCInst *MI, unsigned OpNum,1593 const MCSubtargetInfo &STI,1594 raw_ostream &O) {1595 unsigned psbhintop = MI->getOperand(OpNum).getImm();1596 auto PSB = AArch64PSBHint::lookupPSBByEncoding(psbhintop);1597 if (PSB)1598 O << PSB->Name;1599 else1600 markup(O, Markup::Immediate) << '#' << formatImm(psbhintop);1601}1602 1603void AArch64InstPrinter::printBTIHintOp(const MCInst *MI, unsigned OpNum,1604 const MCSubtargetInfo &STI,1605 raw_ostream &O) {1606 unsigned btihintop = MI->getOperand(OpNum).getImm() ^ 32;1607 auto BTI = AArch64BTIHint::lookupBTIByEncoding(btihintop);1608 if (BTI)1609 O << BTI->Name;1610 else1611 markup(O, Markup::Immediate) << '#' << formatImm(btihintop);1612}1613 1614void AArch64InstPrinter::printCMHPriorityHintOp(const MCInst *MI,1615 unsigned OpNum,1616 const MCSubtargetInfo &STI,1617 raw_ostream &O) {1618 unsigned priorityhint_op = MI->getOperand(OpNum).getImm();1619 auto PHint =1620 AArch64CMHPriorityHint::lookupCMHPriorityHintByEncoding(priorityhint_op);1621 if (PHint)1622 O << PHint->Name;1623 else1624 markup(O, Markup::Immediate) << '#' << formatImm(priorityhint_op);1625}1626 1627void AArch64InstPrinter::printTIndexHintOp(const MCInst *MI, unsigned OpNum,1628 const MCSubtargetInfo &STI,1629 raw_ostream &O) {1630 unsigned tindexhintop = MI->getOperand(OpNum).getImm();1631 auto TIndex = AArch64TIndexHint::lookupTIndexByEncoding(tindexhintop);1632 if (TIndex)1633 O << TIndex->Name;1634 else1635 markup(O, Markup::Immediate) << '#' << formatImm(tindexhintop);1636}1637 1638void AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum,1639 const MCSubtargetInfo &STI,1640 raw_ostream &O) {1641 const MCOperand &MO = MI->getOperand(OpNum);1642 float FPImm = MO.isDFPImm() ? bit_cast<double>(MO.getDFPImm())1643 : AArch64_AM::getFPImmFloat(MO.getImm());1644 1645 // 8 decimal places are enough to perfectly represent permitted floats.1646 markup(O, Markup::Immediate) << format("#%.8f", FPImm);1647}1648 1649static MCRegister getNextVectorRegister(MCRegister Reg, unsigned Stride = 1) {1650 while (Stride--) {1651 switch (Reg.id()) {1652 default:1653 llvm_unreachable("Vector register expected!");1654 case AArch64::Q0: Reg = AArch64::Q1; break;1655 case AArch64::Q1: Reg = AArch64::Q2; break;1656 case AArch64::Q2: Reg = AArch64::Q3; break;1657 case AArch64::Q3: Reg = AArch64::Q4; break;1658 case AArch64::Q4: Reg = AArch64::Q5; break;1659 case AArch64::Q5: Reg = AArch64::Q6; break;1660 case AArch64::Q6: Reg = AArch64::Q7; break;1661 case AArch64::Q7: Reg = AArch64::Q8; break;1662 case AArch64::Q8: Reg = AArch64::Q9; break;1663 case AArch64::Q9: Reg = AArch64::Q10; break;1664 case AArch64::Q10: Reg = AArch64::Q11; break;1665 case AArch64::Q11: Reg = AArch64::Q12; break;1666 case AArch64::Q12: Reg = AArch64::Q13; break;1667 case AArch64::Q13: Reg = AArch64::Q14; break;1668 case AArch64::Q14: Reg = AArch64::Q15; break;1669 case AArch64::Q15: Reg = AArch64::Q16; break;1670 case AArch64::Q16: Reg = AArch64::Q17; break;1671 case AArch64::Q17: Reg = AArch64::Q18; break;1672 case AArch64::Q18: Reg = AArch64::Q19; break;1673 case AArch64::Q19: Reg = AArch64::Q20; break;1674 case AArch64::Q20: Reg = AArch64::Q21; break;1675 case AArch64::Q21: Reg = AArch64::Q22; break;1676 case AArch64::Q22: Reg = AArch64::Q23; break;1677 case AArch64::Q23: Reg = AArch64::Q24; break;1678 case AArch64::Q24: Reg = AArch64::Q25; break;1679 case AArch64::Q25: Reg = AArch64::Q26; break;1680 case AArch64::Q26: Reg = AArch64::Q27; break;1681 case AArch64::Q27: Reg = AArch64::Q28; break;1682 case AArch64::Q28: Reg = AArch64::Q29; break;1683 case AArch64::Q29: Reg = AArch64::Q30; break;1684 case AArch64::Q30: Reg = AArch64::Q31; break;1685 // Vector lists can wrap around.1686 case AArch64::Q31:1687 Reg = AArch64::Q0;1688 break;1689 case AArch64::Z0: Reg = AArch64::Z1; break;1690 case AArch64::Z1: Reg = AArch64::Z2; break;1691 case AArch64::Z2: Reg = AArch64::Z3; break;1692 case AArch64::Z3: Reg = AArch64::Z4; break;1693 case AArch64::Z4: Reg = AArch64::Z5; break;1694 case AArch64::Z5: Reg = AArch64::Z6; break;1695 case AArch64::Z6: Reg = AArch64::Z7; break;1696 case AArch64::Z7: Reg = AArch64::Z8; break;1697 case AArch64::Z8: Reg = AArch64::Z9; break;1698 case AArch64::Z9: Reg = AArch64::Z10; break;1699 case AArch64::Z10: Reg = AArch64::Z11; break;1700 case AArch64::Z11: Reg = AArch64::Z12; break;1701 case AArch64::Z12: Reg = AArch64::Z13; break;1702 case AArch64::Z13: Reg = AArch64::Z14; break;1703 case AArch64::Z14: Reg = AArch64::Z15; break;1704 case AArch64::Z15: Reg = AArch64::Z16; break;1705 case AArch64::Z16: Reg = AArch64::Z17; break;1706 case AArch64::Z17: Reg = AArch64::Z18; break;1707 case AArch64::Z18: Reg = AArch64::Z19; break;1708 case AArch64::Z19: Reg = AArch64::Z20; break;1709 case AArch64::Z20: Reg = AArch64::Z21; break;1710 case AArch64::Z21: Reg = AArch64::Z22; break;1711 case AArch64::Z22: Reg = AArch64::Z23; break;1712 case AArch64::Z23: Reg = AArch64::Z24; break;1713 case AArch64::Z24: Reg = AArch64::Z25; break;1714 case AArch64::Z25: Reg = AArch64::Z26; break;1715 case AArch64::Z26: Reg = AArch64::Z27; break;1716 case AArch64::Z27: Reg = AArch64::Z28; break;1717 case AArch64::Z28: Reg = AArch64::Z29; break;1718 case AArch64::Z29: Reg = AArch64::Z30; break;1719 case AArch64::Z30: Reg = AArch64::Z31; break;1720 // Vector lists can wrap around.1721 case AArch64::Z31:1722 Reg = AArch64::Z0;1723 break;1724 case AArch64::P0: Reg = AArch64::P1; break;1725 case AArch64::P1: Reg = AArch64::P2; break;1726 case AArch64::P2: Reg = AArch64::P3; break;1727 case AArch64::P3: Reg = AArch64::P4; break;1728 case AArch64::P4: Reg = AArch64::P5; break;1729 case AArch64::P5: Reg = AArch64::P6; break;1730 case AArch64::P6: Reg = AArch64::P7; break;1731 case AArch64::P7: Reg = AArch64::P8; break;1732 case AArch64::P8: Reg = AArch64::P9; break;1733 case AArch64::P9: Reg = AArch64::P10; break;1734 case AArch64::P10: Reg = AArch64::P11; break;1735 case AArch64::P11: Reg = AArch64::P12; break;1736 case AArch64::P12: Reg = AArch64::P13; break;1737 case AArch64::P13: Reg = AArch64::P14; break;1738 case AArch64::P14: Reg = AArch64::P15; break;1739 // Vector lists can wrap around.1740 case AArch64::P15: Reg = AArch64::P0; break;1741 }1742 }1743 return Reg;1744}1745 1746template<unsigned size>1747void AArch64InstPrinter::printGPRSeqPairsClassOperand(const MCInst *MI,1748 unsigned OpNum,1749 const MCSubtargetInfo &STI,1750 raw_ostream &O) {1751 static_assert(size == 64 || size == 32,1752 "Template parameter must be either 32 or 64");1753 MCRegister Reg = MI->getOperand(OpNum).getReg();1754 1755 unsigned Sube = (size == 32) ? AArch64::sube32 : AArch64::sube64;1756 unsigned Subo = (size == 32) ? AArch64::subo32 : AArch64::subo64;1757 1758 MCRegister Even = MRI.getSubReg(Reg, Sube);1759 MCRegister Odd = MRI.getSubReg(Reg, Subo);1760 printRegName(O, Even);1761 O << ", ";1762 printRegName(O, Odd);1763}1764 1765void AArch64InstPrinter::printMatrixTileList(const MCInst *MI, unsigned OpNum,1766 const MCSubtargetInfo &STI,1767 raw_ostream &O) {1768 unsigned MaxRegs = 8;1769 unsigned RegMask = MI->getOperand(OpNum).getImm();1770 1771 unsigned NumRegs = 0;1772 for (unsigned I = 0; I < MaxRegs; ++I)1773 if ((RegMask & (1 << I)) != 0)1774 ++NumRegs;1775 1776 O << "{";1777 unsigned Printed = 0;1778 for (unsigned I = 0; I < MaxRegs; ++I) {1779 unsigned Reg = RegMask & (1 << I);1780 if (Reg == 0)1781 continue;1782 printRegName(O, AArch64::ZAD0 + I);1783 if (Printed + 1 != NumRegs)1784 O << ", ";1785 ++Printed;1786 }1787 O << "}";1788}1789 1790void AArch64InstPrinter::printVectorList(const MCInst *MI, unsigned OpNum,1791 const MCSubtargetInfo &STI,1792 raw_ostream &O,1793 StringRef LayoutSuffix) {1794 MCRegister Reg = MI->getOperand(OpNum).getReg();1795 1796 O << "{ ";1797 1798 // Work out how many registers there are in the list (if there is an actual1799 // list).1800 unsigned NumRegs = 1;1801 if (MRI.getRegClass(AArch64::DDRegClassID).contains(Reg) ||1802 MRI.getRegClass(AArch64::ZPR2RegClassID).contains(Reg) ||1803 MRI.getRegClass(AArch64::QQRegClassID).contains(Reg) ||1804 MRI.getRegClass(AArch64::PPR2RegClassID).contains(Reg) ||1805 MRI.getRegClass(AArch64::ZPR2StridedRegClassID).contains(Reg))1806 NumRegs = 2;1807 else if (MRI.getRegClass(AArch64::DDDRegClassID).contains(Reg) ||1808 MRI.getRegClass(AArch64::ZPR3RegClassID).contains(Reg) ||1809 MRI.getRegClass(AArch64::QQQRegClassID).contains(Reg))1810 NumRegs = 3;1811 else if (MRI.getRegClass(AArch64::DDDDRegClassID).contains(Reg) ||1812 MRI.getRegClass(AArch64::ZPR4RegClassID).contains(Reg) ||1813 MRI.getRegClass(AArch64::QQQQRegClassID).contains(Reg) ||1814 MRI.getRegClass(AArch64::ZPR4StridedRegClassID).contains(Reg))1815 NumRegs = 4;1816 1817 unsigned Stride = 1;1818 if (MRI.getRegClass(AArch64::ZPR2StridedRegClassID).contains(Reg))1819 Stride = 8;1820 else if (MRI.getRegClass(AArch64::ZPR4StridedRegClassID).contains(Reg))1821 Stride = 4;1822 1823 // Now forget about the list and find out what the first register is.1824 if (MCRegister FirstReg = MRI.getSubReg(Reg, AArch64::dsub0))1825 Reg = FirstReg;1826 else if (MCRegister FirstReg = MRI.getSubReg(Reg, AArch64::qsub0))1827 Reg = FirstReg;1828 else if (MCRegister FirstReg = MRI.getSubReg(Reg, AArch64::zsub0))1829 Reg = FirstReg;1830 else if (MCRegister FirstReg = MRI.getSubReg(Reg, AArch64::psub0))1831 Reg = FirstReg;1832 1833 // If it's a D-reg, we need to promote it to the equivalent Q-reg before1834 // printing (otherwise getRegisterName fails).1835 if (MRI.getRegClass(AArch64::FPR64RegClassID).contains(Reg)) {1836 const MCRegisterClass &FPR128RC =1837 MRI.getRegClass(AArch64::FPR128RegClassID);1838 Reg = MRI.getMatchingSuperReg(Reg, AArch64::dsub, &FPR128RC);1839 }1840 1841 if ((MRI.getRegClass(AArch64::ZPRRegClassID).contains(Reg) ||1842 MRI.getRegClass(AArch64::PPRRegClassID).contains(Reg)) &&1843 NumRegs > 1 && Stride == 1 &&1844 // Do not print the range when the last register is lower than the first.1845 // Because it is a wrap-around register.1846 Reg < getNextVectorRegister(Reg, NumRegs - 1)) {1847 printRegName(O, Reg);1848 O << LayoutSuffix;1849 if (NumRegs > 1) {1850 // Set of two sve registers should be separated by ','1851 StringRef split_char = NumRegs == 2 ? ", " : " - ";1852 O << split_char;1853 printRegName(O, (getNextVectorRegister(Reg, NumRegs - 1)));1854 O << LayoutSuffix;1855 }1856 } else {1857 for (unsigned i = 0; i < NumRegs;1858 ++i, Reg = getNextVectorRegister(Reg, Stride)) {1859 // wrap-around sve register1860 if (MRI.getRegClass(AArch64::ZPRRegClassID).contains(Reg) ||1861 MRI.getRegClass(AArch64::PPRRegClassID).contains(Reg))1862 printRegName(O, Reg);1863 else1864 printRegName(O, Reg, AArch64::vreg);1865 O << LayoutSuffix;1866 if (i + 1 != NumRegs)1867 O << ", ";1868 }1869 }1870 O << " }";1871}1872 1873void1874AArch64InstPrinter::printImplicitlyTypedVectorList(const MCInst *MI,1875 unsigned OpNum,1876 const MCSubtargetInfo &STI,1877 raw_ostream &O) {1878 printVectorList(MI, OpNum, STI, O, "");1879}1880 1881template <unsigned NumLanes, char LaneKind>1882void AArch64InstPrinter::printTypedVectorList(const MCInst *MI, unsigned OpNum,1883 const MCSubtargetInfo &STI,1884 raw_ostream &O) {1885 if (LaneKind == 0) {1886 printVectorList(MI, OpNum, STI, O, "");1887 return;1888 }1889 std::string Suffix(".");1890 if (NumLanes)1891 Suffix += itostr(NumLanes) + LaneKind;1892 else1893 Suffix += LaneKind;1894 1895 printVectorList(MI, OpNum, STI, O, Suffix);1896}1897 1898template <unsigned Scale>1899void AArch64InstPrinter::printVectorIndex(const MCInst *MI, unsigned OpNum,1900 const MCSubtargetInfo &STI,1901 raw_ostream &O) {1902 O << "[" << Scale * MI->getOperand(OpNum).getImm() << "]";1903}1904 1905template <unsigned Scale>1906void AArch64InstPrinter::printMatrixIndex(const MCInst *MI, unsigned OpNum,1907 const MCSubtargetInfo &STI,1908 raw_ostream &O) {1909 O << Scale * MI->getOperand(OpNum).getImm();1910}1911 1912void AArch64InstPrinter::printAlignedLabel(const MCInst *MI, uint64_t Address,1913 unsigned OpNum,1914 const MCSubtargetInfo &STI,1915 raw_ostream &O) {1916 // Do not print the numeric target address when symbolizing.1917 if (SymbolizeOperands)1918 return;1919 1920 const MCOperand &Op = MI->getOperand(OpNum);1921 1922 // If the label has already been resolved to an immediate offset (say, when1923 // we're running the disassembler), just print the immediate.1924 if (Op.isImm()) {1925 int64_t Offset = Op.getImm() * 4;1926 if (PrintBranchImmAsAddress)1927 markup(O, Markup::Target) << formatHex(Address + Offset);1928 else1929 markup(O, Markup::Immediate) << "#" << formatImm(Offset);1930 return;1931 }1932 1933 // If the branch target is simply an address then print it in hex.1934 const MCConstantExpr *BranchTarget =1935 dyn_cast<MCConstantExpr>(MI->getOperand(OpNum).getExpr());1936 int64_t TargetAddress;1937 if (BranchTarget && BranchTarget->evaluateAsAbsolute(TargetAddress)) {1938 markup(O, Markup::Target) << formatHex((uint64_t)TargetAddress);1939 } else {1940 // Otherwise, just print the expression.1941 MAI.printExpr(O, *MI->getOperand(OpNum).getExpr());1942 }1943}1944 1945void AArch64InstPrinter::printAdrAdrpLabel(const MCInst *MI, uint64_t Address,1946 unsigned OpNum,1947 const MCSubtargetInfo &STI,1948 raw_ostream &O) {1949 // Do not print the numeric target address when symbolizing.1950 // However, do print for ADRP, as this is typically used together with an ADD1951 // or an immediate-offset ldr/str and the label is likely at the wrong point.1952 if (SymbolizeOperands && MI->getOpcode() != AArch64::ADRP)1953 return;1954 1955 const MCOperand &Op = MI->getOperand(OpNum);1956 1957 // If the label has already been resolved to an immediate offset (say, when1958 // we're running the disassembler), just print the immediate.1959 if (Op.isImm()) {1960 int64_t Offset = Op.getImm();1961 if (MI->getOpcode() == AArch64::ADRP) {1962 Offset = Offset * 4096;1963 Address = Address & -4096;1964 }1965 WithMarkup M = markup(O, Markup::Immediate);1966 if (PrintBranchImmAsAddress)1967 markup(O, Markup::Target) << formatHex(Address + Offset);1968 else1969 markup(O, Markup::Immediate) << "#" << Offset;1970 return;1971 }1972 1973 // Otherwise, just print the expression.1974 MAI.printExpr(O, *MI->getOperand(OpNum).getExpr());1975}1976 1977void AArch64InstPrinter::printBarrierOption(const MCInst *MI, unsigned OpNo,1978 const MCSubtargetInfo &STI,1979 raw_ostream &O) {1980 unsigned Val = MI->getOperand(OpNo).getImm();1981 unsigned Opcode = MI->getOpcode();1982 1983 StringRef Name;1984 if (Opcode == AArch64::ISB) {1985 auto ISB = AArch64ISB::lookupISBByEncoding(Val);1986 Name = ISB ? ISB->Name : "";1987 } else if (Opcode == AArch64::TSB) {1988 auto TSB = AArch64TSB::lookupTSBByEncoding(Val);1989 Name = TSB ? TSB->Name : "";1990 } else {1991 auto DB = AArch64DB::lookupDBByEncoding(Val);1992 Name = DB ? DB->Name : "";1993 }1994 if (!Name.empty())1995 O << Name;1996 else1997 markup(O, Markup::Immediate) << "#" << Val;1998}1999 2000void AArch64InstPrinter::printBarriernXSOption(const MCInst *MI, unsigned OpNo,2001 const MCSubtargetInfo &STI,2002 raw_ostream &O) {2003 unsigned Val = MI->getOperand(OpNo).getImm();2004 assert(MI->getOpcode() == AArch64::DSBnXS);2005 2006 StringRef Name;2007 auto DB = AArch64DBnXS::lookupDBnXSByEncoding(Val);2008 Name = DB ? DB->Name : "";2009 2010 if (!Name.empty())2011 O << Name;2012 else2013 markup(O, Markup::Immediate) << "#" << Val;2014}2015 2016static bool isValidSysReg(const AArch64SysReg::SysReg &Reg, bool Read,2017 const MCSubtargetInfo &STI) {2018 return (Read ? Reg.Readable : Reg.Writeable) &&2019 Reg.haveFeatures(STI.getFeatureBits());2020}2021 2022// Looks up a system register either by encoding. Some system2023// registers share the same encoding between different architectures,2024// to work around this tablegen will return a range of registers with the same2025// encodings. We need to check each register in the range to see if it valid.2026static const AArch64SysReg::SysReg *lookupSysReg(unsigned Val, bool Read,2027 const MCSubtargetInfo &STI) {2028 auto Range = AArch64SysReg::lookupSysRegByEncoding(Val);2029 for (auto &Reg : Range) {2030 if (isValidSysReg(Reg, Read, STI))2031 return &Reg;2032 }2033 2034 return nullptr;2035}2036 2037void AArch64InstPrinter::printMRSSystemRegister(const MCInst *MI, unsigned OpNo,2038 const MCSubtargetInfo &STI,2039 raw_ostream &O) {2040 unsigned Val = MI->getOperand(OpNo).getImm();2041 2042 // Horrible hack for the one register that has identical encodings but2043 // different names in MSR and MRS. Because of this, one of MRS and MSR is2044 // going to get the wrong entry2045 if (Val == AArch64SysReg::DBGDTRRX_EL0) {2046 O << "DBGDTRRX_EL0";2047 return;2048 }2049 2050 // Horrible hack for two different registers having the same encoding.2051 if (Val == AArch64SysReg::TRCEXTINSELR) {2052 O << "TRCEXTINSELR";2053 return;2054 }2055 2056 const AArch64SysReg::SysReg *Reg = lookupSysReg(Val, true /*Read*/, STI);2057 2058 if (Reg)2059 O << Reg->Name;2060 else2061 O << AArch64SysReg::genericRegisterString(Val);2062}2063 2064void AArch64InstPrinter::printMSRSystemRegister(const MCInst *MI, unsigned OpNo,2065 const MCSubtargetInfo &STI,2066 raw_ostream &O) {2067 unsigned Val = MI->getOperand(OpNo).getImm();2068 2069 // Horrible hack for the one register that has identical encodings but2070 // different names in MSR and MRS. Because of this, one of MRS and MSR is2071 // going to get the wrong entry2072 if (Val == AArch64SysReg::DBGDTRTX_EL0) {2073 O << "DBGDTRTX_EL0";2074 return;2075 }2076 2077 // Horrible hack for two different registers having the same encoding.2078 if (Val == AArch64SysReg::TRCEXTINSELR) {2079 O << "TRCEXTINSELR";2080 return;2081 }2082 2083 const AArch64SysReg::SysReg *Reg = lookupSysReg(Val, false /*Read*/, STI);2084 2085 if (Reg)2086 O << Reg->Name;2087 else2088 O << AArch64SysReg::genericRegisterString(Val);2089}2090 2091void AArch64InstPrinter::printSystemPStateField(const MCInst *MI, unsigned OpNo,2092 const MCSubtargetInfo &STI,2093 raw_ostream &O) {2094 unsigned Val = MI->getOperand(OpNo).getImm();2095 2096 auto PStateImm15 = AArch64PState::lookupPStateImm0_15ByEncoding(Val);2097 auto PStateImm1 = AArch64PState::lookupPStateImm0_1ByEncoding(Val);2098 if (PStateImm15 && PStateImm15->haveFeatures(STI.getFeatureBits()))2099 O << PStateImm15->Name;2100 else if (PStateImm1 && PStateImm1->haveFeatures(STI.getFeatureBits()))2101 O << PStateImm1->Name;2102 else2103 O << "#" << formatImm(Val);2104}2105 2106void AArch64InstPrinter::printSIMDType10Operand(const MCInst *MI, unsigned OpNo,2107 const MCSubtargetInfo &STI,2108 raw_ostream &O) {2109 unsigned RawVal = MI->getOperand(OpNo).getImm();2110 uint64_t Val = AArch64_AM::decodeAdvSIMDModImmType10(RawVal);2111 markup(O, Markup::Immediate) << format("#%#016llx", Val);2112}2113 2114template<int64_t Angle, int64_t Remainder>2115void AArch64InstPrinter::printComplexRotationOp(const MCInst *MI, unsigned OpNo,2116 const MCSubtargetInfo &STI,2117 raw_ostream &O) {2118 unsigned Val = MI->getOperand(OpNo).getImm();2119 markup(O, Markup::Immediate) << "#" << (Val * Angle) + Remainder;2120}2121 2122void AArch64InstPrinter::printSVEPattern(const MCInst *MI, unsigned OpNum,2123 const MCSubtargetInfo &STI,2124 raw_ostream &O) {2125 unsigned Val = MI->getOperand(OpNum).getImm();2126 if (auto Pat = AArch64SVEPredPattern::lookupSVEPREDPATByEncoding(Val))2127 O << Pat->Name;2128 else2129 markup(O, Markup::Immediate) << '#' << formatImm(Val);2130}2131 2132void AArch64InstPrinter::printSVEVecLenSpecifier(const MCInst *MI,2133 unsigned OpNum,2134 const MCSubtargetInfo &STI,2135 raw_ostream &O) {2136 unsigned Val = MI->getOperand(OpNum).getImm();2137 // Pattern has only 1 bit2138 if (Val > 1)2139 llvm_unreachable("Invalid vector length specifier");2140 if (auto Pat =2141 AArch64SVEVecLenSpecifier::lookupSVEVECLENSPECIFIERByEncoding(Val))2142 O << Pat->Name;2143 else2144 llvm_unreachable("Invalid vector length specifier");2145}2146 2147template <char suffix>2148void AArch64InstPrinter::printSVERegOp(const MCInst *MI, unsigned OpNum,2149 const MCSubtargetInfo &STI,2150 raw_ostream &O) {2151 switch (suffix) {2152 case 0:2153 case 'b':2154 case 'h':2155 case 's':2156 case 'd':2157 case 'q':2158 break;2159 default: llvm_unreachable("Invalid kind specifier.");2160 }2161 2162 MCRegister Reg = MI->getOperand(OpNum).getReg();2163 printRegName(O, Reg);2164 if (suffix != 0)2165 O << '.' << suffix;2166}2167 2168template <typename T>2169void AArch64InstPrinter::printImmSVE(T Value, raw_ostream &O) {2170 std::make_unsigned_t<T> HexValue = Value;2171 2172 if (getPrintImmHex())2173 markup(O, Markup::Immediate) << '#' << formatHex((uint64_t)HexValue);2174 else2175 markup(O, Markup::Immediate) << '#' << formatDec(Value);2176 2177 if (CommentStream) {2178 // Do the opposite to that used for instruction operands.2179 if (getPrintImmHex())2180 *CommentStream << '=' << formatDec(HexValue) << '\n';2181 else2182 *CommentStream << '=' << formatHex((uint64_t)Value) << '\n';2183 }2184}2185 2186template <typename T>2187void AArch64InstPrinter::printImm8OptLsl(const MCInst *MI, unsigned OpNum,2188 const MCSubtargetInfo &STI,2189 raw_ostream &O) {2190 unsigned UnscaledVal = MI->getOperand(OpNum).getImm();2191 unsigned Shift = MI->getOperand(OpNum + 1).getImm();2192 assert(AArch64_AM::getShiftType(Shift) == AArch64_AM::LSL &&2193 "Unexpected shift type!");2194 2195 // #0 lsl #8 is never pretty printed2196 if ((UnscaledVal == 0) && (AArch64_AM::getShiftValue(Shift) != 0)) {2197 markup(O, Markup::Immediate) << '#' << formatImm(UnscaledVal);2198 printShifter(MI, OpNum + 1, STI, O);2199 return;2200 }2201 2202 T Val;2203 if (std::is_signed<T>())2204 Val = (int8_t)UnscaledVal * (1 << AArch64_AM::getShiftValue(Shift));2205 else2206 Val = (uint8_t)UnscaledVal * (1 << AArch64_AM::getShiftValue(Shift));2207 2208 printImmSVE(Val, O);2209}2210 2211template <typename T>2212void AArch64InstPrinter::printSVELogicalImm(const MCInst *MI, unsigned OpNum,2213 const MCSubtargetInfo &STI,2214 raw_ostream &O) {2215 typedef std::make_signed_t<T> SignedT;2216 typedef std::make_unsigned_t<T> UnsignedT;2217 2218 uint64_t Val = MI->getOperand(OpNum).getImm();2219 UnsignedT PrintVal = AArch64_AM::decodeLogicalImmediate(Val, 64);2220 2221 // Prefer the default format for 16bit values, hex otherwise.2222 if ((int16_t)PrintVal == (SignedT)PrintVal)2223 printImmSVE((T)PrintVal, O);2224 else if ((uint16_t)PrintVal == PrintVal)2225 printImmSVE(PrintVal, O);2226 else2227 markup(O, Markup::Immediate) << '#' << formatHex((uint64_t)PrintVal);2228}2229 2230template <int Width>2231void AArch64InstPrinter::printZPRasFPR(const MCInst *MI, unsigned OpNum,2232 const MCSubtargetInfo &STI,2233 raw_ostream &O) {2234 unsigned Base;2235 switch (Width) {2236 case 8: Base = AArch64::B0; break;2237 case 16: Base = AArch64::H0; break;2238 case 32: Base = AArch64::S0; break;2239 case 64: Base = AArch64::D0; break;2240 case 128: Base = AArch64::Q0; break;2241 default:2242 llvm_unreachable("Unsupported width");2243 }2244 MCRegister Reg = MI->getOperand(OpNum).getReg();2245 printRegName(O, Reg - AArch64::Z0 + Base);2246}2247 2248template <unsigned ImmIs0, unsigned ImmIs1>2249void AArch64InstPrinter::printExactFPImm(const MCInst *MI, unsigned OpNum,2250 const MCSubtargetInfo &STI,2251 raw_ostream &O) {2252 auto *Imm0Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmIs0);2253 auto *Imm1Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmIs1);2254 unsigned Val = MI->getOperand(OpNum).getImm();2255 markup(O, Markup::Immediate)2256 << "#" << (Val ? Imm1Desc->Repr : Imm0Desc->Repr);2257}2258 2259void AArch64InstPrinter::printGPR64as32(const MCInst *MI, unsigned OpNum,2260 const MCSubtargetInfo &STI,2261 raw_ostream &O) {2262 MCRegister Reg = MI->getOperand(OpNum).getReg();2263 printRegName(O, getWRegFromXReg(Reg));2264}2265 2266void AArch64InstPrinter::printGPR64x8(const MCInst *MI, unsigned OpNum,2267 const MCSubtargetInfo &STI,2268 raw_ostream &O) {2269 MCRegister Reg = MI->getOperand(OpNum).getReg();2270 printRegName(O, MRI.getSubReg(Reg, AArch64::x8sub_0));2271}2272 2273void AArch64InstPrinter::printSyspXzrPair(const MCInst *MI, unsigned OpNum,2274 const MCSubtargetInfo &STI,2275 raw_ostream &O) {2276 MCRegister Reg = MI->getOperand(OpNum).getReg();2277 assert(Reg == AArch64::XZR &&2278 "MC representation of SyspXzrPair should be XZR");2279 O << getRegisterName(Reg) << ", " << getRegisterName(Reg);2280}2281 2282void AArch64InstPrinter::printPHintOp(const MCInst *MI, unsigned OpNum,2283 const MCSubtargetInfo &STI,2284 raw_ostream &O) {2285 unsigned Op = MI->getOperand(OpNum).getImm();2286 auto PH = AArch64PHint::lookupPHintByEncoding(Op);2287 if (PH)2288 O << PH->Name;2289 else2290 markup(O, Markup::Immediate) << '#' << formatImm(Op);2291}2292