Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ARMUtils.h
39642 views
//===-- ARMUtils.h ----------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H9#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H1011#include "ARMDefines.h"12#include "InstructionUtils.h"13#include "llvm/ADT/bit.h"14#include "llvm/Support/MathExtras.h"1516// Common utilities for the ARM/Thumb Instruction Set Architecture.1718namespace lldb_private {1920static inline uint32_t Align(uint32_t val, uint32_t alignment) {21return alignment * (val / alignment);22}2324static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5,25ARM_ShifterType &shift_t) {26switch (type) {27default:28assert(0 && "Invalid shift type");29break;30case 0:31shift_t = SRType_LSL;32return imm5;33case 1:34shift_t = SRType_LSR;35return (imm5 == 0 ? 32 : imm5);36case 2:37shift_t = SRType_ASR;38return (imm5 == 0 ? 32 : imm5);39case 3:40if (imm5 == 0) {41shift_t = SRType_RRX;42return 1;43} else {44shift_t = SRType_ROR;45return imm5;46}47}48shift_t = SRType_Invalid;49return UINT32_MAX;50}5152// A8.6.35 CMP (register) -- Encoding T353// Convenience function.54static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode,55ARM_ShifterType &shift_t) {56return DecodeImmShift(Bits32(opcode, 5, 4),57Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6),58shift_t);59}6061// A8.6.35 CMP (register) -- Encoding A162// Convenience function.63static inline uint32_t DecodeImmShiftARM(const uint32_t opcode,64ARM_ShifterType &shift_t) {65return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);66}6768static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t,69const uint32_t imm5) {70ARM_ShifterType dont_care;71return DecodeImmShift(shift_t, imm5, dont_care);72}7374static inline ARM_ShifterType DecodeRegShift(const uint32_t type) {75switch (type) {76default:77// assert(0 && "Invalid shift type");78return SRType_Invalid;79case 0:80return SRType_LSL;81case 1:82return SRType_LSR;83case 2:84return SRType_ASR;85case 3:86return SRType_ROR;87}88}8990static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount,91uint32_t &carry_out, bool *success) {92if (amount == 0) {93*success = false;94return 0;95}96*success = true;97carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;98return value << amount;99}100101static inline uint32_t LSL(const uint32_t value, const uint32_t amount,102bool *success) {103*success = true;104if (amount == 0)105return value;106uint32_t dont_care;107uint32_t result = LSL_C(value, amount, dont_care, success);108if (*success)109return result;110else111return 0;112}113114static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount,115uint32_t &carry_out, bool *success) {116if (amount == 0) {117*success = false;118return 0;119}120*success = true;121carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;122return value >> amount;123}124125static inline uint32_t LSR(const uint32_t value, const uint32_t amount,126bool *success) {127*success = true;128if (amount == 0)129return value;130uint32_t dont_care;131uint32_t result = LSR_C(value, amount, dont_care, success);132if (*success)133return result;134else135return 0;136}137138static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount,139uint32_t &carry_out, bool *success) {140if (amount == 0 || amount > 32) {141*success = false;142return 0;143}144*success = true;145bool negative = BitIsSet(value, 31);146if (amount <= 32) {147carry_out = Bit32(value, amount - 1);148int64_t extended = llvm::SignExtend64<32>(value);149return UnsignedBits(extended, amount + 31, amount);150} else {151carry_out = (negative ? 1 : 0);152return (negative ? 0xffffffff : 0);153}154}155156static inline uint32_t ASR(const uint32_t value, const uint32_t amount,157bool *success) {158*success = true;159if (amount == 0)160return value;161uint32_t dont_care;162uint32_t result = ASR_C(value, amount, dont_care, success);163if (*success)164return result;165else166return 0;167}168169static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount,170uint32_t &carry_out, bool *success) {171if (amount == 0) {172*success = false;173return 0;174}175*success = true;176uint32_t result = llvm::rotr<uint32_t>(value, amount);177carry_out = Bit32(value, 31);178return result;179}180181static inline uint32_t ROR(const uint32_t value, const uint32_t amount,182bool *success) {183*success = true;184if (amount == 0)185return value;186uint32_t dont_care;187uint32_t result = ROR_C(value, amount, dont_care, success);188if (*success)189return result;190else191return 0;192}193194static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in,195uint32_t &carry_out, bool *success) {196*success = true;197carry_out = Bit32(value, 0);198return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);199}200201static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in,202bool *success) {203*success = true;204uint32_t dont_care;205uint32_t result = RRX_C(value, carry_in, dont_care, success);206if (*success)207return result;208else209return 0;210}211212static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type,213const uint32_t amount, const uint32_t carry_in,214uint32_t &carry_out, bool *success) {215if (type == SRType_RRX && amount != 1) {216*success = false;217return 0;218}219*success = true;220221if (amount == 0) {222carry_out = carry_in;223return value;224}225uint32_t result;226switch (type) {227case SRType_LSL:228result = LSL_C(value, amount, carry_out, success);229break;230case SRType_LSR:231result = LSR_C(value, amount, carry_out, success);232break;233case SRType_ASR:234result = ASR_C(value, amount, carry_out, success);235break;236case SRType_ROR:237result = ROR_C(value, amount, carry_out, success);238break;239case SRType_RRX:240result = RRX_C(value, carry_in, carry_out, success);241break;242default:243*success = false;244break;245}246if (*success)247return result;248else249return 0;250}251252static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type,253const uint32_t amount, const uint32_t carry_in,254bool *success) {255// Don't care about carry out in this case.256uint32_t dont_care;257uint32_t result = Shift_C(value, type, amount, carry_in, dont_care, success);258if (*success)259return result;260else261return 0;262}263264static inline uint32_t bits(const uint32_t val, const uint32_t msbit,265const uint32_t lsbit) {266return Bits32(val, msbit, lsbit);267}268269static inline uint32_t bit(const uint32_t val, const uint32_t msbit) {270return bits(val, msbit, msbit);271}272273static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift) {274uint32_t m = shift % N;275return (val >> m) | (val << (N - m));276}277278// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)279static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in,280uint32_t &carry_out) {281uint32_t imm32; // the expanded result282uint32_t imm = bits(opcode, 7, 0); // immediate value283uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount284if (amt == 0) {285imm32 = imm;286carry_out = carry_in;287} else {288imm32 = ror(imm, 32, amt);289carry_out = Bit32(imm32, 31);290}291return imm32;292}293294static inline uint32_t ARMExpandImm(uint32_t opcode) {295// 'carry_in' argument to following function call does not affect the imm32296// result.297uint32_t carry_in = 0;298uint32_t carry_out;299return ARMExpandImm_C(opcode, carry_in, carry_out);300}301302// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)303static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in,304uint32_t &carry_out) {305uint32_t imm32 = 0; // the expanded result306const uint32_t i = bit(opcode, 26);307const uint32_t imm3 = bits(opcode, 14, 12);308const uint32_t abcdefgh = bits(opcode, 7, 0);309const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;310311if (bits(imm12, 11, 10) == 0) {312switch (bits(imm12, 9, 8)) {313default: // Keep static analyzer happy with a default case314break;315316case 0:317imm32 = abcdefgh;318break;319320case 1:321imm32 = abcdefgh << 16 | abcdefgh;322break;323324case 2:325imm32 = abcdefgh << 24 | abcdefgh << 8;326break;327328case 3:329imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;330break;331}332carry_out = carry_in;333} else {334const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);335imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));336carry_out = Bit32(imm32, 31);337}338return imm32;339}340341static inline uint32_t ThumbExpandImm(uint32_t opcode) {342// 'carry_in' argument to following function call does not affect the imm32343// result.344uint32_t carry_in = 0;345uint32_t carry_out;346return ThumbExpandImm_C(opcode, carry_in, carry_out);347}348349// imm32 = ZeroExtend(i:imm3:imm8, 32)350static inline uint32_t ThumbImm12(uint32_t opcode) {351const uint32_t i = bit(opcode, 26);352const uint32_t imm3 = bits(opcode, 14, 12);353const uint32_t imm8 = bits(opcode, 7, 0);354const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;355return imm12;356}357358// imm32 = ZeroExtend(imm7:'00', 32)359static inline uint32_t ThumbImm7Scaled(uint32_t opcode) {360const uint32_t imm7 = bits(opcode, 6, 0);361return imm7 * 4;362}363364// imm32 = ZeroExtend(imm8:'00', 32)365static inline uint32_t ThumbImm8Scaled(uint32_t opcode) {366const uint32_t imm8 = bits(opcode, 7, 0);367return imm8 * 4;368}369370// This function performs the check for the register numbers 13 and 15 that are371// not permitted for many Thumb register specifiers.372static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }373374} // namespace lldb_private375376#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H377378379