mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-23 17:13:13 -05:00
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>
72 lines
3.4 KiB
C++
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;
|
|
}
|
|
}
|