diff --git a/src/common/bit_util.h b/src/common/bit_util.h index 723fffa74..9c9dc619e 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h @@ -2,31 +2,44 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include -#include namespace BitUtil { -/// Extract bits [begin_bit, end_bit] inclusive from s of type T. -template -constexpr T Bits(T s) { - static_assert(begin_bit <= end_bit, "bit range must begin before it ends"); - static_assert(begin_bit < sizeof(s) * 8, "begin_bit must be smaller than size of T"); - static_assert(end_bit < sizeof(s) * 8, "begin_bit must be smaller than size of T"); - - return (s >> begin_bit) & ((1 << (end_bit - begin_bit + 1)) - 1); +/// The size of a type in terms of bits +template +constexpr size_t BitSize() { + return sizeof(T) * CHAR_BIT; } -/// Sign-extends a val of type T that has NBits bits. +/// Extract bits [begin_bit, end_bit] inclusive from val of type T. +template +constexpr T Bits(const T value) { + static_assert(begin_bit <= end_bit, "bit range must begin before it ends"); + static_assert(begin_bit < BitSize(), "begin_bit must be smaller than size of T"); + static_assert(end_bit < BitSize(), "begin_bit must be smaller than size of T"); + + return (value >> begin_bit) & ((1 << (end_bit - begin_bit + 1)) - 1); +} + +/// Extracts a single bit at bit_position from val of type T. +template +constexpr T Bit(const T value) { + return Bits(value); +} + +/// Sign-extends a val that has NBits bits to the full bitwidth of type T. template -inline T SignExtend(const T val) { - static_assert(std::is_signed(), "T must be signed"); - static_assert(NBits <= 8 * sizeof(T), "NBits larger that bitsize of T"); +inline T SignExtend(const T value) { + static_assert(NBits <= BitSize(), "NBits larger that bitsize of T"); - using unsignedT = typename std::make_unsigned::type; - - constexpr size_t shift = 8 * sizeof(T) - NBits; - return static_cast(static_cast(val) << shift) >> shift; + constexpr T mask = static_cast(1ULL << NBits) - 1; + const T signbit = (value >> NBits) & 1; + if (signbit != 0) { + return value | ~mask; + } + return value; } } // namespace BitUtil diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index 40cdf34c2..cf3bc12e1 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -519,7 +519,7 @@ std::string ARM_Disasm::DisassembleBLX(u32 insn) if ((insn & 0xFE000000) == 0xFA000000) { u32 imm24 = insn & 0xFFFFFF; u32 H = (insn >> 24) & 1; - s32 offset = BitUtil::SignExtend<26, s32>((imm24 << 2) + (H << 1)) + 8; + s32 offset = BitUtil::SignExtend<26>((imm24 << 2) + (H << 1)) + 8; return Common::StringFromFormat("blx\t#+%d", offset); } else if ((insn & 0x0FFFFFF0) == 0x012FFF30) { u8 cond = (insn >> 28) & 0xf; diff --git a/src/core/arm/jit_x64/instructions/branch.cpp b/src/core/arm/jit_x64/instructions/branch.cpp index 53516b312..400d55973 100644 --- a/src/core/arm/jit_x64/instructions/branch.cpp +++ b/src/core/arm/jit_x64/instructions/branch.cpp @@ -13,7 +13,7 @@ using namespace Gen; void JitX64::B(Cond cond, ArmImm24 imm24) { cond_manager.CompileCond(cond); - const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<26, s32>(imm24 << 2); + const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<26>(imm24 << 2); reg_alloc.FlushEverything(); current.arm_pc += GetInstSize(); @@ -28,7 +28,7 @@ void JitX64::B(Cond cond, ArmImm24 imm24) { void JitX64::BL(Cond cond, ArmImm24 imm24) { cond_manager.CompileCond(cond); - const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<26, s32>(imm24 << 2); + const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<26>(imm24 << 2); ASSERT(!current.TFlag); const u32 link_pc = current.arm_pc + GetInstSize(); @@ -49,7 +49,7 @@ void JitX64::BL(Cond cond, ArmImm24 imm24) { void JitX64::BLX_imm(bool H, ArmImm24 imm24) { cond_manager.Always(); - const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<26, s32>(imm24 << 2) + (H ? 2 : 0); + const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<26>(imm24 << 2) + (H ? 2 : 0); ASSERT(!current.TFlag); const u32 link_pc = current.arm_pc + GetInstSize(); diff --git a/src/core/arm/jit_x64/instructions/thumb.cpp b/src/core/arm/jit_x64/instructions/thumb.cpp index d82ecfb1e..7bb0be1c3 100644 --- a/src/core/arm/jit_x64/instructions/thumb.cpp +++ b/src/core/arm/jit_x64/instructions/thumb.cpp @@ -16,7 +16,7 @@ void JitX64::thumb_B(Cond cond, ArmImm8 imm8) { ASSERT_MSG(current.TFlag, "thumb_B may only be called in thumb mode"); - const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<9, s32>(imm8 << 1); + const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<9>(imm8 << 1); reg_alloc.FlushEverything(); current.arm_pc += GetInstSize(); @@ -33,7 +33,7 @@ void JitX64::thumb_B(ArmImm11 imm11) { ASSERT_MSG(current.TFlag, "thumb_B may only be called in thumb mode"); - const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<12, s32>(imm11 << 1); + const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<12>(imm11 << 1); reg_alloc.FlushEverything(); current.arm_pc += GetInstSize(); @@ -73,11 +73,11 @@ void JitX64::thumb_BLX_suffix(bool X, ArmImm11 imm11) { ASSERT_MSG(current.TFlag, "thumb_BLX_suffix should only be called in thumb mode, pc = %u", current.arm_pc); u32 new_pc = (current.arm_pc + 2) + - BitUtil::SignExtend<23, s32>(thumb_BLX_prefix_imm11 << 12) + + BitUtil::SignExtend<23>(thumb_BLX_prefix_imm11 << 12) + (imm11 << 1); u32 new_lr = (current.arm_pc + 2) | 1; - Gen::OpArg LR = reg_alloc.LockArmForWrite(ArmReg::LR); + OpArg LR = reg_alloc.LockArmForWrite(ArmReg::LR); code->MOV(32, LR, Imm32(new_lr)); reg_alloc.UnlockArm(ArmReg::LR);