[dynarmic] Implement constant folding for CountLeadingZeros, add readXX constnat folding for A64

Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2025-09-09 11:04:34 +00:00
parent 86a82da228
commit 615f2935aa
Signed by: Lizzie
GPG key ID: 00287378CADCAB13

View file

@ -31,10 +31,11 @@
namespace Dynarmic::Optimization { namespace Dynarmic::Optimization {
static void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) { static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
for (auto& inst : block) { for (auto& inst : block) {
switch (inst.GetOpcode()) { switch (inst.GetOpcode()) {
case IR::Opcode::A32ReadMemory8: { case IR::Opcode::A32ReadMemory8:
case IR::Opcode::A64ReadMemory8: {
if (inst.AreAllArgsImmediates()) { if (inst.AreAllArgsImmediates()) {
const u32 vaddr = inst.GetArg(1).GetU32(); const u32 vaddr = inst.GetArg(1).GetU32();
if (cb->IsReadOnlyMemory(vaddr)) { if (cb->IsReadOnlyMemory(vaddr)) {
@ -44,7 +45,8 @@ static void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
} }
break; break;
} }
case IR::Opcode::A32ReadMemory16: { case IR::Opcode::A32ReadMemory16:
case IR::Opcode::A64ReadMemory16: {
if (inst.AreAllArgsImmediates()) { if (inst.AreAllArgsImmediates()) {
const u32 vaddr = inst.GetArg(1).GetU32(); const u32 vaddr = inst.GetArg(1).GetU32();
if (cb->IsReadOnlyMemory(vaddr)) { if (cb->IsReadOnlyMemory(vaddr)) {
@ -54,7 +56,8 @@ static void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
} }
break; break;
} }
case IR::Opcode::A32ReadMemory32: { case IR::Opcode::A32ReadMemory32:
case IR::Opcode::A64ReadMemory32: {
if (inst.AreAllArgsImmediates()) { if (inst.AreAllArgsImmediates()) {
const u32 vaddr = inst.GetArg(1).GetU32(); const u32 vaddr = inst.GetArg(1).GetU32();
if (cb->IsReadOnlyMemory(vaddr)) { if (cb->IsReadOnlyMemory(vaddr)) {
@ -64,7 +67,8 @@ static void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
} }
break; break;
} }
case IR::Opcode::A32ReadMemory64: { case IR::Opcode::A32ReadMemory64:
case IR::Opcode::A64ReadMemory64: {
if (inst.AreAllArgsImmediates()) { if (inst.AreAllArgsImmediates()) {
const u32 vaddr = inst.GetArg(1).GetU32(); const u32 vaddr = inst.GetArg(1).GetU32();
if (cb->IsReadOnlyMemory(vaddr)) { if (cb->IsReadOnlyMemory(vaddr)) {
@ -667,14 +671,14 @@ using Op = Dynarmic::IR::Opcode;
// bit size all over the place within folding functions. // bit size all over the place within folding functions.
static void ReplaceUsesWith(IR::Inst& inst, bool is_32_bit, u64 value) { static void ReplaceUsesWith(IR::Inst& inst, bool is_32_bit, u64 value) {
if (is_32_bit) { if (is_32_bit) {
inst.ReplaceUsesWith(IR::Value{static_cast<u32>(value)}); inst.ReplaceUsesWith(IR::Value{u32(value)});
} else { } else {
inst.ReplaceUsesWith(IR::Value{value}); inst.ReplaceUsesWith(IR::Value{value});
} }
} }
static IR::Value Value(bool is_32_bit, u64 value) { static IR::Value Value(bool is_32_bit, u64 value) {
return is_32_bit ? IR::Value{static_cast<u32>(value)} : IR::Value{value}; return is_32_bit ? IR::Value{u32(value)} : IR::Value{value};
} }
template<typename ImmFn> template<typename ImmFn>
@ -800,6 +804,23 @@ static void FoldByteReverse(IR::Inst& inst, Op op) {
} }
} }
/// Folds leading zero population count
///
/// 1. imm -> countl_zero(imm)
///
static void FoldCountLeadingZeros(IR::Inst& inst, bool is_32_bit) {
const auto operand = inst.GetArg(0);
if (operand.IsImmediate()) {
if (is_32_bit) {
const u32 result = std::countl_zero(u32(operand.GetImmediateAsU64()));
inst.ReplaceUsesWith(IR::Value{result});
} else {
const u64 result = std::countl_zero(operand.GetImmediateAsU64());
inst.ReplaceUsesWith(IR::Value{result});
}
}
}
/// Folds division operations based on the following: /// Folds division operations based on the following:
/// ///
/// 1. x / 0 -> 0 (NOTE: This is an ARM-specific behavior defined in the architecture reference manual) /// 1. x / 0 -> 0 (NOTE: This is an ARM-specific behavior defined in the architecture reference manual)
@ -1020,8 +1041,7 @@ static void FoldZeroExtendXToLong(IR::Inst& inst) {
static void ConstantPropagation(IR::Block& block) { static void ConstantPropagation(IR::Block& block) {
for (auto& inst : block) { for (auto& inst : block) {
const auto opcode = inst.GetOpcode(); auto const opcode = inst.GetOpcode();
switch (opcode) { switch (opcode) {
case Op::LeastSignificantWord: case Op::LeastSignificantWord:
FoldLeastSignificantWord(inst); FoldLeastSignificantWord(inst);
@ -1110,12 +1130,12 @@ static void ConstantPropagation(IR::Block& block) {
break; break;
case Op::ArithmeticShiftRightMasked32: case Op::ArithmeticShiftRightMasked32:
if (inst.AreAllArgsImmediates()) { if (inst.AreAllArgsImmediates()) {
ReplaceUsesWith(inst, true, static_cast<s32>(inst.GetArg(0).GetU32()) >> (inst.GetArg(1).GetU32() & 0x1f)); ReplaceUsesWith(inst, true, s32(inst.GetArg(0).GetU32()) >> (inst.GetArg(1).GetU32() & 0x1f));
} }
break; break;
case Op::ArithmeticShiftRightMasked64: case Op::ArithmeticShiftRightMasked64:
if (inst.AreAllArgsImmediates()) { if (inst.AreAllArgsImmediates()) {
ReplaceUsesWith(inst, false, static_cast<s64>(inst.GetArg(0).GetU64()) >> (inst.GetArg(1).GetU64() & 0x3f)); ReplaceUsesWith(inst, false, s64(inst.GetArg(0).GetU64()) >> (inst.GetArg(1).GetU64() & 0x3f));
} }
break; break;
case Op::RotateRightMasked32: case Op::RotateRightMasked32:
@ -1187,6 +1207,10 @@ static void ConstantPropagation(IR::Block& block) {
case Op::ByteReverseDual: case Op::ByteReverseDual:
FoldByteReverse(inst, opcode); FoldByteReverse(inst, opcode);
break; break;
case Op::CountLeadingZeros32:
case Op::CountLeadingZeros64:
FoldCountLeadingZeros(inst, opcode == Op::CountLeadingZeros32);
break;
default: default:
break; break;
} }
@ -1462,7 +1486,7 @@ void Optimize(IR::Block& block, const A32::UserConfig& conf, const Optimization:
Optimization::DeadCodeElimination(block); Optimization::DeadCodeElimination(block);
} }
if (conf.HasOptimization(OptimizationFlag::ConstProp)) [[likely]] { if (conf.HasOptimization(OptimizationFlag::ConstProp)) [[likely]] {
Optimization::A32ConstantMemoryReads(block, conf.callbacks); Optimization::ConstantMemoryReads(block, conf.callbacks);
Optimization::ConstantPropagation(block); Optimization::ConstantPropagation(block);
Optimization::DeadCodeElimination(block); Optimization::DeadCodeElimination(block);
} }