shader: cache integer dependency checks

This commit is contained in:
nmzik
2026-09-05 20:35:18 +04:00
parent 86b539a9ea
commit 43de8bfaac
2 changed files with 47 additions and 0 deletions
@@ -167,11 +167,14 @@ private:
default: return false;
}
}
// Integer-only dependency checks do not depend on the active EXEC mask.
if (!require_uniform && m_validated_dependencies.contains(inst)) return true;
if (!m_visiting.insert(inst).second) {
return !require_uniform;
}
const auto finish = [&](bool valid) {
m_visiting.erase(inst);
if (valid && !require_uniform) m_validated_dependencies.insert(inst);
return valid;
};
const auto op = inst->GetOpcode();
@@ -299,6 +302,7 @@ private:
RuntimeValueType m_type;
Value m_active_mask;
std::unordered_set<const Inst*> m_visiting;
std::unordered_set<const Inst*> m_validated_dependencies;
};
class PlanBuilder {
+43
View File
@@ -398,6 +398,48 @@ void TestUniformFirstLaneSamplerLod() {
"uniform sampler LOD clamp evaluated incorrectly");
}
void TestSharedIntegerRuntimeDependencies() {
Fixture fixture;
const auto lane = fixture.Emit(ValueOpcode::LaneId);
const auto active =
fixture.Emit(ValueOpcode::IEqual32, {lane, Value(0u)});
auto inactive = lane;
for (uint32_t level = 0; level < 36; level++) {
const auto left =
fixture.Emit(ValueOpcode::IAdd32, {inactive, Value(1u)});
const auto right =
fixture.Emit(ValueOpcode::IMul32, {inactive, Value(3u)});
inactive = fixture.Emit(ValueOpcode::BitwiseXor32, {left, right});
}
const auto selected = fixture.Emit(
ValueOpcode::SelectU32, {active, Value(42u), inactive});
const auto first =
fixture.Emit(ValueOpcode::ReadFirstLane, {selected, active});
Check(ValidateRuntimeValue(fixture.program, first, RuntimeValueType::Integer),
"shared integer dependencies behind an inactive arm were rejected");
const auto uniform_use = fixture.Emit(ValueOpcode::IAdd32, {first, inactive});
Check(!ValidateRuntimeValue(fixture.program, uniform_use,
RuntimeValueType::Integer),
"integer-only dependency acceptance was reused as uniform acceptance");
const auto other_active =
fixture.Emit(ValueOpcode::IEqual32, {lane, Value(1u)});
const auto other_first =
fixture.Emit(ValueOpcode::ReadFirstLane, {selected, other_active});
const auto both = fixture.Emit(ValueOpcode::IAdd32, {first, other_first});
Check(!ValidateRuntimeValue(fixture.program, both, RuntimeValueType::Integer),
"uniform acceptance was reused across different execution masks");
const auto floating =
fixture.Emit(ValueOpcode::BitCastU32F32, {Value::F32(1.f)});
const auto mixed =
fixture.Emit(ValueOpcode::BitwiseOr32, {inactive, floating});
selected.ResolveInstruction()->SetArg(2, mixed);
Check(!ValidateRuntimeValue(fixture.program, first, RuntimeValueType::Integer),
"shared integer dependencies hid a floating-point sibling");
}
void TestConstantBufferBounds() {
Fixture fixture;
const auto memory = fixture.AddMemory(ResourceKind::ScalarBuffer);
@@ -555,6 +597,7 @@ int main() {
TestControlDependentStandaloneLoadStaysTyped();
TestRuntime64BitDescriptorOps();
TestUniformFirstLaneSamplerLod();
TestSharedIntegerRuntimeDependencies();
TestConstantBufferBounds();
TestReadLaneElimination();
TestOptimizationPipeline();