blob: a1bf0e2a115a9b4461180b215b70e0dcc3607e26 [file] [log] [blame]
/* Capstone Disassembly Engine, http://www.capstone-engine.org */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2022, */
/* Rot127 <unisono@quyllur.org> 2022-2023 */
/* Automatically translated source file from LLVM. */
/* LLVM-commit: <commit> */
/* LLVM-tag: <tag> */
/* Only small edits allowed. */
/* For multiple similar edits, please create a Patch for the translator. */
/* Capstone's C++ file translator: */
/* https://github.com/capstone-engine/capstone/tree/next/suite/auto-sync */
//==-- AArch64InstPrinter.cpp - Convert AArch64 MCInst to assembly syntax --==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This class prints an AArch64 MCInst to a .s file.
//
//===----------------------------------------------------------------------===//
#include <capstone/platform.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../Mapping.h"
#include "../../MCInst.h"
#include "../../MCInstPrinter.h"
#include "../../MCRegisterInfo.h"
#include "../../SStream.h"
#include "../../utils.h"
#include "AArch64AddressingModes.h"
#include "AArch64BaseInfo.h"
#include "AArch64DisassemblerExtension.h"
#include "AArch64InstPrinter.h"
#include "AArch64Linkage.h"
#include "AArch64Mapping.h"
#define GET_BANKEDREG_IMPL
#include "AArch64GenSystemOperands.inc"
#define CONCAT(a, b) CONCAT_(a, b)
#define CONCAT_(a, b) a##_##b
#define CONCATs(a, b) CONCATS(a, b)
#define CONCATS(a, b) a##b
#define DEBUG_TYPE "asm-printer"
#ifndef CAPSTONE_DIET
static void printCustomAliasOperand(
MCInst *MI, uint64_t Address, unsigned OpIdx,
unsigned PrintMethodIdx,
SStream *OS);
#endif
#define DECLARE_printComplexRotationOp(Angle, Remainder) \
static void CONCAT(printComplexRotationOp, CONCAT(Angle, Remainder))( \
MCInst * MI, unsigned OpNo, SStream *O);
DECLARE_printComplexRotationOp(180, 90);
DECLARE_printComplexRotationOp(90, 0);
static void printFPImmOperand(MCInst *MI, unsigned OpNum, SStream *O);
#define GET_INSTRUCTION_NAME
#define PRINT_ALIAS_INSTR
#include "AArch64GenAsmWriter.inc"
void printRegName(SStream *OS, unsigned Reg)
{
SStream_concat(OS, "%s%s", markup("<reg:"), getRegisterName(Reg, AArch64_NoRegAltName));
SStream_concat0(OS, markup(">"));
}
void printRegNameAlt(SStream *OS, unsigned Reg, unsigned AltIdx)
{
SStream_concat(OS, "%s%s", markup("<reg:"), getRegisterName(Reg, AltIdx));
SStream_concat0(OS, markup(">"));
}
const char *getRegName(unsigned Reg) { return getRegisterName(Reg, AArch64_NoRegAltName); }
void printInst(MCInst *MI, uint64_t Address, const char *Annot, SStream *O)
{
bool isAlias = false;
bool useAliasDetails = map_use_alias_details(MI);
map_set_fill_detail_ops(MI, useAliasDetails);
unsigned Opcode = MCInst_getOpcode(MI);
if (Opcode == AArch64_SYSxt) {
if (printSysAlias(MI, O)) {
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
if (useAliasDetails)
return;
}
}
if (Opcode == AArch64_SYSPxt || Opcode == AArch64_SYSPxt_XZR) {
if (printSyspAlias(MI, O)) {
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
if (useAliasDetails)
return;
}
}
// RPRFM overlaps PRFM (reg), so try to print it as RPRFM here.
if ((Opcode == AArch64_PRFMroX) || (Opcode == AArch64_PRFMroW)) {
if (printRangePrefetchAlias(MI, O, Annot)) {
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
if (useAliasDetails)
return;
}
}
// SBFM/UBFM should print to a nicer aliased form if possible.
if (Opcode == AArch64_SBFMXri || Opcode == AArch64_SBFMWri ||
Opcode == AArch64_UBFMXri || Opcode == AArch64_UBFMWri) {
MCOperand *Op0 = MCInst_getOperand(MI, (0));
MCOperand *Op1 = MCInst_getOperand(MI, (1));
MCOperand *Op2 = MCInst_getOperand(MI, (2));
MCOperand *Op3 = MCInst_getOperand(MI, (3));
bool IsSigned =
(Opcode == AArch64_SBFMXri || Opcode == AArch64_SBFMWri);
bool Is64Bit = (Opcode == AArch64_SBFMXri || Opcode == AArch64_UBFMXri);
if (MCOperand_isImm(Op2) && MCOperand_getImm(Op2) == 0 &&
MCOperand_isImm(Op3)) {
const char *AsmMnemonic = NULL;
switch (MCOperand_getImm(Op3)) {
default:
break;
case 7:
if (IsSigned)
AsmMnemonic = "sxtb";
else if (!Is64Bit)
AsmMnemonic = "uxtb";
break;
case 15:
if (IsSigned)
AsmMnemonic = "sxth";
else if (!Is64Bit)
AsmMnemonic = "uxth";
break;
case 31:
// *xtw is only valid for signed 64-bit operations.
if (Is64Bit && IsSigned)
AsmMnemonic = "sxtw";
break;
}
if (AsmMnemonic) {
SStream_concat(O, "%s", AsmMnemonic);
SStream_concat0(O, " ");
printRegName(O, MCOperand_getReg(Op0));
SStream_concat0(O, ", ");
printRegName(O, getWRegFromXReg(MCOperand_getReg(Op1)));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCOperand_getReg(Op0));
AArch64_set_detail_op_reg(MI, 1, getWRegFromXReg(MCOperand_getReg(Op1)));
if (strings_match(AsmMnemonic, "uxtb"))
AArch64_get_detail_op(MI, -1)->ext = AArch64_EXT_UXTB;
else if (strings_match(AsmMnemonic, "sxtb"))
AArch64_get_detail_op(MI, -1)->ext = AArch64_EXT_SXTB;
else if (strings_match(AsmMnemonic, "uxth"))
AArch64_get_detail_op(MI, -1)->ext = AArch64_EXT_UXTH;
else if (strings_match(AsmMnemonic, "sxth"))
AArch64_get_detail_op(MI, -1)->ext = AArch64_EXT_SXTH;
else if (strings_match(AsmMnemonic, "sxtw"))
AArch64_get_detail_op(MI, -1)->ext = AArch64_EXT_SXTW;
else
AArch64_get_detail_op(MI, -1)->ext = AArch64_EXT_INVALID;
}
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
if (useAliasDetails)
return;
else
goto add_real_detail;
}
}
// All immediate shifts are aliases, implemented using the Bitfield
// instruction. In all cases the immediate shift amount shift must be in
// the range 0 to (reg.size -1).
if (MCOperand_isImm(Op2) && MCOperand_isImm(Op3)) {
const char *AsmMnemonic = NULL;
int shift = 0;
int64_t immr = MCOperand_getImm(Op2);
int64_t imms = MCOperand_getImm(Op3);
if (Opcode == AArch64_UBFMWri && imms != 0x1F &&
((imms + 1) == immr)) {
AsmMnemonic = "lsl";
shift = 31 - imms;
} else if (Opcode == AArch64_UBFMXri && imms != 0x3f &&
((imms + 1 == immr))) {
AsmMnemonic = "lsl";
shift = 63 - imms;
} else if (Opcode == AArch64_UBFMWri && imms == 0x1f) {
AsmMnemonic = "lsr";
shift = immr;
} else if (Opcode == AArch64_UBFMXri && imms == 0x3f) {
AsmMnemonic = "lsr";
shift = immr;
} else if (Opcode == AArch64_SBFMWri && imms == 0x1f) {
AsmMnemonic = "asr";
shift = immr;
} else if (Opcode == AArch64_SBFMXri && imms == 0x3f) {
AsmMnemonic = "asr";
shift = immr;
}
if (AsmMnemonic) {
SStream_concat(O, "%s", AsmMnemonic);
SStream_concat0(O, " ");
printRegName(O, MCOperand_getReg(Op0));
SStream_concat0(O, ", ");
printRegName(O, MCOperand_getReg(Op1));
SStream_concat(O, "%s%s#%d", ", ", markup("<imm:"), shift);
SStream_concat0(O, markup(">"));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCOperand_getReg(Op0));
AArch64_set_detail_op_reg(MI, 1, MCOperand_getReg(Op1));
if (strings_match(AsmMnemonic, "lsl"))
AArch64_get_detail_op(MI, -1)->shift.type = AArch64_SFT_LSL;
else if (strings_match(AsmMnemonic, "lsr"))
AArch64_get_detail_op(MI, -1)->shift.type = AArch64_SFT_LSR;
else if (strings_match(AsmMnemonic, "asr"))
AArch64_get_detail_op(MI, -1)->shift.type = AArch64_SFT_ASR;
else
AArch64_get_detail_op(MI, -1)->shift.type = AArch64_SFT_INVALID;
AArch64_get_detail_op(MI, -1)->shift.value = shift;
}
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
if (useAliasDetails)
return;
else
goto add_real_detail;
}
}
// SBFIZ/UBFIZ aliases
if (MCOperand_getImm(Op2) > MCOperand_getImm(Op3)) {
SStream_concat(O, "%s", (IsSigned ? "sbfiz" : "ubfiz"));
SStream_concat0(O, " ");
printRegName(O, MCOperand_getReg(Op0));
SStream_concat0(O, ", ");
printRegName(O, MCOperand_getReg(Op1));
SStream_concat(O, "%s%s", ", ", markup("<imm:"));
printUInt32Bang(O, (Is64Bit ? 64 : 32) - MCOperand_getImm(Op2));
SStream_concat(O, "%s%s%s", markup(">"), ", ", markup("<imm:"));
printInt64Bang(O, MCOperand_getImm(Op3) + 1);
SStream_concat0(O, markup(">"));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCOperand_getReg(Op0));
AArch64_set_detail_op_reg(MI, 1, MCOperand_getReg(Op1));
AArch64_set_detail_op_imm(MI, 2, AArch64_OP_IMM, (Is64Bit ? 64 : 32) - MCOperand_getImm(Op2));
AArch64_set_detail_op_imm(MI, 3, AArch64_OP_IMM, MCOperand_getImm(Op3) + 1);
}
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
if (useAliasDetails)
return;
else
goto add_real_detail;
}
// Otherwise SBFX/UBFX is the preferred form
SStream_concat(O, "%s", (IsSigned ? "sbfx" : "ubfx"));
SStream_concat0(O, " ");
printRegName(O, MCOperand_getReg(Op0));
SStream_concat0(O, ", ");
printRegName(O, MCOperand_getReg(Op1));
SStream_concat(O, "%s%s", ", ", markup("<imm:"));
printInt64Bang(O, MCOperand_getImm(Op2));
SStream_concat(O, "%s%s%s", markup(">"), ", ", markup("<imm:"));
printInt64Bang(O, MCOperand_getImm(Op3) - MCOperand_getImm(Op2) + 1);
SStream_concat0(O, markup(">"));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCOperand_getReg(Op0));
AArch64_set_detail_op_reg(MI, 1, MCOperand_getReg(Op1));
AArch64_set_detail_op_imm(MI, 2, AArch64_OP_IMM, MCOperand_getImm(Op2));
AArch64_set_detail_op_imm(MI, 3, AArch64_OP_IMM, MCOperand_getImm(Op3) - MCOperand_getImm(Op2) + 1);
}
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
if (useAliasDetails)
return;
else
goto add_real_detail;
}
if (Opcode == AArch64_BFMXri || Opcode == AArch64_BFMWri) {
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
MCOperand *Op0 = MCInst_getOperand(MI, (0)); // Op1 == Op0
MCOperand *Op2 = MCInst_getOperand(MI, (2));
int ImmR = MCOperand_getImm(MCInst_getOperand(MI, (3)));
int ImmS = MCOperand_getImm(MCInst_getOperand(MI, (4)));
if ((MCOperand_getReg(Op2) == AArch64_WZR ||
MCOperand_getReg(Op2) == AArch64_XZR) &&
(ImmR == 0 || ImmS < ImmR) &&
(AArch64_getFeatureBits(MI->csh->mode, AArch64_FeatureAll) ||
AArch64_getFeatureBits(MI->csh->mode, AArch64_HasV8_2aOps))) {
// BFC takes precedence over its entire range, slightly differently
// to BFI.
int BitWidth = Opcode == AArch64_BFMXri ? 64 : 32;
int LSB = (BitWidth - ImmR) % BitWidth;
int Width = ImmS + 1;
SStream_concat0(O, "bfc ");
printRegName(O, MCOperand_getReg(Op0));
SStream_concat(O, "%s%s#%d", ", ", markup("<imm:"), LSB);
SStream_concat(O, "%s%s%s#%d", markup(">"), ", ", markup("<imm:"), Width);
SStream_concat0(O, markup(">"));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCOperand_getReg(Op0));
AArch64_set_detail_op_imm(MI, 3, AArch64_OP_IMM, LSB);
AArch64_set_detail_op_imm(MI, 4, AArch64_OP_IMM, Width);
}
if (useAliasDetails)
return;
else
goto add_real_detail;
} else if (ImmS < ImmR) {
// BFI alias
int BitWidth = Opcode == AArch64_BFMXri ? 64 : 32;
int LSB = (BitWidth - ImmR) % BitWidth;
int Width = ImmS + 1;
SStream_concat0(O, "bfi ");
printRegName(O, MCOperand_getReg(Op0));
SStream_concat0(O, ", ");
printRegName(O, MCOperand_getReg(Op2));
SStream_concat(O, "%s%s#%d", ", ", markup("<imm:"), LSB);
SStream_concat(O, "%s%s%s#%d", markup(">"), ", ", markup("<imm:"), Width);
SStream_concat0(O, markup(">"));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCOperand_getReg(Op0));
AArch64_set_detail_op_reg(MI, 2, MCOperand_getReg(Op2));
AArch64_set_detail_op_imm(MI, 3, AArch64_OP_IMM, LSB);
AArch64_set_detail_op_imm(MI, 4, AArch64_OP_IMM, Width);
}
if (useAliasDetails)
return;
else
goto add_real_detail;
}
int LSB = ImmR;
int Width = ImmS - ImmR + 1;
// Otherwise BFXIL the preferred form
SStream_concat0(O, "bfxil ");
printRegName(O, MCOperand_getReg(Op0));
SStream_concat0(O, ", ");
printRegName(O, MCOperand_getReg(Op2));
SStream_concat(O, "%s%s#%d", ", ", markup("<imm:"), LSB);
SStream_concat(O, "%s%s%s#%d", markup(">"), ", ", markup("<imm:"), Width);
SStream_concat0(O, markup(">"));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCOperand_getReg(Op0));
AArch64_set_detail_op_reg(MI, 2, MCOperand_getReg(Op2));
AArch64_set_detail_op_imm(MI, 3, AArch64_OP_IMM, LSB);
AArch64_set_detail_op_imm(MI, 4, AArch64_OP_IMM, Width);
}
if (useAliasDetails)
return;
}
// Symbolic operands for MOVZ, MOVN and MOVK already imply a shift
// (e.g. :gottprel_g1: is always going to be "lsl #16") so it should not be
// printed.
if ((Opcode == AArch64_MOVZXi || Opcode == AArch64_MOVZWi ||
Opcode == AArch64_MOVNXi || Opcode == AArch64_MOVNWi) &&
MCOperand_isExpr(MCInst_getOperand(MI, (1)))) {
assert(0 && "Expressions are not supported.");
}
if ((Opcode == AArch64_MOVKXi || Opcode == AArch64_MOVKWi) &&
MCOperand_isExpr(MCInst_getOperand(MI, (2)))) {
assert(0 && "Expressions are not supported.");
}
// MOVZ, MOVN and "ORR wzr, #imm" instructions are aliases for MOV, but
// their domains overlap so they need to be prioritized. The chain is "MOVZ
// lsl #0 > MOVZ lsl #N > MOVN lsl #0 > MOVN lsl #N > ORR". The highest
// instruction that can represent the move is the MOV alias, and the rest
// get printed normally.
if ((Opcode == AArch64_MOVZXi || Opcode == AArch64_MOVZWi) &&
MCOperand_isImm(MCInst_getOperand(MI, (1))) &&
MCOperand_isImm(MCInst_getOperand(MI, (2)))) {
int RegWidth = Opcode == AArch64_MOVZXi ? 64 : 32;
int Shift = MCOperand_getImm(MCInst_getOperand(MI, (2)));
uint64_t Value = (uint64_t)MCOperand_getImm(MCInst_getOperand(MI, (1)))
<< Shift;
if (AArch64_AM_isMOVZMovAlias(Value, Shift,
Opcode == AArch64_MOVZXi ? 64 : 32)) {
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
SStream_concat0(O, "mov ");
printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, (0))));
SStream_concat(O, "%s%s", ", ", markup("<imm:"));
printInt64Bang(O, SignExtend64(Value, RegWidth));
SStream_concat0(O, markup(">"));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCInst_getOpVal(MI, 0));
AArch64_set_detail_op_imm(MI, 1, AArch64_OP_IMM, SignExtend64(Value, RegWidth));
}
if (useAliasDetails)
return;
}
}
if ((Opcode == AArch64_MOVNXi || Opcode == AArch64_MOVNWi) &&
MCOperand_isImm(MCInst_getOperand(MI, (1))) &&
MCOperand_isImm(MCInst_getOperand(MI, (2)))) {
int RegWidth = Opcode == AArch64_MOVNXi ? 64 : 32;
int Shift = MCOperand_getImm(MCInst_getOperand(MI, (2)));
uint64_t Value =
~((uint64_t)MCOperand_getImm(MCInst_getOperand(MI, (1))) << Shift);
if (RegWidth == 32)
Value = Value & 0xffffffff;
if (AArch64_AM_isMOVNMovAlias(Value, Shift, RegWidth)) {
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
SStream_concat0(O, "mov ");
printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, (0))));
SStream_concat(O, "%s%s", ", ", markup("<imm:"));
printInt64Bang(O, SignExtend64(Value, RegWidth));
SStream_concat0(O, markup(">"));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCInst_getOpVal(MI, 0));
AArch64_set_detail_op_imm(MI, 1, AArch64_OP_IMM, SignExtend64(Value, RegWidth));
}
if (useAliasDetails)
return;
}
}
if ((Opcode == AArch64_ORRXri || Opcode == AArch64_ORRWri) &&
(MCOperand_getReg(MCInst_getOperand(MI, (1))) == AArch64_XZR ||
MCOperand_getReg(MCInst_getOperand(MI, (1))) == AArch64_WZR) &&
MCOperand_isImm(MCInst_getOperand(MI, (2)))) {
int RegWidth = Opcode == AArch64_ORRXri ? 64 : 32;
uint64_t Value = AArch64_AM_decodeLogicalImmediate(
MCOperand_getImm(MCInst_getOperand(MI, (2))), RegWidth);
if (!AArch64_AM_isAnyMOVWMovAlias(Value, RegWidth)) {
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
SStream_concat0(O, "mov ");
printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, (0))));
SStream_concat(O, "%s%s", ", ", markup("<imm:"));
printInt64Bang(O, SignExtend64(Value, RegWidth));
SStream_concat0(O, markup(">"));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_reg(MI, 0, MCInst_getOpVal(MI, 0));
AArch64_set_detail_op_imm(MI, 2, AArch64_OP_IMM, SignExtend64(Value, RegWidth));
}
if (useAliasDetails)
return;
}
}
if (Opcode == AArch64_SPACE) {
isAlias = true;
MCInst_setIsAlias(MI, isAlias);
SStream_concat1(O, ' ');
SStream_concat(O, "%s", " SPACE ");
printInt64(O, MCOperand_getImm(MCInst_getOperand(MI, (1))));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_imm(MI, 1, AArch64_OP_IMM, MCInst_getOpVal(MI, 1));
}
if (useAliasDetails)
return;
}
if (!isAlias)
isAlias |= printAliasInstr(MI, Address, O);
add_real_detail:
MCInst_setIsAlias(MI, isAlias);
if (!isAlias || !useAliasDetails) {
map_set_fill_detail_ops(MI, !(isAlias && useAliasDetails));
if (isAlias)
SStream_Close(O);
printInstruction(MI, Address, O);
if (isAlias)
SStream_Open(O);
}
}
static bool isTblTbxInstruction(unsigned Opcode, const char **Layout, bool *IsTbx)
{
switch (Opcode) {
case AArch64_TBXv8i8One:
case AArch64_TBXv8i8Two:
case AArch64_TBXv8i8Three:
case AArch64_TBXv8i8Four:
*IsTbx = true;
*Layout = ".8b";
return true;
case AArch64_TBLv8i8One:
case AArch64_TBLv8i8Two:
case AArch64_TBLv8i8Three:
case AArch64_TBLv8i8Four:
*IsTbx = false;
*Layout = ".8b";
return true;
case AArch64_TBXv16i8One:
case AArch64_TBXv16i8Two:
case AArch64_TBXv16i8Three:
case AArch64_TBXv16i8Four:
*IsTbx = true;
*Layout = ".16b";
return true;
case AArch64_TBLv16i8One:
case AArch64_TBLv16i8Two:
case AArch64_TBLv16i8Three:
case AArch64_TBLv16i8Four:
*IsTbx = false;
*Layout = ".16b";
return true;
default:
return false;
}
}
typedef struct LdStNInstrDesc {
unsigned Opcode;
const char *Mnemonic;
const char *Layout;
int ListOperand;
bool HasLane;
int NaturalOffset;
} LdStNInstrDesc;
static const LdStNInstrDesc LdStNInstInfo[] = {
{AArch64_LD1i8, "ld1", ".b", 1, true, 0},
{AArch64_LD1i16, "ld1", ".h", 1, true, 0},
{AArch64_LD1i32, "ld1", ".s", 1, true, 0},
{AArch64_LD1i64, "ld1", ".d", 1, true, 0},
{AArch64_LD1i8_POST, "ld1", ".b", 2, true, 1},
{AArch64_LD1i16_POST, "ld1", ".h", 2, true, 2},
{AArch64_LD1i32_POST, "ld1", ".s", 2, true, 4},
{AArch64_LD1i64_POST, "ld1", ".d", 2, true, 8},
{AArch64_LD1Rv16b, "ld1r", ".16b", 0, false, 0},
{AArch64_LD1Rv8h, "ld1r", ".8h", 0, false, 0},
{AArch64_LD1Rv4s, "ld1r", ".4s", 0, false, 0},
{AArch64_LD1Rv2d, "ld1r", ".2d", 0, false, 0},
{AArch64_LD1Rv8b, "ld1r", ".8b", 0, false, 0},
{AArch64_LD1Rv4h, "ld1r", ".4h", 0, false, 0},
{AArch64_LD1Rv2s, "ld1r", ".2s", 0, false, 0},
{AArch64_LD1Rv1d, "ld1r", ".1d", 0, false, 0},
{AArch64_LD1Rv16b_POST, "ld1r", ".16b", 1, false, 1},
{AArch64_LD1Rv8h_POST, "ld1r", ".8h", 1, false, 2},
{AArch64_LD1Rv4s_POST, "ld1r", ".4s", 1, false, 4},
{AArch64_LD1Rv2d_POST, "ld1r", ".2d", 1, false, 8},
{AArch64_LD1Rv8b_POST, "ld1r", ".8b", 1, false, 1},
{AArch64_LD1Rv4h_POST, "ld1r", ".4h", 1, false, 2},
{AArch64_LD1Rv2s_POST, "ld1r", ".2s", 1, false, 4},
{AArch64_LD1Rv1d_POST, "ld1r", ".1d", 1, false, 8},
{AArch64_LD1Onev16b, "ld1", ".16b", 0, false, 0},
{AArch64_LD1Onev8h, "ld1", ".8h", 0, false, 0},
{AArch64_LD1Onev4s, "ld1", ".4s", 0, false, 0},
{AArch64_LD1Onev2d, "ld1", ".2d", 0, false, 0},
{AArch64_LD1Onev8b, "ld1", ".8b", 0, false, 0},
{AArch64_LD1Onev4h, "ld1", ".4h", 0, false, 0},
{AArch64_LD1Onev2s, "ld1", ".2s", 0, false, 0},
{AArch64_LD1Onev1d, "ld1", ".1d", 0, false, 0},
{AArch64_LD1Onev16b_POST, "ld1", ".16b", 1, false, 16},
{AArch64_LD1Onev8h_POST, "ld1", ".8h", 1, false, 16},
{AArch64_LD1Onev4s_POST, "ld1", ".4s", 1, false, 16},
{AArch64_LD1Onev2d_POST, "ld1", ".2d", 1, false, 16},
{AArch64_LD1Onev8b_POST, "ld1", ".8b", 1, false, 8},
{AArch64_LD1Onev4h_POST, "ld1", ".4h", 1, false, 8},
{AArch64_LD1Onev2s_POST, "ld1", ".2s", 1, false, 8},
{AArch64_LD1Onev1d_POST, "ld1", ".1d", 1, false, 8},
{AArch64_LD1Twov16b, "ld1", ".16b", 0, false, 0},
{AArch64_LD1Twov8h, "ld1", ".8h", 0, false, 0},
{AArch64_LD1Twov4s, "ld1", ".4s", 0, false, 0},
{AArch64_LD1Twov2d, "ld1", ".2d", 0, false, 0},
{AArch64_LD1Twov8b, "ld1", ".8b", 0, false, 0},
{AArch64_LD1Twov4h, "ld1", ".4h", 0, false, 0},
{AArch64_LD1Twov2s, "ld1", ".2s", 0, false, 0},
{AArch64_LD1Twov1d, "ld1", ".1d", 0, false, 0},
{AArch64_LD1Twov16b_POST, "ld1", ".16b", 1, false, 32},
{AArch64_LD1Twov8h_POST, "ld1", ".8h", 1, false, 32},
{AArch64_LD1Twov4s_POST, "ld1", ".4s", 1, false, 32},
{AArch64_LD1Twov2d_POST, "ld1", ".2d", 1, false, 32},
{AArch64_LD1Twov8b_POST, "ld1", ".8b", 1, false, 16},
{AArch64_LD1Twov4h_POST, "ld1", ".4h", 1, false, 16},
{AArch64_LD1Twov2s_POST, "ld1", ".2s", 1, false, 16},
{AArch64_LD1Twov1d_POST, "ld1", ".1d", 1, false, 16},
{AArch64_LD1Threev16b, "ld1", ".16b", 0, false, 0},
{AArch64_LD1Threev8h, "ld1", ".8h", 0, false, 0},
{AArch64_LD1Threev4s, "ld1", ".4s", 0, false, 0},
{AArch64_LD1Threev2d, "ld1", ".2d", 0, false, 0},
{AArch64_LD1Threev8b, "ld1", ".8b", 0, false, 0},
{AArch64_LD1Threev4h, "ld1", ".4h", 0, false, 0},
{AArch64_LD1Threev2s, "ld1", ".2s", 0, false, 0},
{AArch64_LD1Threev1d, "ld1", ".1d", 0, false, 0},
{AArch64_LD1Threev16b_POST, "ld1", ".16b", 1, false, 48},
{AArch64_LD1Threev8h_POST, "ld1", ".8h", 1, false, 48},
{AArch64_LD1Threev4s_POST, "ld1", ".4s", 1, false, 48},
{AArch64_LD1Threev2d_POST, "ld1", ".2d", 1, false, 48},
{AArch64_LD1Threev8b_POST, "ld1", ".8b", 1, false, 24},
{AArch64_LD1Threev4h_POST, "ld1", ".4h", 1, false, 24},
{AArch64_LD1Threev2s_POST, "ld1", ".2s", 1, false, 24},
{AArch64_LD1Threev1d_POST, "ld1", ".1d", 1, false, 24},
{AArch64_LD1Fourv16b, "ld1", ".16b", 0, false, 0},
{AArch64_LD1Fourv8h, "ld1", ".8h", 0, false, 0},
{AArch64_LD1Fourv4s, "ld1", ".4s", 0, false, 0},
{AArch64_LD1Fourv2d, "ld1", ".2d", 0, false, 0},
{AArch64_LD1Fourv8b, "ld1", ".8b", 0, false, 0},
{AArch64_LD1Fourv4h, "ld1", ".4h", 0, false, 0},
{AArch64_LD1Fourv2s, "ld1", ".2s", 0, false, 0},
{AArch64_LD1Fourv1d, "ld1", ".1d", 0, false, 0},
{AArch64_LD1Fourv16b_POST, "ld1", ".16b", 1, false, 64},
{AArch64_LD1Fourv8h_POST, "ld1", ".8h", 1, false, 64},
{AArch64_LD1Fourv4s_POST, "ld1", ".4s", 1, false, 64},
{AArch64_LD1Fourv2d_POST, "ld1", ".2d", 1, false, 64},
{AArch64_LD1Fourv8b_POST, "ld1", ".8b", 1, false, 32},
{AArch64_LD1Fourv4h_POST, "ld1", ".4h", 1, false, 32},
{AArch64_LD1Fourv2s_POST, "ld1", ".2s", 1, false, 32},
{AArch64_LD1Fourv1d_POST, "ld1", ".1d", 1, false, 32},
{AArch64_LD2i8, "ld2", ".b", 1, true, 0},
{AArch64_LD2i16, "ld2", ".h", 1, true, 0},
{AArch64_LD2i32, "ld2", ".s", 1, true, 0},
{AArch64_LD2i64, "ld2", ".d", 1, true, 0},
{AArch64_LD2i8_POST, "ld2", ".b", 2, true, 2},
{AArch64_LD2i16_POST, "ld2", ".h", 2, true, 4},
{AArch64_LD2i32_POST, "ld2", ".s", 2, true, 8},
{AArch64_LD2i64_POST, "ld2", ".d", 2, true, 16},
{AArch64_LD2Rv16b, "ld2r", ".16b", 0, false, 0},
{AArch64_LD2Rv8h, "ld2r", ".8h", 0, false, 0},
{AArch64_LD2Rv4s, "ld2r", ".4s", 0, false, 0},
{AArch64_LD2Rv2d, "ld2r", ".2d", 0, false, 0},
{AArch64_LD2Rv8b, "ld2r", ".8b", 0, false, 0},
{AArch64_LD2Rv4h, "ld2r", ".4h", 0, false, 0},
{AArch64_LD2Rv2s, "ld2r", ".2s", 0, false, 0},
{AArch64_LD2Rv1d, "ld2r", ".1d", 0, false, 0},
{AArch64_LD2Rv16b_POST, "ld2r", ".16b", 1, false, 2},
{AArch64_LD2Rv8h_POST, "ld2r", ".8h", 1, false, 4},
{AArch64_LD2Rv4s_POST, "ld2r", ".4s", 1, false, 8},
{AArch64_LD2Rv2d_POST, "ld2r", ".2d", 1, false, 16},
{AArch64_LD2Rv8b_POST, "ld2r", ".8b", 1, false, 2},
{AArch64_LD2Rv4h_POST, "ld2r", ".4h", 1, false, 4},
{AArch64_LD2Rv2s_POST, "ld2r", ".2s", 1, false, 8},
{AArch64_LD2Rv1d_POST, "ld2r", ".1d", 1, false, 16},
{AArch64_LD2Twov16b, "ld2", ".16b", 0, false, 0},
{AArch64_LD2Twov8h, "ld2", ".8h", 0, false, 0},
{AArch64_LD2Twov4s, "ld2", ".4s", 0, false, 0},
{AArch64_LD2Twov2d, "ld2", ".2d", 0, false, 0},
{AArch64_LD2Twov8b, "ld2", ".8b", 0, false, 0},
{AArch64_LD2Twov4h, "ld2", ".4h", 0, false, 0},
{AArch64_LD2Twov2s, "ld2", ".2s", 0, false, 0},
{AArch64_LD2Twov16b_POST, "ld2", ".16b", 1, false, 32},
{AArch64_LD2Twov8h_POST, "ld2", ".8h", 1, false, 32},
{AArch64_LD2Twov4s_POST, "ld2", ".4s", 1, false, 32},
{AArch64_LD2Twov2d_POST, "ld2", ".2d", 1, false, 32},
{AArch64_LD2Twov8b_POST, "ld2", ".8b", 1, false, 16},
{AArch64_LD2Twov4h_POST, "ld2", ".4h", 1, false, 16},
{AArch64_LD2Twov2s_POST, "ld2", ".2s", 1, false, 16},
{AArch64_LD3i8, "ld3", ".b", 1, true, 0},
{AArch64_LD3i16, "ld3", ".h", 1, true, 0},
{AArch64_LD3i32, "ld3", ".s", 1, true, 0},
{AArch64_LD3i64, "ld3", ".d", 1, true, 0},
{AArch64_LD3i8_POST, "ld3", ".b", 2, true, 3},
{AArch64_LD3i16_POST, "ld3", ".h", 2, true, 6},
{AArch64_LD3i32_POST, "ld3", ".s", 2, true, 12},
{AArch64_LD3i64_POST, "ld3", ".d", 2, true, 24},
{AArch64_LD3Rv16b, "ld3r", ".16b", 0, false, 0},
{AArch64_LD3Rv8h, "ld3r", ".8h", 0, false, 0},
{AArch64_LD3Rv4s, "ld3r", ".4s", 0, false, 0},
{AArch64_LD3Rv2d, "ld3r", ".2d", 0, false, 0},
{AArch64_LD3Rv8b, "ld3r", ".8b", 0, false, 0},
{AArch64_LD3Rv4h, "ld3r", ".4h", 0, false, 0},
{AArch64_LD3Rv2s, "ld3r", ".2s", 0, false, 0},
{AArch64_LD3Rv1d, "ld3r", ".1d", 0, false, 0},
{AArch64_LD3Rv16b_POST, "ld3r", ".16b", 1, false, 3},
{AArch64_LD3Rv8h_POST, "ld3r", ".8h", 1, false, 6},
{AArch64_LD3Rv4s_POST, "ld3r", ".4s", 1, false, 12},
{AArch64_LD3Rv2d_POST, "ld3r", ".2d", 1, false, 24},
{AArch64_LD3Rv8b_POST, "ld3r", ".8b", 1, false, 3},
{AArch64_LD3Rv4h_POST, "ld3r", ".4h", 1, false, 6},
{AArch64_LD3Rv2s_POST, "ld3r", ".2s", 1, false, 12},
{AArch64_LD3Rv1d_POST, "ld3r", ".1d", 1, false, 24},
{AArch64_LD3Threev16b, "ld3", ".16b", 0, false, 0},
{AArch64_LD3Threev8h, "ld3", ".8h", 0, false, 0},
{AArch64_LD3Threev4s, "ld3", ".4s", 0, false, 0},
{AArch64_LD3Threev2d, "ld3", ".2d", 0, false, 0},
{AArch64_LD3Threev8b, "ld3", ".8b", 0, false, 0},
{AArch64_LD3Threev4h, "ld3", ".4h", 0, false, 0},
{AArch64_LD3Threev2s, "ld3", ".2s", 0, false, 0},
{AArch64_LD3Threev16b_POST, "ld3", ".16b", 1, false, 48},
{AArch64_LD3Threev8h_POST, "ld3", ".8h", 1, false, 48},
{AArch64_LD3Threev4s_POST, "ld3", ".4s", 1, false, 48},
{AArch64_LD3Threev2d_POST, "ld3", ".2d", 1, false, 48},
{AArch64_LD3Threev8b_POST, "ld3", ".8b", 1, false, 24},
{AArch64_LD3Threev4h_POST, "ld3", ".4h", 1, false, 24},
{AArch64_LD3Threev2s_POST, "ld3", ".2s", 1, false, 24},
{AArch64_LD4i8, "ld4", ".b", 1, true, 0},
{AArch64_LD4i16, "ld4", ".h", 1, true, 0},
{AArch64_LD4i32, "ld4", ".s", 1, true, 0},
{AArch64_LD4i64, "ld4", ".d", 1, true, 0},
{AArch64_LD4i8_POST, "ld4", ".b", 2, true, 4},
{AArch64_LD4i16_POST, "ld4", ".h", 2, true, 8},
{AArch64_LD4i32_POST, "ld4", ".s", 2, true, 16},
{AArch64_LD4i64_POST, "ld4", ".d", 2, true, 32},
{AArch64_LD4Rv16b, "ld4r", ".16b", 0, false, 0},
{AArch64_LD4Rv8h, "ld4r", ".8h", 0, false, 0},
{AArch64_LD4Rv4s, "ld4r", ".4s", 0, false, 0},
{AArch64_LD4Rv2d, "ld4r", ".2d", 0, false, 0},
{AArch64_LD4Rv8b, "ld4r", ".8b", 0, false, 0},
{AArch64_LD4Rv4h, "ld4r", ".4h", 0, false, 0},
{AArch64_LD4Rv2s, "ld4r", ".2s", 0, false, 0},
{AArch64_LD4Rv1d, "ld4r", ".1d", 0, false, 0},
{AArch64_LD4Rv16b_POST, "ld4r", ".16b", 1, false, 4},
{AArch64_LD4Rv8h_POST, "ld4r", ".8h", 1, false, 8},
{AArch64_LD4Rv4s_POST, "ld4r", ".4s", 1, false, 16},
{AArch64_LD4Rv2d_POST, "ld4r", ".2d", 1, false, 32},
{AArch64_LD4Rv8b_POST, "ld4r", ".8b", 1, false, 4},
{AArch64_LD4Rv4h_POST, "ld4r", ".4h", 1, false, 8},
{AArch64_LD4Rv2s_POST, "ld4r", ".2s", 1, false, 16},
{AArch64_LD4Rv1d_POST, "ld4r", ".1d", 1, false, 32},
{AArch64_LD4Fourv16b, "ld4", ".16b", 0, false, 0},
{AArch64_LD4Fourv8h, "ld4", ".8h", 0, false, 0},
{AArch64_LD4Fourv4s, "ld4", ".4s", 0, false, 0},
{AArch64_LD4Fourv2d, "ld4", ".2d", 0, false, 0},
{AArch64_LD4Fourv8b, "ld4", ".8b", 0, false, 0},
{AArch64_LD4Fourv4h, "ld4", ".4h", 0, false, 0},
{AArch64_LD4Fourv2s, "ld4", ".2s", 0, false, 0},
{AArch64_LD4Fourv16b_POST, "ld4", ".16b", 1, false, 64},
{AArch64_LD4Fourv8h_POST, "ld4", ".8h", 1, false, 64},
{AArch64_LD4Fourv4s_POST, "ld4", ".4s", 1, false, 64},
{AArch64_LD4Fourv2d_POST, "ld4", ".2d", 1, false, 64},
{AArch64_LD4Fourv8b_POST, "ld4", ".8b", 1, false, 32},
{AArch64_LD4Fourv4h_POST, "ld4", ".4h", 1, false, 32},
{AArch64_LD4Fourv2s_POST, "ld4", ".2s", 1, false, 32},
{AArch64_ST1i8, "st1", ".b", 0, true, 0},
{AArch64_ST1i16, "st1", ".h", 0, true, 0},
{AArch64_ST1i32, "st1", ".s", 0, true, 0},
{AArch64_ST1i64, "st1", ".d", 0, true, 0},
{AArch64_ST1i8_POST, "st1", ".b", 1, true, 1},
{AArch64_ST1i16_POST, "st1", ".h", 1, true, 2},
{AArch64_ST1i32_POST, "st1", ".s", 1, true, 4},
{AArch64_ST1i64_POST, "st1", ".d", 1, true, 8},
{AArch64_ST1Onev16b, "st1", ".16b", 0, false, 0},
{AArch64_ST1Onev8h, "st1", ".8h", 0, false, 0},
{AArch64_ST1Onev4s, "st1", ".4s", 0, false, 0},
{AArch64_ST1Onev2d, "st1", ".2d", 0, false, 0},
{AArch64_ST1Onev8b, "st1", ".8b", 0, false, 0},
{AArch64_ST1Onev4h, "st1", ".4h", 0, false, 0},
{AArch64_ST1Onev2s, "st1", ".2s", 0, false, 0},
{AArch64_ST1Onev1d, "st1", ".1d", 0, false, 0},
{AArch64_ST1Onev16b_POST, "st1", ".16b", 1, false, 16},
{AArch64_ST1Onev8h_POST, "st1", ".8h", 1, false, 16},
{AArch64_ST1Onev4s_POST, "st1", ".4s", 1, false, 16},
{AArch64_ST1Onev2d_POST, "st1", ".2d", 1, false, 16},
{AArch64_ST1Onev8b_POST, "st1", ".8b", 1, false, 8},
{AArch64_ST1Onev4h_POST, "st1", ".4h", 1, false, 8},
{AArch64_ST1Onev2s_POST, "st1", ".2s", 1, false, 8},
{AArch64_ST1Onev1d_POST, "st1", ".1d", 1, false, 8},
{AArch64_ST1Twov16b, "st1", ".16b", 0, false, 0},
{AArch64_ST1Twov8h, "st1", ".8h", 0, false, 0},
{AArch64_ST1Twov4s, "st1", ".4s", 0, false, 0},
{AArch64_ST1Twov2d, "st1", ".2d", 0, false, 0},
{AArch64_ST1Twov8b, "st1", ".8b", 0, false, 0},
{AArch64_ST1Twov4h, "st1", ".4h", 0, false, 0},
{AArch64_ST1Twov2s, "st1", ".2s", 0, false, 0},
{AArch64_ST1Twov1d, "st1", ".1d", 0, false, 0},
{AArch64_ST1Twov16b_POST, "st1", ".16b", 1, false, 32},
{AArch64_ST1Twov8h_POST, "st1", ".8h", 1, false, 32},
{AArch64_ST1Twov4s_POST, "st1", ".4s", 1, false, 32},
{AArch64_ST1Twov2d_POST, "st1", ".2d", 1, false, 32},
{AArch64_ST1Twov8b_POST, "st1", ".8b", 1, false, 16},
{AArch64_ST1Twov4h_POST, "st1", ".4h", 1, false, 16},
{AArch64_ST1Twov2s_POST, "st1", ".2s", 1, false, 16},
{AArch64_ST1Twov1d_POST, "st1", ".1d", 1, false, 16},
{AArch64_ST1Threev16b, "st1", ".16b", 0, false, 0},
{AArch64_ST1Threev8h, "st1", ".8h", 0, false, 0},
{AArch64_ST1Threev4s, "st1", ".4s", 0, false, 0},
{AArch64_ST1Threev2d, "st1", ".2d", 0, false, 0},
{AArch64_ST1Threev8b, "st1", ".8b", 0, false, 0},
{AArch64_ST1Threev4h, "st1", ".4h", 0, false, 0},
{AArch64_ST1Threev2s, "st1", ".2s", 0, false, 0},
{AArch64_ST1Threev1d, "st1", ".1d", 0, false, 0},
{AArch64_ST1Threev16b_POST, "st1", ".16b", 1, false, 48},
{AArch64_ST1Threev8h_POST, "st1", ".8h", 1, false, 48},
{AArch64_ST1Threev4s_POST, "st1", ".4s", 1, false, 48},
{AArch64_ST1Threev2d_POST, "st1", ".2d", 1, false, 48},
{AArch64_ST1Threev8b_POST, "st1", ".8b", 1, false, 24},
{AArch64_ST1Threev4h_POST, "st1", ".4h", 1, false, 24},
{AArch64_ST1Threev2s_POST, "st1", ".2s", 1, false, 24},
{AArch64_ST1Threev1d_POST, "st1", ".1d", 1, false, 24},
{AArch64_ST1Fourv16b, "st1", ".16b", 0, false, 0},
{AArch64_ST1Fourv8h, "st1", ".8h", 0, false, 0},
{AArch64_ST1Fourv4s, "st1", ".4s", 0, false, 0},
{AArch64_ST1Fourv2d, "st1", ".2d", 0, false, 0},
{AArch64_ST1Fourv8b, "st1", ".8b", 0, false, 0},
{AArch64_ST1Fourv4h, "st1", ".4h", 0, false, 0},
{AArch64_ST1Fourv2s, "st1", ".2s", 0, false, 0},
{AArch64_ST1Fourv1d, "st1", ".1d", 0, false, 0},
{AArch64_ST1Fourv16b_POST, "st1", ".16b", 1, false, 64},
{AArch64_ST1Fourv8h_POST, "st1", ".8h", 1, false, 64},
{AArch64_ST1Fourv4s_POST, "st1", ".4s", 1, false, 64},
{AArch64_ST1Fourv2d_POST, "st1", ".2d", 1, false, 64},
{AArch64_ST1Fourv8b_POST, "st1", ".8b", 1, false, 32},
{AArch64_ST1Fourv4h_POST, "st1", ".4h", 1, false, 32},
{AArch64_ST1Fourv2s_POST, "st1", ".2s", 1, false, 32},
{AArch64_ST1Fourv1d_POST, "st1", ".1d", 1, false, 32},
{AArch64_ST2i8, "st2", ".b", 0, true, 0},
{AArch64_ST2i16, "st2", ".h", 0, true, 0},
{AArch64_ST2i32, "st2", ".s", 0, true, 0},
{AArch64_ST2i64, "st2", ".d", 0, true, 0},
{AArch64_ST2i8_POST, "st2", ".b", 1, true, 2},
{AArch64_ST2i16_POST, "st2", ".h", 1, true, 4},
{AArch64_ST2i32_POST, "st2", ".s", 1, true, 8},
{AArch64_ST2i64_POST, "st2", ".d", 1, true, 16},
{AArch64_ST2Twov16b, "st2", ".16b", 0, false, 0},
{AArch64_ST2Twov8h, "st2", ".8h", 0, false, 0},
{AArch64_ST2Twov4s, "st2", ".4s", 0, false, 0},
{AArch64_ST2Twov2d, "st2", ".2d", 0, false, 0},
{AArch64_ST2Twov8b, "st2", ".8b", 0, false, 0},
{AArch64_ST2Twov4h, "st2", ".4h", 0, false, 0},
{AArch64_ST2Twov2s, "st2", ".2s", 0, false, 0},
{AArch64_ST2Twov16b_POST, "st2", ".16b", 1, false, 32},
{AArch64_ST2Twov8h_POST, "st2", ".8h", 1, false, 32},
{AArch64_ST2Twov4s_POST, "st2", ".4s", 1, false, 32},
{AArch64_ST2Twov2d_POST, "st2", ".2d", 1, false, 32},
{AArch64_ST2Twov8b_POST, "st2", ".8b", 1, false, 16},
{AArch64_ST2Twov4h_POST, "st2", ".4h", 1, false, 16},
{AArch64_ST2Twov2s_POST, "st2", ".2s", 1, false, 16},
{AArch64_ST3i8, "st3", ".b", 0, true, 0},
{AArch64_ST3i16, "st3", ".h", 0, true, 0},
{AArch64_ST3i32, "st3", ".s", 0, true, 0},
{AArch64_ST3i64, "st3", ".d", 0, true, 0},
{AArch64_ST3i8_POST, "st3", ".b", 1, true, 3},
{AArch64_ST3i16_POST, "st3", ".h", 1, true, 6},
{AArch64_ST3i32_POST, "st3", ".s", 1, true, 12},
{AArch64_ST3i64_POST, "st3", ".d", 1, true, 24},
{AArch64_ST3Threev16b, "st3", ".16b", 0, false, 0},
{AArch64_ST3Threev8h, "st3", ".8h", 0, false, 0},
{AArch64_ST3Threev4s, "st3", ".4s", 0, false, 0},
{AArch64_ST3Threev2d, "st3", ".2d", 0, false, 0},
{AArch64_ST3Threev8b, "st3", ".8b", 0, false, 0},
{AArch64_ST3Threev4h, "st3", ".4h", 0, false, 0},
{AArch64_ST3Threev2s, "st3", ".2s", 0, false, 0},
{AArch64_ST3Threev16b_POST, "st3", ".16b", 1, false, 48},
{AArch64_ST3Threev8h_POST, "st3", ".8h", 1, false, 48},
{AArch64_ST3Threev4s_POST, "st3", ".4s", 1, false, 48},
{AArch64_ST3Threev2d_POST, "st3", ".2d", 1, false, 48},
{AArch64_ST3Threev8b_POST, "st3", ".8b", 1, false, 24},
{AArch64_ST3Threev4h_POST, "st3", ".4h", 1, false, 24},
{AArch64_ST3Threev2s_POST, "st3", ".2s", 1, false, 24},
{AArch64_ST4i8, "st4", ".b", 0, true, 0},
{AArch64_ST4i16, "st4", ".h", 0, true, 0},
{AArch64_ST4i32, "st4", ".s", 0, true, 0},
{AArch64_ST4i64, "st4", ".d", 0, true, 0},
{AArch64_ST4i8_POST, "st4", ".b", 1, true, 4},
{AArch64_ST4i16_POST, "st4", ".h", 1, true, 8},
{AArch64_ST4i32_POST, "st4", ".s", 1, true, 16},
{AArch64_ST4i64_POST, "st4", ".d", 1, true, 32},
{AArch64_ST4Fourv16b, "st4", ".16b", 0, false, 0},
{AArch64_ST4Fourv8h, "st4", ".8h", 0, false, 0},
{AArch64_ST4Fourv4s, "st4", ".4s", 0, false, 0},
{AArch64_ST4Fourv2d, "st4", ".2d", 0, false, 0},
{AArch64_ST4Fourv8b, "st4", ".8b", 0, false, 0},
{AArch64_ST4Fourv4h, "st4", ".4h", 0, false, 0},
{AArch64_ST4Fourv2s, "st4", ".2s", 0, false, 0},
{AArch64_ST4Fourv16b_POST, "st4", ".16b", 1, false, 64},
{AArch64_ST4Fourv8h_POST, "st4", ".8h", 1, false, 64},
{AArch64_ST4Fourv4s_POST, "st4", ".4s", 1, false, 64},
{AArch64_ST4Fourv2d_POST, "st4", ".2d", 1, false, 64},
{AArch64_ST4Fourv8b_POST, "st4", ".8b", 1, false, 32},
{AArch64_ST4Fourv4h_POST, "st4", ".4h", 1, false, 32},
{AArch64_ST4Fourv2s_POST, "st4", ".2s", 1, false, 32},
};
static const LdStNInstrDesc *getLdStNInstrDesc(unsigned Opcode)
{
for (int i = 0; i < (sizeof(LdStNInstInfo)/sizeof(LdStNInstInfo[0])); ++i) {
const LdStNInstrDesc *Info = &LdStNInstInfo[i];
if (Info->Opcode == Opcode)
return Info;
}
return NULL;
}
void AArch64AppleInstPrinter_printInst(MCInst *MI, uint64_t Address, const char *Annot, SStream *O)
{
unsigned Opcode = MCInst_getOpcode(MI);
const char *Layout;
bool IsTbx;
if (isTblTbxInstruction(MCInst_getOpcode(MI), &Layout, &IsTbx)) {
SStream_concat(O, "%s%s", (IsTbx ? "tbx" : "tbl"), Layout);
SStream_concat0(O, " ");
printRegNameAlt(O, MCOperand_getReg(MCInst_getOperand(MI, (0))),
AArch64_vreg);
SStream_concat0(O, ", ");
unsigned ListOpNum = IsTbx ? 2 : 1;
printVectorList(MI, ListOpNum, O, "");
SStream_concat0(O, ", ");
printRegNameAlt(O,
MCOperand_getReg(MCInst_getOperand(MI, (ListOpNum + 1))),
AArch64_vreg);
;
return;
}
const LdStNInstrDesc *LdStDesc = getLdStNInstrDesc(Opcode);
if (LdStDesc) {
SStream_concat(O, "%s%s", LdStDesc->Mnemonic, LdStDesc->Layout);
SStream_concat0(O, " ");
// Now onto the operands: first a vector list with possible lane
// specifier. E.g. { v0 }[2]
int OpNum = LdStDesc->ListOperand;
printVectorList(MI, OpNum++, O, "");
if (LdStDesc->HasLane) {
SStream_concat1(O, '[');
SStream_concat(O, "%s",
MCOperand_getImm(MCInst_getOperand(MI, (OpNum++))));
SStream_concat0(O, "]");
}
// Next the address: [xN]
unsigned AddrReg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum++)));
SStream_concat0(O, ", [");
printRegName(O, AddrReg);
SStream_concat0(O, "]");
// Finally, there might be a post-indexed offset.
if (LdStDesc->NaturalOffset != 0) {
unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum++)));
if (Reg != AArch64_XZR) {
SStream_concat0(O, ", ");
printRegName(O, Reg);
} else {
SStream_concat(O, "%s%s%s%s", ", ", markup("<imm:"), "#",
LdStDesc->NaturalOffset);
SStream_concat0(O, markup(">"));
}
}
;
return;
}
printInst(MI, Address, Annot, O);
}
bool printRangePrefetchAlias(MCInst *MI, SStream *O, const char *Annot)
{
unsigned Opcode = MCInst_getOpcode(MI);
#ifndef NDEBUG
#endif
unsigned PRFOp = MCOperand_getImm(MCInst_getOperand(MI, (0)));
unsigned Mask = 0x18; // 0b11000
if ((PRFOp & Mask) != Mask)
return false; // Rt != '11xxx', it's a PRFM instruction.
unsigned Rm = MCOperand_getReg(MCInst_getOperand(MI, (2)));
// "Rm" must be a 64-bit GPR for RPRFM.
if (MCRegisterInfo_getRegClass(MI->MRI, Rm))
Rm = MCRegisterInfo_getMatchingSuperReg(MI->MRI, Rm, AArch64_sub_32,
MCRegisterInfo_getRegClass(MI->MRI, Rm));
unsigned SignExtend =
MCOperand_getImm(MCInst_getOperand(MI, (3))); // encoded in "option<2>".
unsigned Shift =
MCOperand_getImm(MCInst_getOperand(MI, (4))); // encoded in "S".
unsigned Option0 = (Opcode == AArch64_PRFMroX) ? 1 : 0;
// encoded in "option<2>:option<0>:S:Rt<2:0>".
unsigned RPRFOp =
(SignExtend << 5) | (Option0 << 4) | (Shift << 3) | (PRFOp & 0x7);
SStream_concat0(O, "rprfm ");
const AArch64RPRFM_RPRFM *RPRFM = AArch64RPRFM_lookupRPRFMByEncoding(RPRFOp);
if (RPRFM) {
SStream_concat0(O, RPRFM->Name);
if (detail_is_set(MI)) {
aarch64_sysop sysop;
sysop.alias = RPRFM->SysAlias;
sysop.sub_type = AArch64_OP_RPRFM;
AArch64_get_detail_op(MI, 0)->type = AArch64_OP_SYSALIAS;
AArch64_get_detail_op(MI, 0)->sysop = sysop;
AArch64_inc_op_count(MI);
}
}
SStream_concat0(O, ", [");
printOperand(MI, 1, O); // "Rn".
SStream_concat0(O, "]");
;
return true;
}
bool printSysAlias(MCInst *MI, SStream *O)
{
MCOperand *Op1 = MCInst_getOperand(MI, (0));
MCOperand *Cn = MCInst_getOperand(MI, (1));
MCOperand *Cm = MCInst_getOperand(MI, (2));
MCOperand *Op2 = MCInst_getOperand(MI, (3));
unsigned Op1Val = MCOperand_getImm(Op1);
unsigned CnVal = MCOperand_getImm(Cn);
unsigned CmVal = MCOperand_getImm(Cm);
unsigned Op2Val = MCOperand_getImm(Op2);
uint16_t Encoding = Op2Val;
Encoding |= CmVal << 3;
Encoding |= CnVal << 7;
Encoding |= Op1Val << 11;
bool NeedsReg;
const char *Ins;
const char *Name;
if (CnVal == 7) {
switch (CmVal) {
default:
return false;
// Maybe IC, maybe Prediction Restriction
case 1:
switch (Op1Val) {
default:
return false;
case 0:
goto Search_IC;
case 3:
goto Search_PRCTX;
}
// Prediction Restriction aliases
case 3: {
Search_PRCTX:
if (Op1Val != 3 || CnVal != 7 || CmVal != 3)
return false;
aarch64_insn_group Requires =
Op2Val == 6 ? AArch64_FeatureSPECRES2 : AArch64_FeaturePredRes;
if (!(AArch64_getFeatureBits(MI->csh->mode, AArch64_FeatureAll) ||
AArch64_getFeatureBits(MI->csh->mode, Requires)))
return false;
NeedsReg = true;
switch (Op2Val) {
default:
return false;
case 4:
Ins = "cfp ";
break;
case 5:
Ins = "dvp ";
break;
case 6:
Ins = "cosp ";
break;
case 7:
Ins = "cpp ";
break;
}
Name = "RCTX";
} break;
// IC aliases
case 5: {
Search_IC: {
const AArch64IC_IC *IC = AArch64IC_lookupICByEncoding(Encoding);
if (!IC || !AArch64_testFeatureList(MI->csh->mode, IC->FeaturesRequired))
return false;
if (detail_is_set(MI)) {
aarch64_sysop sysop;
sysop.reg = IC->SysReg;
sysop.sub_type = AArch64_OP_IC;
AArch64_get_detail_op(MI, 0)->type = AArch64_OP_SYSREG;
AArch64_get_detail_op(MI, 0)->sysop = sysop;
AArch64_inc_op_count(MI);
}
NeedsReg = IC->NeedsReg;
Ins = "ic ";
Name = IC->Name;
}
} break;
// DC aliases
case 4:
case 6:
case 10:
case 11:
case 12:
case 13:
case 14: {
const AArch64DC_DC *DC = AArch64DC_lookupDCByEncoding(Encoding);
if (!DC || !AArch64_testFeatureList(MI->csh->mode, DC->FeaturesRequired))
return false;
if (detail_is_set(MI)) {
aarch64_sysop sysop;
sysop.alias = DC->SysAlias;
sysop.sub_type = AArch64_OP_DC;
AArch64_get_detail_op(MI, 0)->type = AArch64_OP_SYSALIAS;
AArch64_get_detail_op(MI, 0)->sysop = sysop;
AArch64_inc_op_count(MI);
}
NeedsReg = true;
Ins = "dc ";
Name = DC->Name;
} break;
// AT aliases
case 8:
case 9: {
const AArch64AT_AT *AT = AArch64AT_lookupATByEncoding(Encoding);
if (!AT || !AArch64_testFeatureList(MI->csh->mode, AT->FeaturesRequired))
return false;
if (detail_is_set(MI)) {
aarch64_sysop sysop;
sysop.alias = AT->SysAlias;
sysop.sub_type = AArch64_OP_AT;
AArch64_get_detail_op(MI, 0)->type = AArch64_OP_SYSALIAS;
AArch64_get_detail_op(MI, 0)->sysop = sysop;
AArch64_inc_op_count(MI);
}
NeedsReg = true;
Ins = "at ";
Name = AT->Name;
} break;
}
} else if (CnVal == 8 || CnVal == 9) {
// TLBI aliases
const AArch64TLBI_TLBI *TLBI =
AArch64TLBI_lookupTLBIByEncoding(Encoding);
if (!TLBI || !AArch64_testFeatureList(MI->csh->mode, TLBI->FeaturesRequired))
return false;
if (detail_is_set(MI)) {
aarch64_sysop sysop;
sysop.reg = TLBI->SysReg;
sysop.sub_type = AArch64_OP_TLBI;
AArch64_get_detail_op(MI, 0)->type = AArch64_OP_SYSREG;
AArch64_get_detail_op(MI, 0)->sysop = sysop;
AArch64_inc_op_count(MI);
}
NeedsReg = TLBI->NeedsReg;
Ins = "tlbi ";
Name = TLBI->Name;
} else
return false;
#define TMP_STR_LEN 32
char Str[TMP_STR_LEN] = {0};
append_to_str_lower(Str, TMP_STR_LEN, Ins);
append_to_str_lower(Str, TMP_STR_LEN, Name);
#undef TMP_STR_LEN
SStream_concat1(O, ' ');
SStream_concat0(O, Str);
if (NeedsReg) {
SStream_concat0(O, ", ");
printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, (4))));
AArch64_set_detail_op_reg(MI, 4, MCInst_getOpVal(MI, 4));
}
return true;
}
bool printSyspAlias(MCInst *MI, SStream *O)
{
MCOperand *Op1 = MCInst_getOperand(MI, (0));
MCOperand *Cn = MCInst_getOperand(MI, (1));
MCOperand *Cm = MCInst_getOperand(MI, (2));
MCOperand *Op2 = MCInst_getOperand(MI, (3));
unsigned Op1Val = MCOperand_getImm(Op1);
unsigned CnVal = MCOperand_getImm(Cn);
unsigned CmVal = MCOperand_getImm(Cm);
unsigned Op2Val = MCOperand_getImm(Op2);
uint16_t Encoding = Op2Val;
Encoding |= CmVal << 3;
Encoding |= CnVal << 7;
Encoding |= Op1Val << 11;
const char *Ins;
const char *Name;
if (CnVal == 8 || CnVal == 9) {
// TLBIP aliases
if (CnVal == 9) {
if (!AArch64_getFeatureBits(MI->csh->mode, AArch64_FeatureAll) ||
!AArch64_getFeatureBits(MI->csh->mode, AArch64_FeatureXS))
return false;
Encoding &= ~(1 << 7);
}
const AArch64TLBI_TLBI *TLBI =
AArch64TLBI_lookupTLBIByEncoding(Encoding);
if (!TLBI || !AArch64_testFeatureList(MI->csh->mode, TLBI->FeaturesRequired))
return false;
if (detail_is_set(MI)) {
aarch64_sysop sysop;
sysop.reg = TLBI->SysReg;
sysop.sub_type = AArch64_OP_TLBI;
AArch64_get_detail_op(MI, 0)->type = AArch64_OP_SYSREG;
AArch64_get_detail_op(MI, 0)->sysop = sysop;
AArch64_inc_op_count(MI);
}
Ins = "tlbip ";
Name = TLBI->Name;
} else
return false;
#define TMP_STR_LEN 32
char Str[TMP_STR_LEN] = {0};
append_to_str_lower(Str, TMP_STR_LEN, Ins);
append_to_str_lower(Str, TMP_STR_LEN, Name);
if (CnVal == 9) {
append_to_str_lower(Str, TMP_STR_LEN, "nxs");
}
#undef TMP_STR_LEN
SStream_concat1(O, ' ');
SStream_concat0(O, Str);
SStream_concat0(O, ", ");
if (MCOperand_getReg(MCInst_getOperand(MI, (4))) == AArch64_XZR)
printSyspXzrPair(MI, 4, O);
else
CONCAT(printGPRSeqPairsClassOperand, 64)(MI, 4, O);
return true;
}
#define DEFINE_printMatrix(EltSize) \
void CONCAT(printMatrix, EltSize)(MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_Matrix, EltSize), OpNum, \
EltSize); \
MCOperand *RegOp = MCInst_getOperand(MI, (OpNum)); \
\
printRegName(O, MCOperand_getReg(RegOp)); \
switch (EltSize) { \
case 0: \
break; \
case 8: \
SStream_concat0(O, ".b"); \
break; \
case 16: \
SStream_concat0(O, ".h"); \
break; \
case 32: \
SStream_concat0(O, ".s"); \
break; \
case 64: \
SStream_concat0(O, ".d"); \
break; \
case 128: \
SStream_concat0(O, ".q"); \
break; \
default: \
assert(0 && "Unsupported element size"); \
} \
}
DEFINE_printMatrix(64);
DEFINE_printMatrix(32);
DEFINE_printMatrix(16);
DEFINE_printMatrix(0);
#define DEFINE_printMatrixTileVector(IsVertical) \
void CONCAT(printMatrixTileVector, IsVertical)(MCInst * MI, \
unsigned OpNum, SStream *O) \
{ \
add_cs_detail(MI, \
CONCAT(AArch64_OP_GROUP_MatrixTileVector, IsVertical), \
OpNum, IsVertical); \
MCOperand *RegOp = MCInst_getOperand(MI, (OpNum)); \
\
const char *RegName = getRegisterName(MCOperand_getReg(RegOp), AArch64_NoRegAltName); \
\
unsigned buf_len = strlen(RegName) + 1; \
char *Base = cs_mem_calloc(1, buf_len); \
memcpy(Base, RegName, buf_len); \
char *Dot = strchr(Base, '.'); \
if (!Dot) { \
SStream_concat0(O, RegName); \
return; \
} \
*Dot = '\0'; /* Split string */ \
char *Suffix = Dot + 1; \
SStream_concat(O, "%s%s", Base, (IsVertical ? "v" : "h")); \
SStream_concat1(O, '.'); \
SStream_concat0(O, Suffix); \
cs_mem_free(Base); \
}
DEFINE_printMatrixTileVector(0);
DEFINE_printMatrixTileVector(1);
void printMatrixTile(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_MatrixTile, OpNum);
MCOperand *RegOp = MCInst_getOperand(MI, (OpNum));
printRegName(O, MCOperand_getReg(RegOp));
}
void printSVCROp(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_SVCROp, OpNum);
MCOperand *MO = MCInst_getOperand(MI, (OpNum));
unsigned svcrop = MCOperand_getImm(MO);
const AArch64SVCR_SVCR *SVCR = AArch64SVCR_lookupSVCRByEncoding(svcrop);
SStream_concat0(O, SVCR->Name);
}
void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_Operand, OpNo);
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
if (MCOperand_isReg(Op)) {
unsigned Reg = MCOperand_getReg(Op);
printRegName(O, Reg);
} else if (MCOperand_isImm(Op)) {
Op = MCInst_getOperand(MI, (OpNo));
SStream_concat(O, "%s", markup("<imm:"));
printInt64Bang(O, MCOperand_getImm(Op));
SStream_concat0(O, markup(">"));
} else {
assert(0 && "Expressions are not supported.");
}
}
void printImm(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_Imm, OpNo);
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
SStream_concat(O, "%s", markup("<imm:"));
printInt64Bang(O, MCOperand_getImm(Op));
SStream_concat0(O, markup(">"));
}
void printImmHex(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_ImmHex, OpNo);
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
SStream_concat(O, "%s", markup("<imm:"));
printInt64Bang(O, MCOperand_getImm(Op));
SStream_concat0(O, markup(">"));
}
#define DEFINE_printSImm(Size) \
void CONCAT(printSImm, Size)(MCInst * MI, unsigned OpNo, SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_SImm, Size), OpNo, Size); \
MCOperand *Op = MCInst_getOperand(MI, (OpNo)); \
if (Size == 8) { \
SStream_concat(O, "%s", markup("<imm:")); \
printInt32Bang(O, MCOperand_getImm(Op)); \
SStream_concat0(O, markup(">")); \
} else if (Size == 16) { \
SStream_concat(O, "%s", markup("<imm:")); \
printInt32Bang(O, MCOperand_getImm(Op)); \
SStream_concat0(O, markup(">")); \
} else { \
SStream_concat(O, "%s", markup("<imm:")); \
printInt64Bang(O, MCOperand_getImm(Op)); \
SStream_concat0(O, markup(">")); \
} \
}
DEFINE_printSImm(16);
DEFINE_printSImm(8);
void printPostIncOperand(MCInst *MI, unsigned OpNo, unsigned Imm, SStream *O)
{
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
if (MCOperand_isReg(Op)) {
unsigned Reg = MCOperand_getReg(Op);
if (Reg == AArch64_XZR) {
SStream_concat(O, "%s", markup("<imm:"));
printUInt64Bang(O, Imm);
SStream_concat0(O, markup(">"));
} else
printRegName(O, Reg);
} else
assert(0 && "unknown operand kind in printPostIncOperand64");
}
void printVRegOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_VRegOperand, OpNo);
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
unsigned Reg = MCOperand_getReg(Op);
printRegNameAlt(O, Reg, AArch64_vreg);
}
void printSysCROperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_SysCROperand, OpNo);
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
SStream_concat(O, "%s", "c");
printUInt32(O, MCOperand_getImm(Op));
SStream_concat1(O, '\0');
}
void printAddSubImm(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_AddSubImm, OpNum);
MCOperand *MO = MCInst_getOperand(MI, (OpNum));
if (MCOperand_isImm(MO)) {
unsigned Val = (MCOperand_getImm(MO) & 0xfff);
unsigned Shift = AArch64_AM_getShiftValue(
MCOperand_getImm(MCInst_getOperand(MI, (OpNum + 1))));
SStream_concat(O, "%s", markup("<imm:"));
printUInt32Bang(O, (Val));
SStream_concat0(O, markup(">"));
if (Shift != 0) {
printShifter(MI, OpNum + 1, O);
}
} else {
printShifter(MI, OpNum + 1, O);
}
}
#define DEFINE_printLogicalImm(T) \
void CONCAT(printLogicalImm, T)(MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_LogicalImm, T), OpNum, sizeof(T)); \
uint64_t Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); \
SStream_concat(O, "%s", markup("<imm:")); \
printUInt64Bang(O, (AArch64_AM_decodeLogicalImmediate(Val, 8 * sizeof(T)))); \
SStream_concat0(O, markup(">")); \
}
DEFINE_printLogicalImm(int64_t);
DEFINE_printLogicalImm(int32_t);
DEFINE_printLogicalImm(int8_t);
DEFINE_printLogicalImm(int16_t);
void printShifter(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_Shifter, OpNum);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
// LSL #0 should not be printed.
if (AArch64_AM_getShiftType(Val) == AArch64_AM_LSL &&
AArch64_AM_getShiftValue(Val) == 0)
return;
SStream_concat(O, "%s%s%s%s#%d", ", ",
AArch64_AM_getShiftExtendName(AArch64_AM_getShiftType(Val)),
" ", markup("<imm:"), AArch64_AM_getShiftValue(Val));
SStream_concat0(O, markup(">"));
}
void printShiftedRegister(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_ShiftedRegister, OpNum);
printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, (OpNum))));
printShifter(MI, OpNum + 1, O);
}
void printExtendedRegister(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_ExtendedRegister, OpNum);
printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, (OpNum))));
printArithExtend(MI, OpNum + 1, O);
}
void printArithExtend(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_ArithExtend, OpNum);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
AArch64_AM_ShiftExtendType ExtType = AArch64_AM_getArithExtendType(Val);
unsigned ShiftVal = AArch64_AM_getArithShiftValue(Val);
// If the destination or first source register operand is [W]SP, print
// UXTW/UXTX as LSL, and if the shift amount is also zero, print nothing at
// all.
if (ExtType == AArch64_AM_UXTW || ExtType == AArch64_AM_UXTX) {
unsigned Dest = MCOperand_getReg(MCInst_getOperand(MI, (0)));
unsigned Src1 = MCOperand_getReg(MCInst_getOperand(MI, (1)));
if (((Dest == AArch64_SP || Src1 == AArch64_SP) &&
ExtType == AArch64_AM_UXTX) ||
((Dest == AArch64_WSP || Src1 == AArch64_WSP) &&
ExtType == AArch64_AM_UXTW)) {
if (ShiftVal != 0) {
SStream_concat(O, "%s%s", ", lsl ", markup("<imm:"));
printUInt32Bang(O, ShiftVal);
SStream_concat0(O, markup(">"));
}
return;
}
}
SStream_concat(O, "%s", ", ");
SStream_concat0(O, AArch64_AM_getShiftExtendName(ExtType));
if (ShiftVal != 0) {
SStream_concat(O, "%s%s#%d", " ", markup("<imm:"), ShiftVal);
SStream_concat0(O, markup(">"));
}
}
static void printMemExtendImpl(bool SignExtend, bool DoShift, unsigned Width,
char SrcRegKind, SStream *O, bool getUseMarkup)
{
// sxtw, sxtx, uxtw or lsl (== uxtx)
bool IsLSL = !SignExtend && SrcRegKind == 'x';
if (IsLSL)
SStream_concat0(O, "lsl");
else {
SStream_concat(O, "%c%s", (SignExtend ? 's' : 'u'), "xt");
SStream_concat1(O, SrcRegKind);
}
if (DoShift || IsLSL) {
SStream_concat0(O, " ");
if (getUseMarkup)
SStream_concat0(O, "<imm:");
unsigned ShiftAmount = DoShift ? Log2_32(Width / 8) : 0;
SStream_concat(O, "%s%d", "#", ShiftAmount);
if (getUseMarkup)
SStream_concat0(O, ">");
}
}
void printMemExtend(MCInst *MI, unsigned OpNum, SStream *O, char SrcRegKind,
unsigned Width)
{
bool SignExtend = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
bool DoShift = MCOperand_getImm(MCInst_getOperand(MI, (OpNum + 1)));
printMemExtendImpl(SignExtend, DoShift, Width, SrcRegKind, O,
getUseMarkup());
}
#define DEFINE_printRegWithShiftExtend(SignExtend, ExtWidth, SrcRegKind, \
Suffix) \
void CONCAT( \
printRegWithShiftExtend, \
CONCAT(SignExtend, CONCAT(ExtWidth, CONCAT(SrcRegKind, Suffix))))( \
MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail( \
MI, \
CONCAT(CONCAT(CONCAT(CONCAT(AArch64_OP_GROUP_RegWithShiftExtend, \
SignExtend), \
ExtWidth), \
SrcRegKind), \
Suffix), \
OpNum, SignExtend, ExtWidth, CHAR(SrcRegKind), CHAR(Suffix)); \
printOperand(MI, OpNum, O); \
if (CHAR(Suffix) == 's' || CHAR(Suffix) == 'd') { \
SStream_concat1(O, '.'); \
SStream_concat1(O, CHAR(Suffix)); \
SStream_concat1(O, '\0'); \
} else \
assert((CHAR(Suffix) == '0') && "Unsupported suffix size"); \
bool DoShift = ExtWidth != 8; \
if (SignExtend || DoShift || CHAR(SrcRegKind) == 'w') { \
SStream_concat0(O, ", "); \
printMemExtendImpl(SignExtend, DoShift, ExtWidth, CHAR(SrcRegKind), O, \
getUseMarkup()); \
} \
}
DEFINE_printRegWithShiftExtend(false, 8, x, d);
DEFINE_printRegWithShiftExtend(true, 8, w, d);
DEFINE_printRegWithShiftExtend(false, 8, w, d);
DEFINE_printRegWithShiftExtend(false, 8, x, 0);
DEFINE_printRegWithShiftExtend(true, 8, w, s);
DEFINE_printRegWithShiftExtend(false, 8, w, s);
DEFINE_printRegWithShiftExtend(false, 64, x, d);
DEFINE_printRegWithShiftExtend(true, 64, w, d);
DEFINE_printRegWithShiftExtend(false, 64, w, d);
DEFINE_printRegWithShiftExtend(false, 64, x, 0);
DEFINE_printRegWithShiftExtend(true, 64, w, s);
DEFINE_printRegWithShiftExtend(false, 64, w, s);
DEFINE_printRegWithShiftExtend(false, 16, x, d);
DEFINE_printRegWithShiftExtend(true, 16, w, d);
DEFINE_printRegWithShiftExtend(false, 16, w, d);
DEFINE_printRegWithShiftExtend(false, 16, x, 0);
DEFINE_printRegWithShiftExtend(true, 16, w, s);
DEFINE_printRegWithShiftExtend(false, 16, w, s);
DEFINE_printRegWithShiftExtend(false, 32, x, d);
DEFINE_printRegWithShiftExtend(true, 32, w, d);
DEFINE_printRegWithShiftExtend(false, 32, w, d);
DEFINE_printRegWithShiftExtend(false, 32, x, 0);
DEFINE_printRegWithShiftExtend(true, 32, w, s);
DEFINE_printRegWithShiftExtend(false, 32, w, s);
DEFINE_printRegWithShiftExtend(false, 8, x, s);
DEFINE_printRegWithShiftExtend(false, 16, x, s);
DEFINE_printRegWithShiftExtend(false, 32, x, s);
DEFINE_printRegWithShiftExtend(false, 64, x, s);
DEFINE_printRegWithShiftExtend(false, 128, x, 0);
#define DEFINE_printPredicateAsCounter(EltSize) \
void CONCAT(printPredicateAsCounter, EltSize)(MCInst * MI, unsigned OpNum, \
SStream *O) \
{ \
add_cs_detail(MI, \
CONCAT(AArch64_OP_GROUP_PredicateAsCounter, EltSize), \
OpNum, EltSize); \
unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum))); \
\
SStream_concat(O, "%s", "pn"); \
printUInt32(O, (Reg - AArch64_P0)); \
switch (EltSize) { \
case 0: \
break; \
case 8: \
SStream_concat0(O, ".b"); \
break; \
case 16: \
SStream_concat0(O, ".h"); \
break; \
case 32: \
SStream_concat0(O, ".s"); \
break; \
case 64: \
SStream_concat0(O, ".d"); \
break; \
default: \
assert(0 && "Unsupported element size"); \
} \
}
DEFINE_printPredicateAsCounter(8);
DEFINE_printPredicateAsCounter(64);
DEFINE_printPredicateAsCounter(16);
DEFINE_printPredicateAsCounter(32);
DEFINE_printPredicateAsCounter(0);
void printCondCode(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_CondCode, OpNum);
AArch64CC_CondCode CC =
(AArch64CC_CondCode)MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
SStream_concat0(O, AArch64CC_getCondCodeName(CC));
}
void printInverseCondCode(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_InverseCondCode, OpNum);
AArch64CC_CondCode CC =
(AArch64CC_CondCode)MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
SStream_concat0(
O, AArch64CC_getCondCodeName(AArch64CC_getInvertedCondCode(CC)));
}
void printAMNoIndex(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_AMNoIndex, OpNum);
SStream_concat0(O, "[");
printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, (OpNum))));
SStream_concat0(O, "]");
}
#define DEFINE_printImmScale(Scale) \
void CONCAT(printImmScale, Scale)(MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_ImmScale, Scale), OpNum, \
Scale); \
SStream_concat(O, "%s", markup("<imm:")); \
printInt32Bang(O, \
Scale * MCOperand_getImm( \
MCInst_getOperand(MI, (OpNum)))); \
SStream_concat0(O, markup(">")); \
}
DEFINE_printImmScale(8);
DEFINE_printImmScale(2);
DEFINE_printImmScale(4);
DEFINE_printImmScale(16);
DEFINE_printImmScale(32);
DEFINE_printImmScale(3);
#define DEFINE_printImmRangeScale(Scale, Offset) \
void CONCAT(printImmRangeScale, CONCAT(Scale, Offset))( \
MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail( \
MI, CONCAT(CONCAT(AArch64_OP_GROUP_ImmRangeScale, Scale), Offset), \
OpNum, Scale, Offset); \
unsigned FirstImm = \
Scale * MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); \
printUInt32(O, (FirstImm)); \
SStream_concat(O, "%s", ":"); \
printUInt32(O, (FirstImm + Offset)); \
SStream_concat1(O, '\0'); \
}
DEFINE_printImmRangeScale(2, 1);
DEFINE_printImmRangeScale(4, 3);
void printUImm12Offset(MCInst *MI, unsigned OpNum, unsigned Scale, SStream *O)
{
MCOperand *MO = MCInst_getOperand(MI, (OpNum));
if (MCOperand_isImm(MO)) {
SStream_concat(O, "%s", markup("<imm:"));
printUInt32Bang(O, (MCOperand_getImm(MO) * Scale));
SStream_concat0(O, markup(">"));
} else {
assert(0 && "Expressions not supported.");
}
}
void printAMIndexedWB(MCInst *MI, unsigned OpNum, unsigned Scale, SStream *O)
{
MCOperand *MO1 = MCInst_getOperand(MI, (OpNum + 1));
SStream_concat0(O, "[");
printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, (OpNum))));
if (MCOperand_isImm(MO1)) {
SStream_concat(O, "%s%s", ", ", markup("<imm:"));
printUInt32Bang(O, MCOperand_getImm(MO1) * Scale);
SStream_concat0(O, markup(">"));
} else {
assert(0 && "Expressions not supported.");
}
SStream_concat0(O, "]");
}
void printRPRFMOperand(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_RPRFMOperand, OpNum);
unsigned prfop = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
const AArch64PRFM_PRFM *PRFM = AArch64RPRFM_lookupRPRFMByEncoding(prfop);
if (PRFM) {
SStream_concat0(O, PRFM->Name);
return;
}
printUInt32Bang(O, (prfop));
SStream_concat1(O, '\0');
}
#define DEFINE_printPrefetchOp(IsSVEPrefetch) \
void CONCAT(printPrefetchOp, IsSVEPrefetch)(MCInst * MI, unsigned OpNum, \
SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_PrefetchOp, IsSVEPrefetch), \
OpNum, IsSVEPrefetch); \
unsigned prfop = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); \
if (IsSVEPrefetch) { \
const AArch64SVEPRFM_SVEPRFM *PRFM = AArch64SVEPRFM_lookupSVEPRFMByEncoding(prfop); \
if (PRFM) { \
SStream_concat0(O, PRFM->Name); \
return; \
} \
} else { \
const AArch64PRFM_PRFM *PRFM = AArch64PRFM_lookupPRFMByEncoding(prfop); \
if (PRFM && AArch64_testFeatureList(MI->csh->mode, PRFM->FeaturesRequired)) { \
SStream_concat0(O, PRFM->Name); \
return; \
} \
} \
\
SStream_concat(O, "%s", markup("<imm:")); \
printUInt32Bang(O, (prfop)); \
SStream_concat0(O, markup(">")); \
}
DEFINE_printPrefetchOp(false);
DEFINE_printPrefetchOp(true);
void printPSBHintOp(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_PSBHintOp, OpNum);
unsigned psbhintop = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
const AArch64PSBHint_PSB *PSB = AArch64PSBHint_lookupPSBByEncoding(psbhintop);
if (PSB)
SStream_concat0(O, PSB->Name);
else {
SStream_concat(O, "%s", markup("<imm:"));
SStream_concat1(O, '#');
printUInt32Bang(O, (psbhintop));
SStream_concat0(O, markup(">"));
}
}
void printBTIHintOp(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_BTIHintOp, OpNum);
unsigned btihintop = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))) ^ 32;
const AArch64BTIHint_BTI *BTI = AArch64BTIHint_lookupBTIByEncoding(btihintop);
if (BTI)
SStream_concat0(O, BTI->Name);
else {
SStream_concat(O, "%s", markup("<imm:"));
printUInt32Bang(O, (btihintop));
SStream_concat0(O, markup(">"));
}
}
static void printFPImmOperand(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_FPImmOperand, OpNum);
MCOperand *MO = MCInst_getOperand(MI, (OpNum));
float FPImm = MCOperand_isDFPImm(MO)
? BitsToDouble(MCOperand_getImm(MO))
: AArch64_AM_getFPImmFloat(MCOperand_getImm(MO));
// 8 decimal places are enough to perfectly represent permitted floats.
SStream_concat(O, "%s", markup("<imm:"));
SStream_concat(O, "#%.8f", FPImm);
SStream_concat0(O, markup(">"));
}
static unsigned getNextVectorRegister(unsigned Reg, unsigned Stride /* = 1 */)
{
while (Stride--) {
switch (Reg) {
default:
assert(0 && "Vector register expected!");
case AArch64_Q0:
Reg = AArch64_Q1;
break;
case AArch64_Q1:
Reg = AArch64_Q2;
break;
case AArch64_Q2:
Reg = AArch64_Q3;
break;
case AArch64_Q3:
Reg = AArch64_Q4;
break;
case AArch64_Q4:
Reg = AArch64_Q5;
break;
case AArch64_Q5:
Reg = AArch64_Q6;
break;
case AArch64_Q6:
Reg = AArch64_Q7;
break;
case AArch64_Q7:
Reg = AArch64_Q8;
break;
case AArch64_Q8:
Reg = AArch64_Q9;
break;
case AArch64_Q9:
Reg = AArch64_Q10;
break;
case AArch64_Q10:
Reg = AArch64_Q11;
break;
case AArch64_Q11:
Reg = AArch64_Q12;
break;
case AArch64_Q12:
Reg = AArch64_Q13;
break;
case AArch64_Q13:
Reg = AArch64_Q14;
break;
case AArch64_Q14:
Reg = AArch64_Q15;
break;
case AArch64_Q15:
Reg = AArch64_Q16;
break;
case AArch64_Q16:
Reg = AArch64_Q17;
break;
case AArch64_Q17:
Reg = AArch64_Q18;
break;
case AArch64_Q18:
Reg = AArch64_Q19;
break;
case AArch64_Q19:
Reg = AArch64_Q20;
break;
case AArch64_Q20:
Reg = AArch64_Q21;
break;
case AArch64_Q21:
Reg = AArch64_Q22;
break;
case AArch64_Q22:
Reg = AArch64_Q23;
break;
case AArch64_Q23:
Reg = AArch64_Q24;
break;
case AArch64_Q24:
Reg = AArch64_Q25;
break;
case AArch64_Q25:
Reg = AArch64_Q26;
break;
case AArch64_Q26:
Reg = AArch64_Q27;
break;
case AArch64_Q27:
Reg = AArch64_Q28;
break;
case AArch64_Q28:
Reg = AArch64_Q29;
break;
case AArch64_Q29:
Reg = AArch64_Q30;
break;
case AArch64_Q30:
Reg = AArch64_Q31;
break;
// Vector lists can wrap around.
case AArch64_Q31:
Reg = AArch64_Q0;
break;
case AArch64_Z0:
Reg = AArch64_Z1;
break;
case AArch64_Z1:
Reg = AArch64_Z2;
break;
case AArch64_Z2:
Reg = AArch64_Z3;
break;
case AArch64_Z3:
Reg = AArch64_Z4;
break;
case AArch64_Z4:
Reg = AArch64_Z5;
break;
case AArch64_Z5:
Reg = AArch64_Z6;
break;
case AArch64_Z6:
Reg = AArch64_Z7;
break;
case AArch64_Z7:
Reg = AArch64_Z8;
break;
case AArch64_Z8:
Reg = AArch64_Z9;
break;
case AArch64_Z9:
Reg = AArch64_Z10;
break;
case AArch64_Z10:
Reg = AArch64_Z11;
break;
case AArch64_Z11:
Reg = AArch64_Z12;
break;
case AArch64_Z12:
Reg = AArch64_Z13;
break;
case AArch64_Z13:
Reg = AArch64_Z14;
break;
case AArch64_Z14:
Reg = AArch64_Z15;
break;
case AArch64_Z15:
Reg = AArch64_Z16;
break;
case AArch64_Z16:
Reg = AArch64_Z17;
break;
case AArch64_Z17:
Reg = AArch64_Z18;
break;
case AArch64_Z18:
Reg = AArch64_Z19;
break;
case AArch64_Z19:
Reg = AArch64_Z20;
break;
case AArch64_Z20:
Reg = AArch64_Z21;
break;
case AArch64_Z21:
Reg = AArch64_Z22;
break;
case AArch64_Z22:
Reg = AArch64_Z23;
break;
case AArch64_Z23:
Reg = AArch64_Z24;
break;
case AArch64_Z24:
Reg = AArch64_Z25;
break;
case AArch64_Z25:
Reg = AArch64_Z26;
break;
case AArch64_Z26:
Reg = AArch64_Z27;
break;
case AArch64_Z27:
Reg = AArch64_Z28;
break;
case AArch64_Z28:
Reg = AArch64_Z29;
break;
case AArch64_Z29:
Reg = AArch64_Z30;
break;
case AArch64_Z30:
Reg = AArch64_Z31;
break;
// Vector lists can wrap around.
case AArch64_Z31:
Reg = AArch64_Z0;
break;
case AArch64_P0:
Reg = AArch64_P1;
break;
case AArch64_P1:
Reg = AArch64_P2;
break;
case AArch64_P2:
Reg = AArch64_P3;
break;
case AArch64_P3:
Reg = AArch64_P4;
break;
case AArch64_P4:
Reg = AArch64_P5;
break;
case AArch64_P5:
Reg = AArch64_P6;
break;
case AArch64_P6:
Reg = AArch64_P7;
break;
case AArch64_P7:
Reg = AArch64_P8;
break;
case AArch64_P8:
Reg = AArch64_P9;
break;
case AArch64_P9:
Reg = AArch64_P10;
break;
case AArch64_P10:
Reg = AArch64_P11;
break;
case AArch64_P11:
Reg = AArch64_P12;
break;
case AArch64_P12:
Reg = AArch64_P13;
break;
case AArch64_P13:
Reg = AArch64_P14;
break;
case AArch64_P14:
Reg = AArch64_P15;
break;
// Vector lists can wrap around.
case AArch64_P15:
Reg = AArch64_P0;
break;
}
}
return Reg;
}
#define DEFINE_printGPRSeqPairsClassOperand(size) \
void CONCAT(printGPRSeqPairsClassOperand, \
size)(MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail(MI, \
CONCAT(AArch64_OP_GROUP_GPRSeqPairsClassOperand, size), \
OpNum, size); \
assert((size == 64 || size == 32) && \
"Template parameter must be either 32 or 64"); \
unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum))); \
\
unsigned Sube = (size == 32) ? AArch64_sube32 : AArch64_sube64; \
unsigned Subo = (size == 32) ? AArch64_subo32 : AArch64_subo64; \
\
unsigned Even = MCRegisterInfo_getSubReg(MI->MRI, Reg, Sube); \
unsigned Odd = MCRegisterInfo_getSubReg(MI->MRI, Reg, Subo); \
printRegName(O, Even); \
SStream_concat0(O, ", "); \
printRegName(O, Odd); \
}
DEFINE_printGPRSeqPairsClassOperand(32);
DEFINE_printGPRSeqPairsClassOperand(64);
void printMatrixTileList(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_MatrixTileList, OpNum);
unsigned MaxRegs = 8;
unsigned RegMask = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
unsigned NumRegs = 0;
for (unsigned I = 0; I < MaxRegs; ++I)
if ((RegMask & (1 << I)) != 0)
++NumRegs;
SStream_concat0(O, "{");
unsigned Printed = 0;
for (unsigned I = 0; I < MaxRegs; ++I) {
unsigned Reg = RegMask & (1 << I);
if (Reg == 0)
continue;
printRegName(O, AArch64_ZAD0 + I);
if (Printed + 1 != NumRegs)
SStream_concat0(O, ", ");
++Printed;
}
SStream_concat0(O, "}");
}
void printVectorList(MCInst *MI, unsigned OpNum, SStream *O,
const char *LayoutSuffix)
{
unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum)));
SStream_concat0(O, "{ ");
// Work out how many registers there are in the list (if there is an actual
// list).
unsigned NumRegs = 1;
if (MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_DDRegClassID), Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_ZPR2RegClassID),
Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_QQRegClassID), Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_PPR2RegClassID),
Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_ZPR2StridedRegClassID),
Reg))
NumRegs = 2;
else if (MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_DDDRegClassID),
Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_ZPR3RegClassID),
Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_QQQRegClassID),
Reg))
NumRegs = 3;
else if (MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_DDDDRegClassID),
Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_ZPR4RegClassID),
Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_QQQQRegClassID),
Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI,
AArch64_ZPR4StridedRegClassID),
Reg))
NumRegs = 4;
unsigned Stride = 1;
if (MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_ZPR2StridedRegClassID),
Reg))
Stride = 8;
else if (MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI,
AArch64_ZPR4StridedRegClassID),
Reg))
Stride = 4;
// Now forget about the list and find out what the first register is.
if (MCRegisterInfo_getSubReg(MI->MRI, Reg, AArch64_dsub0))
Reg = MCRegisterInfo_getSubReg(MI->MRI, Reg, AArch64_dsub0);
else if (MCRegisterInfo_getSubReg(MI->MRI, Reg, AArch64_qsub0))
Reg = MCRegisterInfo_getSubReg(MI->MRI, Reg, AArch64_qsub0);
else if (MCRegisterInfo_getSubReg(MI->MRI, Reg, AArch64_zsub0))
Reg = MCRegisterInfo_getSubReg(MI->MRI, Reg, AArch64_zsub0);
else if (MCRegisterInfo_getSubReg(MI->MRI, Reg, AArch64_psub0))
Reg = MCRegisterInfo_getSubReg(MI->MRI, Reg, AArch64_psub0);
// If it's a D-reg, we need to promote it to the equivalent Q-reg before
// printing (otherwise getRegisterName fails).
if (MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_FPR64RegClassID),
Reg)) {
const MCRegisterClass *FPR128RC =
MCRegisterInfo_getRegClass(MI->MRI, AArch64_FPR128RegClassID);
Reg = MCRegisterInfo_getMatchingSuperReg(MI->MRI, Reg, AArch64_dsub,
FPR128RC);
}
if ((MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_ZPRRegClassID),
Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_PPRRegClassID),
Reg)) &&
NumRegs > 1 && Stride == 1 &&
// Do not print the range when the last register is lower than the
// first. Because it is a wrap-around register.
Reg < getNextVectorRegister(Reg, NumRegs - 1)) {
printRegName(O, Reg);
SStream_concat0(O, LayoutSuffix);
if (NumRegs > 1) {
// Set of two sve registers should be separated by ','
const char *split_char = NumRegs == 2 ? ", " : " - ";
SStream_concat0(O, split_char);
printRegName(O, (getNextVectorRegister(Reg, NumRegs - 1)));
SStream_concat0(O, LayoutSuffix);
}
} else {
for (unsigned i = 0; i < NumRegs;
++i, Reg = getNextVectorRegister(Reg, Stride)) {
// wrap-around sve register
if (MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_ZPRRegClassID),
Reg) ||
MCRegisterClass_contains(
MCRegisterInfo_getRegClass(MI->MRI, AArch64_PPRRegClassID),
Reg))
printRegName(O, Reg);
else
printRegNameAlt(O, Reg, AArch64_vreg);
SStream_concat0(O, LayoutSuffix);
if (i + 1 != NumRegs)
SStream_concat0(O, ", ");
}
}
SStream_concat0(O, " }");
}
void printImplicitlyTypedVectorList(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_ImplicitlyTypedVectorList, OpNum);
printVectorList(MI, OpNum, O, "");
}
#define DEFINE_printTypedVectorList(NumLanes, LaneKind) \
void CONCAT(printTypedVectorList, CONCAT(NumLanes, LaneKind))( \
MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail( \
MI, \
CONCAT(CONCAT(AArch64_OP_GROUP_TypedVectorList, NumLanes), \
LaneKind), \
OpNum, NumLanes, CHAR(LaneKind)); \
char Suffix[32]; \
if (NumLanes) \
cs_snprintf(Suffix, sizeof(Suffix), ".%u%c", NumLanes, CHAR(LaneKind)); \
else \
cs_snprintf(Suffix, sizeof(Suffix), ".%c", CHAR(LaneKind)); \
\
printVectorList(MI, OpNum, O, ((const char *)&Suffix)); \
}
DEFINE_printTypedVectorList(0, b);
DEFINE_printTypedVectorList(0, d);
DEFINE_printTypedVectorList(0, h);
DEFINE_printTypedVectorList(0, s);
DEFINE_printTypedVectorList(0, q);
DEFINE_printTypedVectorList(16, b);
DEFINE_printTypedVectorList(1, d);
DEFINE_printTypedVectorList(2, d);
DEFINE_printTypedVectorList(2, s);
DEFINE_printTypedVectorList(4, h);
DEFINE_printTypedVectorList(4, s);
DEFINE_printTypedVectorList(8, b);
DEFINE_printTypedVectorList(8, h);
#define DEFINE_printVectorIndex(Scale) \
void CONCAT(printVectorIndex, Scale)(MCInst * MI, unsigned OpNum, \
SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_VectorIndex, Scale), OpNum, \
Scale); \
SStream_concat(O, "%s", "["); \
printUInt64(O, Scale * MCOperand_getImm(MCInst_getOperand(MI, (OpNum)))); \
SStream_concat0(O, "]"); \
}
DEFINE_printVectorIndex(1);
DEFINE_printVectorIndex(8);
void printMatrixIndex(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_MatrixIndex, OpNum);
printUInt32(O, MCOperand_getImm(MCInst_getOperand(MI, (OpNum))));
}
void printAlignedLabel(MCInst *MI, uint64_t Address, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_AlignedLabel, OpNum);
MCOperand *Op = MCInst_getOperand(MI, (OpNum));
// If the label has already been resolved to an immediate offset (say, when
// we're running the disassembler), just print the immediate.
if (MCOperand_isImm(Op)) {
SStream_concat0(O, markup("<imm:"));
int64_t Offset = MCOperand_getImm(Op) * 4;
if (!MI->csh->PrintBranchImmNotAsAddress)
printUInt64(O, (Address + Offset));
else {
printUInt64Bang(O, (Offset));
}
SStream_concat0(O, markup(">"));
return;
}
// If the branch target is simply an address then print it in hex.
assert(0 && "Expressions are not supported.");
}
void printAdrLabel(MCInst *MI, uint64_t Address, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_AdrLabel, OpNum);
MCOperand *Op = MCInst_getOperand(MI, (OpNum));
// If the label has already been resolved to an immediate offset (say, when
// we're running the disassembler), just print the immediate.
if (MCOperand_isImm(Op)) {
const int64_t Offset = MCOperand_getImm(Op);
SStream_concat0(O, markup("<imm:"));
if (!MI->csh->PrintBranchImmNotAsAddress)
printUInt64(O, ((Address & -4) + Offset));
else {
printUInt64Bang(O, Offset);
}
SStream_concat0(O, markup(">"));
return;
}
// Otherwise, just print the expression.
assert(0 && "Expressions are not supported.");
}
void printAdrpLabel(MCInst *MI, uint64_t Address, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_AdrpLabel, OpNum);
MCOperand *Op = MCInst_getOperand(MI, (OpNum));
// If the label has already been resolved to an immediate offset (say, when
// we're running the disassembler), just print the immediate.
if (MCOperand_isImm(Op)) {
const int64_t Offset = MCOperand_getImm(Op) * 4096;
SStream_concat0(O, markup("<imm:"));
if (!MI->csh->PrintBranchImmNotAsAddress)
printUInt64(O, ((Address & -4096) + Offset));
else {
printUInt64Bang(O, Offset);
}
SStream_concat0(O, markup(">"));
return;
}
// Otherwise, just print the expression.
assert(0 && "Expressions are not supported.");
}
void printBarrierOption(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_BarrierOption, OpNo);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
unsigned Opcode = MCInst_getOpcode(MI);
const char *Name;
if (Opcode == AArch64_ISB) {
const AArch64ISB_ISB *ISB = AArch64ISB_lookupISBByEncoding(Val);
Name = ISB ? ISB->Name : "";
} else if (Opcode == AArch64_TSB) {
const AArch64TSB_TSB *TSB = AArch64TSB_lookupTSBByEncoding(Val);
Name = TSB ? TSB->Name : "";
} else {
const AArch64DB_DB *DB = AArch64DB_lookupDBByEncoding(Val);
Name = DB ? DB->Name : "";
}
if (Name[0] != '\0')
SStream_concat0(O, Name);
else {
SStream_concat(O, "%s", markup("<imm:"));
printUInt32Bang(O, Val);
SStream_concat0(O, markup(">"));
}
}
void printBarriernXSOption(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_BarriernXSOption, OpNo);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
const char *Name;
const AArch64DBnXS_DBnXS *DB = AArch64DBnXS_lookupDBnXSByEncoding(Val);
Name = DB ? DB->Name : "";
if (Name[0] != '\0')
SStream_concat0(O, Name);
else {
SStream_concat(O, "%s%s%s", markup("<imm:"), "#", Val);
SStream_concat0(O, markup(">"));
}
}
static bool isValidSysReg(const AArch64SysReg_SysReg *Reg, bool Read, unsigned mode)
{
return (Reg && (Read ? Reg->Readable : Reg->Writeable) &&
AArch64_testFeatureList(mode, Reg->FeaturesRequired));
}
// Looks up a system register either by encoding or by name. Some system
// registers share the same encoding between different architectures,
// therefore a tablegen lookup by encoding will return an entry regardless
// of the register's predication on a specific subtarget feature. To work
// around this problem we keep an alternative name for such registers and
// look them up by that name if the first lookup was unsuccessful.
static const AArch64SysReg_SysReg *lookupSysReg(unsigned Val, bool Read, unsigned mode)
{
const AArch64SysReg_SysReg *Reg = AArch64SysReg_lookupSysRegByEncoding(Val);
if (Reg && !isValidSysReg(Reg, Read, mode))
Reg = AArch64SysReg_lookupSysRegByName(Reg->AltName);
return Reg;
}
void printMRSSystemRegister(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_MRSSystemRegister, OpNo);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
// Horrible hack for the one register that has identical encodings but
// different names in MSR and MRS. Because of this, one of MRS and MSR is
// going to get the wrong entry
if (Val == AArch64_SYSREG_DBGDTRRX_EL0) {
SStream_concat0(O, "DBGDTRRX_EL0");
return;
}
// Horrible hack for two different registers having the same encoding.
if (Val == AArch64_SYSREG_TRCEXTINSELR) {
SStream_concat0(O, "TRCEXTINSELR");
return;
}
const AArch64SysReg_SysReg *Reg = lookupSysReg(Val, true /*Read*/, MI->csh->mode);
if (isValidSysReg(Reg, true /*Read*/, MI->csh->mode))
SStream_concat0(O, Reg->Name);
else {
char result[AARCH64_GRS_LEN + 1] = {0};
AArch64SysReg_genericRegisterString(Val, result);
SStream_concat0(O, result);
}
}
void printMSRSystemRegister(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_MSRSystemRegister, OpNo);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
// Horrible hack for the one register that has identical encodings but
// different names in MSR and MRS. Because of this, one of MRS and MSR is
// going to get the wrong entry
if (Val == AArch64_SYSREG_DBGDTRTX_EL0) {
SStream_concat0(O, "DBGDTRTX_EL0");
return;
}
// Horrible hack for two different registers having the same encoding.
if (Val == AArch64_SYSREG_TRCEXTINSELR) {
SStream_concat0(O, "TRCEXTINSELR");
return;
}
const AArch64SysReg_SysReg *Reg = lookupSysReg(Val, false /*Read*/, MI->csh->mode);
if (isValidSysReg(Reg, false /*Read*/, MI->csh->mode))
SStream_concat0(O, Reg->Name);
else {
char result[AARCH64_GRS_LEN + 1] = {0};
AArch64SysReg_genericRegisterString(Val, result);
SStream_concat0(O, result);
}
}
void printSystemPStateField(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_SystemPStateField, OpNo);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
const AArch64PState_PStateImm0_15 *PStateImm15 = AArch64PState_lookupPStateImm0_15ByEncoding(Val);
const AArch64PState_PStateImm0_1 *PStateImm1 = AArch64PState_lookupPStateImm0_1ByEncoding(Val);
if (PStateImm15 && AArch64_testFeatureList(MI->csh->mode, PStateImm15->FeaturesRequired))
SStream_concat0(O, PStateImm15->Name);
else if (PStateImm1 && AArch64_testFeatureList(MI->csh->mode, PStateImm1->FeaturesRequired))
SStream_concat0(O, PStateImm1->Name);
else {
printUInt32Bang(O, (Val));
SStream_concat1(O, '\0');
}
}
void printSIMDType10Operand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_SIMDType10Operand, OpNo);
unsigned RawVal = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
uint64_t Val = AArch64_AM_decodeAdvSIMDModImmType10(RawVal);
SStream_concat(O, "%s#%#016llx", markup("<imm:"), Val);
SStream_concat0(O, markup(">"));
}
#define DEFINE_printComplexRotationOp(Angle, Remainder) \
static void CONCAT(printComplexRotationOp, CONCAT(Angle, Remainder))( \
MCInst * MI, unsigned OpNo, SStream *O) \
{ \
add_cs_detail( \
MI, \
CONCAT(CONCAT(AArch64_OP_GROUP_ComplexRotationOp, Angle), \
Remainder), \
OpNo, Angle, Remainder); \
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); \
SStream_concat(O, "%s", markup("<imm:")); \
SStream_concat(O, "#%d", (Val * Angle) + Remainder); \
SStream_concat0(O, markup(">")); \
}
DEFINE_printComplexRotationOp(180, 90);
DEFINE_printComplexRotationOp(90, 0);
void printSVEPattern(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_SVEPattern, OpNum);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
const AArch64SVEPredPattern_SVEPREDPAT *Pat = AArch64SVEPredPattern_lookupSVEPREDPATByEncoding(Val);
if (Pat)
SStream_concat0(O, Pat->Name);
}
void printSVEVecLenSpecifier(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_SVEVecLenSpecifier, OpNum);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
// Pattern has only 1 bit
if (Val > 1)
assert(0 && "Invalid vector length specifier");
const AArch64SVEVecLenSpecifier_SVEVECLENSPECIFIER *Pat =
AArch64SVEVecLenSpecifier_lookupSVEVECLENSPECIFIERByEncoding(Val);
if (Pat)
SStream_concat0(O, Pat->Name);
}
#define DEFINE_printSVERegOp(suffix) \
void CONCAT(printSVERegOp, suffix)(MCInst * MI, unsigned OpNum, \
SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_SVERegOp, suffix), OpNum, \
CHAR(suffix)); \
switch (CHAR(suffix)) { \
case '0': \
case 'b': \
case 'h': \
case 's': \
case 'd': \
case 'q': \
break; \
default: \
assert(0 && "Invalid kind specifier."); \
} \
\
unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum))); \
printRegName(O, Reg); \
if (CHAR(suffix) != '0') { \
SStream_concat1(O, '.'); \
SStream_concat1(O, CHAR(suffix)); \
} \
}
DEFINE_printSVERegOp(b);
DEFINE_printSVERegOp(d);
DEFINE_printSVERegOp(h);
DEFINE_printSVERegOp(s);
DEFINE_printSVERegOp(0);
DEFINE_printSVERegOp(q);
#define DECLARE_printImmSVE_S32(T) \
void CONCAT(printImmSVE, T)(T Val, SStream *O) { \
printInt32Bang(O, Val); \
}
DECLARE_printImmSVE_S32(int16_t);
DECLARE_printImmSVE_S32(int8_t);
DECLARE_printImmSVE_S32(int32_t);
#define DECLARE_printImmSVE_U32(T) \
void CONCAT(printImmSVE, T)(T Val, SStream *O) { \
printUInt32Bang(O, Val); \
}
DECLARE_printImmSVE_U32(uint16_t);
DECLARE_printImmSVE_U32(uint8_t);
DECLARE_printImmSVE_U32(uint32_t);
#define DECLARE_printImmSVE_S64(T) \
void CONCAT(printImmSVE, T)(T Val, SStream *O) { \
printInt64Bang(O, Val); \
}
DECLARE_printImmSVE_S64(uint64_t);
#define DECLARE_printImmSVE_U64(T) \
void CONCAT(printImmSVE, T)(T Val, SStream *O) { \
printUInt64Bang(O, Val); \
}
DECLARE_printImmSVE_U64(int64_t);
#define DEFINE_isSignedType(T) \
static inline bool CONCAT(isSignedType, T)() {\
return CHAR(t) == 'i'; \
}
DEFINE_isSignedType(int8_t);
DEFINE_isSignedType(int16_t);
DEFINE_isSignedType(int32_t);
DEFINE_isSignedType(int64_t);
DEFINE_isSignedType(uint8_t);
DEFINE_isSignedType(uint16_t);
DEFINE_isSignedType(uint32_t);
DEFINE_isSignedType(uint64_t);
#define DEFINE_printImm8OptLsl(T) \
void CONCAT(printImm8OptLsl, T)(MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_Imm8OptLsl, T), OpNum, sizeof(T)); \
unsigned UnscaledVal = \
MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); \
unsigned Shift = MCOperand_getImm(MCInst_getOperand(MI, (OpNum + 1))); \
\
if ((UnscaledVal == 0) && (AArch64_AM_getShiftValue(Shift) != 0)) { \
SStream_concat(O, "%s", markup("<imm:")); \
SStream_concat1(O, '#'); \
printUInt64(O, (UnscaledVal)); \
SStream_concat0(O, markup(">")); \
printShifter(MI, OpNum + 1, O); \
return; \
} \
\
T Val; \
if (CONCAT(isSignedType, T)()) \
Val = \
(int8_t)UnscaledVal * (1 << AArch64_AM_getShiftValue(Shift)); \
else \
Val = \
(uint8_t)UnscaledVal * (1 << AArch64_AM_getShiftValue(Shift)); \
\
CONCAT(printImmSVE, T)(Val, O); \
}
DEFINE_printImm8OptLsl(int16_t);
DEFINE_printImm8OptLsl(int8_t);
DEFINE_printImm8OptLsl(int64_t);
DEFINE_printImm8OptLsl(int32_t);
DEFINE_printImm8OptLsl(uint16_t);
DEFINE_printImm8OptLsl(uint8_t);
DEFINE_printImm8OptLsl(uint64_t);
DEFINE_printImm8OptLsl(uint32_t);
#define DEFINE_printSVELogicalImm(T) \
void CONCAT(printSVELogicalImm, T)(MCInst * MI, unsigned OpNum, \
SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_SVELogicalImm, T), OpNum, \
sizeof(T)); \
typedef T SignedT; \
typedef CONCATS(u, T) UnsignedT; \
\
uint64_t Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); \
UnsignedT PrintVal = AArch64_AM_decodeLogicalImmediate(Val, 64); \
\
if ((int16_t)PrintVal == (SignedT)PrintVal) \
CONCAT(printImmSVE, T)((T)PrintVal, O); \
else if ((uint16_t)PrintVal == PrintVal) \
CONCAT(printImmSVE, T)(PrintVal, O); \
else { \
SStream_concat(O, "%s", markup("<imm:")); \
printUInt64Bang(O, ((uint64_t)PrintVal)); \
SStream_concat0(O, markup(">")); \
} \
}
DEFINE_printSVELogicalImm(int16_t);
DEFINE_printSVELogicalImm(int32_t);
DEFINE_printSVELogicalImm(int64_t);
#define DEFINE_printZPRasFPR(Width) \
void CONCAT(printZPRasFPR, Width)(MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_ZPRasFPR, Width), OpNum, \
Width); \
unsigned Base; \
switch (Width) { \
case 8: \
Base = AArch64_B0; \
break; \
case 16: \
Base = AArch64_H0; \
break; \
case 32: \
Base = AArch64_S0; \
break; \
case 64: \
Base = AArch64_D0; \
break; \
case 128: \
Base = AArch64_Q0; \
break; \
default: \
assert(0 && "Unsupported width"); \
} \
unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum))); \
printRegName(O, Reg - AArch64_Z0 + Base); \
}
DEFINE_printZPRasFPR(8);
DEFINE_printZPRasFPR(64);
DEFINE_printZPRasFPR(16);
DEFINE_printZPRasFPR(32);
DEFINE_printZPRasFPR(128);
#define DEFINE_printExactFPImm(ImmIs0, ImmIs1) \
void CONCAT(printExactFPImm, CONCAT(ImmIs0, ImmIs1))( \
MCInst * MI, unsigned OpNum, SStream *O) \
{ \
add_cs_detail( \
MI, CONCAT(CONCAT(AArch64_OP_GROUP_ExactFPImm, ImmIs0), ImmIs1), \
OpNum, ImmIs0, ImmIs1); \
const AArch64ExactFPImm_ExactFPImm *Imm0Desc = AArch64ExactFPImm_lookupExactFPImmByEnum(ImmIs0); \
const AArch64ExactFPImm_ExactFPImm *Imm1Desc = AArch64ExactFPImm_lookupExactFPImmByEnum(ImmIs1); \
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); \
SStream_concat(O, "%s%s%s", markup("<imm:"), "#", \
(Val ? Imm1Desc->Repr : Imm0Desc->Repr)); \
SStream_concat0(O, markup(">")); \
}
DEFINE_printExactFPImm(AArch64ExactFPImm_half, AArch64ExactFPImm_one);
DEFINE_printExactFPImm(AArch64ExactFPImm_zero, AArch64ExactFPImm_one);
DEFINE_printExactFPImm(AArch64ExactFPImm_half, AArch64ExactFPImm_two);
void printGPR64as32(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_GPR64as32, OpNum);
unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum)));
printRegName(O, getWRegFromXReg(Reg));
}
void printGPR64x8(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_GPR64x8, OpNum);
unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum)));
printRegName(O, MCRegisterInfo_getSubReg(MI->MRI, Reg, AArch64_x8sub_0));
}
void printSyspXzrPair(MCInst *MI, unsigned OpNum, SStream *O)
{
add_cs_detail(MI, AArch64_OP_GROUP_SyspXzrPair, OpNum);
unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, (OpNum)));
SStream_concat(O, "%s%s", getRegisterName(Reg, AArch64_NoRegAltName), ", ");
SStream_concat0(O, getRegisterName(Reg, AArch64_NoRegAltName));
}
const char *AArch64_LLVM_getRegisterName(unsigned RegNo, unsigned AltIdx) {
return getRegisterName(RegNo, AltIdx);
}
void AArch64_LLVM_printInstruction(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info) {
printInst(MI, MI->address, "", O);
}