//===- AArch64AddressingModes.h - AArch64 Addressing Modes ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the AArch64 addressing mode implementation stuff. // //===----------------------------------------------------------------------===// #ifndef CS_AARCH64_ADDRESSINGMODES_H #define CS_AARCH64_ADDRESSINGMODES_H /* Capstone Disassembly Engine */ /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014 */ #include "../../MathExtras.h" /// AArch64_AM - AArch64 Addressing Mode Stuff //===----------------------------------------------------------------------===// // Shifts // typedef enum AArch64_AM_ShiftExtendType { AArch64_AM_InvalidShiftExtend = -1, AArch64_AM_LSL = 0, AArch64_AM_LSR, AArch64_AM_ASR, AArch64_AM_ROR, AArch64_AM_MSL, AArch64_AM_UXTB, AArch64_AM_UXTH, AArch64_AM_UXTW, AArch64_AM_UXTX, AArch64_AM_SXTB, AArch64_AM_SXTH, AArch64_AM_SXTW, AArch64_AM_SXTX, } AArch64_AM_ShiftExtendType; /// getShiftName - Get the string encoding for the shift type. static inline const char *AArch64_AM_getShiftExtendName(AArch64_AM_ShiftExtendType ST) { switch (ST) { default: return NULL; // never reach case AArch64_AM_LSL: return "lsl"; case AArch64_AM_LSR: return "lsr"; case AArch64_AM_ASR: return "asr"; case AArch64_AM_ROR: return "ror"; case AArch64_AM_MSL: return "msl"; case AArch64_AM_UXTB: return "uxtb"; case AArch64_AM_UXTH: return "uxth"; case AArch64_AM_UXTW: return "uxtw"; case AArch64_AM_UXTX: return "uxtx"; case AArch64_AM_SXTB: return "sxtb"; case AArch64_AM_SXTH: return "sxth"; case AArch64_AM_SXTW: return "sxtw"; case AArch64_AM_SXTX: return "sxtx"; } } /// getShiftType - Extract the shift type. static inline AArch64_AM_ShiftExtendType AArch64_AM_getShiftType(unsigned Imm) { switch ((Imm >> 6) & 0x7) { default: return AArch64_AM_InvalidShiftExtend; case 0: return AArch64_AM_LSL; case 1: return AArch64_AM_LSR; case 2: return AArch64_AM_ASR; case 3: return AArch64_AM_ROR; case 4: return AArch64_AM_MSL; } } /// getShiftValue - Extract the shift value. static inline unsigned AArch64_AM_getShiftValue(unsigned Imm) { return Imm & 0x3f; } //===----------------------------------------------------------------------===// // Extends // /// getArithShiftValue - get the arithmetic shift value. static inline unsigned AArch64_AM_getArithShiftValue(unsigned Imm) { return Imm & 0x7; } /// getExtendType - Extract the extend type for operands of arithmetic ops. static inline AArch64_AM_ShiftExtendType AArch64_AM_getExtendType(unsigned Imm) { // assert((Imm & 0x7) == Imm && "invalid immediate!"); switch (Imm) { default: // llvm_unreachable("Compiler bug!"); case 0: return AArch64_AM_UXTB; case 1: return AArch64_AM_UXTH; case 2: return AArch64_AM_UXTW; case 3: return AArch64_AM_UXTX; case 4: return AArch64_AM_SXTB; case 5: return AArch64_AM_SXTH; case 6: return AArch64_AM_SXTW; case 7: return AArch64_AM_SXTX; } } static inline AArch64_AM_ShiftExtendType AArch64_AM_getArithExtendType(unsigned Imm) { return AArch64_AM_getExtendType((Imm >> 3) & 0x7); } static inline uint64_t ror(uint64_t elt, unsigned size) { return ((elt & 1) << (size-1)) | (elt >> 1); } /// decodeLogicalImmediate - Decode a logical immediate value in the form /// "N:immr:imms" (where the immr and imms fields are each 6 bits) into the /// integer value it represents with regSize bits. static inline uint64_t AArch64_AM_decodeLogicalImmediate(uint64_t val, unsigned regSize) { // Extract the N, imms, and immr fields. unsigned N = (val >> 12) & 1; unsigned immr = (val >> 6) & 0x3f; unsigned imms = val & 0x3f; unsigned i; // assert((regSize == 64 || N == 0) && "undefined logical immediate encoding"); int len = 31 - countLeadingZeros((N << 6) | (~imms & 0x3f)); // assert(len >= 0 && "undefined logical immediate encoding"); unsigned size = (1 << len); unsigned R = immr & (size - 1); unsigned S = imms & (size - 1); // assert(S != size - 1 && "undefined logical immediate encoding"); uint64_t pattern = (1ULL << (S + 1)) - 1; for (i = 0; i < R; ++i) pattern = ror(pattern, size); // Replicate the pattern to fill the regSize. while (size != regSize) { pattern |= (pattern << size); size *= 2; } return pattern; } /// isValidDecodeLogicalImmediate - Check to see if the logical immediate value /// in the form "N:immr:imms" (where the immr and imms fields are each 6 bits) /// is a valid encoding for an integer value with regSize bits. static inline bool AArch64_AM_isValidDecodeLogicalImmediate(uint64_t val, unsigned regSize) { unsigned size; unsigned S; int len; // Extract the N and imms fields needed for checking. unsigned N = (val >> 12) & 1; unsigned imms = val & 0x3f; if (regSize == 32 && N != 0) // undefined logical immediate encoding return false; len = 31 - countLeadingZeros((N << 6) | (~imms & 0x3f)); if (len < 0) // undefined logical immediate encoding return false; size = (1 << len); S = imms & (size - 1); if (S == size - 1) // undefined logical immediate encoding return false; return true; } //===----------------------------------------------------------------------===// // Floating-point Immediates // static inline float AArch64_AM_getFPImmFloat(unsigned Imm) { // We expect an 8-bit binary encoding of a floating-point number here. union { uint32_t I; float F; } FPUnion; uint8_t Sign = (Imm >> 7) & 0x1; uint8_t Exp = (Imm >> 4) & 0x7; uint8_t Mantissa = Imm & 0xf; // 8-bit FP iEEEE Float Encoding // abcd efgh aBbbbbbc defgh000 00000000 00000000 // // where B = NOT(b); FPUnion.I = 0; FPUnion.I |= Sign << 31; FPUnion.I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30; FPUnion.I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25; FPUnion.I |= (Exp & 0x3) << 23; FPUnion.I |= Mantissa << 19; return FPUnion.F; } //===--------------------------------------------------------------------===// // AdvSIMD Modified Immediates //===--------------------------------------------------------------------===// static inline uint64_t AArch64_AM_decodeAdvSIMDModImmType10(uint8_t Imm) { static const uint32_t lookup[16] = { 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff }; return lookup[Imm & 0x0f] | ((uint64_t)lookup[Imm >> 4] << 32); } #endif