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>
This commit is contained in:
parent
09bd4aa1a3
commit
d809958b27
|
|
@ -28,6 +28,22 @@ bool foldsTo(std::uint32_t word, bool expected, bool maskedShift) {
|
|||
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;
|
||||
|
|
@ -42,6 +58,11 @@ int main() {
|
|||
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());
|
||||
|
|
|
|||
|
|
@ -623,6 +623,19 @@ bool ConstantFolder::tryFoldValue(IrProgram& program, IrValue& value) const {
|
|||
replaceWith(value, builder.Constant(static_cast<std::uint32_t>(std::popcount(operand.ImmediateU64()))));
|
||||
return true;
|
||||
}
|
||||
case IrOpcode::BitReverse32: {
|
||||
auto& operand = resolveArg(value, 0);
|
||||
if (!isImmediate(operand, IrType::U32)) {
|
||||
return false;
|
||||
}
|
||||
const std::uint32_t word = operand.ImmediateU32();
|
||||
std::uint32_t reversed = 0;
|
||||
for (std::uint32_t bit = 0; bit < 32; ++bit) {
|
||||
reversed |= ((word >> bit) & 1u) << (31u - bit);
|
||||
}
|
||||
replaceWith(value, builder.Constant(reversed));
|
||||
return true;
|
||||
}
|
||||
case IrOpcode::SMin32:
|
||||
case IrOpcode::SMax32: {
|
||||
const auto opcode = value.Opcode();
|
||||
|
|
|
|||
Loading…
Reference in New Issue