mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
fix(recompiler): accept optional-body merges implied by the skip predicate in stencil replay
An EXEC- or VCC-skipped optional body is accepted when every merge phi's value from the body equals the skipped value on lanes inactive in the body. A body value that implies the skip predicate is false on every inactive lane, so it equals the skipped value when that value is the predicate itself. inactiveEquals now accepts that case, which covers a lane's own bit of a ballot of the predicate merged with the predicate. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
570089a806
commit
bf0589e282
2 files changed
+33
No files matched your search
@@ -1236,6 +1236,38 @@ int main() {
|
||||
return StencilReplaySafe(b.program);
|
||||
};
|
||||
|
||||
const auto optionalPredicateBody = [&](bool negated) {
|
||||
Builder b;
|
||||
b.program.Resources().stage = IrShaderStage::Pixel;
|
||||
auto& entry = *b.block;
|
||||
auto& predicate = pixelPredicate(b);
|
||||
auto& condition = b.emit(IrOpcode::LogicalNot, IrType::Bool, {&predicate});
|
||||
auto& body = b.newBlock();
|
||||
auto& merge = b.newBlock();
|
||||
entry.AddBranch(&body);
|
||||
entry.AddBranch(&merge);
|
||||
body.AddBranch(&merge);
|
||||
auto& entryInfo = b.program.Metadata().blockInfo[0u];
|
||||
entryInfo.terminator.kind = TerminatorKind::ConditionalBranch;
|
||||
entryInfo.terminator.condition = BranchCondition::ExecZero;
|
||||
entryInfo.terminator.trueBlock = merge.Id();
|
||||
entryInfo.terminator.falseBlock = body.Id();
|
||||
entryInfo.condition = &condition;
|
||||
auto& bodyInfo = b.program.Metadata().blockInfo[1u];
|
||||
bodyInfo.terminator.kind = TerminatorKind::Branch;
|
||||
bodyInfo.terminator.trueBlock = merge.Id();
|
||||
b.block = &body;
|
||||
auto& written = negated ? b.emit(IrOpcode::LogicalNot, IrType::Bool, {&predicate}) : b.ballotBit(predicate);
|
||||
b.block = &merge;
|
||||
auto& merged = b.phi(IrType::Bool, entry, predicate);
|
||||
merged.AddPhiOperand(&body, &written);
|
||||
b.keep(b.select(merged, b.constant(1u), b.constant(0u)));
|
||||
exportUnder(b, b.truth(), true, true);
|
||||
return StencilReplaySafe(b.program);
|
||||
};
|
||||
|
||||
passed &= run("an optional wave body may merge a lane's own bit of the predicate's ballot with the skipped predicate", [&] { return optionalPredicateBody(false); });
|
||||
passed &= run("an optional wave body cannot merge a value that differs from the skipped predicate on inactive lanes", [&] { return !optionalPredicateBody(true); });
|
||||
passed &= run("an optional wave body preserves inactive values consumed only within a lane", [&] { return optionalPixelBody(false); });
|
||||
passed &= run("an optional wave body cannot change helper coordinates for later implicit samples", [&] { return !optionalPixelBody(true); });
|
||||
passed &= run("an optional wave body cannot change helper coordinates for LOD queries", [&] { return !optionalPixelBody(true, IrOpcode::ImageQueryLod); });
|
||||
|
||||
@@ -497,6 +497,7 @@ private:
|
||||
if (depth > 32u) return false;
|
||||
value = value->Resolve();
|
||||
if (sameValue(value, other)) return true;
|
||||
if (value->Type() == IrType::Bool && other->Resolve() == predicate->Resolve() && GuardImplies(program, value, predicate)) return true;
|
||||
if ((value->Opcode() == IrOpcode::SelectU32 || value->Opcode() == IrOpcode::SelectF32 || value->Opcode() == IrOpcode::SelectU1) && value->ArgumentCount() == 3u && (value->Argument(0)->Resolve() == predicate->Resolve() || GuardImplies(program, value->Argument(0), predicate))) return inactiveEquals(value->Argument(2), other, predicate, region, depth + 1u);
|
||||
if (value->IsPhi() && region.contains(value->Parent()) && value->ArgumentCount() != 0u && value->ArgumentCount() == value->PhiBlockCount()) {
|
||||
return std::all_of(value->Arguments().begin(), value->Arguments().end(), [&](const IrValue* argument) { return inactiveEquals(argument, other, predicate, region, depth + 1u); });
|
||||
|
||||
Reference in new issue
Block a user