shader_recompiler: add SSA

This commit is contained in:
nmzik
2026-08-15 03:11:19 +02:00
parent bc2f077c37
commit b42380ced6
113 changed files with 40415 additions and 32616 deletions
@@ -0,0 +1,195 @@
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
bool Translator::TranslateIntegerCompare(const IR::Instruction& inst) {
IR::ValueOpcode opcode {};
IR::Type type = IR::Type::U32;
switch (inst.op) {
case IR::Opcode::CompareFalse:
WriteCompareResult(inst.dst, IR::U1(IR::Value(false)));
return true;
case IR::Opcode::CompareTrue:
WriteCompareResult(inst.dst, IR::U1(IR::Value(true)));
return true;
case IR::Opcode::CompareEqU32:
case IR::Opcode::CompareMaskEqU32:
case IR::Opcode::CompareEqI32:
case IR::Opcode::CompareMaskEqI32: opcode = IR::ValueOpcode::IEqual32; break;
case IR::Opcode::CompareNeU32:
case IR::Opcode::CompareMaskNeU32:
case IR::Opcode::CompareNeI32:
case IR::Opcode::CompareMaskNeI32: opcode = IR::ValueOpcode::INotEqual32; break;
case IR::Opcode::CompareGtU32:
case IR::Opcode::CompareMaskGtU32: opcode = IR::ValueOpcode::UGreaterThan32; break;
case IR::Opcode::CompareGeU32:
case IR::Opcode::CompareMaskGeU32: opcode = IR::ValueOpcode::UGreaterThanEqual32; break;
case IR::Opcode::CompareLtU32:
case IR::Opcode::CompareMaskLtU32: opcode = IR::ValueOpcode::ULessThan32; break;
case IR::Opcode::CompareLeU32:
case IR::Opcode::CompareMaskLeU32: opcode = IR::ValueOpcode::ULessThanEqual32; break;
case IR::Opcode::CompareGtI32:
case IR::Opcode::CompareMaskGtI32: opcode = IR::ValueOpcode::SGreaterThan32; break;
case IR::Opcode::CompareGeI32:
case IR::Opcode::CompareMaskGeI32: opcode = IR::ValueOpcode::SGreaterThanEqual32; break;
case IR::Opcode::CompareLtI32:
case IR::Opcode::CompareMaskLtI32: opcode = IR::ValueOpcode::SLessThan32; break;
case IR::Opcode::CompareLeI32:
case IR::Opcode::CompareMaskLeI32: opcode = IR::ValueOpcode::SLessThanEqual32; break;
case IR::Opcode::CompareEqU64:
opcode = IR::ValueOpcode::IEqual64;
type = IR::Type::U64;
break;
case IR::Opcode::CompareNeU64:
opcode = IR::ValueOpcode::INotEqual64;
type = IR::Type::U64;
break;
default: return false;
}
const auto lhs = ReadOperand(inst.src[0], type);
const auto rhs = ReadOperand(inst.src[1], type);
WriteCompareResult(inst.dst, IR::U1(ir.Emit(opcode, {lhs, rhs})));
return true;
}
bool Translator::TranslateInteger16Compare(const IR::Instruction& inst) {
IR::ValueOpcode opcode {};
bool signed_value = false;
switch (inst.op) {
case IR::Opcode::CompareEqU16:
case IR::Opcode::CompareEqI16: opcode = IR::ValueOpcode::IEqual32; break;
case IR::Opcode::CompareNeU16:
case IR::Opcode::CompareNeI16: opcode = IR::ValueOpcode::INotEqual32; break;
case IR::Opcode::CompareGtU16: opcode = IR::ValueOpcode::UGreaterThan32; break;
case IR::Opcode::CompareGeU16: opcode = IR::ValueOpcode::UGreaterThanEqual32; break;
case IR::Opcode::CompareLtU16: opcode = IR::ValueOpcode::ULessThan32; break;
case IR::Opcode::CompareLeU16: opcode = IR::ValueOpcode::ULessThanEqual32; break;
case IR::Opcode::CompareGtI16:
opcode = IR::ValueOpcode::SGreaterThan32;
signed_value = true;
break;
case IR::Opcode::CompareGeI16:
opcode = IR::ValueOpcode::SGreaterThanEqual32;
signed_value = true;
break;
case IR::Opcode::CompareLtI16:
opcode = IR::ValueOpcode::SLessThan32;
signed_value = true;
break;
case IR::Opcode::CompareLeI16:
opcode = IR::ValueOpcode::SLessThanEqual32;
signed_value = true;
break;
default: return false;
}
if (inst.op == IR::Opcode::CompareEqI16 || inst.op == IR::Opcode::CompareNeI16) {
signed_value = true;
}
WriteCompareResult(inst.dst,
IR::U1(ir.Emit(opcode, {ReadU16AsU32(inst.src[0], signed_value),
ReadU16AsU32(inst.src[1], signed_value)})));
return true;
}
bool Translator::TranslateFloatCompare(const IR::Instruction& inst) {
IR::ValueOpcode opcode {};
bool half = false;
switch (inst.op) {
case IR::Opcode::CompareEqF32:
case IR::Opcode::CompareMaskEqF32: opcode = IR::ValueOpcode::FPOrdEqual32; break;
case IR::Opcode::CompareNeF32:
case IR::Opcode::CompareMaskNeF32: opcode = IR::ValueOpcode::FPOrdNotEqual32; break;
case IR::Opcode::CompareGtF32:
case IR::Opcode::CompareMaskGtF32: opcode = IR::ValueOpcode::FPOrdGreaterThan32; break;
case IR::Opcode::CompareGeF32:
case IR::Opcode::CompareMaskGeF32: opcode = IR::ValueOpcode::FPOrdGreaterThanEqual32; break;
case IR::Opcode::CompareLtF32:
case IR::Opcode::CompareMaskLtF32: opcode = IR::ValueOpcode::FPOrdLessThan32; break;
case IR::Opcode::CompareLeF32:
case IR::Opcode::CompareMaskLeF32: opcode = IR::ValueOpcode::FPOrdLessThanEqual32; break;
case IR::Opcode::CompareUnordEqF32:
case IR::Opcode::CompareMaskUnordEqF32: opcode = IR::ValueOpcode::FPUnordEqual32; break;
case IR::Opcode::CompareUnordNeF32:
case IR::Opcode::CompareMaskUnordNeF32: opcode = IR::ValueOpcode::FPUnordNotEqual32; break;
case IR::Opcode::CompareUnordGtF32:
case IR::Opcode::CompareMaskUnordGtF32:
opcode = IR::ValueOpcode::FPUnordGreaterThan32;
break;
case IR::Opcode::CompareUnordGeF32:
case IR::Opcode::CompareMaskUnordGeF32:
opcode = IR::ValueOpcode::FPUnordGreaterThanEqual32;
break;
case IR::Opcode::CompareUnordLtF32:
case IR::Opcode::CompareMaskUnordLtF32: opcode = IR::ValueOpcode::FPUnordLessThan32; break;
case IR::Opcode::CompareUnordLeF32:
case IR::Opcode::CompareMaskUnordLeF32:
opcode = IR::ValueOpcode::FPUnordLessThanEqual32;
break;
case IR::Opcode::CompareEqF16:
case IR::Opcode::CompareMaskEqF16:
opcode = IR::ValueOpcode::FPOrdEqual32;
half = true;
break;
case IR::Opcode::CompareNeF16:
case IR::Opcode::CompareMaskNeF16:
opcode = IR::ValueOpcode::FPOrdNotEqual32;
half = true;
break;
case IR::Opcode::CompareGtF16:
case IR::Opcode::CompareMaskGtF16:
opcode = IR::ValueOpcode::FPOrdGreaterThan32;
half = true;
break;
case IR::Opcode::CompareGeF16:
case IR::Opcode::CompareMaskGeF16:
opcode = IR::ValueOpcode::FPOrdGreaterThanEqual32;
half = true;
break;
case IR::Opcode::CompareLtF16:
case IR::Opcode::CompareMaskLtF16:
opcode = IR::ValueOpcode::FPOrdLessThan32;
half = true;
break;
case IR::Opcode::CompareLeF16:
case IR::Opcode::CompareMaskLeF16:
opcode = IR::ValueOpcode::FPOrdLessThanEqual32;
half = true;
break;
case IR::Opcode::CompareUnordNeF16:
case IR::Opcode::CompareMaskUnordNeF16:
opcode = IR::ValueOpcode::FPUnordNotEqual32;
half = true;
break;
case IR::Opcode::CompareMaskUnordGeF16:
opcode = IR::ValueOpcode::FPUnordGreaterThanEqual32;
half = true;
break;
case IR::Opcode::CompareOrderedF32:
case IR::Opcode::CompareUnorderedF32: {
const auto lhs = IR::F32(ReadOperand(inst.src[0], IR::Type::F32));
const auto rhs = IR::F32(ReadOperand(inst.src[1], IR::Type::F32));
const auto unordered = ir.LogicalOr(IR::U1(ir.Emit(IR::ValueOpcode::FPIsNan32, {lhs})),
IR::U1(ir.Emit(IR::ValueOpcode::FPIsNan32, {rhs})));
const auto result =
inst.op == IR::Opcode::CompareUnorderedF32 ? unordered : ir.LogicalNot(unordered);
WriteCompareResult(inst.dst, result);
return true;
}
case IR::Opcode::CompareClassF32: {
const auto value = ReadOperand(inst.src[0], IR::Type::F32);
const auto mask = ReadOperand(inst.src[1], IR::Type::U32);
WriteCompareResult(inst.dst,
IR::U1(ir.Emit(IR::ValueOpcode::FPCmpClass32, {value, mask})));
return true;
}
default: return false;
}
const auto lhs =
half ? IR::Value(ReadF16AsF32(inst.src[0])) : ReadOperand(inst.src[0], IR::Type::F32);
const auto rhs =
half ? IR::Value(ReadF16AsF32(inst.src[1])) : ReadOperand(inst.src[1], IR::Type::F32);
WriteCompareResult(inst.dst, IR::U1(ir.Emit(opcode, {lhs, rhs})));
return true;
}
} // namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail