mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
shader: preserve folded native constants for descriptor provenance
This commit is contained in:
@@ -566,7 +566,7 @@ void PrepareCallTarget(ShaderSource& source, const CompileOptions& options) {
|
||||
}
|
||||
RewriteToSsa(query.blocks);
|
||||
ConstantPropagationPass(query.blocks, query.wave_size);
|
||||
RemoveIdentities(query.blocks);
|
||||
RemoveIdentities(query);
|
||||
EliminateDeadCode(query.blocks);
|
||||
for (auto& value: source.call->target) value = value.Instruction()->Arg(0).Resolve();
|
||||
query.value_storage.clear();
|
||||
@@ -791,8 +791,7 @@ TranslateResult TranslateProgram(const Decoder::Program& decoded, const CompileO
|
||||
IR::RewriteToSsa(ir.blocks);
|
||||
const auto simplify = [&ir] {
|
||||
IR::ConstantPropagationPass(ir.blocks, ir.wave_size);
|
||||
IR::ResolveControlFlowIdentities(ir);
|
||||
IR::RemoveIdentities(ir.blocks);
|
||||
IR::RemoveIdentities(ir);
|
||||
IR::EliminateDeadCode(ir.blocks);
|
||||
};
|
||||
simplify();
|
||||
@@ -872,7 +871,7 @@ CompileResult CompileProgram(TranslateResult translated, const CompileOptions& o
|
||||
}
|
||||
}
|
||||
ir.value_storage.clear();
|
||||
IR::RemoveIdentities(ir.blocks);
|
||||
IR::RemoveIdentities(ir);
|
||||
IR::EliminateDeadCode(ir.blocks);
|
||||
|
||||
IR::CollectShaderInfo(ir, options.input_info);
|
||||
|
||||
@@ -318,7 +318,7 @@ void LowerTessellationMemory(IR::Program& program, const CompileOptions& options
|
||||
}
|
||||
}
|
||||
ConstantPropagationPass(program.blocks, program.wave_size);
|
||||
RemoveIdentities(program.blocks);
|
||||
RemoveIdentities(program);
|
||||
EliminateDeadCode(program.blocks);
|
||||
LOGF("%s tessellation lowering: reads=%u writes=%u factors=%u\n",
|
||||
options.stage == ShaderType::Local ? "LS"
|
||||
|
||||
@@ -319,7 +319,7 @@ void Translator::WriteRawU32(const Decoder::Operand& operand, IR::U32 value) {
|
||||
case Decoder::OperandKind::Sgpr: {
|
||||
const auto reg = static_cast<IR::ScalarReg>(operand.reg);
|
||||
ir.SetScalarReg(reg, value);
|
||||
program.scalar_writes.push_back({current_pc, reg});
|
||||
program.scalar_writes.push_back({current_pc, reg, value});
|
||||
ir.SetScalarMaskTag(reg, IR::U1(IR::Value(false)));
|
||||
if (IR::RegIndex(reg) > 0u) {
|
||||
ir.SetScalarMaskTag(static_cast<IR::ScalarReg>(IR::RegIndex(reg) - 1u),
|
||||
@@ -685,13 +685,13 @@ std::array<IR::U32, 2> Translator::WriteMask(const Decoder::Operand& operand, IR
|
||||
IR::U1(IR::Value(false)));
|
||||
}
|
||||
ir.SetScalarReg(reg, mask[0]);
|
||||
program.scalar_writes.push_back({current_pc, reg});
|
||||
program.scalar_writes.push_back({current_pc, reg, mask[0]});
|
||||
// A wave32 VALU mask destination must not overwrite the neighboring SGPR.
|
||||
if ((write_64 || program.wave_size == 64u) &&
|
||||
IR::RegIndex(reg) + 1u < IR::NumScalarRegs) {
|
||||
const auto high = static_cast<IR::ScalarReg>(IR::RegIndex(reg) + 1u);
|
||||
ir.SetScalarReg(high, mask[1]);
|
||||
program.scalar_writes.push_back({current_pc, high});
|
||||
program.scalar_writes.push_back({current_pc, high, mask[1]});
|
||||
ir.SetThreadBitScalarReg(high, IR::U1(IR::Value(false)));
|
||||
ir.SetScalarMaskTag(high, IR::U1(IR::Value(false)));
|
||||
}
|
||||
|
||||
@@ -679,13 +679,6 @@ void ValidateProgram(const Program& program, bool require_ssa) {
|
||||
}
|
||||
}
|
||||
|
||||
void ResolveControlFlowIdentities(Program& program) {
|
||||
for (auto* block: program.blocks) {
|
||||
block->condition = block->condition.Resolve();
|
||||
block->indirect_target = block->indirect_target.Resolve();
|
||||
}
|
||||
}
|
||||
|
||||
std::string ProgramToString(const Program& program) {
|
||||
std::map<const Inst*, size_t> ids;
|
||||
size_t next_id = 1;
|
||||
|
||||
@@ -701,7 +701,7 @@ struct Program: ResourcePlan {
|
||||
bool dispatcher_fallback = false;
|
||||
CFG::FailureKind cfg_failure_kind = CFG::FailureKind::None;
|
||||
std::string fallback_reason;
|
||||
struct ScalarWrite { uint32_t pc; ScalarReg reg; };
|
||||
struct ScalarWrite { uint32_t pc; ScalarReg reg; Value value; };
|
||||
std::vector<ScalarWrite> scalar_writes;
|
||||
// Typed memory and export instructions reference shader-local metadata by dense index.
|
||||
// Decoder-only details (such as NSA register numbers) have already become IR operands.
|
||||
@@ -718,7 +718,6 @@ std::string ProgramToString(const Program& program);
|
||||
bool HasShaderMemoryWrites(const Program& program);
|
||||
|
||||
void ValidateProgram(const Program& program, bool require_ssa);
|
||||
void ResolveControlFlowIdentities(Program& program);
|
||||
bool EquivalentValue(const ResourcePlan& program, Value left, Value right);
|
||||
bool EquivalentSelectorDomain(const ResourcePlan& program,
|
||||
const DescriptorSource::IndirectDescriptor& left,
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
#include "graphics/shader/recompiler/ir/passes/DeadCodeElimination.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::IR {
|
||||
|
||||
void RemoveIdentities(const BlockList& blocks) {
|
||||
for (auto* block: blocks) {
|
||||
void RemoveIdentities(Program& program) {
|
||||
// Resolve metadata before deleting its identity nodes; retain only folded native constants.
|
||||
for (auto& write: program.scalar_writes) {
|
||||
const auto value = write.value.Resolve();
|
||||
write.value = value.IsImmediate() && value.GetType() == Type::U32 ? value : Value {};
|
||||
}
|
||||
for (auto* block: program.blocks) {
|
||||
block->condition = block->condition.Resolve();
|
||||
block->indirect_target = block->indirect_target.Resolve();
|
||||
}
|
||||
for (auto* block: program.blocks) {
|
||||
auto& instructions = block->Instructions();
|
||||
for (auto inst = instructions.begin(); inst != instructions.end();) {
|
||||
if (inst->GetOpcode() != ValueOpcode::Identity) {
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::IR {
|
||||
|
||||
void RemoveIdentities(const BlockList& blocks);
|
||||
struct Program;
|
||||
|
||||
void RemoveIdentities(Program& program);
|
||||
void EliminateDeadCode(const BlockList& blocks);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::IR
|
||||
|
||||
@@ -604,9 +604,20 @@ private:
|
||||
candidates.push_back(inst);
|
||||
}
|
||||
}
|
||||
if (candidates.empty()) return value;
|
||||
const auto source_at = [&](uint32_t pc) {
|
||||
Value source;
|
||||
bool dynamic = false;
|
||||
for (auto write = std::ranges::lower_bound(m_scalar_writes, pc, {}, &Program::ScalarWrite::pc);
|
||||
write != m_scalar_writes.end() && write->pc == pc; ++write) {
|
||||
if (RegIndex(write->reg) != reg) continue;
|
||||
if (!write->value.IsImmediate() || write->value.GetType() != Type::U32) {
|
||||
dynamic = true;
|
||||
continue;
|
||||
}
|
||||
if (!source.IsEmpty() && source != write->value) return Value {};
|
||||
source = write->value;
|
||||
}
|
||||
if (!source.IsEmpty()) return dynamic ? Value {} : source;
|
||||
const auto native = std::ranges::lower_bound(m_decoded.instructions, pc, {},
|
||||
&Decoder::Instruction::pc);
|
||||
for (const auto* candidate: candidates) {
|
||||
@@ -644,8 +655,9 @@ private:
|
||||
const auto source = source_at(pc);
|
||||
if (source.IsEmpty()) return false;
|
||||
if (!selected.IsEmpty()) {
|
||||
const auto op = source.TryInstruction()->GetOpcode();
|
||||
if ((op == ValueOpcode::LoadAddressU32 || op == ValueOpcode::ReadConstBuffer) &&
|
||||
const auto* inst = source.TryInstruction();
|
||||
if (inst != nullptr &&
|
||||
(inst->GetOpcode() == ValueOpcode::LoadAddressU32 || inst->GetOpcode() == ValueOpcode::ReadConstBuffer) &&
|
||||
selected_pc != pc) return false;
|
||||
if (!EquivalentValue(m_program, selected, source)) return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user