Browse Source

[dynarmic] cleanup duplicate code and reimpls of std::* bit stuff (#4017)

A bit of a minor cleanup
- std::rotr instead of mcl::bit::rotate_right
- std::rotl likewise
- std::popcount instaed of "count ones"
- use ConvertRoundingModeToX64Immediate where appropiate
- std integral

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4017
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
lizzie/tryfixrandomvkshit
lizzie 4 days ago
committed by crueter
parent
commit
5f4a286046
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 2
      src/dynarmic/src/dynarmic/backend/arm64/fastmem.h
  2. 4
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp
  3. 2
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp
  4. 2
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp
  5. 30
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp
  6. 4
      src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h
  7. 2
      src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_misc.cpp
  8. 32
      src/dynarmic/src/dynarmic/frontend/A32/translate/impl/load_store.cpp
  9. 14
      src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp
  10. 8
      src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp
  11. 2
      src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.cpp
  12. 14
      src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_copy.cpp
  13. 10
      src/dynarmic/src/dynarmic/ir/opt_passes.cpp
  14. 137
      src/dynarmic/src/dynarmic/mcl/bit.hpp
  15. 8
      src/dynarmic/src/dynarmic/mcl/integer_of_size.hpp
  16. 15
      src/dynarmic/src/dynarmic/mcl/is_instance_of_template.hpp
  17. 2
      src/dynarmic/tests/A32/fuzz_arm.cpp
  18. 12
      tools/gendynarm.cpp

2
src/dynarmic/src/dynarmic/backend/arm64/fastmem.h

@ -24,7 +24,7 @@ using DoNotFastmemMarker = std::tuple<IR::LocationDescriptor, unsigned>;
constexpr std::size_t xmrx(std::size_t x) noexcept { constexpr std::size_t xmrx(std::size_t x) noexcept {
x ^= x >> 32; x ^= x >> 32;
x *= 0xff51afd7ed558ccd; x *= 0xff51afd7ed558ccd;
x ^= mcl::bit::rotate_right(x, 47) ^ mcl::bit::rotate_right(x, 23);
x ^= std::rotr(x, 47) ^ std::rotr(x, 23);
return x; return x;
} }

4
src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp

@ -1532,7 +1532,7 @@ void EmitX64::EmitFPSingleToHalf(EmitContext& ctx, IR::Inst* inst) {
if (ctx.FPCR().DN()) { if (ctx.FPCR().DN()) {
ForceToDefaultNaN<32>(code, result); ForceToDefaultNaN<32>(code, result);
} }
code.vcvtps2ph(result, result, static_cast<u8>(*round_imm));
code.vcvtps2ph(result, result, u8(*round_imm));
ctx.reg_alloc.DefineValue(code, inst, result); ctx.reg_alloc.DefineValue(code, inst, result);
return; return;
@ -1540,7 +1540,7 @@ void EmitX64::EmitFPSingleToHalf(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(code, inst, args[0]); ctx.reg_alloc.HostCall(code, inst, args[0]);
code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value());
code.mov(code.ABI_PARAM3.cvt32(), static_cast<u32>(rounding_mode));
code.mov(code.ABI_PARAM3.cvt32(), u32(rounding_mode));
code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPConvert<u16, u32>); code.CallFunction(&FP::FPConvert<u16, u32>);
} }

2
src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp

@ -38,7 +38,7 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst)
Xbyak::Reg addend = ctx.reg_alloc.UseGpr(code, args[1]).changeBit(size); Xbyak::Reg addend = ctx.reg_alloc.UseGpr(code, args[1]).changeBit(size);
Xbyak::Reg overflow = ctx.reg_alloc.ScratchGpr(code).changeBit(size); Xbyak::Reg overflow = ctx.reg_alloc.ScratchGpr(code).changeBit(size);
constexpr u64 int_max = static_cast<u64>((std::numeric_limits<mcl::signed_integer_of_size<size>>::max)());
constexpr u64 int_max = u64((std::numeric_limits<std::make_signed_t<mcl::unsigned_integer_of_size<size>>>::max)());
if constexpr (size < 64) { if constexpr (size < 64) {
code.xor_(overflow.cvt32(), overflow.cvt32()); code.xor_(overflow.cvt32(), overflow.cvt32());
code.bt(result.cvt32(), size - 1); code.bt(result.cvt32(), size - 1);

2
src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp

@ -3553,7 +3553,7 @@ void EmitX64::EmitVectorPopulationCount(EmitContext& ctx, IR::Inst* inst) {
EmitOneArgumentFallback(code, ctx, inst, [](VectorArray<u8>& result, const VectorArray<u8>& a) { EmitOneArgumentFallback(code, ctx, inst, [](VectorArray<u8>& result, const VectorArray<u8>& a) {
std::transform(a.begin(), a.end(), result.begin(), [](u8 val) { std::transform(a.begin(), a.end(), result.begin(), [](u8 val) {
return static_cast<u8>(mcl::bit::count_ones(val));
return static_cast<u8>(std::popcount(val));
}); });
}); });
} }

30
src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp

@ -1657,20 +1657,10 @@ void EmitFPVectorRoundInt(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
if constexpr (fsize != 16) { if constexpr (fsize != 16) {
if (code.HasHostFeature(HostFeature::SSE41) && rounding != FP::RoundingMode::ToNearest_TieAwayFromZero && !exact) { if (code.HasHostFeature(HostFeature::SSE41) && rounding != FP::RoundingMode::ToNearest_TieAwayFromZero && !exact) {
const u8 round_imm = [&]() -> u8 {
switch (rounding) {
case FP::RoundingMode::ToNearest_TieEven: return 0b00;
case FP::RoundingMode::TowardsPlusInfinity: return 0b10;
case FP::RoundingMode::TowardsMinusInfinity: return 0b01;
case FP::RoundingMode::TowardsZero: return 0b11;
default: UNREACHABLE();
}
}();
const auto round_imm = ConvertRoundingModeToX64Immediate(rounding);
EmitTwoOpVectorOperation<fsize, DefaultIndexer, 3>(code, ctx, inst, [&](const Xbyak::Xmm& result, const Xbyak::Xmm& xmm_a) { EmitTwoOpVectorOperation<fsize, DefaultIndexer, 3>(code, ctx, inst, [&](const Xbyak::Xmm& result, const Xbyak::Xmm& xmm_a) {
FCODE(roundp)(result, xmm_a, round_imm);
FCODE(roundp)(result, xmm_a, *round_imm);
}); });
return; return;
} }
} }
@ -2002,19 +1992,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const Xbyak::Xmm src = ctx.reg_alloc.UseScratchXmm(code, args[0]); const Xbyak::Xmm src = ctx.reg_alloc.UseScratchXmm(code, args[0]);
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] { MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
const int round_imm = [&] {
switch (rounding) {
case FP::RoundingMode::ToNearest_TieEven:
default:
return 0b00;
case FP::RoundingMode::TowardsPlusInfinity:
return 0b10;
case FP::RoundingMode::TowardsMinusInfinity:
return 0b01;
case FP::RoundingMode::TowardsZero:
return 0b11;
}
}();
const auto round_imm = ConvertRoundingModeToX64Immediate(rounding);
const auto perform_conversion = [&code, &ctx](const Xbyak::Xmm& src) { const auto perform_conversion = [&code, &ctx](const Xbyak::Xmm& src) {
// MSVC doesn't allow us to use a [&] capture, so we have to do this instead. // MSVC doesn't allow us to use a [&] capture, so we have to do this instead.
(void)ctx; (void)ctx;
@ -2046,7 +2024,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
FCODE(mulp)(src, GetVectorOf<fsize>(code, scale_factor)); FCODE(mulp)(src, GetVectorOf<fsize>(code, scale_factor));
} }
FCODE(roundp)(src, src, u8(round_imm));
FCODE(roundp)(src, src, u8(*round_imm));
const Xbyak::Xmm nan_mask = xmm0; const Xbyak::Xmm nan_mask = xmm0;
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) { if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
static constexpr u32 nan_to_zero = FixupLUT(FpFixup::PosZero, FpFixup::PosZero); static constexpr u32 nan_to_zero = FixupLUT(FpFixup::PosZero, FpFixup::PosZero);

4
src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h

@ -52,7 +52,7 @@ struct TranslatorVisitor final {
u32 imm32 = imm8.ZeroExtend(); u32 imm32 = imm8.ZeroExtend();
auto carry_out = carry_in; auto carry_out = carry_in;
if (rotate) { if (rotate) {
imm32 = mcl::bit::rotate_right<u32>(imm8.ZeroExtend(), rotate * 2);
imm32 = std::rotr<u32>(imm8.ZeroExtend(), rotate * 2);
carry_out = ir.Imm1(mcl::bit::get_bit<31>(imm32)); carry_out = ir.Imm1(mcl::bit::get_bit<31>(imm32));
} }
return {imm32, carry_out}; return {imm32, carry_out};
@ -81,7 +81,7 @@ struct TranslatorVisitor final {
}(); }();
return {imm32, carry_in}; return {imm32, carry_in};
} }
const u32 imm32 = mcl::bit::rotate_right<u32>((1 << 7) | imm12.Bits<0, 6>(), imm12.Bits<7, 11>());
const u32 imm32 = std::rotr<u32>((1 << 7) | imm12.Bits<0, 6>(), imm12.Bits<7, 11>());
return {imm32, ir.Imm1(mcl::bit::get_bit<31>(imm32))}; return {imm32, ir.Imm1(mcl::bit::get_bit<31>(imm32))};
} }

2
src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_misc.cpp

@ -79,7 +79,7 @@ bool TranslatorVisitor::asimd_VDUP_scalar(bool D, Imm<4> imm4, size_t Vd, bool Q
return UndefinedInstruction(); return UndefinedInstruction();
} }
const size_t imm4_lsb = mcl::bit::lowest_set_bit(imm4.ZeroExtend());
const size_t imm4_lsb = std::countr_zero(imm4.ZeroExtend());
const size_t esize = 8u << imm4_lsb; const size_t esize = 8u << imm4_lsb;
const size_t index = imm4.ZeroExtend() >> (imm4_lsb + 1); const size_t index = imm4.ZeroExtend() >> (imm4_lsb + 1);
const auto d = ToVector(Q, Vd, D); const auto d = ToVector(Q, Vd, D);

32
src/dynarmic/src/dynarmic/frontend/A32/translate/impl/load_store.cpp

@ -799,7 +799,7 @@ static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 s
// LDM <Rn>{!}, <reg_list> // LDM <Rn>{!}, <reg_list>
bool TranslatorVisitor::arm_LDM(Cond cond, bool W, Reg n, RegList list) { bool TranslatorVisitor::arm_LDM(Cond cond, bool W, Reg n, RegList list) {
if (n == Reg::PC || mcl::bit::count_ones(list) < 1) {
if (n == Reg::PC || std::popcount(list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
if (W && mcl::bit::get_bit(static_cast<size_t>(n), list)) { if (W && mcl::bit::get_bit(static_cast<size_t>(n), list)) {
@ -811,13 +811,13 @@ bool TranslatorVisitor::arm_LDM(Cond cond, bool W, Reg n, RegList list) {
} }
const auto start_address = ir.GetRegister(n); const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(mcl::bit::count_ones(list) * 4)));
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(std::popcount(list) * 4)));
return LDMHelper(ir, W, n, list, start_address, writeback_address); return LDMHelper(ir, W, n, list, start_address, writeback_address);
} }
// LDMDA <Rn>{!}, <reg_list> // LDMDA <Rn>{!}, <reg_list>
bool TranslatorVisitor::arm_LDMDA(Cond cond, bool W, Reg n, RegList list) { bool TranslatorVisitor::arm_LDMDA(Cond cond, bool W, Reg n, RegList list) {
if (n == Reg::PC || mcl::bit::count_ones(list) < 1) {
if (n == Reg::PC || std::popcount(list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
if (W && mcl::bit::get_bit(static_cast<size_t>(n), list)) { if (W && mcl::bit::get_bit(static_cast<size_t>(n), list)) {
@ -828,14 +828,14 @@ bool TranslatorVisitor::arm_LDMDA(Cond cond, bool W, Reg n, RegList list) {
return true; return true;
} }
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list) - 4)));
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * std::popcount(list) - 4)));
const auto writeback_address = ir.Sub(start_address, ir.Imm32(4)); const auto writeback_address = ir.Sub(start_address, ir.Imm32(4));
return LDMHelper(ir, W, n, list, start_address, writeback_address); return LDMHelper(ir, W, n, list, start_address, writeback_address);
} }
// LDMDB <Rn>{!}, <reg_list> // LDMDB <Rn>{!}, <reg_list>
bool TranslatorVisitor::arm_LDMDB(Cond cond, bool W, Reg n, RegList list) { bool TranslatorVisitor::arm_LDMDB(Cond cond, bool W, Reg n, RegList list) {
if (n == Reg::PC || mcl::bit::count_ones(list) < 1) {
if (n == Reg::PC || std::popcount(list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
if (W && mcl::bit::get_bit(static_cast<size_t>(n), list)) { if (W && mcl::bit::get_bit(static_cast<size_t>(n), list)) {
@ -846,14 +846,14 @@ bool TranslatorVisitor::arm_LDMDB(Cond cond, bool W, Reg n, RegList list) {
return true; return true;
} }
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * std::popcount(list))));
const auto writeback_address = start_address; const auto writeback_address = start_address;
return LDMHelper(ir, W, n, list, start_address, writeback_address); return LDMHelper(ir, W, n, list, start_address, writeback_address);
} }
// LDMIB <Rn>{!}, <reg_list> // LDMIB <Rn>{!}, <reg_list>
bool TranslatorVisitor::arm_LDMIB(Cond cond, bool W, Reg n, RegList list) { bool TranslatorVisitor::arm_LDMIB(Cond cond, bool W, Reg n, RegList list) {
if (n == Reg::PC || mcl::bit::count_ones(list) < 1) {
if (n == Reg::PC || std::popcount(list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
if (W && mcl::bit::get_bit(static_cast<size_t>(n), list)) { if (W && mcl::bit::get_bit(static_cast<size_t>(n), list)) {
@ -865,7 +865,7 @@ bool TranslatorVisitor::arm_LDMIB(Cond cond, bool W, Reg n, RegList list) {
} }
const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4)); const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4));
const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * std::popcount(list))));
return LDMHelper(ir, W, n, list, start_address, writeback_address); return LDMHelper(ir, W, n, list, start_address, writeback_address);
} }
@ -896,7 +896,7 @@ static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 s
// STM <Rn>{!}, <reg_list> // STM <Rn>{!}, <reg_list>
bool TranslatorVisitor::arm_STM(Cond cond, bool W, Reg n, RegList list) { bool TranslatorVisitor::arm_STM(Cond cond, bool W, Reg n, RegList list) {
if (n == Reg::PC || mcl::bit::count_ones(list) < 1) {
if (n == Reg::PC || std::popcount(list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
@ -905,13 +905,13 @@ bool TranslatorVisitor::arm_STM(Cond cond, bool W, Reg n, RegList list) {
} }
const auto start_address = ir.GetRegister(n); const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(mcl::bit::count_ones(list) * 4)));
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(std::popcount(list) * 4)));
return STMHelper(ir, W, n, list, start_address, writeback_address); return STMHelper(ir, W, n, list, start_address, writeback_address);
} }
// STMDA <Rn>{!}, <reg_list> // STMDA <Rn>{!}, <reg_list>
bool TranslatorVisitor::arm_STMDA(Cond cond, bool W, Reg n, RegList list) { bool TranslatorVisitor::arm_STMDA(Cond cond, bool W, Reg n, RegList list) {
if (n == Reg::PC || mcl::bit::count_ones(list) < 1) {
if (n == Reg::PC || std::popcount(list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
@ -919,14 +919,14 @@ bool TranslatorVisitor::arm_STMDA(Cond cond, bool W, Reg n, RegList list) {
return true; return true;
} }
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list) - 4)));
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * std::popcount(list) - 4)));
const auto writeback_address = ir.Sub(start_address, ir.Imm32(4)); const auto writeback_address = ir.Sub(start_address, ir.Imm32(4));
return STMHelper(ir, W, n, list, start_address, writeback_address); return STMHelper(ir, W, n, list, start_address, writeback_address);
} }
// STMDB <Rn>{!}, <reg_list> // STMDB <Rn>{!}, <reg_list>
bool TranslatorVisitor::arm_STMDB(Cond cond, bool W, Reg n, RegList list) { bool TranslatorVisitor::arm_STMDB(Cond cond, bool W, Reg n, RegList list) {
if (n == Reg::PC || mcl::bit::count_ones(list) < 1) {
if (n == Reg::PC || std::popcount(list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
@ -934,14 +934,14 @@ bool TranslatorVisitor::arm_STMDB(Cond cond, bool W, Reg n, RegList list) {
return true; return true;
} }
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * std::popcount(list))));
const auto writeback_address = start_address; const auto writeback_address = start_address;
return STMHelper(ir, W, n, list, start_address, writeback_address); return STMHelper(ir, W, n, list, start_address, writeback_address);
} }
// STMIB <Rn>{!}, <reg_list> // STMIB <Rn>{!}, <reg_list>
bool TranslatorVisitor::arm_STMIB(Cond cond, bool W, Reg n, RegList list) { bool TranslatorVisitor::arm_STMIB(Cond cond, bool W, Reg n, RegList list) {
if (n == Reg::PC || mcl::bit::count_ones(list) < 1) {
if (n == Reg::PC || std::popcount(list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
@ -950,7 +950,7 @@ bool TranslatorVisitor::arm_STMIB(Cond cond, bool W, Reg n, RegList list) {
} }
const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4)); const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4));
const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * std::popcount(list))));
return STMHelper(ir, W, n, list, start_address, writeback_address); return STMHelper(ir, W, n, list, start_address, writeback_address);
} }

14
src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp

@ -688,7 +688,7 @@ bool TranslatorVisitor::thumb16_NOP() {
// IT{<x>{<y>{<z>}}} <cond> // IT{<x>{<y>{<z>}}} <cond>
bool TranslatorVisitor::thumb16_IT(Imm<8> imm8) { bool TranslatorVisitor::thumb16_IT(Imm<8> imm8) {
ASSERT((imm8.Bits<0, 3>() != 0b0000) && "Decode Error"); ASSERT((imm8.Bits<0, 3>() != 0b0000) && "Decode Error");
if (imm8.Bits<4, 7>() == 0b1111 || (imm8.Bits<4, 7>() == 0b1110 && mcl::bit::count_ones(imm8.Bits<0, 3>()) != 1)) {
if (imm8.Bits<4, 7>() == 0b1111 || (imm8.Bits<4, 7>() == 0b1110 && std::popcount(imm8.Bits<0, 3>()) != 1)) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
if (ir.current_location.IT().IsInITBlock()) { if (ir.current_location.IT().IsInITBlock()) {
@ -738,11 +738,11 @@ bool TranslatorVisitor::thumb16_PUSH(bool M, RegList reg_list) {
if (M) { if (M) {
reg_list |= 1 << 14; reg_list |= 1 << 14;
} }
if (mcl::bit::count_ones(reg_list) < 1) {
if (std::popcount(reg_list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
const u32 num_bytes_to_push = static_cast<u32>(4 * mcl::bit::count_ones(reg_list));
const u32 num_bytes_to_push = static_cast<u32>(4 * std::popcount(reg_list));
const auto final_address = ir.Sub(ir.GetRegister(Reg::SP), ir.Imm32(num_bytes_to_push)); const auto final_address = ir.Sub(ir.GetRegister(Reg::SP), ir.Imm32(num_bytes_to_push));
auto address = final_address; auto address = final_address;
for (size_t i = 0; i < 16; i++) { for (size_t i = 0; i < 16; i++) {
@ -764,7 +764,7 @@ bool TranslatorVisitor::thumb16_POP(bool P, RegList reg_list) {
if (P) { if (P) {
reg_list |= 1 << 15; reg_list |= 1 << 15;
} }
if (mcl::bit::count_ones(reg_list) < 1) {
if (std::popcount(reg_list) < 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
@ -851,10 +851,10 @@ bool TranslatorVisitor::thumb16_BKPT(Imm<8> /*imm8*/) {
// STM <Rn>!, <reg_list> // STM <Rn>!, <reg_list>
bool TranslatorVisitor::thumb16_STMIA(Reg n, RegList reg_list) { bool TranslatorVisitor::thumb16_STMIA(Reg n, RegList reg_list) {
if (mcl::bit::count_ones(reg_list) == 0) {
if (std::popcount(reg_list) == 0) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
if (mcl::bit::get_bit(static_cast<size_t>(n), reg_list) && n != static_cast<Reg>(mcl::bit::lowest_set_bit(reg_list))) {
if (mcl::bit::get_bit(static_cast<size_t>(n), reg_list) && n != static_cast<Reg>(std::countr_zero(reg_list))) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
@ -873,7 +873,7 @@ bool TranslatorVisitor::thumb16_STMIA(Reg n, RegList reg_list) {
// LDM <Rn>!, <reg_list> // LDM <Rn>!, <reg_list>
bool TranslatorVisitor::thumb16_LDMIA(Reg n, RegList reg_list) { bool TranslatorVisitor::thumb16_LDMIA(Reg n, RegList reg_list) {
if (mcl::bit::count_ones(reg_list) == 0) {
if (std::popcount(reg_list) == 0) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }

8
src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp

@ -53,7 +53,7 @@ static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32
bool TranslatorVisitor::thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list) { bool TranslatorVisitor::thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list) {
const auto regs_imm = reg_list.ZeroExtend(); const auto regs_imm = reg_list.ZeroExtend();
const auto num_regs = static_cast<u32>(mcl::bit::count_ones(regs_imm));
const auto num_regs = static_cast<u32>(std::popcount(regs_imm));
if (n == Reg::PC || num_regs < 2) { if (n == Reg::PC || num_regs < 2) {
return UnpredictableInstruction(); return UnpredictableInstruction();
@ -78,7 +78,7 @@ bool TranslatorVisitor::thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list) {
bool TranslatorVisitor::thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list) { bool TranslatorVisitor::thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list) {
const auto regs_imm = reg_list.ZeroExtend(); const auto regs_imm = reg_list.ZeroExtend();
const auto num_regs = static_cast<u32>(mcl::bit::count_ones(regs_imm));
const auto num_regs = static_cast<u32>(std::popcount(regs_imm));
if (n == Reg::PC || num_regs < 2) { if (n == Reg::PC || num_regs < 2) {
return UnpredictableInstruction(); return UnpredictableInstruction();
@ -111,7 +111,7 @@ bool TranslatorVisitor::thumb32_PUSH(Imm<15> reg_list) {
bool TranslatorVisitor::thumb32_STMIA(bool W, Reg n, Imm<15> reg_list) { bool TranslatorVisitor::thumb32_STMIA(bool W, Reg n, Imm<15> reg_list) {
const auto regs_imm = reg_list.ZeroExtend(); const auto regs_imm = reg_list.ZeroExtend();
const auto num_regs = static_cast<u32>(mcl::bit::count_ones(regs_imm));
const auto num_regs = static_cast<u32>(std::popcount(regs_imm));
if (n == Reg::PC || num_regs < 2) { if (n == Reg::PC || num_regs < 2) {
return UnpredictableInstruction(); return UnpredictableInstruction();
@ -130,7 +130,7 @@ bool TranslatorVisitor::thumb32_STMIA(bool W, Reg n, Imm<15> reg_list) {
bool TranslatorVisitor::thumb32_STMDB(bool W, Reg n, Imm<15> reg_list) { bool TranslatorVisitor::thumb32_STMDB(bool W, Reg n, Imm<15> reg_list) {
const auto regs_imm = reg_list.ZeroExtend(); const auto regs_imm = reg_list.ZeroExtend();
const auto num_regs = static_cast<u32>(mcl::bit::count_ones(regs_imm));
const auto num_regs = static_cast<u32>(std::popcount(regs_imm));
if (n == Reg::PC || num_regs < 2) { if (n == Reg::PC || num_regs < 2) {
return UnpredictableInstruction(); return UnpredictableInstruction();

2
src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.cpp

@ -55,7 +55,7 @@ std::optional<TranslatorVisitor::BitMasks> TranslatorVisitor::DecodeBitMasks(boo
const size_t esize = size_t{1} << len; const size_t esize = size_t{1} << len;
const u64 welem = mcl::bit::ones<u64>(S + 1); const u64 welem = mcl::bit::ones<u64>(S + 1);
const u64 telem = mcl::bit::ones<u64>(d + 1); const u64 telem = mcl::bit::ones<u64>(d + 1);
const u64 wmask = mcl::bit::rotate_right(mcl::bit::replicate_element<u64>(esize, welem), R);
const u64 wmask = std::rotr(mcl::bit::replicate_element<u64>(esize, welem), R);
const u64 tmask = mcl::bit::replicate_element<u64>(esize, telem); const u64 tmask = mcl::bit::replicate_element<u64>(esize, telem);
return BitMasks{wmask, tmask}; return BitMasks{wmask, tmask};

14
src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_copy.cpp

@ -13,7 +13,7 @@
namespace Dynarmic::A64 { namespace Dynarmic::A64 {
bool TranslatorVisitor::DUP_elt_1(Imm<5> imm5, Vec Vn, Vec Vd) { bool TranslatorVisitor::DUP_elt_1(Imm<5> imm5, Vec Vn, Vec Vd) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size > 3) { if (size > 3) {
return ReservedValue(); return ReservedValue();
} }
@ -30,7 +30,7 @@ bool TranslatorVisitor::DUP_elt_1(Imm<5> imm5, Vec Vn, Vec Vd) {
} }
bool TranslatorVisitor::DUP_elt_2(bool Q, Imm<5> imm5, Vec Vn, Vec Vd) { bool TranslatorVisitor::DUP_elt_2(bool Q, Imm<5> imm5, Vec Vn, Vec Vd) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size > 3) { if (size > 3) {
return ReservedValue(); return ReservedValue();
} }
@ -51,7 +51,7 @@ bool TranslatorVisitor::DUP_elt_2(bool Q, Imm<5> imm5, Vec Vn, Vec Vd) {
} }
bool TranslatorVisitor::DUP_gen(bool Q, Imm<5> imm5, Reg Rn, Vec Vd) { bool TranslatorVisitor::DUP_gen(bool Q, Imm<5> imm5, Reg Rn, Vec Vd) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size > 3) { if (size > 3) {
return ReservedValue(); return ReservedValue();
} }
@ -73,7 +73,7 @@ bool TranslatorVisitor::DUP_gen(bool Q, Imm<5> imm5, Reg Rn, Vec Vd) {
} }
bool TranslatorVisitor::SMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) { bool TranslatorVisitor::SMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size == 2 && !Q) { if (size == 2 && !Q) {
return UnallocatedEncoding(); return UnallocatedEncoding();
} }
@ -96,7 +96,7 @@ bool TranslatorVisitor::SMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) {
} }
bool TranslatorVisitor::UMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) { bool TranslatorVisitor::UMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size < 3 && Q) { if (size < 3 && Q) {
return UnallocatedEncoding(); return UnallocatedEncoding();
} }
@ -123,7 +123,7 @@ bool TranslatorVisitor::UMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) {
} }
bool TranslatorVisitor::INS_gen(Imm<5> imm5, Reg Rn, Vec Vd) { bool TranslatorVisitor::INS_gen(Imm<5> imm5, Reg Rn, Vec Vd) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size > 3) { if (size > 3) {
return ReservedValue(); return ReservedValue();
} }
@ -140,7 +140,7 @@ bool TranslatorVisitor::INS_gen(Imm<5> imm5, Reg Rn, Vec Vd) {
} }
bool TranslatorVisitor::INS_elt(Imm<5> imm5, Imm<4> imm4, Vec Vn, Vec Vd) { bool TranslatorVisitor::INS_elt(Imm<5> imm5, Imm<4> imm4, Vec Vn, Vec Vd) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size > 3) { if (size > 3) {
return ReservedValue(); return ReservedValue();
} }

10
src/dynarmic/src/dynarmic/ir/opt_passes.cpp

@ -9,6 +9,7 @@
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
#include <map> #include <map>
#include <bit>
#include <ankerl/unordered_dense.h> #include <ankerl/unordered_dense.h>
#include "boost/container/small_vector.hpp" #include "boost/container/small_vector.hpp"
@ -28,7 +29,6 @@
#include "dynarmic/ir/opt_passes.h" #include "dynarmic/ir/opt_passes.h"
#include "dynarmic/ir/type.h" #include "dynarmic/ir/type.h"
#include "dynarmic/mcl/bit.hpp" #include "dynarmic/mcl/bit.hpp"
#include "dynarmic/mcl/bit.hpp"
namespace Dynarmic::Optimization { namespace Dynarmic::Optimization {
@ -1074,12 +1074,12 @@ static void ConstantPropagation(IR::Block& block) {
break; break;
case Op::BitRotateRight32: case Op::BitRotateRight32:
if (FoldShifts(inst)) { if (FoldShifts(inst)) {
ReplaceUsesWith(inst, true, mcl::bit::rotate_right<u32>(inst.GetArg(0).GetU32(), inst.GetArg(1).GetU8()));
ReplaceUsesWith(inst, true, std::rotr<u32>(inst.GetArg(0).GetU32(), inst.GetArg(1).GetU8()));
} }
break; break;
case Op::BitRotateRight64: case Op::BitRotateRight64:
if (FoldShifts(inst)) { if (FoldShifts(inst)) {
ReplaceUsesWith(inst, false, mcl::bit::rotate_right<u64>(inst.GetArg(0).GetU64(), inst.GetArg(1).GetU8()));
ReplaceUsesWith(inst, false, std::rotr<u64>(inst.GetArg(0).GetU64(), inst.GetArg(1).GetU8()));
} }
break; break;
case Op::LogicalShiftLeftMasked32: case Op::LogicalShiftLeftMasked32:
@ -1114,12 +1114,12 @@ static void ConstantPropagation(IR::Block& block) {
break; break;
case Op::RotateRightMasked32: case Op::RotateRightMasked32:
if (inst.AreAllArgsImmediates()) { if (inst.AreAllArgsImmediates()) {
ReplaceUsesWith(inst, true, mcl::bit::rotate_right<u32>(inst.GetArg(0).GetU32(), inst.GetArg(1).GetU32()));
ReplaceUsesWith(inst, true, std::rotr<u32>(inst.GetArg(0).GetU32(), inst.GetArg(1).GetU32()));
} }
break; break;
case Op::RotateRightMasked64: case Op::RotateRightMasked64:
if (inst.AreAllArgsImmediates()) { if (inst.AreAllArgsImmediates()) {
ReplaceUsesWith(inst, false, mcl::bit::rotate_right<u64>(inst.GetArg(0).GetU64(), inst.GetArg(1).GetU64()));
ReplaceUsesWith(inst, false, std::rotr<u64>(inst.GetArg(0).GetU64(), inst.GetArg(1).GetU64()));
} }
break; break;
case Op::Add32: case Op::Add32:

137
src/dynarmic/src/dynarmic/mcl/bit.hpp

@ -8,26 +8,15 @@
#include <bitset> #include <bitset>
#include <climits> #include <climits>
#include <cstddef> #include <cstddef>
#include <concepts>
#include <bit>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/assert.h" #include "common/assert.h"
namespace mcl { namespace mcl {
namespace detail {
template<typename T, typename U>
concept SameHelper = std::is_same_v<T, U>;
} // namespace detail
template<typename T, typename U>
concept SameAs = detail::SameHelper<T, U> && detail::SameHelper<U, T>;
template<typename T, typename... U>
concept IsAnyOf = (SameAs<T, U> || ...);
/// Integral upon which bit operations can be safely performed.
template<typename T>
concept BitIntegral = IsAnyOf<T, u8, u16, u32, u64, std::uintptr_t, size_t>;
template<typename T> template<typename T>
constexpr std::size_t bitsizeof = CHAR_BIT * sizeof(T); constexpr std::size_t bitsizeof = CHAR_BIT * sizeof(T);
} // namespace mcl } // namespace mcl
namespace mcl::bit { namespace mcl::bit {
@ -71,58 +60,37 @@ constexpr u64 swap_words_64(u64 value) {
| ((value & 0x00000000ffffffffull) << 32); | ((value & 0x00000000ffffffffull) << 32);
} }
template<BitIntegral T>
constexpr T rotate_right(T x, size_t amount) {
amount %= bitsizeof<T>;
if (amount == 0) {
return x;
}
return static_cast<T>((x >> amount) | (x << (bitsizeof<T> - amount)));
}
template<BitIntegral T>
constexpr T rotate_left(T x, size_t amount) {
amount %= bitsizeof<T>;
if (amount == 0) {
return x;
}
return static_cast<T>((x << amount) | (x >> (bitsizeof<T> - amount)));
}
/// Create a mask with `count` number of one bits. /// Create a mask with `count` number of one bits.
template<size_t count, BitIntegral T>
template<size_t count, std::integral T>
constexpr T ones() { constexpr T ones() {
static_assert(count <= bitsizeof<T>, "count larger than bitsize of T"); static_assert(count <= bitsizeof<T>, "count larger than bitsize of T");
if constexpr (count == 0) { if constexpr (count == 0) {
return 0; return 0;
} else { } else {
return static_cast<T>(~static_cast<T>(0)) >> (bitsizeof<T> - count);
return T(~T(0)) >> (bitsizeof<T> - count);
} }
} }
/// Create a mask with `count` number of one bits. /// Create a mask with `count` number of one bits.
template<BitIntegral T>
template<std::integral T>
constexpr T ones(size_t count) { constexpr T ones(size_t count) {
ASSERT(count <= bitsizeof<T> && "count larger than bitsize of T"); ASSERT(count <= bitsizeof<T> && "count larger than bitsize of T");
if (count == 0) {
if (count == 0)
return 0; return 0;
}
return static_cast<T>(~static_cast<T>(0)) >> (bitsizeof<T> - count);
return T(~T(0)) >> (bitsizeof<T> - count);
} }
/// Create a mask of type T for bits [begin_bit, end_bit] inclusive. /// Create a mask of type T for bits [begin_bit, end_bit] inclusive.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
template<size_t begin_bit, size_t end_bit, std::integral T>
constexpr T mask() { constexpr T mask() {
static_assert(begin_bit <= end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)"); static_assert(begin_bit <= end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)");
static_assert(begin_bit < bitsizeof<T>, "begin_bit must be smaller than size of T"); static_assert(begin_bit < bitsizeof<T>, "begin_bit must be smaller than size of T");
static_assert(end_bit < bitsizeof<T>, "end_bit must be smaller than size of T"); static_assert(end_bit < bitsizeof<T>, "end_bit must be smaller than size of T");
return ones<end_bit - begin_bit + 1, T>() << begin_bit; return ones<end_bit - begin_bit + 1, T>() << begin_bit;
} }
/// Create a mask of type T for bits [begin_bit, end_bit] inclusive. /// Create a mask of type T for bits [begin_bit, end_bit] inclusive.
template<BitIntegral T>
template<std::integral T>
constexpr T mask(size_t begin_bit, size_t end_bit) { constexpr T mask(size_t begin_bit, size_t end_bit) {
ASSERT(begin_bit <= end_bit && "invalid bit range (position of beginning bit cannot be greater than that of end bit)"); ASSERT(begin_bit <= end_bit && "invalid bit range (position of beginning bit cannot be greater than that of end bit)");
ASSERT(begin_bit < bitsizeof<T> && "begin_bit must be smaller than size of T"); ASSERT(begin_bit < bitsizeof<T> && "begin_bit must be smaller than size of T");
@ -131,101 +99,100 @@ constexpr T mask(size_t begin_bit, size_t end_bit) {
} }
/// Extract bits [begin_bit, end_bit] inclusive from value of type T. /// Extract bits [begin_bit, end_bit] inclusive from value of type T.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
template<size_t begin_bit, size_t end_bit, std::integral T>
constexpr T get_bits(T value) { constexpr T get_bits(T value) {
constexpr T m = mask<begin_bit, end_bit, T>(); constexpr T m = mask<begin_bit, end_bit, T>();
return (value & m) >> begin_bit; return (value & m) >> begin_bit;
} }
/// Extract bits [begin_bit, end_bit] inclusive from value of type T. /// Extract bits [begin_bit, end_bit] inclusive from value of type T.
template<BitIntegral T>
template<std::integral T>
constexpr T get_bits(size_t begin_bit, size_t end_bit, T value) { constexpr T get_bits(size_t begin_bit, size_t end_bit, T value) {
const T m = mask<T>(begin_bit, end_bit); const T m = mask<T>(begin_bit, end_bit);
return (value & m) >> begin_bit; return (value & m) >> begin_bit;
} }
/// Clears bits [begin_bit, end_bit] inclusive of value of type T. /// Clears bits [begin_bit, end_bit] inclusive of value of type T.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
template<size_t begin_bit, size_t end_bit, std::integral T>
constexpr T clear_bits(T value) { constexpr T clear_bits(T value) {
constexpr T m = mask<begin_bit, end_bit, T>(); constexpr T m = mask<begin_bit, end_bit, T>();
return value & ~m; return value & ~m;
} }
/// Clears bits [begin_bit, end_bit] inclusive of value of type T. /// Clears bits [begin_bit, end_bit] inclusive of value of type T.
template<BitIntegral T>
template<std::integral T>
constexpr T clear_bits(size_t begin_bit, size_t end_bit, T value) { constexpr T clear_bits(size_t begin_bit, size_t end_bit, T value) {
const T m = mask<T>(begin_bit, end_bit); const T m = mask<T>(begin_bit, end_bit);
return value & ~m; return value & ~m;
} }
/// Modifies bits [begin_bit, end_bit] inclusive of value of type T. /// Modifies bits [begin_bit, end_bit] inclusive of value of type T.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
template<size_t begin_bit, size_t end_bit, std::integral T>
constexpr T set_bits(T value, T new_bits) { constexpr T set_bits(T value, T new_bits) {
constexpr T m = mask<begin_bit, end_bit, T>(); constexpr T m = mask<begin_bit, end_bit, T>();
return (value & ~m) | ((new_bits << begin_bit) & m); return (value & ~m) | ((new_bits << begin_bit) & m);
} }
/// Modifies bits [begin_bit, end_bit] inclusive of value of type T. /// Modifies bits [begin_bit, end_bit] inclusive of value of type T.
template<BitIntegral T>
template<std::integral T>
constexpr T set_bits(size_t begin_bit, size_t end_bit, T value, T new_bits) { constexpr T set_bits(size_t begin_bit, size_t end_bit, T value, T new_bits) {
const T m = mask<T>(begin_bit, end_bit); const T m = mask<T>(begin_bit, end_bit);
return (value & ~m) | ((new_bits << begin_bit) & m); return (value & ~m) | ((new_bits << begin_bit) & m);
} }
/// Extract bit at bit_position from value of type T. /// Extract bit at bit_position from value of type T.
template<size_t bit_position, BitIntegral T>
template<size_t bit_position, std::integral T>
constexpr bool get_bit(T value) { constexpr bool get_bit(T value) {
constexpr T m = mask<bit_position, bit_position, T>(); constexpr T m = mask<bit_position, bit_position, T>();
return (value & m) != 0; return (value & m) != 0;
} }
/// Extract bit at bit_position from value of type T. /// Extract bit at bit_position from value of type T.
template<BitIntegral T>
template<std::integral T>
constexpr bool get_bit(size_t bit_position, T value) { constexpr bool get_bit(size_t bit_position, T value) {
const T m = mask<T>(bit_position, bit_position); const T m = mask<T>(bit_position, bit_position);
return (value & m) != 0; return (value & m) != 0;
} }
/// Clears bit at bit_position of value of type T. /// Clears bit at bit_position of value of type T.
template<size_t bit_position, BitIntegral T>
template<size_t bit_position, std::integral T>
constexpr T clear_bit(T value) { constexpr T clear_bit(T value) {
constexpr T m = mask<bit_position, bit_position, T>(); constexpr T m = mask<bit_position, bit_position, T>();
return value & ~m; return value & ~m;
} }
/// Clears bit at bit_position of value of type T. /// Clears bit at bit_position of value of type T.
template<BitIntegral T>
template<std::integral T>
constexpr T clear_bit(size_t bit_position, T value) { constexpr T clear_bit(size_t bit_position, T value) {
const T m = mask<T>(bit_position, bit_position); const T m = mask<T>(bit_position, bit_position);
return value & ~m; return value & ~m;
} }
/// Modifies bit at bit_position of value of type T. /// Modifies bit at bit_position of value of type T.
template<size_t bit_position, BitIntegral T>
template<size_t bit_position, std::integral T>
constexpr T set_bit(T value, bool new_bit) { constexpr T set_bit(T value, bool new_bit) {
constexpr T m = mask<bit_position, bit_position, T>(); constexpr T m = mask<bit_position, bit_position, T>();
return (value & ~m) | (new_bit ? m : static_cast<T>(0));
return (value & ~m) | (new_bit ? m : T(0));
} }
/// Modifies bit at bit_position of value of type T. /// Modifies bit at bit_position of value of type T.
template<BitIntegral T>
template<std::integral T>
constexpr T set_bit(size_t bit_position, T value, bool new_bit) { constexpr T set_bit(size_t bit_position, T value, bool new_bit) {
const T m = mask<T>(bit_position, bit_position); const T m = mask<T>(bit_position, bit_position);
return (value & ~m) | (new_bit ? m : static_cast<T>(0));
return (value & ~m) | (new_bit ? m : T(0));
} }
/// Sign-extends a value that has bit_count bits to the full bitwidth of type T. /// Sign-extends a value that has bit_count bits to the full bitwidth of type T.
template<size_t bit_count, BitIntegral T>
template<size_t bit_count, std::integral T>
constexpr T sign_extend(T value) { constexpr T sign_extend(T value) {
static_assert(bit_count != 0, "cannot sign-extend zero-sized value"); static_assert(bit_count != 0, "cannot sign-extend zero-sized value");
using S = std::make_signed_t<T>; using S = std::make_signed_t<T>;
constexpr size_t shift_amount = bitsizeof<T> - bit_count; constexpr size_t shift_amount = bitsizeof<T> - bit_count;
return static_cast<T>(static_cast<S>(value << shift_amount) >> shift_amount);
return T(S(value << shift_amount) >> shift_amount);
} }
/// Sign-extends a value that has bit_count bits to the full bitwidth of type T. /// Sign-extends a value that has bit_count bits to the full bitwidth of type T.
template<BitIntegral T>
template<std::integral T>
constexpr T sign_extend(size_t bit_count, T value) { constexpr T sign_extend(size_t bit_count, T value) {
ASSERT(bit_count != 0 && "cannot sign-extend zero-sized value"); ASSERT(bit_count != 0 && "cannot sign-extend zero-sized value");
using S = std::make_signed_t<T>; using S = std::make_signed_t<T>;
@ -234,78 +201,42 @@ constexpr T sign_extend(size_t bit_count, T value) {
} }
/// Replicate an element across a value of type T. /// Replicate an element across a value of type T.
template<size_t element_size, BitIntegral T>
template<size_t element_size, std::integral T>
constexpr T replicate_element(T value) { constexpr T replicate_element(T value) {
static_assert(element_size <= bitsizeof<T>, "element_size is too large"); static_assert(element_size <= bitsizeof<T>, "element_size is too large");
static_assert(bitsizeof<T> % element_size == 0, "bitsize of T not divisible by element_size"); static_assert(bitsizeof<T> % element_size == 0, "bitsize of T not divisible by element_size");
if constexpr (element_size == bitsizeof<T>) { if constexpr (element_size == bitsizeof<T>) {
return value; return value;
} else { } else {
return replicate_element<element_size * 2, T>(static_cast<T>(value | (value << element_size)));
return replicate_element<element_size * 2, T>(T(value | (value << element_size)));
} }
} }
/// Replicate an element of type U across a value of type T. /// Replicate an element of type U across a value of type T.
template<BitIntegral U, BitIntegral T>
template<std::integral U, std::integral T>
constexpr T replicate_element(T value) { constexpr T replicate_element(T value) {
static_assert(bitsizeof<U> <= bitsizeof<T>, "element_size is too large"); static_assert(bitsizeof<U> <= bitsizeof<T>, "element_size is too large");
return replicate_element<bitsizeof<U>, T>(value); return replicate_element<bitsizeof<U>, T>(value);
} }
/// Replicate an element across a value of type T. /// Replicate an element across a value of type T.
template<BitIntegral T>
template<std::integral T>
constexpr T replicate_element(size_t element_size, T value) { constexpr T replicate_element(size_t element_size, T value) {
ASSERT(element_size <= bitsizeof<T> && "element_size is too large"); ASSERT(element_size <= bitsizeof<T> && "element_size is too large");
ASSERT(bitsizeof<T> % element_size == 0 && "bitsize of T not divisible by element_size"); ASSERT(bitsizeof<T> % element_size == 0 && "bitsize of T not divisible by element_size");
if (element_size == bitsizeof<T>) if (element_size == bitsizeof<T>)
return value; return value;
return replicate_element<T>(element_size * 2, static_cast<T>(value | (value << element_size)));
return replicate_element<T>(element_size * 2, T(value | (value << element_size)));
} }
template<BitIntegral T>
template<std::integral T>
constexpr bool most_significant_bit(T value) { constexpr bool most_significant_bit(T value) {
return get_bit<bitsizeof<T> - 1, T>(value); return get_bit<bitsizeof<T> - 1, T>(value);
} }
template<BitIntegral T>
inline size_t count_ones(T x) {
return std::bitset<bitsizeof<T>>(x).count();
}
template<BitIntegral T>
constexpr size_t count_leading_zeros(T x) {
size_t result = bitsizeof<T>;
while (x != 0) {
x >>= 1;
result--;
}
return result;
}
template<BitIntegral T>
template<std::integral T>
constexpr int highest_set_bit(T x) { constexpr int highest_set_bit(T x) {
int result = -1;
while (x != 0) {
x >>= 1;
result++;
}
return result;
}
template<BitIntegral T>
constexpr size_t lowest_set_bit(T x) {
if (x == 0) {
return bitsizeof<T>;
}
size_t result = 0;
while ((x & 1) == 0) {
x >>= 1;
result++;
}
return result;
return std::bit_width(x) - 1;
} }
} // namespace mcl::bit } // namespace mcl::bit

8
src/dynarmic/src/dynarmic/mcl/integer_of_size.hpp

@ -17,25 +17,25 @@ struct integer_of_size_impl {};
template<> template<>
struct integer_of_size_impl<8> { struct integer_of_size_impl<8> {
using unsigned_type = u8; using unsigned_type = u8;
using signed_type = s8;
using signed_type = std::make_signed_t<unsigned_type>;
}; };
template<> template<>
struct integer_of_size_impl<16> { struct integer_of_size_impl<16> {
using unsigned_type = u16; using unsigned_type = u16;
using signed_type = s16;
using signed_type = std::make_signed_t<unsigned_type>;
}; };
template<> template<>
struct integer_of_size_impl<32> { struct integer_of_size_impl<32> {
using unsigned_type = u32; using unsigned_type = u32;
using signed_type = s32;
using signed_type = std::make_signed_t<unsigned_type>;
}; };
template<> template<>
struct integer_of_size_impl<64> { struct integer_of_size_impl<64> {
using unsigned_type = u64; using unsigned_type = u64;
using signed_type = s64;
using signed_type = std::make_signed_t<unsigned_type>;
}; };
} // namespace detail } // namespace detail

15
src/dynarmic/src/dynarmic/mcl/is_instance_of_template.hpp

@ -10,23 +10,12 @@
namespace mcl { namespace mcl {
/// A metavalue (of type VT and value v).
template<class VT, VT v> using value = std::integral_constant<VT, v>;
/// A metavalue of type size_t (and value v).
template<size_t v> using size_value = value<size_t, v>;
/// A metavalue of type bool (and value v). (Aliases to std::bool_constant.)
template<bool v> using bool_value = value<bool, v>;
/// true metavalue (Aliases to std::true_type).
using true_type = bool_value<true>;
/// false metavalue (Aliases to std::false_type).
using false_type = bool_value<false>;
/// Is type T an instance of template class C? /// Is type T an instance of template class C?
template<template<class...> class, class> template<template<class...> class, class>
struct is_instance_of_template : false_type {};
struct is_instance_of_template : std::false_type {};
template<template<class...> class C, class... As> template<template<class...> class C, class... As>
struct is_instance_of_template<C, C<As...>> : true_type {};
struct is_instance_of_template<C, C<As...>> : std::true_type {};
/// Is type T an instance of template class C? /// Is type T an instance of template class C?
template<template<class...> class C, class T> template<template<class...> class C, class T>

2
src/dynarmic/tests/A32/fuzz_arm.cpp

@ -665,7 +665,7 @@ TEST_CASE("A32: Test thumb IT instruction", "[thumb]") {
A32::ITState it_state = [&] { A32::ITState it_state = [&] {
while (true) { while (true) {
const u16 imm8 = RandInt<u16>(0, 0xFF); const u16 imm8 = RandInt<u16>(0, 0xFF);
if (mcl::bit::get_bits<0, 3>(imm8) == 0b0000 || mcl::bit::get_bits<4, 7>(imm8) == 0b1111 || (mcl::bit::get_bits<4, 7>(imm8) == 0b1110 && mcl::bit::count_ones(mcl::bit::get_bits<0, 3>(imm8)) != 1)) {
if (mcl::bit::get_bits<0, 3>(imm8) == 0b0000 || mcl::bit::get_bits<4, 7>(imm8) == 0b1111 || (mcl::bit::get_bits<4, 7>(imm8) == 0b1110 && std::popcount(mcl::bit::get_bits<0, 3>(imm8)) != 1)) {
continue; continue;
} }
instructions.push_back(0b1011111100000000 | imm8); instructions.push_back(0b1011111100000000 | imm8);

12
tools/gendynarm.cpp

@ -17,12 +17,6 @@ namespace mcl {
template<typename T> template<typename T>
constexpr std::size_t bitsizeof = CHAR_BIT * sizeof(T); constexpr std::size_t bitsizeof = CHAR_BIT * sizeof(T);
} }
namespace mcl::bit {
template<typename T>
inline size_t count_ones(T x) {
return std::bitset<bitsizeof<T>>(x).count();
}
}
template<size_t N> template<size_t N>
inline consteval std::array<char, N> StringToArray(const char (&str)[N + 1]) { inline consteval std::array<char, N> StringToArray(const char (&str)[N + 1]) {
std::array<char, N> result{}; std::array<char, N> result{};
@ -380,7 +374,7 @@ INST(arm_SRS, "SRS", "1111100--1-0110100000101000-----
}; };
// If a matcher has more bits in its mask it is more specific, so it should come first. // If a matcher has more bits in its mask it is more specific, so it should come first.
std::stable_sort(list.begin(), list.end(), [](const auto& matcher1, const auto& matcher2) { std::stable_sort(list.begin(), list.end(), [](const auto& matcher1, const auto& matcher2) {
return mcl::bit::count_ones(matcher1.second) > mcl::bit::count_ones(matcher2.second);
return std::popcount(matcher1.second) > std::popcount(matcher2.second);
}); });
for (auto const& e : list) for (auto const& e : list)
printf("%s\n", e.inst_final); printf("%s\n", e.inst_final);
@ -587,7 +581,7 @@ INST(v8_VLD_single, "VLD{1-4} (single)", "111101001D10nnnnddddzzN
}); });
// If a matcher has more bits in its mask it is more specific, so it should come first. // If a matcher has more bits in its mask it is more specific, so it should come first.
std::stable_sort(sort_begin, sort_end, [](const auto& a, const auto& b) { std::stable_sort(sort_begin, sort_end, [](const auto& a, const auto& b) {
return mcl::bit::count_ones(a.second) > mcl::bit::count_ones(b.second);
return std::popcount(a.second) > std::popcount(b.second);
}); });
for (auto const& e : table) for (auto const& e : table)
printf("%s\n", e.inst_final); printf("%s\n", e.inst_final);
@ -1628,7 +1622,7 @@ INST(FNMSUB_float, "FNMSUB", "00011
// If a matcher has more bits in its mask it is more specific, so it should come first. // If a matcher has more bits in its mask it is more specific, so it should come first.
std::stable_sort(list.begin(), list.end(), [](const auto& a, const auto& b) { std::stable_sort(list.begin(), list.end(), [](const auto& a, const auto& b) {
// If a matcher has more bits in its mask it is more specific, so it should come first. // If a matcher has more bits in its mask it is more specific, so it should come first.
return mcl::bit::count_ones(a.second) > mcl::bit::count_ones(b.second);
return std::popcount(a.second) > std::popcount(b.second);
}); });
// Exceptions to the above rule of thumb. // Exceptions to the above rule of thumb.
std::stable_partition(list.begin(), list.end(), [&](const auto& e) { std::stable_partition(list.begin(), list.end(), [&](const auto& e) {

Loading…
Cancel
Save