Files
AnyPS5/core/libs/prx/libSceAgcDriver/tests/ConstantSelect.cpp
T
milescovielloandClaude Opus 5.5 227d1e44a1 perf(shader): fold a select nested in a select on the same condition
select(c, a, select(c, b, d)) is select(c, a, d), and
select(c, select(c, a, b), d) is select(c, a, d). The recompiler leaves
these behind when a register is written more than once under the same
lane mask and when the f32 NaN selection tests the same source twice,
and nothing folded them. The constant folder now takes the inner arm
the outer condition already decides, then folds a select whose arms
became equal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 17:03:09 +00:00

122 lines
4.4 KiB
C++

#include "IntermediateRepresentation/IrBuilder.hpp"
#include "Optimization/ConstantFolder.hpp"
#include "Optimization/DeadCodeEliminator.hpp"
#include <cstdint>
#include <cstdio>
#include <stdexcept>
using namespace ShaderRecompiler;
namespace {
void Require(bool condition, const char* message) {
if (!condition) throw std::runtime_error(message);
}
struct Program {
IrProgram program;
IrBuilder builder{program};
IrValue* lane = nullptr;
IrValue* condition = nullptr;
IrValue* other = nullptr;
std::uint32_t values = 0;
Program() {
auto& block = program.CreateBlock();
program.BlockOrder().push_back(&block);
BlockInfo info;
info.id = 0;
info.terminator.kind = TerminatorKind::Return;
program.Metadata().blockInfo.push_back(info);
program.SetEntryBlock(block);
builder.SetInsertionPoint(block);
lane = &builder.Emit(IrOpcode::LaneId, IrType::U32, {});
condition = &builder.Emit(IrOpcode::ULessThan32, IrType::Bool, {lane, &builder.Constant(16u)});
other = &builder.Emit(IrOpcode::ULessThan32, IrType::Bool, {lane, &builder.Constant(8u)});
}
IrValue& value() {
return builder.Emit(IrOpcode::IAdd32, IrType::U32, {lane, &builder.Constant(++values)});
}
IrValue& select(IrValue& selector, IrValue& onTrue, IrValue& onFalse) {
return builder.Emit(IrOpcode::SelectU32, IrType::U32, {&selector, &onTrue, &onFalse});
}
const IrValue* folded(IrValue& result) {
auto& reference = builder.Emit(IrOpcode::ReferenceU32, IrType::Void, {&result});
ValidateProgram(program, true);
ConstantFolder{}.Fold(program);
DeadCodeEliminator{}.RemoveIdentities(program);
DeadCodeEliminator{}.Eliminate(program);
ValidateProgram(program, true);
return reference.Argument(0)->Resolve();
}
};
bool Selects(const IrValue* value, const IrValue* selector, const IrValue* onTrue, const IrValue* onFalse) {
return value->Opcode() == IrOpcode::SelectU32 && value->Argument(0)->Resolve() == selector && value->Argument(1)->Resolve() == onTrue && value->Argument(2)->Resolve() == onFalse;
}
void CheckFalseArm() {
Program p;
auto& kept = p.value();
auto& dropped = p.value();
auto& fallback = p.value();
auto& inner = p.select(*p.condition, dropped, fallback);
const auto* result = p.folded(p.select(*p.condition, kept, inner));
Require(Selects(result, p.condition, &kept, &fallback), "a select in the false arm of a select on the same condition was not folded to its false arm");
Require(!inner.HasUses(), "the folded inner select is still used");
}
void CheckTrueArm() {
Program p;
auto& kept = p.value();
auto& dropped = p.value();
auto& fallback = p.value();
const auto* result = p.folded(p.select(*p.condition, p.select(*p.condition, kept, dropped), fallback));
Require(Selects(result, p.condition, &kept, &fallback), "a select in the true arm of a select on the same condition was not folded to its true arm");
}
void CheckChain() {
Program p;
auto& last = p.value();
auto& fallback = p.value();
auto* chain = &p.select(*p.condition, p.value(), fallback);
chain = &p.select(*p.condition, p.value(), *chain);
const auto* result = p.folded(p.select(*p.condition, last, *chain));
Require(Selects(result, p.condition, &last, &fallback), "a chain of selects on one condition did not fold to the last write and the fallback");
}
void CheckEqualArms() {
Program p;
auto& same = p.value();
const auto* result = p.folded(p.select(*p.condition, same, p.select(*p.condition, p.value(), same)));
Require(result == &same, "a select whose arms become equal after folding was not replaced by that value");
}
void CheckOtherCondition() {
Program p;
auto& kept = p.value();
auto& inner = p.select(*p.other, p.value(), p.value());
const auto* result = p.folded(p.select(*p.condition, kept, inner));
Require(Selects(result, p.condition, &kept, &inner), "a select nested under a different condition was folded");
}
}
int main() {
try {
CheckFalseArm();
CheckTrueArm();
CheckChain();
CheckEqualArms();
CheckOtherCondition();
std::puts("constant select tests passed");
return 0;
} catch (const std::exception& error) {
std::fprintf(stderr, "%s\n", error.what());
return 1;
}
}