Files
kaizen/external/capstone/arch/AArch64/AArch64InstPrinter.c
T
iris 00cc9309cb Squashed 'external/ircolib/' changes from ce3cd726c..de6e324bd
de6e324bd separate emu thread
10d3daf86 Roms List improvements
95d202f37 Let's make the rom list process on a separate thread so the emulator doesnt take ages to load.
fc306967f Wow the ROM Header was just completely busted. Game list view works now
bad1691ee fuck this shit
2b59e5f46 game list in progress
d26417b83 remappable inputs in progress
ac4af8106 input
e72abc240 update readme
430139dc9 Qt6 frontend
3080d4d45 Fix this small bug too
08cd13b85 Cop0 unused functions do not actually pose a threat (as per manual). They don't do anything, so shall we.
61bb4fb44 make idle loop detection a little more specific with where the load goes
b037de4c3 SAZDFsdff
12e81e73e need to figure out why n64-systemtest loops indefinitely at some address that appears to be valid (i think it's me not invalidating the cache properly)
204f0e13b idle skipping seems to work!
cb8bb634a sdkfjlasdf
58e5c89c1 Fix compilation issue on my machine (no idea)
24fb2898e attempting more serious idle skipping
214719577 Place rsp.Step inside cached interpreter. Gains about 3 more fps
bb97dcc23 mmmmm
920b77d38 wjkhasdfjhkasdf
430ccdab4 it's a start...
4f42a673a Cached interpreter plays Mario 64. Start looking into RSP as well
c9a030787 idle skipping works!
5fbda03ce new idea
366637aba Idle skipping... maybe?
609fa2fb0 Cache instructions implemented but broken lmao. Commented out for now
e140a6d12 - Stop using inheritance for CPU, instead use composition. - Introduce KAIZEN_JIT_ENABLED optional define instead of relying on __aarch64__ and the like. - More cache work
68e613057 prep cache impl
811b4d809 fix clang format
fda755f7d idk
d5024ebbf small MI refactor in preparation of (eventually) implementing the RDRAM interface properly
694b45341 Merge commit '206dcdedf195fb320913584180edb12c7731e396' as 'external/SDL'
206dcdedf Squashed 'external/SDL/' content from commit 4d17b99d0a
4d16e1cb4 need to update sdl
848b19920 Fix compilation error
db61b5299 Merge commit 'e94a94559f28e49678fbcf72199a5258137b0fe9' as 'external/imgui'
e94a94559 Squashed 'external/imgui/' content from commit 02e9b8cac
52edb3757 need to update imgui
c1a705e86 Emulate weird JALR behaviour
4b4c32f4b Fix exception for "unusable COP1" in 4 instructions i missed accidentally (again)
df5828142 Bug putting 0s in the log everywhere
f8b580048 Make isviewer a sink to file
8241e9735 Fix exception for "unusable COP1" in 4 instructions i missed accidentally
b29715f20 small changes
d9a620bc1 make use of my new small utility library
0d1aa938e Add 'external/ircolib/' from commit 'ce3cd726c8df8388d554abf8bb55d55020eb4450'
e64eb40b3 Fuck git

git-subtree-dir: external/ircolib
git-subtree-split: de6e324bde
2026-06-15 11:56:38 +02:00

2590 lines
73 KiB
C

/* 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <capstone/platform.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"
// BEGIN Static declarations.
// These functions must be declared statically here, because they
// are also defined in the ARM module.
// If they are not static, we fail during linking.
static void printCustomAliasOperand(MCInst *MI, uint64_t Address,
unsigned OpIdx, unsigned PrintMethodIdx,
SStream *OS);
static void printFPImmOperand(MCInst *MI, unsigned OpNum, SStream *O);
#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);
// END Static declarations.
#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, sligtly 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)))) {
printUInt64Bang(O, MCInst_getOpVal(MI, 1));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_imm(MI, 1, AARCH64_OP_IMM, MCInst_getOpVal(MI, 1));
}
}
if ((Opcode == AArch64_MOVKXi || Opcode == AArch64_MOVKWi) &&
MCOperand_isExpr(MCInst_getOperand(MI, (2)))) {
printUInt64Bang(O, MCInst_getOpVal(MI, 2));
if (detail_is_set(MI) && useAliasDetails) {
AArch64_set_detail_op_imm(MI, 2, AARCH64_OP_IMM, MCInst_getOpVal(MI, 2));
}
}
// 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);
}
}
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);
} else {
printUInt32Bang(O, RPRFOp);
SStream_concat(O, ", ");
}
SStream_concat0(O, getRegisterName(Rm, AArch64_NoRegAltName));
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;
unsigned int 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 = { 0 };
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 = { 0 };
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 = { 0 };
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 = { 0 };
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 = { 0 };
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) \
{ \
AArch64_add_cs_detail_1( \
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: \
CS_ASSERT_RET(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) \
{ \
AArch64_add_cs_detail_1( \
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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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 {
printUInt64Bang(O, MCInst_getOpVal(MI, OpNo));
}
}
void printImm(MCInst *MI, unsigned OpNo, SStream *O)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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) \
{ \
AArch64_add_cs_detail_1( \
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
CS_ASSERT_RET(0 && "unknown operand kind in printPostIncOperand64");
}
void printVRegOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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) \
{ \
AArch64_add_cs_detail_1( \
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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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) \
{ \
AArch64_add_cs_detail_4( \
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 \
CS_ASSERT_RET((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) \
{ \
AArch64_add_cs_detail_1( \
MI, \
CONCAT(AArch64_OP_GROUP_PredicateAsCounter, EltSize), \
OpNum, EltSize); \
unsigned Reg = \
MCOperand_getReg(MCInst_getOperand(MI, (OpNum))); \
if (Reg < AArch64_PN0 || Reg > AArch64_PN15) \
CS_ASSERT_RET(0 && \
"Unsupported predicate-as-counter register"); \
SStream_concat(O, "%s", "pn"); \
printUInt32(O, (Reg - AArch64_PN0)); \
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: \
CS_ASSERT_RET(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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) \
{ \
AArch64_add_cs_detail_1( \
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) \
{ \
AArch64_add_cs_detail_2( \
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 {
printUInt64Bang(O, MCOperand_getImm(MO));
}
}
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 {
printUInt64Bang(O, MCOperand_getImm(MO1));
}
SStream_concat0(O, "]");
}
void printRPRFMOperand(MCInst *MI, unsigned OpNum, SStream *O)
{
AArch64_add_cs_detail_0(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) \
{ \
AArch64_add_cs_detail_1(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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:
CS_ASSERT_RET_VAL(0 && "Vector register expected!", 0);
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) \
{ \
AArch64_add_cs_detail_1( \
MI, \
CONCAT(AArch64_OP_GROUP_GPRSeqPairsClassOperand, \
size), \
OpNum, size); \
CS_ASSERT_RET((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);
#define DEFINE_printMatrixIndex(Scale) \
void CONCAT(printMatrixIndex, Scale)(MCInst * MI, unsigned OpNum, \
SStream *O) \
{ \
AArch64_add_cs_detail_1(MI, CONCAT(AArch64_OP_GROUP_MatrixIndex, Scale), \
OpNum, Scale); \
printInt64(O, Scale *MCOperand_getImm( \
MCInst_getOperand(MI, (OpNum)))); \
}
DEFINE_printMatrixIndex(8);
DEFINE_printMatrixIndex(0);
DEFINE_printMatrixIndex(1);
void printMatrixTileList(MCInst *MI, unsigned OpNum, SStream *O)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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) \
{ \
AArch64_add_cs_detail_2( \
MI, \
CONCAT(CONCAT(AArch64_OP_GROUP_TypedVectorList, \
NumLanes), \
LaneKind), \
OpNum, NumLanes, CHAR(LaneKind)); \
if (CHAR(LaneKind) == '0') { \
printVectorList(MI, OpNum, O, ""); \
return; \
} \
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_printTypedVectorList(0, 0);
#define DEFINE_printVectorIndex(Scale) \
void CONCAT(printVectorIndex, Scale)(MCInst * MI, unsigned OpNum, \
SStream *O) \
{ \
AArch64_add_cs_detail_1( \
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 printAlignedLabel(MCInst *MI, uint64_t Address, unsigned OpNum, SStream *O)
{
AArch64_add_cs_detail_0(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->PrintBranchImmAsAddress)
printUInt64(O, (Address + Offset));
else {
printUInt64Bang(O, (Offset));
}
SStream_concat0(O, markup(">"));
return;
}
printUInt64Bang(O, MCOperand_getImm(Op));
}
void printAdrLabel(MCInst *MI, uint64_t Address, unsigned OpNum, SStream *O)
{
AArch64_add_cs_detail_0(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->PrintBranchImmAsAddress)
printUInt64(O, ((Address & -4) + Offset));
else {
printUInt64Bang(O, Offset);
}
SStream_concat0(O, markup(">"));
return;
}
printUInt64Bang(O, MCOperand_getImm(Op));
}
void printAdrpLabel(MCInst *MI, uint64_t Address, unsigned OpNum, SStream *O)
{
AArch64_add_cs_detail_0(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->PrintBranchImmAsAddress)
printUInt64(O, ((Address & -4096) + Offset));
else {
printUInt64Bang(O, Offset);
}
SStream_concat0(O, markup(">"));
return;
}
printUInt64Bang(O, MCOperand_getImm(Op));
}
void printAdrAdrpLabel(MCInst *MI, uint64_t Address, unsigned OpNum, SStream *O) {
AArch64_add_cs_detail_0(MI, AArch64_OP_GROUP_AdrAdrpLabel, 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)) {
int64_t Offset = MCOperand_getImm(Op);
if (MCInst_getOpcode(MI) == AArch64_ADRP) {
Offset = Offset * 4096;
Address = Address & -4096;
}
SStream_concat0(O, markup(">"));
if (MI->csh->PrintBranchImmAsAddress)
printUInt64(O, (Address + Offset));
else {
printUInt64Bang(O, Offset);
}
SStream_concat0(O, markup(">"));
return;
}
printUInt64Bang(O, MCOperand_getImm(Op));
}
/// Not part of upstream LLVM.
/// Just prints the barrier options as documented in
/// https://github.com/AsahiLinux/docs/blob/main/docs/hw/cpu/apple-instructions.md
void printAppleSysBarrierOption(MCInst *MI, unsigned OpNo, SStream *O)
{
AArch64_add_cs_detail_0(MI, AArch64_OP_GROUP_AppleSysBarrierOption, OpNo);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
switch (Val) {
default:
SStream_concat0(O, "<undefined>");
break;
case 0:
SStream_concat0(O, "osh");
break;
case 1:
SStream_concat0(O, "nsh");
break;
case 2:
SStream_concat0(O, "ish");
break;
case 3:
SStream_concat0(O, "sy");
break;
}
}
void printBarrierOption(MCInst *MI, unsigned OpNo, SStream *O)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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) \
{ \
AArch64_add_cs_detail_2( \
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)
{
AArch64_add_cs_detail_0(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);
else
printUInt32Bang(O, Val);
}
void printSVEVecLenSpecifier(MCInst *MI, unsigned OpNum, SStream *O)
{
AArch64_add_cs_detail_0(MI, AArch64_OP_GROUP_SVEVecLenSpecifier, OpNum);
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
// Pattern has only 1 bit
if (Val > 1)
CS_ASSERT_RET(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) \
{ \
AArch64_add_cs_detail_1( \
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: \
CS_ASSERT_RET(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(int64_t);
#define DECLARE_printImmSVE_U64(T) \
void CONCAT(printImmSVE, T)(T Val, SStream * O) \
{ \
printUInt64Bang(O, Val); \
}
DECLARE_printImmSVE_U64(uint64_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) \
{ \
AArch64_add_cs_detail_1( \
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) \
{ \
AArch64_add_cs_detail_1( \
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) \
{ \
AArch64_add_cs_detail_1( \
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: \
CS_ASSERT_RET(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) \
{ \
AArch64_add_cs_detail_2( \
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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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)
{
AArch64_add_cs_detail_0(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);
}