Files
AnyPS5/core/libs/prx/libSceAgcDriver/tests/ConstantBitTest.cpp
T
AlexandClaude Haiku 5.5 d809958b27 fix(shader): fold BitReverse32 of an immediate
A descriptor dword built by S_BREV_B32, V_BFREV_B32 or S_BREV_B64 from a
constant stayed a runtime value, so the resource could not be resolved
and the shader failed to prepare. The constant folder now reverses the
bits of an immediate the way the hardware does (D[31-i] = S0[i]), like
the existing BitCount32 fold. ConstantBitTest covers the fold.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-11 05:23:40 -04:00

72 lines
3.4 KiB
C++

#include "IntermediateRepresentation/IrBuilder.hpp"
#include "Optimization/ConstantFolder.hpp"
#include <cstdint>
#include <cstdio>
#include <exception>
using namespace ShaderRecompiler;
namespace {
bool foldsTo(std::uint32_t word, bool expected, bool maskedShift) {
IrProgram program;
auto& block = program.CreateBlock();
program.SetEntryBlock(block);
program.BlockOrder().push_back(&block);
IrBuilder builder(program);
builder.SetInsertionPoint(block);
auto& lane = builder.Emit(IrOpcode::LaneId, IrType::U32, {});
auto& shift = maskedShift ? builder.Emit(IrOpcode::BitwiseAnd32, IrType::U32, {&lane, &builder.Constant(31u)}) : lane;
auto& shifted = builder.Emit(IrOpcode::ShiftRightLogical32, IrType::U32, {&builder.Constant(word), &shift});
auto& bit = builder.Emit(IrOpcode::BitwiseAnd32, IrType::U32, {&shifted, &builder.Constant(1u)});
auto& test = builder.Emit(IrOpcode::INotEqual32, IrType::Bool, {&bit, &builder.Constant(0u)});
auto& user = builder.Emit(IrOpcode::Reference, IrType::Void, {&test});
static_cast<void>(builder.Emit(IrOpcode::Return, IrType::Void, {}));
ConstantFolder().Fold(program);
const IrValue* result = user.Argument(0)->Resolve();
if (!maskedShift || (word != 0u && word != 0xffffffffu)) return result->Opcode() == IrOpcode::INotEqual32;
return result->HasImmediate() && result->ImmediateBool() == expected;
}
bool reversesTo(std::uint32_t word, std::uint32_t expected) {
IrProgram program;
auto& block = program.CreateBlock();
program.SetEntryBlock(block);
program.BlockOrder().push_back(&block);
IrBuilder builder(program);
builder.SetInsertionPoint(block);
auto& reversed = builder.Emit(IrOpcode::BitReverse32, IrType::U32, {&builder.Constant(word)});
auto& test = builder.Emit(IrOpcode::IEqual32, IrType::Bool, {&reversed, &builder.Constant(expected)});
auto& user = builder.Emit(IrOpcode::Reference, IrType::Void, {&test});
static_cast<void>(builder.Emit(IrOpcode::Return, IrType::Void, {}));
ConstantFolder().Fold(program);
const IrValue* result = user.Argument(0)->Resolve();
return result->HasImmediate() && result->ImmediateBool();
}
bool run(const char* name, bool passed) {
if (!passed) std::fprintf(stderr, "%s\n", name);
return passed;
}
}
int main() {
try {
bool passed = true;
passed &= run("an all-zero word must fold the lane bit test to false", foldsTo(0u, false, true));
passed &= run("an all-one word must fold the lane bit test to true", foldsTo(0xffffffffu, true, true));
passed &= run("a mixed word must keep the lane bit test", foldsTo(0x0000ffffu, false, true));
passed &= run("an unmasked lane number must keep the lane bit test", foldsTo(0xffffffffu, true, false));
passed &= run("a reversed zero must fold to zero", reversesTo(0x00000000u, 0x00000000u));
passed &= run("a reversed single bit must fold to the opposite end", reversesTo(0x00000001u, 0x80000000u));
passed &= run("a reversed high bit must fold to bit zero", reversesTo(0x80000000u, 0x00000001u));
passed &= run("a reversed mixed word must fold to its mirror image", reversesTo(0x12345678u, 0x1e6a2c48u));
passed &= run("a reversed descriptor dword must fold to its mirror image", reversesTo(0xdeadbeefu, 0xf77db57bu));
return passed ? 0 : 1;
} catch (const std::exception& error) {
std::fprintf(stderr, "%s\n", error.what());
return 1;
}
}