From c5ee48f54a3e051535cf41db8dcd53f924d33537 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Wed, 13 May 2026 23:27:39 +0200 Subject: [PATCH] Harden bitset access --- rpcs3/Emu/Cell/Modules/cellPamf.cpp | 9 +- rpcs3/Emu/Cell/Modules/cellSsl.cpp | 19 +-- rpcs3/Emu/Cell/SPUCommonRecompiler.cpp | 116 ++++++++-------- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 18 +-- rpcs3/Emu/Cell/SPURecompiler.h | 60 ++++----- rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp | 15 +-- rpcs3/Emu/RSX/Common/bitfield.hpp | 7 +- rpcs3/Emu/RSX/Program/ProgramStateCache.cpp | 6 +- rpcs3/Emu/RSX/Program/ProgramStateCache.h | 2 +- rpcs3/Emu/RSX/Program/RSXVertexProgram.h | 3 +- rpcs3/Emu/RSX/RSXFIFO.cpp | 3 +- rpcs3/rpcs3qt/log_viewer.cpp | 2 +- rpcs3/rpcs3qt/log_viewer.h | 4 +- rpcs3/util/types.hpp | 139 ++++++++++++++++++++ 14 files changed, 264 insertions(+), 139 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellPamf.cpp b/rpcs3/Emu/Cell/Modules/cellPamf.cpp index 4bb383c2d2..42ce5b331c 100644 --- a/rpcs3/Emu/Cell/Modules/cellPamf.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPamf.cpp @@ -2,7 +2,6 @@ #include "Emu/System.h" #include "Emu/Cell/PPUModule.h" -#include #include "cellPamf.h" LOG_CHANNEL(cellPamf); @@ -500,7 +499,7 @@ error_code pamfVerify(vm::cptr pAddr, u64 fileSize, vm::ptrseq_info.grouping_periods.groups.streams; - std::bitset<16> channels_used[6]{}; + std::array, 6> channels_used{}; u32 end_of_streams_addr = 0; u32 next_ep_table_addr = 0; @@ -516,14 +515,16 @@ error_code pamfVerify(vm::cptr pAddr, u64 fileSize, vm::ptr& used_channels = ::at32(channels_used, *type); + // Every channel may only be used once per type - if (channels_used[*type].test(*ch)) + if (used_channels.test(*ch)) { return { CELL_PAMF_ERROR_INVALID_PAMF, "pamfVerify() failed: invalid channel" }; } // Mark channel as used - channels_used[*type].set(*ch); + used_channels.set(*ch, true); const u32 ep_offset = streams[stream_idx].ep_offset; const u32 ep_num = streams[stream_idx].ep_num; diff --git a/rpcs3/Emu/Cell/Modules/cellSsl.cpp b/rpcs3/Emu/Cell/Modules/cellSsl.cpp index d7f32a5636..7c0aa6d9aa 100644 --- a/rpcs3/Emu/Cell/Modules/cellSsl.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSsl.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" -#include #include #include "cellSsl.h" @@ -92,7 +91,7 @@ std::string getCert(const std::string& certPath, const int certID, const bool is newID = certID - 1; } - std::string filePath = fmt::format("%sCA%02d.cer", certPath, newID); + const std::string filePath = fmt::format("%sCA%02d.cer", certPath, newID); if (!fs::exists(filePath)) { @@ -106,7 +105,7 @@ error_code cellSslCertificateLoader(u64 flag, vm::ptr buffer, u32 size, vm { cellSsl.trace("cellSslCertificateLoader(flag=%llu, buffer=*0x%x, size=%zu, required=*0x%x)", flag, buffer, size, required); - const std::bitset<58> flagBits(flag); + const bit_set<58> flagBits(flag); const std::string certPath = vfs::get("/dev_flash/data/cert/"); if (required) @@ -114,10 +113,11 @@ error_code cellSslCertificateLoader(u64 flag, vm::ptr buffer, u32 size, vm *required = 0; for (uint i = 1; i <= flagBits.size(); i++) { - if (!flagBits[i-1]) + if (!flagBits.test(i - 1)) continue; + // If we're loading cert 6 (the baltimore cert), then we need set that we're loading the 'normal' set of certs. - *required += ::size32(getCert(certPath, i, flagBits[BaltimoreCert-1])); + *required += ::size32(getCert(certPath, i, flagBits.test(BaltimoreCert - 1))); } } else @@ -125,14 +125,15 @@ error_code cellSslCertificateLoader(u64 flag, vm::ptr buffer, u32 size, vm std::string final; for (uint i = 1; i <= flagBits.size(); i++) { - if (!flagBits[i-1]) + if (!flagBits.test(i - 1)) continue; + // If we're loading cert 6 (the baltimore cert), then we need set that we're loading the 'normal' set of certs. - final.append(getCert(certPath, i, flagBits[BaltimoreCert-1])); + final.append(getCert(certPath, i, flagBits.test(BaltimoreCert - 1))); } - memset(buffer.get_ptr(), '\0', size - 1); - memcpy(buffer.get_ptr(), final.c_str(), final.size()); + std::memset(buffer.get_ptr(), '\0', size - 1); + std::memcpy(buffer.get_ptr(), final.c_str(), final.size()); } return CELL_OK; diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index b721ebc188..44a3cfc314 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -2905,7 +2905,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s // Check for redundancy if (!m_block_info[target / 4]) { - m_block_info[target / 4] = true; + m_block_info.set(target / 4, true); workload.push_back(target); } @@ -3080,7 +3080,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } else { - m_entry_info[target / 4] = true; + m_entry_info.set(target / 4, true); add_block(target); } } @@ -3091,8 +3091,8 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (!is_no_return && sl && g_cfg.core.spu_block_size != spu_block_size_type::safe) { - m_ret_info[pos / 4 + 1] = true; - m_entry_info[pos / 4 + 1] = true; + m_ret_info.set(pos / 4 + 1, true); + m_entry_info.set(pos / 4 + 1, true); m_targets[pos].push_back(pos + 4); add_block(pos + 4); } @@ -3307,8 +3307,8 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } else { - m_ret_info[pos / 4 + 1] = true; - m_entry_info[pos / 4 + 1] = true; + m_ret_info.set(pos / 4 + 1, true); + m_entry_info.set(pos / 4 + 1, true); m_targets[pos].push_back(pos + 4); add_block(pos + 4); } @@ -3375,15 +3375,15 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (!is_no_return && g_cfg.core.spu_block_size != spu_block_size_type::safe) { - m_ret_info[pos / 4 + 1] = true; - m_entry_info[pos / 4 + 1] = true; + m_ret_info.set(pos / 4 + 1, true); + m_entry_info.set(pos / 4 + 1, true); m_targets[pos].push_back(pos + 4); add_block(pos + 4); } if (!is_no_return && g_cfg.core.spu_block_size == spu_block_size_type::giga && !sync) { - m_entry_info[target / 4] = true; + m_entry_info.set(target / 4, true); add_block(target); } else @@ -3409,7 +3409,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (g_cfg.core.spu_block_size == spu_block_size_type::giga && !sync) { - m_entry_info[target / 4] = true; + m_entry_info.set(target / 4, true); } else { @@ -3714,7 +3714,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s // Bit array used to deduplicate workload list workload.push_back(pair.first); - m_bits[pair.first / 4] = true; + m_bits.set(pair.first / 4, true); for (usz i = 0; !reachable && i < workload.size(); i++) { @@ -3746,7 +3746,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (new_pred >= lsa && new_pred < limit && !m_bits[new_pred / 4]) { workload.push_back(new_pred); - m_bits[new_pred / 4] = true; + m_bits.set(new_pred / 4, true); } } } @@ -3769,7 +3769,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 pred : workload) { - m_bits[pred / 4] = false; + m_bits.set(pred / 4, false); } if (!reachable && pair.first < limit) @@ -3828,9 +3828,9 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (addr < lsa || addr >= limit || !result.data[(addr - lsa) / 4]) { - m_block_info[addr / 4] = false; - m_entry_info[addr / 4] = false; - m_ret_info[addr / 4] = false; + m_block_info.set(addr / 4, false); + m_entry_info.set(addr / 4, false); + m_ret_info.set(addr / 4, false); m_preds.erase(addr); } } @@ -3856,7 +3856,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (it->second.empty() && !m_entry_info[it->first / 4]) { // If not an entry point, remove the block completely - m_block_info[it->first / 4] = false; + m_block_info.set(it->first / 4, false); it = m_preds.erase(it); continue; } @@ -3964,7 +3964,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (type == spu_itype::STQD && op.ra == s_reg_sp && !block.reg_mod[op.rt] && !block.reg_use[op.rt]) { // Register saved onto the stack before use - block.reg_save_dom[op.rt] = true; + block.reg_save_dom.set(op.rt, true); reg_save = op.rt; } @@ -3994,7 +3994,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (reg_save != reg && block.reg_save_dom[reg]) { // Register is still used after saving; probably not eligible for optimization - block.reg_save_dom[reg] = false; + block.reg_save_dom.set(reg, false); } } } @@ -4065,7 +4065,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (!is_tail) { block.reg_mod.set(i); - block.reg_mod_xf[i] = false; + block.reg_mod_xf.set(i, false); } } } @@ -4106,8 +4106,8 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s { const u32 addr = emp.first->first; spu_log.error("[0x%05x] Fixed first function at 0x%05x", entry_point, addr); - m_entry_info[addr / 4] = true; - m_ret_info[addr / 4] = false; + m_entry_info.set(addr / 4, true); + m_ret_info.set(addr / 4, false); } } @@ -4146,9 +4146,9 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (!m_entry_info[target / 4] || m_ret_info[target / 4]) { // Create new function entry (likely a tail call) - m_entry_info[target / 4] = true; + m_entry_info.set(target / 4, true); - m_ret_info[target / 4] = false; + m_ret_info.set(target / 4, false); m_funcs.try_emplace(target); @@ -4246,10 +4246,10 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 entry : new_entries) { - m_entry_info[entry / 4] = true; + m_entry_info.set(entry / 4, true); // Acknowledge artificial (reversible) chunk entry point - m_ret_info[entry / 4] = true; + m_ret_info.set(entry / 4, true); } for (auto& bb : m_bbs) @@ -4435,7 +4435,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (orig < 0x40000) { auto& src = ::at32(m_bbs, orig); - bb.reg_const[i] = src.reg_const[i]; + bb.reg_const.set(i, src.reg_const[i]); bb.reg_val32[i] = src.reg_val32[i]; } @@ -4474,25 +4474,25 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s { case spu_itype::IL: { - bb.reg_const[op.rt] = true; + bb.reg_const.set(op.rt, true); bb.reg_val32[op.rt] = op.si16; break; } case spu_itype::ILA: { - bb.reg_const[op.rt] = true; + bb.reg_const.set(op.rt, true); bb.reg_val32[op.rt] = op.i18; break; } case spu_itype::ILHU: { - bb.reg_const[op.rt] = true; + bb.reg_const.set(op.rt, true); bb.reg_val32[op.rt] = op.i16 << 16; break; } case spu_itype::ILH: { - bb.reg_const[op.rt] = true; + bb.reg_const.set(op.rt, true); bb.reg_val32[op.rt] = op.i16 << 16 | op.i16; break; } @@ -4503,37 +4503,37 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } case spu_itype::ORI: { - bb.reg_const[op.rt] = bb.reg_const[op.ra]; + bb.reg_const.set(op.rt, bb.reg_const[op.ra]); bb.reg_val32[op.rt] = bb.reg_val32[op.ra] | op.si10; break; } case spu_itype::OR: { - bb.reg_const[op.rt] = bb.reg_const[op.ra] && bb.reg_const[op.rb]; + bb.reg_const.set(op.rt, bb.reg_const[op.ra] && bb.reg_const[op.rb]); bb.reg_val32[op.rt] = bb.reg_val32[op.ra] | bb.reg_val32[op.rb]; break; } case spu_itype::AI: { - bb.reg_const[op.rt] = bb.reg_const[op.ra]; + bb.reg_const.set(op.rt, bb.reg_const[op.ra]); bb.reg_val32[op.rt] = bb.reg_val32[op.ra] + op.si10; break; } case spu_itype::A: { - bb.reg_const[op.rt] = bb.reg_const[op.ra] && bb.reg_const[op.rb]; + bb.reg_const.set(op.rt, bb.reg_const[op.ra] && bb.reg_const[op.rb]); bb.reg_val32[op.rt] = bb.reg_val32[op.ra] + bb.reg_val32[op.rb]; break; } case spu_itype::SFI: { - bb.reg_const[op.rt] = bb.reg_const[op.ra]; + bb.reg_const.set(op.rt, bb.reg_const[op.ra]); bb.reg_val32[op.rt] = op.si10 - bb.reg_val32[op.ra]; break; } case spu_itype::SF: { - bb.reg_const[op.rt] = bb.reg_const[op.ra] && bb.reg_const[op.rb]; + bb.reg_const.set(op.rt, bb.reg_const[op.ra] && bb.reg_const[op.rb]); bb.reg_val32[op.rt] = bb.reg_val32[op.rb] - bb.reg_val32[op.ra]; break; } @@ -4566,14 +4566,14 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } // Clear const - bb.reg_const[op.rt] = false; + bb.reg_const.set(op.rt, false); break; } default: { // Clear const if reg is modified here if (u8 reg = m_regmod[ia / 4]; reg < s_reg_max) - bb.reg_const[reg] = false; + bb.reg_const.set(reg, false); break; } } @@ -6103,17 +6103,17 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s u32 ra = s_reg_max, rb = s_reg_max, rc = s_reg_max; - if (::at32(m_use_ra, pos / 4)) + if (m_use_ra.test(pos / 4)) { ra = op.ra; } - if (::at32(m_use_rb, pos / 4)) + if (m_use_rb.test(pos / 4)) { rb = op.rb; } - if (::at32(m_use_rc, pos / 4)) + if (m_use_rc.test(pos / 4)) { rc = op.rc; } @@ -6373,8 +6373,8 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } std::array reg_use{}; - std::bitset reg_maybe_float{}; - std::bitset reg_mod{}; + bit_set reg_maybe_float{}; + bit_set reg_mod{}; for (auto it = m_bbs.find(reduced_loop->loop_pc); it != m_bbs.end() && it->first <= bpc; it++) { @@ -6398,7 +6398,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 i = 0; i < s_reg_max; i++) { - if (!::at32(reduced_loop->loop_dicts, i)) + if (!reduced_loop->loop_dicts.test(i)) { if (reg_use[i] && reg_mod[i]) { @@ -6662,7 +6662,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 i = 0; i < reg->regs.size() && reduced_loop->active; i++) { - if (::at32(reg->regs, i)) + if (reg->regs.test(i)) { if (0) if (i == op_rt || reg->modified == 0) { @@ -6708,11 +6708,11 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s auto reg_org = reduced_loop->find_reg(i); u32 reg_index = i; - if (reg_org && !cond_val_incr_before_cond && reg_org->modified == 0 && reg_org->regs.count() - 1u <= 1u && !::at32(reg_org->regs, i)) + if (reg_org && !cond_val_incr_before_cond && reg_org->modified == 0 && reg_org->regs.count() - 1u <= 1u && !reg_org->regs.test(i)) { for (u32 j = 0; j <= s_reg_127; j++) { - if (::at32(reg_org->regs, j)) + if (reg_org->regs.test(j)) { if (const auto reg_found = reduced_loop->find_reg(j)) { @@ -6781,7 +6781,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s break; } - if (reg_index != i && ::at32(reg->regs, reg_index)) + if (reg_index != i && reg->regs.test(reg_index)) { // Unimplemented break_reduced_loop_pattern(30, reduced_loop->discard()); @@ -7104,8 +7104,8 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } std::array reg_use{}; - std::bitset reg_maybe_float{}; - std::bitset reg_mod{}; + bit_set reg_maybe_float{}; + bit_set reg_mod{}; for (auto it = m_bbs.find(reduced_loop->loop_pc); it != m_bbs.end() && it->first <= bpc; it++) { @@ -7129,7 +7129,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 i = 0; i < s_reg_max; i++) { - if (!::at32(reduced_loop->loop_dicts, i)) + if (!reduced_loop->loop_dicts.test(i)) { if (reg_use[i] && reg_mod[i]) { @@ -8412,17 +8412,17 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s u32 ra = s_reg_max, rb = s_reg_max, rc = s_reg_max; - if (::at32(m_use_ra, pos / 4)) + if (m_use_ra.test(pos / 4)) { ra = op.ra; } - if (::at32(m_use_rb, pos / 4)) + if (m_use_rb.test(pos / 4)) { rb = op.rb; } - if (::at32(m_use_rc, pos / 4)) + if (m_use_rc.test(pos / 4)) { rc = op.rc; } @@ -8693,7 +8693,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 i = 0; i < s_reg_max; i++) { - if (::at32(pattern.loop_writes, i)) + if (pattern.loop_writes.test(i)) { if (regs.size() != 1) { @@ -8703,7 +8703,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s fmt::append(regs, " r%u-w", i); } - if (::at32(pattern.loop_args, i)) + if (pattern.loop_args.test(i)) { if (regs.size() != 1) { @@ -8713,7 +8713,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s fmt::append(regs, " r%u-r", i); } - if (::at32(pattern.loop_may_update, i)) + if (pattern.loop_may_update.test(i)) { if (regs.size() != 1) { diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 1bf37086ad..bd0928f965 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -7148,8 +7148,8 @@ public: { const value_t ab[2]{a, b}; - std::bitset<2> safe_int_compare(0); - std::bitset<2> safe_finite_compare(0); + bit_set<2> safe_int_compare(0); + bit_set<2> safe_finite_compare(0); for (u32 i = 0; i < 2; i++) { @@ -7192,12 +7192,12 @@ public: return eval(sext(bitcast(a) > bitcast(b))); } - if (safe_finite_compare.test(1)) + if (safe_finite_compare.test(1u)) { return eval(sext(fcmp_uno(clamp_negative_smax(a) > b))); } - if (safe_finite_compare.test(0)) + if (safe_finite_compare.test(0u)) { return eval(sext(fcmp_ord(a > clamp_smax(b)))); } @@ -7247,7 +7247,7 @@ public: const value_t ab[2]{a, b}; - std::bitset<2> safe_int_compare(0); + bit_set<2> safe_int_compare(0); for (u32 i = 0; i < 2; i++) { @@ -7521,8 +7521,8 @@ public: const value_t ab[2]{a, b}; - std::bitset<2> safe_float_compare(0); - std::bitset<2> safe_int_compare(0); + bit_set<2> safe_float_compare(0); + bit_set<2> safe_int_compare(0); for (u32 i = 0; i < 2; i++) { @@ -7595,8 +7595,8 @@ public: const value_t ab[2]{a, b}; - std::bitset<2> safe_float_compare(0); - std::bitset<2> safe_int_compare(0); + bit_set<2> safe_float_compare(0); + bit_set<2> safe_int_compare(0); for (u32 i = 0; i < 2; i++) { diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index f1ce3a5982..0dda3a3229 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -6,22 +6,10 @@ #include "SPUThread.h" #include "SPUAnalyser.h" #include -#include #include #include #include -// std::bitset -template - requires requires(std::remove_cvref_t& x, T&& y) { x.count(); x.test(y); x.flip(y); } -[[nodiscard]] constexpr bool at32(CT&& container, T&& index, std::source_location src_loc = std::source_location::current()) -{ - const usz csv = container.size(); - if (csv <= std::forward(index)) [[unlikely]] - fmt::raw_range_error(src_loc, format_object_simplified(index), csv); - return container[std::forward(index)]; -} - // Helper class class spu_cache { @@ -358,15 +346,15 @@ public: } } - std::bitset loop_args; - std::bitset loop_dicts; - std::bitset loop_writes; - std::bitset loop_may_update; - std::bitset gpr_not_nans; + bit_set loop_args; + bit_set loop_dicts; + bit_set loop_writes; + bit_set loop_may_update; + bit_set gpr_not_nans; struct origin_t { - std::bitset regs{}; + bit_set regs{}; u32 modified = 0; spu_itype_t mod1_type = spu_itype::UNK; spu_itype_t mod2_type = spu_itype::UNK; @@ -434,7 +422,7 @@ public: return true; } - return regs.count() == 1 && ::at32(regs, reg_val); + return regs.count() == 1 && regs.test(reg_val); } bool is_loop_dictator(u32 reg_val, bool test_predictable = false, bool should_predictable = true) const @@ -444,7 +432,7 @@ public: return false; } - if (regs.count() >= 1 && ::at32(regs, reg_val)) + if (regs.count() >= 1 && regs.test(reg_val)) { if (!test_predictable) { @@ -503,7 +491,7 @@ public: return false; } - if (regs.count() - (::at32(regs, reg_val) ? 1 : 0)) + if (regs.count() - (regs.test(reg_val) ? 1 : 0)) { return false; } @@ -686,7 +674,7 @@ public: bool is_gpr_not_NaN_hint(u32 i) const noexcept { - return ::at32(gpr_not_nans, i); + return gpr_not_nans.test(i); } origin_t get_reg(u32 reg_val) noexcept @@ -714,14 +702,14 @@ protected: u64 m_hash_start; // Bit indicating start of the block - std::bitset m_block_info; + bit_set m_block_info; // GPR modified by the instruction (-1 = not set) std::array m_regmod; - std::bitset m_use_ra; - std::bitset m_use_rb; - std::bitset m_use_rc; + bit_set m_use_ra; + bit_set m_use_rb; + bit_set m_use_rc; // List of possible targets for the instruction (entry shouldn't exist for simple instructions) std::unordered_map, value_hash> m_targets; @@ -730,10 +718,10 @@ protected: std::unordered_map, value_hash> m_preds; // List of function entry points and return points (set after BRSL, BRASL, BISL, BISLED) - std::bitset m_entry_info; + bit_set m_entry_info; // Set after return points and disjoint chunks - std::bitset m_ret_info; + bit_set m_ret_info; // Basic block information struct block_info @@ -751,28 +739,28 @@ protected: term_type terminator; // Bit mask of the registers modified in the block - std::bitset reg_mod{}; + bit_set reg_mod{}; // Set if last modifying instruction produces xfloat - std::bitset reg_mod_xf{}; + bit_set reg_mod_xf{}; // Set if the initial register value in this block may be xfloat - std::bitset reg_maybe_xf{}; + bit_set reg_maybe_xf{}; // Set if register is used in floating pont instruction - std::bitset reg_maybe_float{}; + bit_set reg_maybe_float{}; // Set if register is used as shuffle mask - std::bitset reg_maybe_shuffle_mask{}; + bit_set reg_maybe_shuffle_mask{}; // Number of times registers are used (before modified) std::array reg_use{}; // Bit mask of the trivial (u32 x 4) constant value resulting in this block - std::bitset reg_const{}; + bit_set reg_const{}; // Bit mask of register saved onto the stack before use - std::bitset reg_save_dom{}; + bit_set reg_save_dom{}; // Address of the function u32 func = 0x40000; @@ -850,7 +838,7 @@ protected: private: // For private use - std::bitset<0x10000> m_bits; + bit_set<0x10000> m_bits; // For private use std::vector workload; diff --git a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp index 29a1fa3501..ebcbd74f8b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp @@ -9,7 +9,6 @@ #include "sys_rsxaudio.h" #include -#include #include #ifdef __linux__ @@ -1651,13 +1650,13 @@ void rsxaudio_backend_thread::set_mute_state(avport_bit muted_avports) u8 rsxaudio_backend_thread::gen_mute_state(avport_bit avports) { - std::bitset mute_state{0}; + bit_set mute_state{0}; - if (avports.hdmi_0) mute_state[static_cast(RsxaudioAvportIdx::HDMI_0)] = true; - if (avports.hdmi_1) mute_state[static_cast(RsxaudioAvportIdx::HDMI_1)] = true; - if (avports.avmulti) mute_state[static_cast(RsxaudioAvportIdx::AVMULTI)] = true; - if (avports.spdif_0) mute_state[static_cast(RsxaudioAvportIdx::SPDIF_0)] = true; - if (avports.spdif_1) mute_state[static_cast(RsxaudioAvportIdx::SPDIF_1)] = true; + if (avports.hdmi_0) mute_state.set(static_cast(RsxaudioAvportIdx::HDMI_0), true); + if (avports.hdmi_1) mute_state.set(static_cast(RsxaudioAvportIdx::HDMI_1), true); + if (avports.avmulti) mute_state.set(static_cast(RsxaudioAvportIdx::AVMULTI), true); + if (avports.spdif_0) mute_state.set(static_cast(RsxaudioAvportIdx::SPDIF_0), true); + if (avports.spdif_1) mute_state.set(static_cast(RsxaudioAvportIdx::SPDIF_1), true); return static_cast(mute_state.to_ulong()); } @@ -1832,7 +1831,7 @@ u32 rsxaudio_backend_thread::write_data_callback(u32 bytes, void* buf) return val; }); - const std::bitset mute_state{cb_cfg.mute_state}; + const bit_set mute_state{cb_cfg.mute_state}; if (cb_cfg.ready && !mute_state[static_cast(cb_cfg.avport_idx)] && Emu.IsRunning()) { diff --git a/rpcs3/Emu/RSX/Common/bitfield.hpp b/rpcs3/Emu/RSX/Common/bitfield.hpp index af02792fc7..4ffc07a537 100644 --- a/rpcs3/Emu/RSX/Common/bitfield.hpp +++ b/rpcs3/Emu/RSX/Common/bitfield.hpp @@ -2,12 +2,11 @@ #include "util/atomic.hpp" #include -#include namespace rsx { template - void unpack_bitset(const std::bitset& block, u64* values) + void unpack_bitset(const bit_set& block, u64* values) { for (int bit = 0, n = -1, shift = 0; bit < N; ++bit, ++shift) { @@ -25,11 +24,11 @@ namespace rsx } template - void pack_bitset(std::bitset& block, u64* values) + void pack_bitset(bit_set& block, u64* values) { for (int n = 0, shift = 0; shift < N; ++n, shift += 64) { - std::bitset tmp = values[n]; + bit_set tmp = values[n]; tmp <<= shift; block |= tmp; } diff --git a/rpcs3/Emu/RSX/Program/ProgramStateCache.cpp b/rpcs3/Emu/RSX/Program/ProgramStateCache.cpp index f1c2d49097..221e24ea75 100644 --- a/rpcs3/Emu/RSX/Program/ProgramStateCache.cpp +++ b/rpcs3/Emu/RSX/Program/ProgramStateCache.cpp @@ -140,7 +140,7 @@ vertex_program_utils::vertex_program_metadata vertex_program_utils::analyse_vert //u32 last_instruction_address = 0; //u32 first_instruction_address = entry; - std::bitset instructions_to_patch; + bit_set instructions_to_patch; std::pair instruction_range{ umax, 0 }; bool has_branch_instruction = false; std::stack call_stack; @@ -178,7 +178,7 @@ vertex_program_utils::vertex_program_metadata vertex_program_utils::analyse_vert d3.HEX = instruction._u32[3]; // Touch current instruction - result.instruction_mask[current_instruction] = true; + result.instruction_mask.set(current_instruction, true); instruction_range.first = std::min(current_instruction, instruction_range.first); instruction_range.second = std::max(current_instruction, instruction_range.second); @@ -258,7 +258,7 @@ vertex_program_utils::vertex_program_metadata vertex_program_utils::analyse_vert case RSX_SCA_OPCODE_CLB: { // Need to patch the jump address to be consistent wherever the program is located - instructions_to_patch[current_instruction] = true; + instructions_to_patch.set(current_instruction, true); has_branch_instruction = true; d0.HEX = instruction._u32[0]; diff --git a/rpcs3/Emu/RSX/Program/ProgramStateCache.h b/rpcs3/Emu/RSX/Program/ProgramStateCache.h index 76e168d20a..e1bdc88523 100644 --- a/rpcs3/Emu/RSX/Program/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Program/ProgramStateCache.h @@ -24,7 +24,7 @@ namespace program_hash_util { struct vertex_program_metadata { - std::bitset instruction_mask; + bit_set instruction_mask; u32 ucode_length; u32 referenced_textures_mask; u16 referenced_inputs_mask; diff --git a/rpcs3/Emu/RSX/Program/RSXVertexProgram.h b/rpcs3/Emu/RSX/Program/RSXVertexProgram.h index 1277250b56..c3834e4f93 100644 --- a/rpcs3/Emu/RSX/Program/RSXVertexProgram.h +++ b/rpcs3/Emu/RSX/Program/RSXVertexProgram.h @@ -3,7 +3,6 @@ #include "program_util.h" #include -#include #include enum vp_reg_type @@ -227,7 +226,7 @@ struct RSXVertexProgram u32 output_mask = 0; u32 base_address = 0; u32 entry = 0; - std::bitset instruction_mask; + bit_set instruction_mask; std::set jump_table; rsx::texture_dimension_extended get_texture_dimension(u8 id) const diff --git a/rpcs3/Emu/RSX/RSXFIFO.cpp b/rpcs3/Emu/RSX/RSXFIFO.cpp index 8ac6a436a2..de0663363a 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.cpp +++ b/rpcs3/Emu/RSX/RSXFIFO.cpp @@ -12,7 +12,6 @@ #include "util/asm.hpp" #include -#include using spu_rdata_t = std::byte[128]; @@ -689,7 +688,7 @@ namespace rsx } // Check for flow control - if (std::bitset<2> jump_type; jump_type + if (bit_set<2> jump_type; jump_type .set(0, (cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD) .set(1, (cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD) .any()) diff --git a/rpcs3/rpcs3qt/log_viewer.cpp b/rpcs3/rpcs3qt/log_viewer.cpp index 623a74b48a..c19c8ef0d7 100644 --- a/rpcs3/rpcs3qt/log_viewer.cpp +++ b/rpcs3/rpcs3qt/log_viewer.cpp @@ -40,7 +40,7 @@ log_viewer::log_viewer(std::shared_ptr gui_settings) m_path_last = m_gui_settings->GetValue(gui::fd_log_viewer).toString(); m_show_timestamps = m_gui_settings->GetValue(gui::lv_show_timestamps).toBool(); m_show_threads = m_gui_settings->GetValue(gui::lv_show_threads).toBool(); - m_log_levels = std::bitset<32>(m_gui_settings->GetValue(gui::lv_log_levels).toUInt()); + m_log_levels = bit_set<32>(m_gui_settings->GetValue(gui::lv_log_levels).toUInt()); m_log_text = new QPlainTextEdit(this); m_log_text->setReadOnly(true); diff --git a/rpcs3/rpcs3qt/log_viewer.h b/rpcs3/rpcs3qt/log_viewer.h index d6ba2ff2a4..443c89eb78 100644 --- a/rpcs3/rpcs3qt/log_viewer.h +++ b/rpcs3/rpcs3qt/log_viewer.h @@ -1,11 +1,11 @@ #pragma once #include "find_dialog.h" +#include "util/types.hpp" #include #include -#include #include class LogHighlighter; @@ -37,7 +37,7 @@ private: QPlainTextEdit* m_log_text; LogHighlighter* m_log_highlighter; std::unique_ptr m_find_dialog; - std::bitset<32> m_log_levels = std::bitset<32>(0b11111111u); + bit_set<32> m_log_levels = bit_set<32>(0b11111111u); bool m_show_timestamps = true; bool m_show_threads = true; bool m_last_actions_only = false; diff --git a/rpcs3/util/types.hpp b/rpcs3/util/types.hpp index a1a07bac69..46a819c78c 100644 --- a/rpcs3/util/types.hpp +++ b/rpcs3/util/types.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1064,6 +1065,144 @@ template requires requires (CT&& x, T&& y) { x.count(y return found->second; } +// Exception friendly std::bitset +template +struct bit_set +{ +public: + constexpr bit_set() noexcept : m_bitset() {} + constexpr bit_set(usz val) noexcept : m_bitset(val) {} + + [[nodiscard]] bool test(usz pos, std::source_location src_loc = std::source_location::current()) const + { + if (pos >= Bits) [[unlikely]] + fmt::raw_range_error(src_loc, format_object_simplified(pos), Bits); + + return m_bitset[pos]; + } + + bit_set& set(usz pos, bool val = true, std::source_location src_loc = std::source_location::current()) + { + if (pos >= Bits) [[unlikely]] + fmt::raw_range_error(src_loc, format_object_simplified(pos), Bits); + + m_bitset[pos] = val; + return *this; + } + + bit_set& reset(usz pos, std::source_location src_loc = std::source_location::current()) + { + if (pos >= Bits) [[unlikely]] + fmt::raw_range_error(src_loc, format_object_simplified(pos), Bits); + + m_bitset[pos] = false; + return *this; + } + + constexpr bit_set& reset() noexcept + { + m_bitset.reset(); + return *this; + } + + [[nodiscard]] constexpr unsigned long to_ulong() const noexcept requires(Bits <= 32) + { + return m_bitset.to_ulong(); + } + + [[nodiscard]] constexpr unsigned long long to_ullong() const noexcept requires(Bits <= 64) + { + return m_bitset.to_ullong(); + } + + [[nodiscard]] constexpr bool any() const noexcept + { + return m_bitset.any(); + } + + [[nodiscard]] constexpr bool none() const noexcept + { + return m_bitset.none(); + } + + [[nodiscard]] constexpr bool all() const noexcept + { + return m_bitset.all(); + } + + [[nodiscard]] constexpr usz count() const noexcept + { + return m_bitset.count(); + } + + [[nodiscard]] constexpr usz size() const noexcept + { + return Bits; + } + + // Helps us getting the source location when using the [] operator + struct location_index + { + template requires std::convertible_to + location_index(T&& pos, std::source_location src_loc = std::source_location::current()) + : index(static_cast(std::forward(pos))), loc(src_loc) + {} + + usz index; + std::source_location loc; + }; + + [[nodiscard]] constexpr bool operator[](location_index index) const + { + return test(index.index, index.loc); + } + + constexpr bit_set& operator&=(const bit_set& r) noexcept + { + m_bitset &= r.m_bitset; + return *this; + } + + constexpr bit_set& operator|=(const bit_set& r) noexcept + { + m_bitset |= r.m_bitset; + return *this; + } + + constexpr bit_set& operator^=(const bit_set& r) noexcept + { + m_bitset ^= r.m_bitset; + return *this; + } + + constexpr bit_set& operator<<=(usz pos) noexcept + { + m_bitset <<= pos; + return *this; + } + + constexpr bit_set& operator>>=(usz pos) noexcept + { + m_bitset >>= pos; + return *this; + } + + [[nodiscard]] constexpr bit_set operator<<(const usz pos) const noexcept + { + return m_bitset << pos; + } + + [[nodiscard]] constexpr bit_set operator>>(const usz pos) const noexcept + { + return m_bitset >> pos; + } + +private: + constexpr bit_set(std::bitset&& set) noexcept : m_bitset(set) {} + + std::bitset m_bitset; +}; + // Simplified hash algorithm. May be used in std::unordered_(map|set). template struct value_hash