shader: handle scalar guards for image bounds

This commit is contained in:
nmzik
2026-09-28 05:30:22 +04:00
parent 720a0b5bbf
commit dacba43fcc
2 changed files with 33 additions and 22 deletions
@@ -705,22 +705,10 @@ private:
return false;
}
const auto* previous = block->ImmPredecessors()[0];
const auto current_it = std::ranges::find(m_program.blocks, block);
const auto previous_it = std::ranges::find(m_program.blocks, previous);
if (current_it == m_program.blocks.end() || previous_it == m_program.blocks.end()) {
return false;
}
const auto& info = m_program.block_info[previous_it - m_program.blocks.begin()];
const auto id = m_program.block_info[current_it - m_program.blocks.begin()].id;
const auto& term = info.terminator;
if (term.kind == CFG::TerminatorKind::ConditionalBranch &&
(term.true_block == id) != (term.false_block == id)) {
bool positive = term.true_block == id;
const auto* test = info.condition.Resolve().TryInstruction();
while (test != nullptr && test->GetOpcode() == ValueOpcode::LogicalNot) {
positive = !positive;
test = test->Arg(0).Resolve().TryInstruction();
}
Value condition;
bool positive = false;
if (ConditionalEdge(previous, block, condition, positive)) {
const auto* test = condition.TryInstruction();
if (test != nullptr && test->NumArgs() == 2u &&
((test->GetOpcode() == ValueOpcode::INotEqual32 && positive) ||
(test->GetOpcode() == ValueOpcode::IEqual32 && !positive))) {
@@ -801,9 +789,17 @@ private:
condition = info.condition;
positive = term.true_block == id;
while (const auto* inst = condition.Resolve().TryInstruction()) {
if (inst->GetOpcode() != ValueOpcode::LogicalNot) break;
if (inst->GetOpcode() == ValueOpcode::LogicalNot) {
positive = !positive;
} else if (inst->GetOpcode() == ValueOpcode::ConditionRef) {
// SCC is uniform across the guest wave; EXEC and VCC are lane predicates.
const auto kind = inst->Flags<CFG::BranchCondition>();
if (kind != CFG::BranchCondition::SccZero &&
kind != CFG::BranchCondition::SccNonZero) break;
} else {
break;
}
condition = inst->Arg(0);
positive = !positive;
}
condition = condition.Resolve();
return true;
+19 -4
View File
@@ -561,9 +561,10 @@ void TestInvariantIndirectImageMaterialization() {
void TestGuardedDirectImageTable() {
namespace CFG = Libs::Graphics::ShaderRecompiler::CFG;
enum class Guard { Nonzero, Zero, Unrelated, Bypass };
enum class Guard { Nonzero, SccNonZero, Plain, Zero, Unrelated, Bypass, ExecZero, VccZero };
const auto make_plan = [](Guard guard) {
Fixture fixture(ShaderType::Pixel);
fixture.program.wave_size = 64u;
auto *entry = fixture.block;
auto *middle = fixture.AddBlock();
auto *before_sample = fixture.AddBlock();
@@ -580,8 +581,19 @@ void TestGuardedDirectImageTable() {
const auto nonzero = fixture.Emit(
ValueOpcode::INotEqual32,
{Value(0u), guard == Guard::Unrelated ? fixture.UserData(2) : mask});
fixture.program.block_info[0].condition =
fixture.Emit(ValueOpcode::LogicalNot, {nonzero});
const auto kind = guard == Guard::ExecZero ? CFG::BranchCondition::ExecZero
: guard == Guard::VccZero ? CFG::BranchCondition::VccZero
: CFG::BranchCondition::SccZero;
auto condition = nonzero;
if (guard == Guard::SccNonZero) {
condition = fixture.Emit(ValueOpcode::ConditionRef, {condition},
CFG::BranchCondition::SccNonZero);
}
condition = fixture.Emit(ValueOpcode::LogicalNot, {condition});
if (guard != Guard::Plain && guard != Guard::SccNonZero) {
condition = fixture.Emit(ValueOpcode::ConditionRef, {condition}, kind);
}
fixture.program.block_info[0].condition = condition;
fixture.program.block_info[0].terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = guard == Guard::Zero ? 1u : 4u,
@@ -645,7 +657,10 @@ void TestGuardedDirectImageTable() {
};
auto plan = make_plan(Guard::Nonzero);
for (const auto guard : {Guard::Zero, Guard::Unrelated, Guard::Bypass}) {
make_plan(Guard::SccNonZero);
make_plan(Guard::Plain);
for (const auto guard : {Guard::Zero, Guard::Unrelated, Guard::Bypass,
Guard::ExecZero, Guard::VccZero}) {
CheckFatal([&] { make_plan(guard); }, "not a valid runtime value",
"direct table accepted a selector without a dominating nonzero guard");
}