shader: reuse operands and remove duplicate helpers

This commit is contained in:
nmzik
2026-09-08 14:01:46 +04:00
parent 9f49ac8249
commit 839c172612
9 changed files with 57 additions and 152 deletions
@@ -7,6 +7,7 @@
#include <iterator> #include <iterator>
#include <map> #include <map>
#include <set> #include <set>
#include <span>
#include <stack> #include <stack>
namespace Libs::Graphics::ShaderRecompiler::CFG { namespace Libs::Graphics::ShaderRecompiler::CFG {
@@ -861,15 +862,15 @@ void ComputeNaturalLoops(Graph& graph) {
loop.header = edge.to; loop.header = edge.to;
loop.latch = edge.from; loop.latch = edge.from;
loop.continue_block = edge.from; loop.continue_block = edge.from;
loop.body_blocks = body; loop.body_blocks = std::move(body);
for (auto block_id: body) { for (auto block_id: loop.body_blocks) {
const auto* block = graph.FindBlock(block_id); const auto* block = graph.FindBlock(block_id);
if (block == nullptr) { if (block == nullptr) {
continue; continue;
} }
for (auto succ: block->successors) { for (auto succ: block->successors) {
if (!Contains(body, succ)) { if (!Contains(loop.body_blocks, succ)) {
AddUnique(loop.exit_blocks, succ); AddUnique(loop.exit_blocks, succ);
} }
} }
@@ -1749,7 +1750,7 @@ bool RouteOneSharedArm(Graph& graph, uint32_t original_block_count, uint32_t out
inner_is_true ? outer->terminator.false_block : outer->terminator.true_block; inner_is_true ? outer->terminator.false_block : outer->terminator.true_block;
const auto* inner = graph.FindBlock(inner_id); const auto* inner = graph.FindBlock(inner_id);
if (inner == nullptr || inner->inst_begin == inner->inst_end || if (inner == nullptr || inner->inst_begin == inner->inst_end ||
inner->predecessors != std::vector<uint32_t> {outer_id} || inner->predecessors.size() != 1u || inner->predecessors.front() != outer_id ||
inner->terminator.kind != TerminatorKind::ConditionalBranch || inner->terminator.kind != TerminatorKind::ConditionalBranch ||
IsInnermostLoopControlConditional(graph, *inner)) { IsInnermostLoopControlConditional(graph, *inner)) {
continue; continue;
@@ -1941,9 +1942,9 @@ Graph BuildGraph(const Decoder::Program& program) {
graph, FailureKind::InvalidBranchTarget, UINT32_MAX, graph, FailureKind::InvalidBranchTarget, UINT32_MAX,
fmt::format("unsupported dynamic S_SETPC_B64 at pc 0x{:08x}", inst.pc)); fmt::format("unsupported dynamic S_SETPC_B64 at pc 0x{:08x}", inst.pc));
} }
const auto& target_pcs = target_info.indirect const auto target_pcs = target_info.indirect
? target_info.target_pcs ? std::span<const uint32_t>(target_info.target_pcs)
: std::vector<uint32_t> {target_info.target}; : std::span<const uint32_t>(&target_info.target, 1);
for (const auto target: target_pcs) { for (const auto target: target_pcs) {
if (!IsValidTarget(target, instruction_pcs, first_pc, end_pc)) { if (!IsValidTarget(target, instruction_pcs, first_pc, end_pc)) {
ExitBuildFailure( ExitBuildFailure(
@@ -2103,11 +2104,7 @@ Graph BuildGraph(const Decoder::Program& program) {
} }
SortUnique(graph.code_table_load_pcs); SortUnique(graph.code_table_load_pcs);
ComputeDominators(graph); RecomputeAnalyses(graph);
ComputePostDominators(graph);
ComputeBackEdges(graph);
ComputeNaturalLoops(graph);
ComputeComponents(graph);
if (indirect_setpc) { if (indirect_setpc) {
graph.irreducible = true; graph.irreducible = true;
@@ -714,57 +714,7 @@ void DecodeVop1Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
ReadLiteralOperands(code, word_index, inst); ReadLiteralOperands(code, word_index, inst);
} }
using Vop1ModifierDecodeFn = void (*)(uint32_t pc, std::span<const uint32_t> code, bool IsVop2FloatOpcode(Opcode opcode) {
uint32_t word_index, uint32_t opcode, uint32_t vdst,
Instruction& inst);
struct Vop1ModifierDecoder {
uint32_t escape = 0;
Vop1ModifierDecodeFn decode = nullptr;
};
constexpr Vop1ModifierDecoder VOP1_MODIFIER_DECODERS[] = {
{249u, DecodeVop1Sdwa},
{250u, DecodeVop1Dpp},
};
bool TryDecodeVop1Modifier(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
uint32_t src0, uint32_t opcode, uint32_t vdst, Instruction& inst) {
for (const auto& decoder: VOP1_MODIFIER_DECODERS) {
if (decoder.escape == src0) {
decoder.decode(pc, code, word_index, opcode, vdst, inst);
return true;
}
}
return false;
}
bool IsVop2FloatSourceOpcode(Opcode opcode) {
switch (opcode) {
case Opcode::V_ADD_F32:
case Opcode::V_SUB_F32:
case Opcode::V_SUBREV_F32:
case Opcode::V_MUL_F32:
case Opcode::V_MIN_F32:
case Opcode::V_MAX_F32:
case Opcode::V_MAC_F32:
case Opcode::V_MADMK_F32:
case Opcode::V_MADAK_F32:
case Opcode::V_CVT_PKRTZ_F16_F32:
case Opcode::V_ADD_F16:
case Opcode::V_SUB_F16:
case Opcode::V_SUBREV_F16:
case Opcode::V_MUL_F16:
case Opcode::V_FMAC_F16:
case Opcode::V_FMAMK_F16:
case Opcode::V_FMAAK_F16:
case Opcode::V_MAX_F16:
case Opcode::V_MIN_F16: return true;
default: return false;
}
}
bool IsVop2FloatResultOpcode(Opcode opcode) {
switch (opcode) { switch (opcode) {
case Opcode::V_ADD_F32: case Opcode::V_ADD_F32:
case Opcode::V_SUB_F32: case Opcode::V_SUB_F32:
@@ -975,12 +925,12 @@ bool ValidateVop2Sdwa(Instruction& inst, uint32_t opcode, const Vop2SdwaFields&
SetUnsupported(inst, Family::VOP2, opcode, "VOP2 SDWA selector is invalid"); SetUnsupported(inst, Family::VOP2, opcode, "VOP2 SDWA selector is invalid");
return false; return false;
} }
if ((fields.clamp != 0u || fields.omod != 0u) && !IsVop2FloatResultOpcode(inst.opcode)) { if ((fields.clamp != 0u || fields.omod != 0u) && !IsVop2FloatOpcode(inst.opcode)) {
SetUnsupported(inst, Family::VOP2, opcode, "VOP2 SDWA output modifiers are not supported"); SetUnsupported(inst, Family::VOP2, opcode, "VOP2 SDWA output modifiers are not supported");
return false; return false;
} }
if (IsFullWidthVop2Sdwa(fields)) { if (IsFullWidthVop2Sdwa(fields)) {
if (!IsVop2FloatSourceOpcode(inst.opcode) && inst.opcode != Opcode::V_CNDMASK_B32 && if (!IsVop2FloatOpcode(inst.opcode) && inst.opcode != Opcode::V_CNDMASK_B32 &&
(fields.src0_neg != 0u || fields.src0_abs != 0u || fields.src1_neg != 0u || (fields.src0_neg != 0u || fields.src0_abs != 0u || fields.src1_neg != 0u ||
fields.src1_abs != 0u)) { fields.src1_abs != 0u)) {
SetUnsupported(inst, Family::VOP2, opcode, SetUnsupported(inst, Family::VOP2, opcode,
@@ -1098,7 +1048,7 @@ void DecodeVop2Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
inst.src1.negate_hi = inst.src1.negate; inst.src1.negate_hi = inst.src1.negate;
} }
if (!IsVop2FloatSourceOpcode(inst.opcode) && !packed_fmac && if (!IsVop2FloatOpcode(inst.opcode) && !packed_fmac &&
(inst.src0.negate || inst.src0.absolute || inst.src1.negate || inst.src1.absolute)) { (inst.src0.negate || inst.src0.absolute || inst.src1.negate || inst.src1.absolute)) {
SetUnsupported(inst, Family::VOP2, opcode, SetUnsupported(inst, Family::VOP2, opcode,
"VOP2 DPP integer source modifiers are not supported"); "VOP2 DPP integer source modifiers are not supported");
@@ -1107,32 +1057,6 @@ void DecodeVop2Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
FinalizeVop2Instruction(code, word_index, inst); FinalizeVop2Instruction(code, word_index, inst);
} }
using Vop2ModifierDecodeFn = void (*)(uint32_t pc, std::span<const uint32_t> code,
uint32_t word_index, uint32_t opcode, uint32_t vdst,
uint32_t vsrc1, Instruction& inst);
struct Vop2ModifierDecoder {
uint32_t escape = 0;
Vop2ModifierDecodeFn decode = nullptr;
};
constexpr Vop2ModifierDecoder VOP2_MODIFIER_DECODERS[] = {
{249u, DecodeVop2Sdwa},
{250u, DecodeVop2Dpp},
};
bool TryDecodeVop2Modifier(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
uint32_t src0, uint32_t opcode, uint32_t vdst, uint32_t vsrc1,
Instruction& inst) {
for (const auto& decoder: VOP2_MODIFIER_DECODERS) {
if (decoder.escape == src0) {
decoder.decode(pc, code, word_index, opcode, vdst, vsrc1, inst);
return true;
}
}
return false;
}
struct VopcSdwaFields { struct VopcSdwaFields {
uint32_t src0 = 0; uint32_t src0 = 0;
uint32_t sdst = 0; uint32_t sdst = 0;
@@ -1543,8 +1467,10 @@ void DecodeVop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
SetUnsupported(inst, Family::VOP2, opcode, "VOP2 opcode is not implemented"); SetUnsupported(inst, Family::VOP2, opcode, "VOP2 opcode is not implemented");
return; return;
} }
if (TryDecodeVop2Modifier(pc, code, word_index, src0, opcode, vdst, vsrc1, inst)) { switch (src0) {
return; case 249u: DecodeVop2Sdwa(pc, code, word_index, opcode, vdst, vsrc1, inst); return;
case 250u: DecodeVop2Dpp(pc, code, word_index, opcode, vdst, vsrc1, inst); return;
default: break;
} }
DecodeVectorGpr(vdst, inst.dst); DecodeVectorGpr(vdst, inst.dst);
@@ -1575,8 +1501,10 @@ void DecodeVop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
inst.src_count = 0; inst.src_count = 0;
return; return;
} }
if (TryDecodeVop1Modifier(pc, code, word_index, src0, opcode, vdst, inst)) { switch (src0) {
return; case 249u: DecodeVop1Sdwa(pc, code, word_index, opcode, vdst, inst); return;
case 250u: DecodeVop1Dpp(pc, code, word_index, opcode, vdst, inst); return;
default: break;
} }
const bool scalar_dst = UsesScalarDestination(inst.opcode); const bool scalar_dst = UsesScalarDestination(inst.opcode);
if (scalar_dst) { if (scalar_dst) {
@@ -89,10 +89,10 @@ void Translator::V_CVT_16_F16(const Decoder::Instruction& inst, bool signed_valu
if (signed_value) { if (signed_value) {
const auto converted = const auto converted =
ConvertF32ToI32Saturated(value, -32768.0f, 32768.0f, 32767.0f, 0xffff8000u, 0x7fffu); ConvertF32ToI32Saturated(value, -32768.0f, 32768.0f, 32767.0f, 0xffff8000u, 0x7fffu);
WriteU16(DestinationOperand(inst), ir.BitwiseAnd(converted, IR::U32(IR::Value(0xffffu)))); Write16Bits(DestinationOperand(inst), ir.BitwiseAnd(converted, IR::U32(IR::Value(0xffffu))));
return; return;
} }
WriteU16(DestinationOperand(inst), Write16Bits(DestinationOperand(inst),
ConvertF32ToU32Saturated(value, 65536.0f, 65535.0f, 0xffffu)); ConvertF32ToU32Saturated(value, 65536.0f, 65535.0f, 0xffffu));
} }
@@ -59,7 +59,7 @@ bool Translator::Float16Unary(const Decoder::Instruction& inst, IR::ValueOpcode
result = ApplyF32ResultModifiers(inst.dst, result); result = ApplyF32ResultModifiers(inst.dst, result);
const auto bits = PackHalf2x16(result, IR::F32(IR::Value::F32(0.0f))); const auto bits = PackHalf2x16(result, IR::F32(IR::Value::F32(0.0f)));
const auto invalid = IR::U32(IR::Value(inst.dst.clamp ? 0u : 0xfe00u)); const auto invalid = IR::U32(IR::Value(inst.dst.clamp ? 0u : 0xfe00u));
WriteU16(DestinationOperand(inst), ir.Select(negative, invalid, bits)); Write16Bits(DestinationOperand(inst), ir.Select(negative, invalid, bits));
return true; return true;
} }
@@ -95,7 +95,7 @@ bool Translator::Float16Trig(const Decoder::Instruction& inst, IR::ValueOpcode o
result = ApplyF32ResultModifiers(inst.dst, result); result = ApplyF32ResultModifiers(inst.dst, result);
const auto bits = PackHalf2x16(result, IR::F32(IR::Value::F32(0.0f))); const auto bits = PackHalf2x16(result, IR::F32(IR::Value::F32(0.0f)));
const auto invalid = IR::U32(IR::Value(inst.dst.clamp ? 0u : 0xfe00u)); const auto invalid = IR::U32(IR::Value(inst.dst.clamp ? 0u : 0xfe00u));
WriteU16(DestinationOperand(inst), ir.Select(infinite, invalid, bits)); Write16Bits(DestinationOperand(inst), ir.Select(infinite, invalid, bits));
return true; return true;
} }
@@ -111,7 +111,7 @@ bool Translator::Float16Ternary(const Decoder::Instruction& inst, IR::ValueOpcod
bool accumulator, bool mix) { bool accumulator, bool mix) {
std::array<IR::Value, 3> args; std::array<IR::Value, 3> args;
for (uint32_t index = 0; index < args.size(); index++) { for (uint32_t index = 0; index < args.size(); index++) {
const auto operand = accumulator && index == 2u ? inst.dst : SourceAt(inst, index); const auto& operand = accumulator && index == 2u ? inst.dst : SourceAt(inst, index);
args[index] = mix ? IR::Value(ReadMixF32(operand)) : IR::Value(ReadF16AsF32(operand)); args[index] = mix ? IR::Value(ReadMixF32(operand)) : IR::Value(ReadF16AsF32(operand));
} }
WriteF16(DestinationOperand(inst), IR::F32(ir.Emit(opcode, {args[0], args[1], args[2]}))); WriteF16(DestinationOperand(inst), IR::F32(ir.Emit(opcode, {args[0], args[1], args[2]})));
@@ -128,7 +128,7 @@ bool Translator::FloatBinary(const Decoder::Instruction& inst, IR::ValueOpcode o
bool reverse) { bool reverse) {
std::array<IR::Value, 2> args; std::array<IR::Value, 2> args;
for (uint32_t index = 0; index < args.size(); index++) { for (uint32_t index = 0; index < args.size(); index++) {
const auto operand = SourceAt(inst, reverse ? 1u - index : index); const auto& operand = SourceAt(inst, reverse ? 1u - index : index);
args[index] = ReadOperand(operand, IR::ArgTypeOf(opcode, index)); args[index] = ReadOperand(operand, IR::ArgTypeOf(opcode, index));
} }
WriteOperand(DestinationOperand(inst), ir.Emit(opcode, {args[0], args[1]})); WriteOperand(DestinationOperand(inst), ir.Emit(opcode, {args[0], args[1]}));
@@ -139,7 +139,7 @@ bool Translator::FloatTernary(const Decoder::Instruction& inst, IR::ValueOpcode
bool accumulator, bool mix) { bool accumulator, bool mix) {
std::array<IR::Value, 3> args; std::array<IR::Value, 3> args;
for (uint32_t index = 0; index < args.size(); index++) { for (uint32_t index = 0; index < args.size(); index++) {
const auto operand = accumulator && index == 2u ? inst.dst : SourceAt(inst, index); const auto& operand = accumulator && index == 2u ? inst.dst : SourceAt(inst, index);
const auto type = IR::ArgTypeOf(opcode, index); const auto type = IR::ArgTypeOf(opcode, index);
args[index] = type == IR::Type::F32 && mix ? IR::Value(ReadMixF32(operand)) args[index] = type == IR::Type::F32 && mix ? IR::Value(ReadMixF32(operand))
: ReadOperand(operand, type); : ReadOperand(operand, type);
@@ -203,9 +203,6 @@ bool Translator::V_CUBEMA_F32(const Decoder::Instruction& inst) {
} }
bool Translator::FloatCube(const Decoder::Instruction& inst, uint32_t result_kind) { bool Translator::FloatCube(const Decoder::Instruction& inst, uint32_t result_kind) {
const auto select_f32 = [&](IR::U1 condition, IR::F32 true_value, IR::F32 false_value) {
return IR::F32(ir.Emit(IR::ValueOpcode::SelectF32, {condition, true_value, false_value}));
};
const auto x = ReadMixF32(inst.src0); const auto x = ReadMixF32(inst.src0);
const auto y = ReadMixF32(inst.src1); const auto y = ReadMixF32(inst.src1);
const auto z = ReadMixF32(inst.src2); const auto z = ReadMixF32(inst.src2);
@@ -223,18 +220,18 @@ bool Translator::FloatCube(const Decoder::Instruction& inst, uint32_t result_kin
const auto y_neg = IR::U1(ir.Emit(IR::ValueOpcode::FPOrdLessThan32, {y, IR::Value::F32(0.0f)})); const auto y_neg = IR::U1(ir.Emit(IR::ValueOpcode::FPOrdLessThan32, {y, IR::Value::F32(0.0f)}));
const auto z_neg = IR::U1(ir.Emit(IR::ValueOpcode::FPOrdLessThan32, {z, IR::Value::F32(0.0f)})); const auto z_neg = IR::U1(ir.Emit(IR::ValueOpcode::FPOrdLessThan32, {z, IR::Value::F32(0.0f)}));
const auto select_face = [&](IR::F32 x_value, IR::F32 y_value, IR::F32 z_value) { const auto select_face = [&](IR::F32 x_value, IR::F32 y_value, IR::F32 z_value) {
return select_f32(z_face, z_value, select_f32(y_face, y_value, x_value)); return SelectF32(z_face, z_value, SelectF32(y_face, y_value, x_value));
}; };
IR::F32 result; IR::F32 result;
switch (result_kind) { switch (result_kind) {
case 0u: case 0u:
result = select_face( result = select_face(
select_f32(x_neg, IR::F32(IR::Value::F32(1.0f)), IR::F32(IR::Value::F32(0.0f))), SelectF32(x_neg, IR::F32(IR::Value::F32(1.0f)), IR::F32(IR::Value::F32(0.0f))),
select_f32(y_neg, IR::F32(IR::Value::F32(3.0f)), IR::F32(IR::Value::F32(2.0f))), SelectF32(y_neg, IR::F32(IR::Value::F32(3.0f)), IR::F32(IR::Value::F32(2.0f))),
select_f32(z_neg, IR::F32(IR::Value::F32(5.0f)), IR::F32(IR::Value::F32(4.0f)))); SelectF32(z_neg, IR::F32(IR::Value::F32(5.0f)), IR::F32(IR::Value::F32(4.0f))));
break; break;
case 1u: result = select_face(select_f32(x_neg, z, nz), x, select_f32(z_neg, nx, x)); break; case 1u: result = select_face(SelectF32(x_neg, z, nz), x, SelectF32(z_neg, nx, x)); break;
case 2u: result = select_face(ny, select_f32(y_neg, nz, z), ny); break; case 2u: result = select_face(ny, SelectF32(y_neg, nz, z), ny); break;
case 3u: { case 3u: {
const auto two = IR::F32(IR::Value::F32(2.0f)); const auto two = IR::F32(IR::Value::F32(2.0f));
result = select_face(IR::F32(ir.Emit(IR::ValueOpcode::FPMul32, {x, two})), result = select_face(IR::F32(ir.Emit(IR::ValueOpcode::FPMul32, {x, two})),
@@ -9,7 +9,7 @@ bool Translator::Integer16Shift(const Decoder::Instruction& inst, IR::ValueOpcod
const auto value = ReadU16AsU32(inst.src1, arithmetic); const auto value = ReadU16AsU32(inst.src1, arithmetic);
const auto count = ir.BitwiseAnd(ReadU16AsU32(inst.src0, false), IR::U32(IR::Value(15u))); const auto count = ir.BitwiseAnd(ReadU16AsU32(inst.src0, false), IR::U32(IR::Value(15u)));
const auto result = IR::U32(ir.Emit(opcode, {value, count})); const auto result = IR::U32(ir.Emit(opcode, {value, count}));
WriteU16(DestinationOperand(inst), ir.BitwiseAnd(result, IR::U32(IR::Value(0xffffu)))); Write16Bits(DestinationOperand(inst), ir.BitwiseAnd(result, IR::U32(IR::Value(0xffffu))));
return true; return true;
} }
@@ -18,7 +18,7 @@ bool Translator::Integer16Binary(const Decoder::Instruction& inst, IR::ValueOpco
const auto lhs = ReadU16AsU32(inst.src0, sign); const auto lhs = ReadU16AsU32(inst.src0, sign);
const auto rhs = ReadU16AsU32(inst.src1, sign); const auto rhs = ReadU16AsU32(inst.src1, sign);
const auto result = IR::U32(ir.Emit(opcode, {lhs, rhs})); const auto result = IR::U32(ir.Emit(opcode, {lhs, rhs}));
WriteU16(DestinationOperand(inst), ir.BitwiseAnd(result, IR::U32(IR::Value(0xffffu)))); Write16Bits(DestinationOperand(inst), ir.BitwiseAnd(result, IR::U32(IR::Value(0xffffu))));
return true; return true;
} }
@@ -26,7 +26,7 @@ bool Translator::V_MED3_I16(const Decoder::Instruction& inst) {
const auto result = IR::U32(ir.Emit( const auto result = IR::U32(ir.Emit(
IR::ValueOpcode::SMedTri32, {ReadU16AsU32(inst.src0, true), ReadU16AsU32(inst.src1, true), IR::ValueOpcode::SMedTri32, {ReadU16AsU32(inst.src0, true), ReadU16AsU32(inst.src1, true),
ReadU16AsU32(inst.src2, true)})); ReadU16AsU32(inst.src2, true)}));
WriteU16(DestinationOperand(inst), ir.BitwiseAnd(result, IR::U32(IR::Value(0xffffu)))); Write16Bits(DestinationOperand(inst), ir.BitwiseAnd(result, IR::U32(IR::Value(0xffffu))));
return true; return true;
} }
@@ -143,7 +143,7 @@ bool Translator::SimpleInteger(const Decoder::Instruction& inst, IR::ValueOpcode
std::array<IR::Value, 3> args; std::array<IR::Value, 3> args;
for (uint32_t index = 0; index < inst.src_count; index++) { for (uint32_t index = 0; index < inst.src_count; index++) {
const auto arg_type = IR::ArgTypeOf(opcode, index); const auto arg_type = IR::ArgTypeOf(opcode, index);
const auto operand = SourceAt(inst, reverse && index < 2u ? 1u - index : index); const auto& operand = SourceAt(inst, reverse && index < 2u ? 1u - index : index);
args[index] = ReadOperand(operand, arg_type == IR::Type::Void ? type : arg_type); args[index] = ReadOperand(operand, arg_type == IR::Type::Void ? type : arg_type);
if (mask_shift_count && index == 1u) { if (mask_shift_count && index == 1u) {
args[index] = ir.BitwiseAnd(IR::U32(args[index]), IR::U32(IR::Value(31u))); args[index] = ir.BitwiseAnd(IR::U32(args[index]), IR::U32(IR::Value(31u)));
@@ -563,10 +563,8 @@ bool Translator::PackB16(const Decoder::Instruction& inst, bool high0, bool high
: ReadU32(inst.src0); : ReadU32(inst.src0);
const auto hi = high1 ? ir.ShiftRightLogical(ReadU32(inst.src1), IR::U32(IR::Value(16u))) const auto hi = high1 ? ir.ShiftRightLogical(ReadU32(inst.src1), IR::U32(IR::Value(16u)))
: ReadU32(inst.src1); : ReadU32(inst.src1);
const auto low_bits = ir.BitwiseAnd(lo, IR::U32(IR::Value(0xffffu))); const auto result = PackU16Lanes(lo, hi);
const auto high_bits = ir.ShiftLeftLogical(ir.BitwiseAnd(hi, IR::U32(IR::Value(0xffffu))), WriteOperand(DestinationOperand(inst), result);
IR::U32(IR::Value(16u)));
WriteOperand(DestinationOperand(inst), ir.BitwiseOr(low_bits, high_bits));
return true; return true;
} }
@@ -71,16 +71,22 @@ ResourceKind FlatSegmentResourceKind(uint32_t segment) {
} }
} }
bool IsScalarAddressLoad(Decoder::Opcode opcode) {
switch (opcode) {
case Decoder::Opcode::S_LOAD_DWORD:
case Decoder::Opcode::S_LOAD_DWORDX2:
case Decoder::Opcode::S_LOAD_DWORDX4:
case Decoder::Opcode::S_LOAD_DWORDX8:
case Decoder::Opcode::S_LOAD_DWORDX16: return true;
default: return false;
}
}
ResourceKind MemoryKind(const Decoder::Instruction& decoded) { ResourceKind MemoryKind(const Decoder::Instruction& decoded) {
switch (decoded.family) { switch (decoded.family) {
case Decoder::Family::SMEM: case Decoder::Family::SMEM:
return decoded.opcode == Decoder::Opcode::S_LOAD_DWORD || return IsScalarAddressLoad(decoded.opcode) ? ResourceKind::ScalarAddress
decoded.opcode == Decoder::Opcode::S_LOAD_DWORDX2 || : ResourceKind::ScalarBuffer;
decoded.opcode == Decoder::Opcode::S_LOAD_DWORDX4 ||
decoded.opcode == Decoder::Opcode::S_LOAD_DWORDX8 ||
decoded.opcode == Decoder::Opcode::S_LOAD_DWORDX16
? ResourceKind::ScalarAddress
: ResourceKind::ScalarBuffer;
case Decoder::Family::MUBUF: case Decoder::Family::MUBUF:
case Decoder::Family::MTBUF: return ResourceKind::Buffer; case Decoder::Family::MTBUF: return ResourceKind::Buffer;
case Decoder::Family::FLAT: return FlatSegmentResourceKind(decoded.memory_segment); case Decoder::Family::FLAT: return FlatSegmentResourceKind(decoded.memory_segment);
@@ -146,16 +152,6 @@ IR::MemoryInfo MemoryInfoFromDecoded(const Decoder::Instruction& decoded) {
return memory; return memory;
} }
bool IsScalarAddressLoad(Decoder::Opcode opcode) {
switch (opcode) {
case Decoder::Opcode::S_LOAD_DWORD:
case Decoder::Opcode::S_LOAD_DWORDX2:
case Decoder::Opcode::S_LOAD_DWORDX4:
case Decoder::Opcode::S_LOAD_DWORDX8:
case Decoder::Opcode::S_LOAD_DWORDX16: return true;
default: return false;
}
}
bool IsScalarBufferLoad(Decoder::Opcode opcode) { bool IsScalarBufferLoad(Decoder::Opcode opcode) {
switch (opcode) { switch (opcode) {
@@ -9,7 +9,7 @@
namespace Libs::Graphics::ShaderRecompiler::Frontend { namespace Libs::Graphics::ShaderRecompiler::Frontend {
Decoder::Operand Translator::SourceAt(const Decoder::Instruction& inst, uint32_t index) { const Decoder::Operand& Translator::SourceAt(const Decoder::Instruction& inst, uint32_t index) {
switch (index) { switch (index) {
case 0: return inst.src0; case 0: return inst.src0;
case 1: return inst.src1; case 1: return inst.src1;
@@ -25,7 +25,7 @@ Decoder::Operand Translator::DestinationOperand(const Decoder::Instruction& inst
return destination; return destination;
} }
for (uint32_t index = 0; index < std::min(inst.src_count, 3u); index++) { for (uint32_t index = 0; index < std::min(inst.src_count, 3u); index++) {
const auto source = SourceAt(inst, index); const auto& source = SourceAt(inst, index);
if (!source.dpp) { if (!source.dpp) {
continue; continue;
} }
@@ -440,10 +440,6 @@ void Translator::WriteF16(const Decoder::Operand& operand, IR::F32 value) {
Write16Bits(operand, bits); Write16Bits(operand, bits);
} }
void Translator::WriteU16(const Decoder::Operand& operand, IR::U32 value) {
Write16Bits(operand, value);
}
IR::U32 Translator::ReadU32(const Decoder::Operand& operand) { IR::U32 Translator::ReadU32(const Decoder::Operand& operand) {
return IR::U32(ReadOperand(operand, IR::Type::U32)); return IR::U32(ReadOperand(operand, IR::Type::U32));
} }
@@ -604,10 +600,6 @@ IR::U1 Translator::ThreadBit(const std::array<IR::U32, 2>& mask) {
IR::U32(IR::Value(0u))); IR::U32(IR::Value(0u)));
} }
IR::U1 Translator::ReadCondition(const Decoder::Operand& operand) {
return IR::U1(ReadOperand(operand, IR::Type::U1));
}
IR::U32 Translator::ConditionBit(const Decoder::Operand& operand) { IR::U32 Translator::ConditionBit(const Decoder::Operand& operand) {
return ir.Select(ReadMask(operand), IR::U32(IR::Value(1u)), IR::U32(IR::Value(0u))); return ir.Select(ReadMask(operand), IR::U32(IR::Value(1u)), IR::U32(IR::Value(0u)));
} }
@@ -18,7 +18,7 @@ public:
void AddBranchCondition(const CFG::BasicBlock& source, IR::BlockInfo& info); void AddBranchCondition(const CFG::BasicBlock& source, IR::BlockInfo& info);
private: private:
Decoder::Operand SourceAt(const Decoder::Instruction& inst, uint32_t index); const Decoder::Operand& SourceAt(const Decoder::Instruction& inst, uint32_t index);
Decoder::Operand DestinationOperand(const Decoder::Instruction& inst); Decoder::Operand DestinationOperand(const Decoder::Instruction& inst);
Decoder::Operand OffsetOperand(const Decoder::Operand& operand, uint32_t offset); Decoder::Operand OffsetOperand(const Decoder::Operand& operand, uint32_t offset);
Decoder::Operand ScalarDestinationOperand(const Decoder::Operand& operand, uint32_t offset); Decoder::Operand ScalarDestinationOperand(const Decoder::Operand& operand, uint32_t offset);
@@ -35,7 +35,6 @@ private:
IR::U32 PackHalf2x16(IR::F32 low, IR::F32 high); IR::U32 PackHalf2x16(IR::F32 low, IR::F32 high);
void Write16Bits(const Decoder::Operand& operand, IR::U32 value); void Write16Bits(const Decoder::Operand& operand, IR::U32 value);
void WriteF16(const Decoder::Operand& operand, IR::F32 value); void WriteF16(const Decoder::Operand& operand, IR::F32 value);
void WriteU16(const Decoder::Operand& operand, IR::U32 value);
IR::U32 ReadU32(const Decoder::Operand& operand); IR::U32 ReadU32(const Decoder::Operand& operand);
std::array<IR::U32, 2> ReadU32Pair(const Decoder::Operand& operand); std::array<IR::U32, 2> ReadU32Pair(const Decoder::Operand& operand);
IR::U64 ReadU64(const Decoder::Operand& operand); IR::U64 ReadU64(const Decoder::Operand& operand);
@@ -48,7 +47,6 @@ private:
IR::U32 ReadF16LaneBits(const Decoder::Operand& operand, bool high_lane); IR::U32 ReadF16LaneBits(const Decoder::Operand& operand, bool high_lane);
std::array<IR::U32, 2> ExtractU64(IR::U64 value); std::array<IR::U32, 2> ExtractU64(IR::U64 value);
void WriteU32Pair(const Decoder::Operand& operand, const std::array<IR::U32, 2>& value); void WriteU32Pair(const Decoder::Operand& operand, const std::array<IR::U32, 2>& value);
IR::U1 ReadCondition(const Decoder::Operand& operand);
IR::U32 ConditionBit(const Decoder::Operand& operand); IR::U32 ConditionBit(const Decoder::Operand& operand);
IR::U1 ReadMask(const Decoder::Operand& operand); IR::U1 ReadMask(const Decoder::Operand& operand);
IR::U1 ReadMaskValid(const Decoder::Operand& operand); IR::U1 ReadMaskValid(const Decoder::Operand& operand);
@@ -280,8 +280,7 @@ private:
return finish(false); return finish(false);
} }
} }
if (op == ValueOpcode::GetBufferResource || op == ValueOpcode::GetImageResource || if (IsDescriptorHandle(op)) {
op == ValueOpcode::GetSamplerResource || op == ValueOpcode::GetAddressResource) {
size_t expected = 4u; size_t expected = 4u;
if (op == ValueOpcode::GetImageResource) { if (op == ValueOpcode::GetImageResource) {
expected = 8u; expected = 8u;