Home | History | Annotate | Download | only in AArch64
      1 //==-- AArch64InstPrinter.cpp - Convert AArch64 MCInst to assembly syntax --==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This class prints an AArch64 MCInst to a .s file.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 /* Capstone Disassembly Engine */
     15 /* By Nguyen Anh Quynh <aquynh (at) gmail.com>, 2013-2014 */
     16 
     17 #ifdef CAPSTONE_HAS_ARM64
     18 
     19 #include <platform.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 
     23 #include "AArch64InstPrinter.h"
     24 #include "AArch64BaseInfo.h"
     25 #include "../../utils.h"
     26 #include "../../MCInst.h"
     27 #include "../../SStream.h"
     28 #include "../../MCRegisterInfo.h"
     29 #include "../../MathExtras.h"
     30 
     31 #include "AArch64Mapping.h"
     32 #include "AArch64AddressingModes.h"
     33 
     34 #define GET_REGINFO_ENUM
     35 #include "AArch64GenRegisterInfo.inc"
     36 
     37 #define GET_INSTRINFO_ENUM
     38 #include "AArch64GenInstrInfo.inc"
     39 
     40 
     41 static char *getRegisterName(unsigned RegNo, int AltIdx);
     42 static void printOperand(MCInst *MI, unsigned OpNo, SStream *O);
     43 static bool printSysAlias(MCInst *MI, SStream *O);
     44 static char *printAliasInstr(MCInst *MI, SStream *OS, void *info);
     45 static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI);
     46 static void printShifter(MCInst *MI, unsigned OpNum, SStream *O);
     47 
     48 static void set_mem_access(MCInst *MI, bool status)
     49 {
     50 	if (MI->csh->detail != CS_OPT_ON)
     51 		return;
     52 
     53 	MI->csh->doing_mem = status;
     54 
     55 	if (status) {
     56 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_MEM;
     57 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.base = ARM64_REG_INVALID;
     58 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.index = ARM64_REG_INVALID;
     59 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.disp = 0;
     60 	} else {
     61 		// done, create the next operand slot
     62 		MI->flat_insn->detail->arm64.op_count++;
     63 	}
     64 }
     65 
     66 void AArch64_printInst(MCInst *MI, SStream *O, void *Info)
     67 {
     68 	// Check for special encodings and print the canonical alias instead.
     69 	unsigned Opcode = MCInst_getOpcode(MI);
     70 	int LSB;
     71 	int Width;
     72 	char *mnem;
     73 
     74 	if (Opcode == AArch64_SYSxt && printSysAlias(MI, O))
     75 		return;
     76 
     77 	// SBFM/UBFM should print to a nicer aliased form if possible.
     78 	if (Opcode == AArch64_SBFMXri || Opcode == AArch64_SBFMWri ||
     79 			Opcode == AArch64_UBFMXri || Opcode == AArch64_UBFMWri) {
     80 		MCOperand *Op0 = MCInst_getOperand(MI, 0);
     81 		MCOperand *Op1 = MCInst_getOperand(MI, 1);
     82 		MCOperand *Op2 = MCInst_getOperand(MI, 2);
     83 		MCOperand *Op3 = MCInst_getOperand(MI, 3);
     84 
     85 		bool IsSigned = (Opcode == AArch64_SBFMXri || Opcode == AArch64_SBFMWri);
     86 		bool Is64Bit = (Opcode == AArch64_SBFMXri || Opcode == AArch64_UBFMXri);
     87 
     88 		if (MCOperand_isImm(Op2) && MCOperand_getImm(Op2) == 0 && MCOperand_isImm(Op3)) {
     89 			char *AsmMnemonic = NULL;
     90 
     91 			switch (MCOperand_getImm(Op3)) {
     92 				default:
     93 					break;
     94 				case 7:
     95 					if (IsSigned)
     96 						AsmMnemonic = "sxtb";
     97 					else if (!Is64Bit)
     98 						AsmMnemonic = "uxtb";
     99 					break;
    100 				case 15:
    101 					if (IsSigned)
    102 						AsmMnemonic = "sxth";
    103 					else if (!Is64Bit)
    104 						AsmMnemonic = "uxth";
    105 					break;
    106 				case 31:
    107 					// *xtw is only valid for signed 64-bit operations.
    108 					if (Is64Bit && IsSigned)
    109 						AsmMnemonic = "sxtw";
    110 					break;
    111 			}
    112 
    113 			if (AsmMnemonic) {
    114 				SStream_concat(O, "%s\t%s, %s", AsmMnemonic,
    115 						getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName),
    116 						getRegisterName(getWRegFromXReg(MCOperand_getReg(Op1)), AArch64_NoRegAltName));
    117 
    118 				if (MI->csh->detail) {
    119 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    120 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0);
    121 					MI->flat_insn->detail->arm64.op_count++;
    122 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    123 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = getWRegFromXReg(MCOperand_getReg(Op1));
    124 					MI->flat_insn->detail->arm64.op_count++;
    125 				}
    126 
    127 				MCInst_setOpcodePub(MI, AArch64_map_insn(AsmMnemonic));
    128 
    129 				return;
    130 			}
    131 		}
    132 
    133 		// All immediate shifts are aliases, implemented using the Bitfield
    134 		// instruction. In all cases the immediate shift amount shift must be in
    135 		// the range 0 to (reg.size -1).
    136 		if (MCOperand_isImm(Op2) && MCOperand_isImm(Op3)) {
    137 			char *AsmMnemonic = NULL;
    138 			int shift = 0;
    139 			int64_t immr = MCOperand_getImm(Op2);
    140 			int64_t imms = MCOperand_getImm(Op3);
    141 
    142 			if (Opcode == AArch64_UBFMWri && imms != 0x1F && ((imms + 1) == immr)) {
    143 				AsmMnemonic = "lsl";
    144 				shift = 31 - imms;
    145 			} else if (Opcode == AArch64_UBFMXri && imms != 0x3f &&
    146 					((imms + 1 == immr))) {
    147 				AsmMnemonic = "lsl";
    148 				shift = 63 - imms;
    149 			} else if (Opcode == AArch64_UBFMWri && imms == 0x1f) {
    150 				AsmMnemonic = "lsr";
    151 				shift = immr;
    152 			} else if (Opcode == AArch64_UBFMXri && imms == 0x3f) {
    153 				AsmMnemonic = "lsr";
    154 				shift = immr;
    155 			} else if (Opcode == AArch64_SBFMWri && imms == 0x1f) {
    156 				AsmMnemonic = "asr";
    157 				shift = immr;
    158 			} else if (Opcode == AArch64_SBFMXri && imms == 0x3f) {
    159 				AsmMnemonic = "asr";
    160 				shift = immr;
    161 			}
    162 
    163 			if (AsmMnemonic) {
    164 				SStream_concat(O, "%s\t%s, %s, ", AsmMnemonic,
    165 						getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName),
    166 						getRegisterName(MCOperand_getReg(Op1), AArch64_NoRegAltName));
    167 
    168 				printInt32Bang(O, shift);
    169 
    170 				MCInst_setOpcodePub(MI, AArch64_map_insn(AsmMnemonic));
    171 
    172 				if (MI->csh->detail) {
    173 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    174 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0);
    175 					MI->flat_insn->detail->arm64.op_count++;
    176 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    177 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op1);
    178 					MI->flat_insn->detail->arm64.op_count++;
    179 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    180 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = shift;
    181 					MI->flat_insn->detail->arm64.op_count++;
    182 				}
    183 
    184 				return;
    185 			}
    186 		}
    187 
    188 		// SBFIZ/UBFIZ aliases
    189 		if (MCOperand_getImm(Op2) > MCOperand_getImm(Op3)) {
    190 			SStream_concat(O, "%s\t%s, %s, ", (IsSigned ? "sbfiz" : "ubfiz"),
    191 					getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName),
    192 					getRegisterName(MCOperand_getReg(Op1), AArch64_NoRegAltName));
    193 			printInt32Bang(O, (int)((Is64Bit ? 64 : 32) - MCOperand_getImm(Op2)));
    194 			SStream_concat0(O, ", ");
    195 			printInt32Bang(O, (int)MCOperand_getImm(Op3) + 1);
    196 
    197 			MCInst_setOpcodePub(MI, AArch64_map_insn(IsSigned ? "sbfiz" : "ubfiz"));
    198 
    199 			if (MI->csh->detail) {
    200 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    201 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0);
    202 				MI->flat_insn->detail->arm64.op_count++;
    203 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    204 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op1);
    205 				MI->flat_insn->detail->arm64.op_count++;
    206 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    207 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = (Is64Bit ? 64 : 32) - (int)MCOperand_getImm(Op2);
    208 				MI->flat_insn->detail->arm64.op_count++;
    209 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    210 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op3) + 1;
    211 				MI->flat_insn->detail->arm64.op_count++;
    212 			}
    213 
    214 			return;
    215 		}
    216 
    217 		// Otherwise SBFX/UBFX is the preferred form
    218 		SStream_concat(O, "%s\t%s, %s, ", (IsSigned ? "sbfx" : "ubfx"),
    219 				getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName),
    220 				getRegisterName(MCOperand_getReg(Op1), AArch64_NoRegAltName));
    221 		printInt32Bang(O, (int)MCOperand_getImm(Op2));
    222 		SStream_concat0(O, ", ");
    223 		printInt32Bang(O, (int)MCOperand_getImm(Op3) - (int)MCOperand_getImm(Op2) + 1);
    224 
    225 		MCInst_setOpcodePub(MI, AArch64_map_insn(IsSigned ? "sbfx" : "ubfx"));
    226 
    227 		if (MI->csh->detail) {
    228 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    229 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0);
    230 			MI->flat_insn->detail->arm64.op_count++;
    231 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    232 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op1);
    233 			MI->flat_insn->detail->arm64.op_count++;
    234 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    235 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op2);
    236 			MI->flat_insn->detail->arm64.op_count++;
    237 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    238 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op3) - MCOperand_getImm(Op2) + 1;
    239 			MI->flat_insn->detail->arm64.op_count++;
    240 		}
    241 
    242 		return;
    243 	}
    244 
    245 	if (Opcode == AArch64_BFMXri || Opcode == AArch64_BFMWri) {
    246 		MCOperand *Op0 = MCInst_getOperand(MI, 0); // Op1 == Op0
    247 		MCOperand *Op2 = MCInst_getOperand(MI, 2);
    248 		int ImmR = (int)MCOperand_getImm(MCInst_getOperand(MI, 3));
    249 		int ImmS = (int)MCOperand_getImm(MCInst_getOperand(MI, 4));
    250 
    251 		// BFI alias
    252 		if (ImmS < ImmR) {
    253 			int BitWidth = Opcode == AArch64_BFMXri ? 64 : 32;
    254 			LSB = (BitWidth - ImmR) % BitWidth;
    255 			Width = ImmS + 1;
    256 
    257 			SStream_concat(O, "bfi\t%s, %s, ",
    258 					getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName),
    259 					getRegisterName(MCOperand_getReg(Op2), AArch64_NoRegAltName));
    260 			printInt32Bang(O, LSB);
    261 			SStream_concat0(O, ", ");
    262 			printInt32Bang(O, Width);
    263 			MCInst_setOpcodePub(MI, AArch64_map_insn("bfi"));
    264 
    265 			if (MI->csh->detail) {
    266 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    267 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0);
    268 				MI->flat_insn->detail->arm64.op_count++;
    269 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    270 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op2);
    271 				MI->flat_insn->detail->arm64.op_count++;
    272 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    273 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = LSB;
    274 				MI->flat_insn->detail->arm64.op_count++;
    275 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    276 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Width;
    277 				MI->flat_insn->detail->arm64.op_count++;
    278 			}
    279 
    280 			return;
    281 		}
    282 
    283 		LSB = ImmR;
    284 		Width = ImmS - ImmR + 1;
    285 		// Otherwise BFXIL the preferred form
    286 		SStream_concat(O, "bfxil\t%s, %s, ",
    287 				getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName),
    288 				getRegisterName(MCOperand_getReg(Op2), AArch64_NoRegAltName));
    289 		printInt32Bang(O, LSB);
    290 		SStream_concat0(O, ", ");
    291 		printInt32Bang(O, Width);
    292 		MCInst_setOpcodePub(MI, AArch64_map_insn("bfxil"));
    293 
    294 		if (MI->csh->detail) {
    295 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    296 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0);
    297 			MI->flat_insn->detail->arm64.op_count++;
    298 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    299 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op2);
    300 			MI->flat_insn->detail->arm64.op_count++;
    301 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    302 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = LSB;
    303 			MI->flat_insn->detail->arm64.op_count++;
    304 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    305 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Width;
    306 			MI->flat_insn->detail->arm64.op_count++;
    307 		}
    308 
    309 		return;
    310 	}
    311 
    312 	mnem = printAliasInstr(MI, O, Info);
    313 	if (mnem) {
    314 		MCInst_setOpcodePub(MI, AArch64_map_insn(mnem));
    315 		cs_mem_free(mnem);
    316 	} else {
    317 		printInstruction(MI, O, Info);
    318 	}
    319 }
    320 
    321 static bool printSysAlias(MCInst *MI, SStream *O)
    322 {
    323 	// unsigned Opcode = MCInst_getOpcode(MI);
    324 	//assert(Opcode == AArch64_SYSxt && "Invalid opcode for SYS alias!");
    325 
    326 	char *Asm = NULL;
    327 	MCOperand *Op1 = MCInst_getOperand(MI, 0);
    328 	MCOperand *Cn = MCInst_getOperand(MI, 1);
    329 	MCOperand *Cm = MCInst_getOperand(MI, 2);
    330 	MCOperand *Op2 = MCInst_getOperand(MI, 3);
    331 
    332 	unsigned Op1Val = (unsigned)MCOperand_getImm(Op1);
    333 	unsigned CnVal = (unsigned)MCOperand_getImm(Cn);
    334 	unsigned CmVal = (unsigned)MCOperand_getImm(Cm);
    335 	unsigned Op2Val = (unsigned)MCOperand_getImm(Op2);
    336 	unsigned insn_id = ARM64_INS_INVALID;
    337 	unsigned op_ic = 0, op_dc = 0, op_at = 0, op_tlbi = 0;
    338 
    339 	if (CnVal == 7) {
    340 		switch (CmVal) {
    341 			default:
    342 				break;
    343 
    344 				// IC aliases
    345 			case 1:
    346 				if (Op1Val == 0 && Op2Val == 0) {
    347 					Asm = "ic\tialluis";
    348 					insn_id = ARM64_INS_IC;
    349 					op_ic = ARM64_IC_IALLUIS;
    350 				}
    351 				break;
    352 			case 5:
    353 				if (Op1Val == 0 && Op2Val == 0) {
    354 					Asm = "ic\tiallu";
    355 					insn_id = ARM64_INS_IC;
    356 					op_ic = ARM64_IC_IALLU;
    357 				} else if (Op1Val == 3 && Op2Val == 1) {
    358 					Asm = "ic\tivau";
    359 					insn_id = ARM64_INS_IC;
    360 					op_ic = ARM64_IC_IVAU;
    361 				}
    362 				break;
    363 
    364 				// DC aliases
    365 			case 4:
    366 				if (Op1Val == 3 && Op2Val == 1) {
    367 					Asm = "dc\tzva";
    368 					insn_id = ARM64_INS_DC;
    369 					op_dc = ARM64_DC_ZVA;
    370 				}
    371 				break;
    372 			case 6:
    373 				if (Op1Val == 0 && Op2Val == 1) {
    374 					Asm = "dc\tivac";
    375 					insn_id = ARM64_INS_DC;
    376 					op_dc = ARM64_DC_IVAC;
    377 				}
    378 				if (Op1Val == 0 && Op2Val == 2) {
    379 					Asm = "dc\tisw";
    380 					insn_id = ARM64_INS_DC;
    381 					op_dc = ARM64_DC_ISW;
    382 				}
    383 				break;
    384 			case 10:
    385 				if (Op1Val == 3 && Op2Val == 1) {
    386 					Asm = "dc\tcvac";
    387 					insn_id = ARM64_INS_DC;
    388 					op_dc = ARM64_DC_CVAC;
    389 				} else if (Op1Val == 0 && Op2Val == 2) {
    390 					Asm = "dc\tcsw";
    391 					insn_id = ARM64_INS_DC;
    392 					op_dc = ARM64_DC_CSW;
    393 				}
    394 				break;
    395 			case 11:
    396 				if (Op1Val == 3 && Op2Val == 1) {
    397 					Asm = "dc\tcvau";
    398 					insn_id = ARM64_INS_DC;
    399 					op_dc = ARM64_DC_CVAU;
    400 				}
    401 				break;
    402 			case 14:
    403 				if (Op1Val == 3 && Op2Val == 1) {
    404 					Asm = "dc\tcivac";
    405 					insn_id = ARM64_INS_DC;
    406 					op_dc = ARM64_DC_CIVAC;
    407 				} else if (Op1Val == 0 && Op2Val == 2) {
    408 					Asm = "dc\tcisw";
    409 					insn_id = ARM64_INS_DC;
    410 					op_dc = ARM64_DC_CISW;
    411 				}
    412 				break;
    413 
    414 				// AT aliases
    415 			case 8:
    416 				switch (Op1Val) {
    417 					default:
    418 						break;
    419 					case 0:
    420 						switch (Op2Val) {
    421 							default:
    422 								break;
    423 							case 0: Asm = "at\ts1e1r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E1R; break;
    424 							case 1: Asm = "at\ts1e1w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E1W; break;
    425 							case 2: Asm = "at\ts1e0r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E0R; break;
    426 							case 3: Asm = "at\ts1e0w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E0W; break;
    427 						}
    428 						break;
    429 					case 4:
    430 						switch (Op2Val) {
    431 							default:
    432 								break;
    433 							case 0: Asm = "at\ts1e2r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E2R; break;
    434 							case 1: Asm = "at\ts1e2w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E2W; break;
    435 							case 4: Asm = "at\ts12e1r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E1R; break;
    436 							case 5: Asm = "at\ts12e1w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E1W; break;
    437 							case 6: Asm = "at\ts12e0r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E0R; break;
    438 							case 7: Asm = "at\ts12e0w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E0W; break;
    439 						}
    440 						break;
    441 					case 6:
    442 						switch (Op2Val) {
    443 							default:
    444 								break;
    445 							case 0: Asm = "at\ts1e3r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E3R; break;
    446 							case 1: Asm = "at\ts1e3w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E3W; break;
    447 						}
    448 						break;
    449 				}
    450 				break;
    451 		}
    452 	} else if (CnVal == 8) {
    453 		// TLBI aliases
    454 		switch (CmVal) {
    455 			default:
    456 				break;
    457 			case 3:
    458 				switch (Op1Val) {
    459 					default:
    460 						break;
    461 					case 0:
    462 						switch (Op2Val) {
    463 							default:
    464 								break;
    465 							case 0: Asm = "tlbi\tvmalle1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VMALLE1IS; break;
    466 							case 1: Asm = "tlbi\tvae1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE1IS; break;
    467 							case 2: Asm = "tlbi\taside1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ASIDE1IS; break;
    468 							case 3: Asm = "tlbi\tvaae1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAAE1IS; break;
    469 							case 5: Asm = "tlbi\tvale1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE1IS; break;
    470 							case 7: Asm = "tlbi\tvaale1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAALE1IS; break;
    471 						}
    472 						break;
    473 					case 4:
    474 						switch (Op2Val) {
    475 							default:
    476 								break;
    477 							case 0: Asm = "tlbi\talle2is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE2IS; break;
    478 							case 1: Asm = "tlbi\tvae2is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE2IS; break;
    479 							case 4: Asm = "tlbi\talle1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE1IS; break;
    480 							case 5: Asm = "tlbi\tvale2is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE2IS; break;
    481 							case 6: Asm = "tlbi\tvmalls12e1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VMALLS12E1IS; break;
    482 						}
    483 						break;
    484 					case 6:
    485 						switch (Op2Val) {
    486 							default:
    487 								break;
    488 							case 0: Asm = "tlbi\talle3is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE3IS; break;
    489 							case 1: Asm = "tlbi\tvae3is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE3IS; break;
    490 							case 5: Asm = "tlbi\tvale3is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE3IS; break;
    491 						}
    492 						break;
    493 				}
    494 				break;
    495 			case 0:
    496 				switch (Op1Val) {
    497 					default:
    498 						break;
    499 					case 4:
    500 						switch (Op2Val) {
    501 							default:
    502 								break;
    503 							case 1: Asm = "tlbi\tipas2e1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_IPAS2E1IS; break;
    504 							case 5: Asm = "tlbi\tipas2le1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_IPAS2LE1IS; break;
    505 						}
    506 						break;
    507 				}
    508 				break;
    509 			case 4:
    510 				switch (Op1Val) {
    511 					default:
    512 						break;
    513 					case 4:
    514 						switch (Op2Val) {
    515 							default:
    516 								break;
    517 							case 1: Asm = "tlbi\tipas2e1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_IPAS2E1; break;
    518 							case 5: Asm = "tlbi\tipas2le1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_IPAS2LE1; break;
    519 						}
    520 						break;
    521 				}
    522 				break;
    523 			case 7:
    524 				switch (Op1Val) {
    525 					default:
    526 						break;
    527 					case 0:
    528 						switch (Op2Val) {
    529 							default:
    530 								break;
    531 							case 0: Asm = "tlbi\tvmalle1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VMALLE1; break;
    532 							case 1: Asm = "tlbi\tvae1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE1; break;
    533 							case 2: Asm = "tlbi\taside1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ASIDE1; break;
    534 							case 3: Asm = "tlbi\tvaae1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAAE1; break;
    535 							case 5: Asm = "tlbi\tvale1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE1; break;
    536 							case 7: Asm = "tlbi\tvaale1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAALE1; break;
    537 						}
    538 						break;
    539 					case 4:
    540 						switch (Op2Val) {
    541 							default:
    542 								break;
    543 							case 0: Asm = "tlbi\talle2"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE2; break;
    544 							case 1: Asm = "tlbi\tvae2"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE2; break;
    545 							case 4: Asm = "tlbi\talle1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE1; break;
    546 							case 5: Asm = "tlbi\tvale2"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE2; break;
    547 							case 6: Asm = "tlbi\tvmalls12e1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VMALLS12E1; break;
    548 						}
    549 						break;
    550 					case 6:
    551 						switch (Op2Val) {
    552 							default:
    553 								break;
    554 							case 0: Asm = "tlbi\talle3"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE3; break;
    555 							case 1: Asm = "tlbi\tvae3"; insn_id = ARM64_INS_TLBI;  op_tlbi = ARM64_TLBI_VAE3; break;
    556 							case 5: Asm = "tlbi\tvale3"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE3; break;
    557 						}
    558 						break;
    559 				}
    560 				break;
    561 		}
    562 	}
    563 
    564 	if (Asm) {
    565 		MCInst_setOpcodePub(MI, insn_id);
    566 		SStream_concat0(O, Asm);
    567 		if (MI->csh->detail) {
    568 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_SYS;
    569 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].sys = op_ic + op_dc + op_at + op_tlbi;
    570 			MI->flat_insn->detail->arm64.op_count++;
    571 		}
    572 
    573 		if (!strstr(Asm, "all")) {
    574 			unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, 4));
    575 			SStream_concat(O, ", %s", getRegisterName(Reg, AArch64_NoRegAltName));
    576 			if (MI->csh->detail) {
    577 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    578 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Reg;
    579 				MI->flat_insn->detail->arm64.op_count++;
    580 			}
    581 		}
    582 	}
    583 
    584 	return Asm != NULL;
    585 }
    586 
    587 static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
    588 {
    589 	MCOperand *Op = MCInst_getOperand(MI, OpNo);
    590 
    591 	if (MCOperand_isReg(Op)) {
    592 		unsigned Reg = MCOperand_getReg(Op);
    593 		SStream_concat0(O, getRegisterName(Reg, AArch64_NoRegAltName));
    594 		if (MI->csh->detail) {
    595 			if (MI->csh->doing_mem) {
    596 				if (MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.base == ARM64_REG_INVALID) {
    597 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.base = Reg;
    598 				}
    599 				else if (MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.index == ARM64_REG_INVALID) {
    600 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.index = Reg;
    601 				}
    602 			} else {
    603 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    604 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Reg;
    605 				MI->flat_insn->detail->arm64.op_count++;
    606 			}
    607 		}
    608 	} else if (MCOperand_isImm(Op)) {
    609 		int64_t imm = MCOperand_getImm(Op);
    610 
    611 		if (MI->Opcode == AArch64_ADR) {
    612 			imm += MI->address;
    613 			printUInt64Bang(O, imm);
    614 		} else
    615 			printUInt64Bang(O, imm);
    616 		if (MI->csh->detail) {
    617 			if (MI->csh->doing_mem) {
    618 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.disp = (int32_t)imm;
    619 			} else {
    620 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    621 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = imm;
    622 				MI->flat_insn->detail->arm64.op_count++;
    623 			}
    624 		}
    625 	}
    626 }
    627 
    628 static void printHexImm(MCInst *MI, unsigned OpNo, SStream *O)
    629 {
    630 	MCOperand *Op = MCInst_getOperand(MI, OpNo);
    631 	SStream_concat(O, "#%#llx", MCOperand_getImm(Op));
    632 	if (MI->csh->detail) {
    633 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    634 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op);
    635 		MI->flat_insn->detail->arm64.op_count++;
    636 	}
    637 }
    638 
    639 static void printPostIncOperand(MCInst *MI, unsigned OpNo,
    640 		unsigned Imm, SStream *O)
    641 {
    642 	MCOperand *Op = MCInst_getOperand(MI, OpNo);
    643 
    644 	if (MCOperand_isReg(Op)) {
    645 		unsigned Reg = MCOperand_getReg(Op);
    646 		if (Reg == AArch64_XZR) {
    647 			printInt32Bang(O, Imm);
    648 			if (MI->csh->detail) {
    649 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    650 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Imm;
    651 				MI->flat_insn->detail->arm64.op_count++;
    652 			}
    653 		} else {
    654 			SStream_concat0(O, getRegisterName(Reg, AArch64_NoRegAltName));
    655 			if (MI->csh->detail) {
    656 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    657 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Reg;
    658 				MI->flat_insn->detail->arm64.op_count++;
    659 			}
    660 		}
    661 	}
    662 	//llvm_unreachable("unknown operand kind in printPostIncOperand64");
    663 }
    664 
    665 static void printPostIncOperand2(MCInst *MI, unsigned OpNo, SStream *O, int Amount)
    666 {
    667 	printPostIncOperand(MI, OpNo, Amount, O);
    668 }
    669 
    670 static void printVRegOperand(MCInst *MI, unsigned OpNo, SStream *O)
    671 {
    672 	MCOperand *Op = MCInst_getOperand(MI, OpNo);
    673 	//assert(Op.isReg() && "Non-register vreg operand!");
    674 	unsigned Reg = MCOperand_getReg(Op);
    675 	SStream_concat0(O, getRegisterName(Reg, AArch64_vreg));
    676 	if (MI->csh->detail) {
    677 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    678 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = AArch64_map_vregister(Reg);
    679 		MI->flat_insn->detail->arm64.op_count++;
    680 	}
    681 }
    682 
    683 static void printSysCROperand(MCInst *MI, unsigned OpNo, SStream *O)
    684 {
    685 	MCOperand *Op = MCInst_getOperand(MI, OpNo);
    686 	//assert(Op.isImm() && "System instruction C[nm] operands must be immediates!");
    687 	SStream_concat(O, "c%u", MCOperand_getImm(Op));
    688 	if (MI->csh->detail) {
    689 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_CIMM;
    690 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op);
    691 		MI->flat_insn->detail->arm64.op_count++;
    692 	}
    693 }
    694 
    695 static void printAddSubImm(MCInst *MI, unsigned OpNum, SStream *O)
    696 {
    697 	MCOperand *MO = MCInst_getOperand(MI, OpNum);
    698 	if (MCOperand_isImm(MO)) {
    699 		unsigned Val = (MCOperand_getImm(MO) & 0xfff);
    700 		//assert(Val == MO.getImm() && "Add/sub immediate out of range!");
    701 		unsigned Shift = AArch64_AM_getShiftValue((int)MCOperand_getImm(MCInst_getOperand(MI, OpNum + 1)));
    702 
    703 		printInt32Bang(O, Val);
    704 
    705 		if (MI->csh->detail) {
    706 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    707 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val;
    708 			MI->flat_insn->detail->arm64.op_count++;
    709 		}
    710 
    711 		if (Shift != 0)
    712 			printShifter(MI, OpNum + 1, O);
    713 	}
    714 }
    715 
    716 static void printLogicalImm32(MCInst *MI, unsigned OpNum, SStream *O)
    717 {
    718 	int64_t Val = MCOperand_getImm(MCInst_getOperand(MI, OpNum));
    719 
    720 	Val = AArch64_AM_decodeLogicalImmediate(Val, 32);
    721 	printUInt32Bang(O, (int)Val);
    722 
    723 	if (MI->csh->detail) {
    724 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    725 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val;
    726 		MI->flat_insn->detail->arm64.op_count++;
    727 	}
    728 }
    729 
    730 static void printLogicalImm64(MCInst *MI, unsigned OpNum, SStream *O)
    731 {
    732 	int64_t Val = MCOperand_getImm(MCInst_getOperand(MI, OpNum));
    733 	Val = AArch64_AM_decodeLogicalImmediate(Val, 64);
    734 
    735 	switch(MI->flat_insn->id) {
    736 		default:
    737 			printInt64Bang(O, Val);
    738 			break;
    739 		case ARM64_INS_ORR:
    740 		case ARM64_INS_AND:
    741 		case ARM64_INS_EOR:
    742 		case ARM64_INS_TST:
    743 			// do not print number in negative form
    744 			if (Val >= 0 && Val <= HEX_THRESHOLD)
    745 				SStream_concat(O, "#%u", (int)Val);
    746 			else
    747 				SStream_concat(O, "#0x%"PRIx64, Val);
    748 			break;
    749 	}
    750 
    751 	if (MI->csh->detail) {
    752 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    753 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val;
    754 		MI->flat_insn->detail->arm64.op_count++;
    755 	}
    756 }
    757 
    758 static void printShifter(MCInst *MI, unsigned OpNum, SStream *O)
    759 {
    760 	unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum));
    761 
    762 	// LSL #0 should not be printed.
    763 	if (AArch64_AM_getShiftType(Val) == AArch64_AM_LSL &&
    764 			AArch64_AM_getShiftValue(Val) == 0)
    765 		return;
    766 
    767 	SStream_concat(O, ", %s ", AArch64_AM_getShiftExtendName(AArch64_AM_getShiftType(Val)));
    768 	printInt32BangDec(O, AArch64_AM_getShiftValue(Val));
    769 	if (MI->csh->detail) {
    770 		arm64_shifter shifter = ARM64_SFT_INVALID;
    771 		switch(AArch64_AM_getShiftType(Val)) {
    772 			default:	// never reach
    773 			case AArch64_AM_LSL:
    774 				shifter = ARM64_SFT_LSL;
    775 				break;
    776 			case AArch64_AM_LSR:
    777 				shifter = ARM64_SFT_LSR;
    778 				break;
    779 			case AArch64_AM_ASR:
    780 				shifter = ARM64_SFT_ASR;
    781 				break;
    782 			case AArch64_AM_ROR:
    783 				shifter = ARM64_SFT_ROR;
    784 				break;
    785 			case AArch64_AM_MSL:
    786 				shifter = ARM64_SFT_MSL;
    787 				break;
    788 		}
    789 
    790 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.type = shifter;
    791 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.value = AArch64_AM_getShiftValue(Val);
    792 	}
    793 }
    794 
    795 static void printShiftedRegister(MCInst *MI, unsigned OpNum, SStream *O)
    796 {
    797 	SStream_concat0(O, getRegisterName(MCOperand_getReg(MCInst_getOperand(MI, OpNum)), AArch64_NoRegAltName));
    798 	if (MI->csh->detail) {
    799 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    800 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(MCInst_getOperand(MI, OpNum));
    801 		MI->flat_insn->detail->arm64.op_count++;
    802 	}
    803 	printShifter(MI, OpNum + 1, O);
    804 }
    805 
    806 static void printArithExtend(MCInst *MI, unsigned OpNum, SStream *O)
    807 {
    808 	unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum));
    809 	AArch64_AM_ShiftExtendType ExtType = AArch64_AM_getArithExtendType(Val);
    810 	unsigned ShiftVal = AArch64_AM_getArithShiftValue(Val);
    811 
    812 	// If the destination or first source register operand is [W]SP, print
    813 	// UXTW/UXTX as LSL, and if the shift amount is also zero, print nothing at
    814 	// all.
    815 	if (ExtType == AArch64_AM_UXTW || ExtType == AArch64_AM_UXTX) {
    816 		unsigned Dest = MCOperand_getReg(MCInst_getOperand(MI, 0));
    817 		unsigned Src1 = MCOperand_getReg(MCInst_getOperand(MI, 1));
    818 		if ( ((Dest == AArch64_SP || Src1 == AArch64_SP) &&
    819 					ExtType == AArch64_AM_UXTX) ||
    820 				((Dest == AArch64_WSP || Src1 == AArch64_WSP) &&
    821 				 ExtType == AArch64_AM_UXTW) ) {
    822 			if (ShiftVal != 0) {
    823 				SStream_concat0(O, ", lsl ");
    824 				printInt32Bang(O, ShiftVal);
    825 				if (MI->csh->detail) {
    826 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.type = ARM64_SFT_LSL;
    827 					MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.value = ShiftVal;
    828 				}
    829 			}
    830 
    831 			return;
    832 		}
    833 	}
    834 
    835 	SStream_concat(O, ", %s", AArch64_AM_getShiftExtendName(ExtType));
    836 	if (MI->csh->detail) {
    837 		arm64_extender ext = ARM64_EXT_INVALID;
    838 		switch(ExtType) {
    839 			default:	// never reach
    840 			case AArch64_AM_UXTB:
    841 				ext = ARM64_EXT_UXTB;
    842 				break;
    843 			case AArch64_AM_UXTH:
    844 				ext = ARM64_EXT_UXTH;
    845 				break;
    846 			case AArch64_AM_UXTW:
    847 				ext = ARM64_EXT_UXTW;
    848 				break;
    849 			case AArch64_AM_UXTX:
    850 				ext = ARM64_EXT_UXTX;
    851 				break;
    852 			case AArch64_AM_SXTB:
    853 				ext = ARM64_EXT_SXTB;
    854 				break;
    855 			case AArch64_AM_SXTH:
    856 				ext = ARM64_EXT_SXTH;
    857 				break;
    858 			case AArch64_AM_SXTW:
    859 				ext = ARM64_EXT_SXTW;
    860 				break;
    861 			case AArch64_AM_SXTX:
    862 				ext = ARM64_EXT_SXTX;
    863 				break;
    864 		}
    865 
    866 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].ext = ext;
    867 	}
    868 
    869 	if (ShiftVal != 0) {
    870 		SStream_concat0(O, " ");
    871 		printInt32Bang(O, ShiftVal);
    872 		if (MI->csh->detail) {
    873 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.type = ARM64_SFT_LSL;
    874 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.value = ShiftVal;
    875 		}
    876 	}
    877 }
    878 
    879 static void printExtendedRegister(MCInst *MI, unsigned OpNum, SStream *O)
    880 {
    881 	unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, OpNum));
    882 
    883 	SStream_concat0(O, getRegisterName(Reg, AArch64_NoRegAltName));
    884 	if (MI->csh->detail) {
    885 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
    886 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Reg;
    887 		MI->flat_insn->detail->arm64.op_count++;
    888 	}
    889 
    890 	printArithExtend(MI, OpNum + 1, O);
    891 }
    892 
    893 static void printMemExtend(MCInst *MI, unsigned OpNum, SStream *O, char SrcRegKind, unsigned Width)
    894 {
    895 	unsigned SignExtend = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum));
    896 	unsigned DoShift = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum + 1));
    897 
    898 	// sxtw, sxtx, uxtw or lsl (== uxtx)
    899 	bool IsLSL = !SignExtend && SrcRegKind == 'x';
    900 	if (IsLSL) {
    901 		SStream_concat0(O, "lsl");
    902 		if (MI->csh->detail) {
    903 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].shift.type = ARM64_SFT_LSL;
    904 		}
    905 	} else {
    906 		SStream_concat(O, "%cxt%c", (SignExtend ? 's' : 'u'), SrcRegKind);
    907 		if (MI->csh->detail) {
    908 			if (!SignExtend) {
    909 				switch(SrcRegKind) {
    910 					default: break;
    911 					case 'b':
    912 							 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_UXTB;
    913 							 break;
    914 					case 'h':
    915 							 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_UXTH;
    916 							 break;
    917 					case 'w':
    918 							 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_UXTW;
    919 							 break;
    920 				}
    921 			} else {
    922 					switch(SrcRegKind) {
    923 						default: break;
    924 						case 'b':
    925 							MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_SXTB;
    926 							break;
    927 						case 'h':
    928 							MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_SXTH;
    929 							break;
    930 						case 'w':
    931 							MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_SXTW;
    932 							break;
    933 						case 'x':
    934 							MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_SXTX;
    935 							break;
    936 					}
    937 			}
    938 		}
    939 	}
    940 
    941 	if (DoShift || IsLSL) {
    942 		SStream_concat(O, " #%u", Log2_32(Width / 8));
    943 		if (MI->csh->detail) {
    944 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].shift.type = ARM64_SFT_LSL;
    945 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].shift.value = Log2_32(Width / 8);
    946 		}
    947 	}
    948 }
    949 
    950 static void printCondCode(MCInst *MI, unsigned OpNum, SStream *O)
    951 {
    952 	A64CC_CondCode CC = (A64CC_CondCode)MCOperand_getImm(MCInst_getOperand(MI, OpNum));
    953 	SStream_concat0(O, getCondCodeName(CC));
    954 
    955 	if (MI->csh->detail)
    956 		MI->flat_insn->detail->arm64.cc = (arm64_cc)(CC + 1);
    957 }
    958 
    959 static void printInverseCondCode(MCInst *MI, unsigned OpNum, SStream *O)
    960 {
    961 	A64CC_CondCode CC = (A64CC_CondCode)MCOperand_getImm(MCInst_getOperand(MI, OpNum));
    962 	SStream_concat0(O, getCondCodeName(getInvertedCondCode(CC)));
    963 
    964 	if (MI->csh->detail) {
    965 		MI->flat_insn->detail->arm64.cc = (arm64_cc)(getInvertedCondCode(CC) + 1);
    966 	}
    967 }
    968 
    969 static void printImmScale(MCInst *MI, unsigned OpNum, SStream *O, int Scale)
    970 {
    971 	int64_t val = Scale * MCOperand_getImm(MCInst_getOperand(MI, OpNum));
    972 
    973 	printInt64Bang(O, val);
    974 
    975 	if (MI->csh->detail) {
    976 		if (MI->csh->doing_mem) {
    977 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.disp = val;
    978 		} else {
    979 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    980 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = val;
    981 			MI->flat_insn->detail->arm64.op_count++;
    982 		}
    983 	}
    984 }
    985 
    986 static void printUImm12Offset(MCInst *MI, unsigned OpNum, unsigned Scale, SStream *O)
    987 {
    988 	MCOperand *MO = MCInst_getOperand(MI, OpNum);
    989 
    990 	if (MCOperand_isImm(MO)) {
    991 		int64_t val = Scale * MCOperand_getImm(MO);
    992 		printInt64Bang(O, val);
    993 		if (MI->csh->detail) {
    994 			if (MI->csh->doing_mem) {
    995 				MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.disp = val;
    996 			} else {
    997 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
    998 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = val;
    999 			MI->flat_insn->detail->arm64.op_count++;
   1000 			}
   1001 		}
   1002 	}
   1003 }
   1004 
   1005 static void printUImm12Offset2(MCInst *MI, unsigned OpNum, SStream *O, int Scale)
   1006 {
   1007 	printUImm12Offset(MI, OpNum, Scale, O);
   1008 }
   1009 
   1010 static void printPrefetchOp(MCInst *MI, unsigned OpNum, SStream *O)
   1011 {
   1012 	unsigned prfop = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum));
   1013 	bool Valid;
   1014 	char *Name = A64NamedImmMapper_toString(&A64PRFM_PRFMMapper, prfop, &Valid);
   1015 
   1016 	if (Valid) {
   1017 		SStream_concat0(O, Name);
   1018 		if (MI->csh->detail) {
   1019 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_PREFETCH;
   1020 			// we have to plus 1 to prfop because 0 is a valid value of prfop
   1021 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].prefetch = prfop + 1;
   1022 			MI->flat_insn->detail->arm64.op_count++;
   1023 		}
   1024 	} else {
   1025 		printInt32Bang(O, prfop);
   1026 		if (MI->csh->detail) {
   1027 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
   1028 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = prfop;
   1029 			MI->flat_insn->detail->arm64.op_count++;
   1030 		}
   1031 	}
   1032 }
   1033 
   1034 static void printFPImmOperand(MCInst *MI, unsigned OpNum, SStream *O)
   1035 {
   1036 	MCOperand *MO = MCInst_getOperand(MI, OpNum);
   1037 	double FPImm = MCOperand_isFPImm(MO) ? MCOperand_getFPImm(MO) : AArch64_AM_getFPImmFloat((int)MCOperand_getImm(MO));
   1038 
   1039 	// 8 decimal places are enough to perfectly represent permitted floats.
   1040 #if defined(_KERNEL_MODE)
   1041 	// Issue #681: Windows kernel does not support formatting float point
   1042 	SStream_concat(O, "#<float_point_unsupported>");
   1043 #else
   1044 	SStream_concat(O, "#%.8f", FPImm);
   1045 #endif
   1046 	if (MI->csh->detail) {
   1047 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_FP;
   1048 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].fp = FPImm;
   1049 		MI->flat_insn->detail->arm64.op_count++;
   1050 	}
   1051 }
   1052 
   1053 //static unsigned getNextVectorRegister(unsigned Reg, unsigned Stride = 1)
   1054 static unsigned getNextVectorRegister(unsigned Reg, unsigned Stride)
   1055 {
   1056 	while (Stride--) {
   1057 		switch (Reg) {
   1058 			default:
   1059 				// llvm_unreachable("Vector register expected!");
   1060 			case AArch64_Q0:  Reg = AArch64_Q1;  break;
   1061 			case AArch64_Q1:  Reg = AArch64_Q2;  break;
   1062 			case AArch64_Q2:  Reg = AArch64_Q3;  break;
   1063 			case AArch64_Q3:  Reg = AArch64_Q4;  break;
   1064 			case AArch64_Q4:  Reg = AArch64_Q5;  break;
   1065 			case AArch64_Q5:  Reg = AArch64_Q6;  break;
   1066 			case AArch64_Q6:  Reg = AArch64_Q7;  break;
   1067 			case AArch64_Q7:  Reg = AArch64_Q8;  break;
   1068 			case AArch64_Q8:  Reg = AArch64_Q9;  break;
   1069 			case AArch64_Q9:  Reg = AArch64_Q10; break;
   1070 			case AArch64_Q10: Reg = AArch64_Q11; break;
   1071 			case AArch64_Q11: Reg = AArch64_Q12; break;
   1072 			case AArch64_Q12: Reg = AArch64_Q13; break;
   1073 			case AArch64_Q13: Reg = AArch64_Q14; break;
   1074 			case AArch64_Q14: Reg = AArch64_Q15; break;
   1075 			case AArch64_Q15: Reg = AArch64_Q16; break;
   1076 			case AArch64_Q16: Reg = AArch64_Q17; break;
   1077 			case AArch64_Q17: Reg = AArch64_Q18; break;
   1078 			case AArch64_Q18: Reg = AArch64_Q19; break;
   1079 			case AArch64_Q19: Reg = AArch64_Q20; break;
   1080 			case AArch64_Q20: Reg = AArch64_Q21; break;
   1081 			case AArch64_Q21: Reg = AArch64_Q22; break;
   1082 			case AArch64_Q22: Reg = AArch64_Q23; break;
   1083 			case AArch64_Q23: Reg = AArch64_Q24; break;
   1084 			case AArch64_Q24: Reg = AArch64_Q25; break;
   1085 			case AArch64_Q25: Reg = AArch64_Q26; break;
   1086 			case AArch64_Q26: Reg = AArch64_Q27; break;
   1087 			case AArch64_Q27: Reg = AArch64_Q28; break;
   1088 			case AArch64_Q28: Reg = AArch64_Q29; break;
   1089 			case AArch64_Q29: Reg = AArch64_Q30; break;
   1090 			case AArch64_Q30: Reg = AArch64_Q31; break;
   1091 							   // Vector lists can wrap around.
   1092 			case AArch64_Q31: Reg = AArch64_Q0; break;
   1093 		}
   1094 	}
   1095 
   1096 	return Reg;
   1097 }
   1098 
   1099 static void printVectorList(MCInst *MI, unsigned OpNum, SStream *O, char *LayoutSuffix, MCRegisterInfo *MRI, arm64_vas vas, arm64_vess vess)
   1100 {
   1101 #define GETREGCLASS_CONTAIN0(_class, _reg) MCRegisterClass_contains(MCRegisterInfo_getRegClass(MRI, _class), _reg)
   1102 
   1103 	unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, OpNum));
   1104 	unsigned NumRegs = 1, FirstReg, i;
   1105 
   1106 	SStream_concat0(O, "{");
   1107 
   1108 	// Work out how many registers there are in the list (if there is an actual
   1109 	// list).
   1110 	if (GETREGCLASS_CONTAIN0(AArch64_DDRegClassID , Reg) ||
   1111 			GETREGCLASS_CONTAIN0(AArch64_QQRegClassID, Reg))
   1112 		NumRegs = 2;
   1113 	else if (GETREGCLASS_CONTAIN0(AArch64_DDDRegClassID, Reg) ||
   1114 			GETREGCLASS_CONTAIN0(AArch64_QQQRegClassID, Reg))
   1115 		NumRegs = 3;
   1116 	else if (GETREGCLASS_CONTAIN0(AArch64_DDDDRegClassID, Reg) ||
   1117 			GETREGCLASS_CONTAIN0(AArch64_QQQQRegClassID, Reg))
   1118 		NumRegs = 4;
   1119 
   1120 	// Now forget about the list and find out what the first register is.
   1121 	if ((FirstReg = MCRegisterInfo_getSubReg(MRI, Reg, AArch64_dsub0)))
   1122 		Reg = FirstReg;
   1123 	else if ((FirstReg = MCRegisterInfo_getSubReg(MRI, Reg, AArch64_qsub0)))
   1124 		Reg = FirstReg;
   1125 
   1126 	// If it's a D-reg, we need to promote it to the equivalent Q-reg before
   1127 	// printing (otherwise getRegisterName fails).
   1128 	if (GETREGCLASS_CONTAIN0(AArch64_FPR64RegClassID, Reg)) {
   1129 		MCRegisterClass *FPR128RC = MCRegisterInfo_getRegClass(MRI, AArch64_FPR128RegClassID);
   1130 		Reg = MCRegisterInfo_getMatchingSuperReg(MRI, Reg, AArch64_dsub, FPR128RC);
   1131 	}
   1132 
   1133 	for (i = 0; i < NumRegs; ++i, Reg = getNextVectorRegister(Reg, 1)) {
   1134 		SStream_concat(O, "%s%s", getRegisterName(Reg, AArch64_vreg), LayoutSuffix);
   1135 		if (i + 1 != NumRegs)
   1136 			SStream_concat0(O, ", ");
   1137 		if (MI->csh->detail) {
   1138 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG;
   1139 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = AArch64_map_vregister(Reg);
   1140 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].vas = vas;
   1141 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].vess = vess;
   1142 			MI->flat_insn->detail->arm64.op_count++;
   1143 		}
   1144 	}
   1145 
   1146 	SStream_concat0(O, "}");
   1147 }
   1148 
   1149 static void printTypedVectorList(MCInst *MI, unsigned OpNum, SStream *O, unsigned NumLanes, char LaneKind, MCRegisterInfo *MRI)
   1150 {
   1151 	char Suffix[32];
   1152 	arm64_vas vas = 0;
   1153 	arm64_vess vess = 0;
   1154 
   1155 	if (NumLanes) {
   1156 		cs_snprintf(Suffix, sizeof(Suffix), ".%u%c", NumLanes, LaneKind);
   1157 		switch(LaneKind) {
   1158 			default: break;
   1159 			case 'b':
   1160 				switch(NumLanes) {
   1161 					default: break;
   1162 					case 8:
   1163 							 vas = ARM64_VAS_8B;
   1164 							 break;
   1165 					case 16:
   1166 							 vas = ARM64_VAS_16B;
   1167 							 break;
   1168 				}
   1169 				break;
   1170 			case 'h':
   1171 				switch(NumLanes) {
   1172 					default: break;
   1173 					case 4:
   1174 							 vas = ARM64_VAS_4H;
   1175 							 break;
   1176 					case 8:
   1177 							 vas = ARM64_VAS_8H;
   1178 							 break;
   1179 				}
   1180 				break;
   1181 			case 's':
   1182 				switch(NumLanes) {
   1183 					default: break;
   1184 					case 2:
   1185 							 vas = ARM64_VAS_2S;
   1186 							 break;
   1187 					case 4:
   1188 							 vas = ARM64_VAS_4S;
   1189 							 break;
   1190 				}
   1191 				break;
   1192 			case 'd':
   1193 				switch(NumLanes) {
   1194 					default: break;
   1195 					case 1:
   1196 							 vas = ARM64_VAS_1D;
   1197 							 break;
   1198 					case 2:
   1199 							 vas = ARM64_VAS_2D;
   1200 							 break;
   1201 				}
   1202 				break;
   1203 			case 'q':
   1204 				switch(NumLanes) {
   1205 					default: break;
   1206 					case 1:
   1207 							 vas = ARM64_VAS_1Q;
   1208 							 break;
   1209 				}
   1210 				break;
   1211 		}
   1212 	} else {
   1213 		cs_snprintf(Suffix, sizeof(Suffix), ".%c", LaneKind);
   1214 		switch(LaneKind) {
   1215 			default: break;
   1216 			case 'b':
   1217 					 vess = ARM64_VESS_B;
   1218 					 break;
   1219 			case 'h':
   1220 					 vess = ARM64_VESS_H;
   1221 					 break;
   1222 			case 's':
   1223 					 vess = ARM64_VESS_S;
   1224 					 break;
   1225 			case 'd':
   1226 					 vess = ARM64_VESS_D;
   1227 					 break;
   1228 		}
   1229 	}
   1230 
   1231 	printVectorList(MI, OpNum, O, Suffix, MRI, vas, vess);
   1232 }
   1233 
   1234 static void printVectorIndex(MCInst *MI, unsigned OpNum, SStream *O)
   1235 {
   1236 	SStream_concat0(O, "[");
   1237 	printInt32(O, (int)MCOperand_getImm(MCInst_getOperand(MI, OpNum)));
   1238 	SStream_concat0(O, "]");
   1239 	if (MI->csh->detail) {
   1240 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].vector_index = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNum));
   1241 	}
   1242 }
   1243 
   1244 static void printAlignedLabel(MCInst *MI, unsigned OpNum, SStream *O)
   1245 {
   1246 	MCOperand *Op = MCInst_getOperand(MI, OpNum);
   1247 
   1248 	// If the label has already been resolved to an immediate offset (say, when
   1249 	// we're running the disassembler), just print the immediate.
   1250 	if (MCOperand_isImm(Op)) {
   1251 		uint64_t imm = (MCOperand_getImm(Op) << 2) + MI->address;
   1252 		printUInt64Bang(O, imm);
   1253 		if (MI->csh->detail) {
   1254 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
   1255 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = imm;
   1256 			MI->flat_insn->detail->arm64.op_count++;
   1257 		}
   1258 		return;
   1259 	}
   1260 }
   1261 
   1262 static void printAdrpLabel(MCInst *MI, unsigned OpNum, SStream *O)
   1263 {
   1264 	MCOperand *Op = MCInst_getOperand(MI, OpNum);
   1265 
   1266 	if (MCOperand_isImm(Op)) {
   1267 		// ADRP sign extends a 21-bit offset, shifts it left by 12
   1268 		// and adds it to the value of the PC with its bottom 12 bits cleared
   1269 		uint64_t imm = (MCOperand_getImm(Op) << 12) + (MI->address & ~0xfff);
   1270 		if (imm > HEX_THRESHOLD)
   1271 			SStream_concat(O, "#0x%"PRIx64, imm);
   1272 		else
   1273 			SStream_concat(O, "#%"PRIu64, imm);
   1274 
   1275 		if (MI->csh->detail) {
   1276 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
   1277 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = imm;
   1278 			MI->flat_insn->detail->arm64.op_count++;
   1279 		}
   1280 		return;
   1281 	}
   1282 }
   1283 
   1284 static void printBarrierOption(MCInst *MI, unsigned OpNo, SStream *O)
   1285 {
   1286 	unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
   1287 	unsigned Opcode = MCInst_getOpcode(MI);
   1288 	bool Valid;
   1289 	char *Name;
   1290 
   1291 	if (Opcode == AArch64_ISB)
   1292 		Name = A64NamedImmMapper_toString(&A64ISB_ISBMapper, Val, &Valid);
   1293 	else
   1294 		Name = A64NamedImmMapper_toString(&A64DB_DBarrierMapper, Val, &Valid);
   1295 
   1296 	if (Valid) {
   1297 		SStream_concat0(O, Name);
   1298 		if (MI->csh->detail) {
   1299 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_BARRIER;
   1300 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].barrier = Val;
   1301 			MI->flat_insn->detail->arm64.op_count++;
   1302 		}
   1303 	} else {
   1304 		printUInt32Bang(O, Val);
   1305 		if (MI->csh->detail) {
   1306 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
   1307 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val;
   1308 			MI->flat_insn->detail->arm64.op_count++;
   1309 		}
   1310 	}
   1311 }
   1312 
   1313 static void printMRSSystemRegister(MCInst *MI, unsigned OpNo, SStream *O)
   1314 {
   1315 	unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
   1316 	bool Valid;
   1317 	char Name[128];
   1318 
   1319 	A64SysRegMapper_toString(&AArch64_MRSMapper, Val, &Valid, Name);
   1320 
   1321 	if (Valid) {
   1322 		SStream_concat0(O, Name);
   1323 		if (MI->csh->detail) {
   1324 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG_MRS;
   1325 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Val;
   1326 			MI->flat_insn->detail->arm64.op_count++;
   1327 		}
   1328 	}
   1329 }
   1330 
   1331 static void printMSRSystemRegister(MCInst *MI, unsigned OpNo, SStream *O)
   1332 {
   1333 	unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
   1334 	bool Valid;
   1335 	char Name[128];
   1336 
   1337 	A64SysRegMapper_toString(&AArch64_MSRMapper, Val, &Valid, Name);
   1338 
   1339 	if (Valid) {
   1340 		SStream_concat0(O, Name);
   1341 		if (MI->csh->detail) {
   1342 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG_MSR;
   1343 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Val;
   1344 			MI->flat_insn->detail->arm64.op_count++;
   1345 		}
   1346 	}
   1347 }
   1348 
   1349 static void printSystemPStateField(MCInst *MI, unsigned OpNo, SStream *O)
   1350 {
   1351 	unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
   1352 	bool Valid;
   1353 	char *Name;
   1354 
   1355 	Name = A64NamedImmMapper_toString(&A64PState_PStateMapper, Val, &Valid);
   1356 	if (Valid) {
   1357 		SStream_concat0(O, Name);
   1358 		if (MI->csh->detail) {
   1359 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_PSTATE;
   1360 			MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].pstate = Val;
   1361 			MI->flat_insn->detail->arm64.op_count++;
   1362 		}
   1363 	} else {
   1364 		printInt32Bang(O, Val);
   1365 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
   1366 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val;
   1367 		MI->flat_insn->detail->arm64.op_count++;
   1368 	}
   1369 }
   1370 
   1371 static void printSIMDType10Operand(MCInst *MI, unsigned OpNo, SStream *O)
   1372 {
   1373 	uint8_t RawVal = (uint8_t)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
   1374 	uint64_t Val = AArch64_AM_decodeAdvSIMDModImmType10(RawVal);
   1375 	SStream_concat(O, "#%#016llx", Val);
   1376 	if (MI->csh->detail) {
   1377 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM;
   1378 		MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val;
   1379 		MI->flat_insn->detail->arm64.op_count++;
   1380 	}
   1381 }
   1382 
   1383 
   1384 #define PRINT_ALIAS_INSTR
   1385 #include "AArch64GenAsmWriter.inc"
   1386 
   1387 void AArch64_post_printer(csh handle, cs_insn *flat_insn, char *insn_asm, MCInst *mci)
   1388 {
   1389 	if (((cs_struct *)handle)->detail != CS_OPT_ON)
   1390 		return;
   1391 
   1392 	// check if this insn requests write-back
   1393 	if (strrchr(insn_asm, '!') != NULL)
   1394 		flat_insn->detail->arm64.writeback = true;
   1395 }
   1396 
   1397 #endif
   1398