[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>
This commit is contained in:
lizzie 2026-05-31 04:18:12 +02:00 committed by crueter
parent b7fcec4985
commit 5f4a286046
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
18 changed files with 96 additions and 204 deletions

View file

@ -24,7 +24,7 @@ using DoNotFastmemMarker = std::tuple<IR::LocationDescriptor, unsigned>;
constexpr std::size_t xmrx(std::size_t x) noexcept {
x ^= x >> 32;
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;
}

View file

@ -1532,7 +1532,7 @@ void EmitX64::EmitFPSingleToHalf(EmitContext& ctx, IR::Inst* inst) {
if (ctx.FPCR().DN()) {
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);
return;
@ -1540,7 +1540,7 @@ void EmitX64::EmitFPSingleToHalf(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(code, inst, args[0]);
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.CallFunction(&FP::FPConvert<u16, u32>);
}

View file

@ -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 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) {
code.xor_(overflow.cvt32(), overflow.cvt32());
code.bt(result.cvt32(), size - 1);

View file

@ -3553,7 +3553,7 @@ void EmitX64::EmitVectorPopulationCount(EmitContext& ctx, IR::Inst* inst) {
EmitOneArgumentFallback(code, ctx, inst, [](VectorArray<u8>& result, const VectorArray<u8>& a) {
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));
});
});
}

View file

@ -1657,20 +1657,10 @@ void EmitFPVectorRoundInt(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
if constexpr (fsize != 16) {
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) {
FCODE(roundp)(result, xmm_a, round_imm);
FCODE(roundp)(result, xmm_a, *round_imm);
});
return;
}
}
@ -2002,19 +1992,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const Xbyak::Xmm src = ctx.reg_alloc.UseScratchXmm(code, args[0]);
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) {
// MSVC doesn't allow us to use a [&] capture, so we have to do this instead.
(void)ctx;
@ -2046,7 +2024,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
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;
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
static constexpr u32 nan_to_zero = FixupLUT(FpFixup::PosZero, FpFixup::PosZero);

View file

@ -52,7 +52,7 @@ struct TranslatorVisitor final {
u32 imm32 = imm8.ZeroExtend();
auto carry_out = carry_in;
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));
}
return {imm32, carry_out};
@ -81,7 +81,7 @@ struct TranslatorVisitor final {
}();
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))};
}

View file

@ -79,7 +79,7 @@ bool TranslatorVisitor::asimd_VDUP_scalar(bool D, Imm<4> imm4, size_t Vd, bool Q
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 index = imm4.ZeroExtend() >> (imm4_lsb + 1);
const auto d = ToVector(Q, Vd, D);

View file

@ -799,7 +799,7 @@ static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 s
// LDM <Rn>{!}, <reg_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();
}
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 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);
}
// LDMDA <Rn>{!}, <reg_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();
}
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;
}
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));
return LDMHelper(ir, W, n, list, start_address, writeback_address);
}
// LDMDB <Rn>{!}, <reg_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();
}
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;
}
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;
return LDMHelper(ir, W, n, list, start_address, writeback_address);
}
// LDMIB <Rn>{!}, <reg_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();
}
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 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);
}
@ -896,7 +896,7 @@ static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 s
// STM <Rn>{!}, <reg_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();
}
@ -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 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);
}
// STMDA <Rn>{!}, <reg_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();
}
@ -919,14 +919,14 @@ bool TranslatorVisitor::arm_STMDA(Cond cond, bool W, Reg n, RegList list) {
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));
return STMHelper(ir, W, n, list, start_address, writeback_address);
}
// STMDB <Rn>{!}, <reg_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();
}
@ -934,14 +934,14 @@ bool TranslatorVisitor::arm_STMDB(Cond cond, bool W, Reg n, RegList list) {
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;
return STMHelper(ir, W, n, list, start_address, writeback_address);
}
// STMIB <Rn>{!}, <reg_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();
}
@ -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 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);
}

View file

@ -688,7 +688,7 @@ bool TranslatorVisitor::thumb16_NOP() {
// IT{<x>{<y>{<z>}}} <cond>
bool TranslatorVisitor::thumb16_IT(Imm<8> imm8) {
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();
}
if (ir.current_location.IT().IsInITBlock()) {
@ -738,11 +738,11 @@ bool TranslatorVisitor::thumb16_PUSH(bool M, RegList reg_list) {
if (M) {
reg_list |= 1 << 14;
}
if (mcl::bit::count_ones(reg_list) < 1) {
if (std::popcount(reg_list) < 1) {
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));
auto address = final_address;
for (size_t i = 0; i < 16; i++) {
@ -764,7 +764,7 @@ bool TranslatorVisitor::thumb16_POP(bool P, RegList reg_list) {
if (P) {
reg_list |= 1 << 15;
}
if (mcl::bit::count_ones(reg_list) < 1) {
if (std::popcount(reg_list) < 1) {
return UnpredictableInstruction();
}
@ -851,10 +851,10 @@ bool TranslatorVisitor::thumb16_BKPT(Imm<8> /*imm8*/) {
// STM <Rn>!, <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();
}
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();
}
@ -873,7 +873,7 @@ bool TranslatorVisitor::thumb16_STMIA(Reg n, RegList reg_list) {
// LDM <Rn>!, <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();
}

View file

@ -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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
return UnpredictableInstruction();

View file

@ -55,7 +55,7 @@ std::optional<TranslatorVisitor::BitMasks> TranslatorVisitor::DecodeBitMasks(boo
const size_t esize = size_t{1} << len;
const u64 welem = mcl::bit::ones<u64>(S + 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);
return BitMasks{wmask, tmask};

View file

@ -13,7 +13,7 @@
namespace Dynarmic::A64 {
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) {
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) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size > 3) {
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) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size > 3) {
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) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size == 2 && !Q) {
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) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size < 3 && Q) {
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) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size > 3) {
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) {
const size_t size = mcl::bit::lowest_set_bit(imm5.ZeroExtend());
const size_t size = std::countr_zero(imm5.ZeroExtend());
if (size > 3) {
return ReservedValue();
}

View file

@ -9,6 +9,7 @@
#include <algorithm>
#include <cstdio>
#include <map>
#include <bit>
#include <ankerl/unordered_dense.h>
#include "boost/container/small_vector.hpp"
@ -28,7 +29,6 @@
#include "dynarmic/ir/opt_passes.h"
#include "dynarmic/ir/type.h"
#include "dynarmic/mcl/bit.hpp"
#include "dynarmic/mcl/bit.hpp"
namespace Dynarmic::Optimization {
@ -1074,12 +1074,12 @@ static void ConstantPropagation(IR::Block& block) {
break;
case Op::BitRotateRight32:
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;
case Op::BitRotateRight64:
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;
case Op::LogicalShiftLeftMasked32:
@ -1114,12 +1114,12 @@ static void ConstantPropagation(IR::Block& block) {
break;
case Op::RotateRightMasked32:
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;
case Op::RotateRightMasked64:
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;
case Op::Add32:

View file

@ -8,26 +8,15 @@
#include <bitset>
#include <climits>
#include <cstddef>
#include <concepts>
#include <bit>
#include "common/common_types.h"
#include "common/assert.h"
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>
constexpr std::size_t bitsizeof = CHAR_BIT * sizeof(T);
} // namespace mcl
namespace mcl::bit {
@ -71,58 +60,37 @@ constexpr u64 swap_words_64(u64 value) {
| ((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.
template<size_t count, BitIntegral T>
template<size_t count, std::integral T>
constexpr T ones() {
static_assert(count <= bitsizeof<T>, "count larger than bitsize of T");
if constexpr (count == 0) {
return 0;
} 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.
template<BitIntegral T>
template<std::integral T>
constexpr T ones(size_t count) {
ASSERT(count <= bitsizeof<T> && "count larger than bitsize of T");
if (count == 0) {
if (count == 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.
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() {
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(end_bit < bitsizeof<T>, "end_bit must be smaller than size of T");
return ones<end_bit - begin_bit + 1, T>() << begin_bit;
}
/// 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) {
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");
@ -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.
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 m = mask<begin_bit, end_bit, T>();
return (value & m) >> begin_bit;
}
/// 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) {
const T m = mask<T>(begin_bit, end_bit);
return (value & m) >> begin_bit;
}
/// 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 m = mask<begin_bit, end_bit, T>();
return value & ~m;
}
/// 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) {
const T m = mask<T>(begin_bit, end_bit);
return value & ~m;
}
/// 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 m = mask<begin_bit, end_bit, T>();
return (value & ~m) | ((new_bits << begin_bit) & m);
}
/// 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) {
const T m = mask<T>(begin_bit, end_bit);
return (value & ~m) | ((new_bits << begin_bit) & m);
}
/// 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 T m = mask<bit_position, bit_position, T>();
return (value & m) != 0;
}
/// 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) {
const T m = mask<T>(bit_position, bit_position);
return (value & m) != 0;
}
/// 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 m = mask<bit_position, bit_position, T>();
return value & ~m;
}
/// 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) {
const T m = mask<T>(bit_position, bit_position);
return value & ~m;
}
/// 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 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.
template<BitIntegral T>
template<std::integral T>
constexpr T set_bit(size_t bit_position, T value, bool new_bit) {
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.
template<size_t bit_count, BitIntegral T>
template<size_t bit_count, std::integral T>
constexpr T sign_extend(T value) {
static_assert(bit_count != 0, "cannot sign-extend zero-sized value");
using S = std::make_signed_t<T>;
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.
template<BitIntegral T>
template<std::integral T>
constexpr T sign_extend(size_t bit_count, T value) {
ASSERT(bit_count != 0 && "cannot sign-extend zero-sized value");
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.
template<size_t element_size, BitIntegral T>
template<size_t element_size, std::integral T>
constexpr T replicate_element(T value) {
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");
if constexpr (element_size == bitsizeof<T>) {
return value;
} 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.
template<BitIntegral U, BitIntegral T>
template<std::integral U, std::integral T>
constexpr T replicate_element(T value) {
static_assert(bitsizeof<U> <= bitsizeof<T>, "element_size is too large");
return replicate_element<bitsizeof<U>, T>(value);
}
/// 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) {
ASSERT(element_size <= bitsizeof<T> && "element_size is too large");
ASSERT(bitsizeof<T> % element_size == 0 && "bitsize of T not divisible by element_size");
if (element_size == bitsizeof<T>)
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) {
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) {
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

View file

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

View file

@ -10,23 +10,12 @@
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?
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>
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?
template<template<class...> class C, class T>

View file

@ -665,7 +665,7 @@ TEST_CASE("A32: Test thumb IT instruction", "[thumb]") {
A32::ITState it_state = [&] {
while (true) {
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;
}
instructions.push_back(0b1011111100000000 | imm8);

View file

@ -17,12 +17,6 @@ namespace mcl {
template<typename 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>
inline consteval std::array<char, N> StringToArray(const char (&str)[N + 1]) {
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.
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)
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.
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)
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.
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.
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.
std::stable_partition(list.begin(), list.end(), [&](const auto& e) {