mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-26 12:56:54 +01:00
shader: remove second IR layer
This commit is contained in:
@@ -1,42 +1,104 @@
|
||||
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
IR::ExportFlags Translator::AddExportInfo(const IR::Instruction& inst) {
|
||||
const auto index = static_cast<uint32_t>(value_program.export_info.size());
|
||||
value_program.export_info.push_back(inst.export_info);
|
||||
namespace {
|
||||
|
||||
IR::ExportTargetKind ExportTargetKindFromTarget(uint32_t target, uint32_t& index) {
|
||||
index = 0;
|
||||
switch (target) {
|
||||
case 0x08u: return IR::ExportTargetKind::MrtZ;
|
||||
case 0x09u: return IR::ExportTargetKind::Null;
|
||||
case 0x14u: return IR::ExportTargetKind::Primitive;
|
||||
default: break;
|
||||
}
|
||||
if (target <= 0x07u) {
|
||||
index = target;
|
||||
return IR::ExportTargetKind::Mrt;
|
||||
}
|
||||
if (target >= 0x0cu && target <= 0x0fu) {
|
||||
index = target - 0x0cu;
|
||||
return IR::ExportTargetKind::Position;
|
||||
}
|
||||
if (target >= 0x20u && target <= 0x3fu) {
|
||||
index = target - 0x20u;
|
||||
return IR::ExportTargetKind::Parameter;
|
||||
}
|
||||
return IR::ExportTargetKind::Unknown;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
IR::ExportFlags Translator::AddExportInfo(const Decoder::Instruction& inst) {
|
||||
IR::ExportInfo info;
|
||||
info.kind = ExportTargetKindFromTarget(inst.exp.target, info.index);
|
||||
info.target = inst.exp.target;
|
||||
info.en = inst.exp.en;
|
||||
info.done = inst.exp.done;
|
||||
info.compr = inst.exp.compr;
|
||||
info.vm = inst.exp.vm;
|
||||
const auto index = static_cast<uint32_t>(program.export_info.size());
|
||||
program.export_info.push_back(info);
|
||||
return {.index = index, .pc = inst.pc};
|
||||
}
|
||||
|
||||
bool Translator::TranslateAttributeOperation(const IR::Instruction& inst) {
|
||||
if (inst.op == IR::Opcode::LoadInputF32) {
|
||||
for (uint32_t component = 0; component < inst.input_info.component_count; component++) {
|
||||
const auto chan = inst.input_info.chan + component;
|
||||
const auto value = inst.input_info.interpolation_mode < 3u
|
||||
? ir.Emit(IR::ValueOpcode::GetInterpolationParameter,
|
||||
{IR::Value(inst.input_info.attr), IR::Value(chan),
|
||||
IR::Value(inst.input_info.interpolation_mode)})
|
||||
: ir.Emit(IR::ValueOpcode::GetAttribute,
|
||||
{IR::Value(inst.input_info.attr), IR::Value(chan)});
|
||||
WriteOperand(OffsetOperand(inst.dst, component), value);
|
||||
}
|
||||
return true;
|
||||
bool Translator::TranslateEmbeddedFetch(const Decoder::Instruction& inst, uint32_t attribute,
|
||||
uint32_t component_count) {
|
||||
for (uint32_t component = 0; component < component_count; component++) {
|
||||
const auto value =
|
||||
ir.Emit(IR::ValueOpcode::GetAttribute, {IR::Value(attribute), IR::Value(component)});
|
||||
WriteOperand(OffsetOperand(inst.dst, component), value);
|
||||
}
|
||||
if (inst.op == IR::Opcode::Export) {
|
||||
std::array<IR::Value, 4> components {IR::Value(0u), IR::Value(0u), IR::Value(0u),
|
||||
IR::Value(0u)};
|
||||
for (uint32_t index = 0; index < std::min(inst.src_count, 4u); index++) {
|
||||
components[index] = ReadRawU32(PlainOperand(inst.src[index]));
|
||||
}
|
||||
const auto data = ir.Emit(IR::ValueOpcode::CompositeConstructU32x4,
|
||||
{components[0], components[1], components[2], components[3]});
|
||||
ir.Emit(IR::ValueOpcode::SetAttribute, {data, ir.GetExec()}, AddExportInfo(inst));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail
|
||||
bool Translator::TranslateAttributeOperation(const Decoder::Instruction& inst, std::string* error) {
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_INTERP_P1_F32: return true;
|
||||
case Decoder::Opcode::V_INTERP_P2_F32:
|
||||
case Decoder::Opcode::V_INTERP_MOV_F32: {
|
||||
if (inst.opcode == Decoder::Opcode::V_INTERP_MOV_F32 && inst.src0.value >= 3u) {
|
||||
return ShaderError::Fail(
|
||||
error, fmt::format("v_interp_mov_f32 mode {} is reserved at pc 0x{:08x}",
|
||||
inst.src0.value, inst.pc));
|
||||
}
|
||||
const auto interpolation_mode =
|
||||
inst.opcode == Decoder::Opcode::V_INTERP_MOV_F32 ? inst.src0.value : 3u;
|
||||
const auto value =
|
||||
interpolation_mode < 3u
|
||||
? ir.Emit(IR::ValueOpcode::GetInterpolationParameter,
|
||||
{IR::Value(inst.src1.value), IR::Value(inst.src2.value),
|
||||
IR::Value(interpolation_mode)})
|
||||
: ir.Emit(IR::ValueOpcode::GetAttribute,
|
||||
{IR::Value(inst.src1.value), IR::Value(inst.src2.value)});
|
||||
WriteOperand(inst.dst, value);
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::EXP: {
|
||||
uint32_t index = 0;
|
||||
if (ExportTargetKindFromTarget(inst.exp.target, index) ==
|
||||
IR::ExportTargetKind::Unknown) {
|
||||
return ShaderError::Fail(
|
||||
error, fmt::format("unsupported EXP target 0x{:02x} at pc 0x{:08x}",
|
||||
inst.exp.target, inst.pc));
|
||||
}
|
||||
std::array<IR::Value, 4> components {IR::Value(0u), IR::Value(0u), IR::Value(0u),
|
||||
IR::Value(0u)};
|
||||
for (uint32_t source = 0; source < std::min(inst.src_count, 4u); source++) {
|
||||
components[source] = ReadRawU32(PlainOperand(SourceAt(inst, source)));
|
||||
}
|
||||
const auto data = ir.Emit(IR::ValueOpcode::CompositeConstructU32x4,
|
||||
{components[0], components[1], components[2], components[3]});
|
||||
ir.Emit(IR::ValueOpcode::SetAttribute, {data, ir.GetExec()}, AddExportInfo(inst));
|
||||
return true;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
@@ -1,187 +1,210 @@
|
||||
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
bool Translator::TranslateIntegerCompare(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateIntegerCompare(const Decoder::Instruction& inst) {
|
||||
IR::ValueOpcode opcode {};
|
||||
IR::Type type = IR::Type::U32;
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::CompareFalse:
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_CMP_F_I32:
|
||||
case Decoder::Opcode::V_CMP_F_U32:
|
||||
WriteCompareResult(inst.dst, IR::U1(IR::Value(false)));
|
||||
return true;
|
||||
case IR::Opcode::CompareTrue:
|
||||
case Decoder::Opcode::V_CMP_T_I32:
|
||||
case Decoder::Opcode::V_CMP_T_U32:
|
||||
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:
|
||||
case Decoder::Opcode::S_CMP_EQ_U32:
|
||||
case Decoder::Opcode::V_CMP_EQ_U32:
|
||||
case Decoder::Opcode::V_CMPX_EQ_U32:
|
||||
case Decoder::Opcode::S_CMP_EQ_I32:
|
||||
case Decoder::Opcode::V_CMP_EQ_I32:
|
||||
case Decoder::Opcode::V_CMPX_EQ_I32: opcode = IR::ValueOpcode::IEqual32; break;
|
||||
case Decoder::Opcode::S_CMP_LG_U32:
|
||||
case Decoder::Opcode::V_CMP_NE_U32:
|
||||
case Decoder::Opcode::V_CMPX_NE_U32:
|
||||
case Decoder::Opcode::S_CMP_LG_I32:
|
||||
case Decoder::Opcode::V_CMP_NE_I32:
|
||||
case Decoder::Opcode::V_CMPX_NE_I32: opcode = IR::ValueOpcode::INotEqual32; break;
|
||||
case Decoder::Opcode::S_CMP_GT_U32:
|
||||
case Decoder::Opcode::V_CMP_GT_U32:
|
||||
case Decoder::Opcode::V_CMPX_GT_U32: opcode = IR::ValueOpcode::UGreaterThan32; break;
|
||||
case Decoder::Opcode::S_CMP_GE_U32:
|
||||
case Decoder::Opcode::V_CMP_GE_U32:
|
||||
case Decoder::Opcode::V_CMPX_GE_U32: opcode = IR::ValueOpcode::UGreaterThanEqual32; break;
|
||||
case Decoder::Opcode::S_CMP_LT_U32:
|
||||
case Decoder::Opcode::V_CMP_LT_U32:
|
||||
case Decoder::Opcode::V_CMPX_LT_U32: opcode = IR::ValueOpcode::ULessThan32; break;
|
||||
case Decoder::Opcode::S_CMP_LE_U32:
|
||||
case Decoder::Opcode::V_CMP_LE_U32:
|
||||
case Decoder::Opcode::V_CMPX_LE_U32: opcode = IR::ValueOpcode::ULessThanEqual32; break;
|
||||
case Decoder::Opcode::S_CMP_GT_I32:
|
||||
case Decoder::Opcode::V_CMP_GT_I32:
|
||||
case Decoder::Opcode::V_CMPX_GT_I32: opcode = IR::ValueOpcode::SGreaterThan32; break;
|
||||
case Decoder::Opcode::S_CMP_GE_I32:
|
||||
case Decoder::Opcode::V_CMP_GE_I32:
|
||||
case Decoder::Opcode::V_CMPX_GE_I32: opcode = IR::ValueOpcode::SGreaterThanEqual32; break;
|
||||
case Decoder::Opcode::S_CMP_LT_I32:
|
||||
case Decoder::Opcode::V_CMP_LT_I32:
|
||||
case Decoder::Opcode::V_CMPX_LT_I32: opcode = IR::ValueOpcode::SLessThan32; break;
|
||||
case Decoder::Opcode::S_CMP_LE_I32:
|
||||
case Decoder::Opcode::V_CMP_LE_I32:
|
||||
case Decoder::Opcode::V_CMPX_LE_I32: opcode = IR::ValueOpcode::SLessThanEqual32; break;
|
||||
case Decoder::Opcode::S_CMP_EQ_U64:
|
||||
case Decoder::Opcode::V_CMP_EQ_I64:
|
||||
opcode = IR::ValueOpcode::IEqual64;
|
||||
type = IR::Type::U64;
|
||||
break;
|
||||
case IR::Opcode::CompareGtU64:
|
||||
case Decoder::Opcode::V_CMP_GT_U64:
|
||||
opcode = IR::ValueOpcode::UGreaterThan64;
|
||||
type = IR::Type::U64;
|
||||
break;
|
||||
case IR::Opcode::CompareNeU64:
|
||||
case Decoder::Opcode::S_CMP_LG_U64:
|
||||
case Decoder::Opcode::V_CMP_NE_U64:
|
||||
case Decoder::Opcode::V_CMPX_NE_I64:
|
||||
case Decoder::Opcode::V_CMPX_NE_U64:
|
||||
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);
|
||||
const auto lhs = ReadOperand(inst.src0, type);
|
||||
const auto rhs = ReadOperand(inst.src1, type);
|
||||
WriteCompareResult(inst.dst, IR::U1(ir.Emit(opcode, {lhs, rhs})));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateInteger16Compare(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateInteger16Compare(const Decoder::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:
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_CMP_EQ_U16:
|
||||
case Decoder::Opcode::V_CMP_EQ_I16: opcode = IR::ValueOpcode::IEqual32; break;
|
||||
case Decoder::Opcode::V_CMP_NE_U16:
|
||||
case Decoder::Opcode::V_CMP_NE_I16: opcode = IR::ValueOpcode::INotEqual32; break;
|
||||
case Decoder::Opcode::V_CMP_GT_U16: opcode = IR::ValueOpcode::UGreaterThan32; break;
|
||||
case Decoder::Opcode::V_CMP_GE_U16: opcode = IR::ValueOpcode::UGreaterThanEqual32; break;
|
||||
case Decoder::Opcode::V_CMP_LT_U16: opcode = IR::ValueOpcode::ULessThan32; break;
|
||||
case Decoder::Opcode::V_CMP_LE_U16: opcode = IR::ValueOpcode::ULessThanEqual32; break;
|
||||
case Decoder::Opcode::V_CMP_GT_I16:
|
||||
opcode = IR::ValueOpcode::SGreaterThan32;
|
||||
signed_value = true;
|
||||
break;
|
||||
case IR::Opcode::CompareGeI16:
|
||||
case Decoder::Opcode::V_CMP_GE_I16:
|
||||
opcode = IR::ValueOpcode::SGreaterThanEqual32;
|
||||
signed_value = true;
|
||||
break;
|
||||
case IR::Opcode::CompareLtI16:
|
||||
case Decoder::Opcode::V_CMP_LT_I16:
|
||||
opcode = IR::ValueOpcode::SLessThan32;
|
||||
signed_value = true;
|
||||
break;
|
||||
case IR::Opcode::CompareLeI16:
|
||||
case Decoder::Opcode::V_CMP_LE_I16:
|
||||
opcode = IR::ValueOpcode::SLessThanEqual32;
|
||||
signed_value = true;
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
if (inst.op == IR::Opcode::CompareEqI16 || inst.op == IR::Opcode::CompareNeI16) {
|
||||
if (inst.opcode == Decoder::Opcode::V_CMP_EQ_I16 ||
|
||||
inst.opcode == Decoder::Opcode::V_CMP_NE_I16) {
|
||||
signed_value = true;
|
||||
}
|
||||
WriteCompareResult(inst.dst,
|
||||
IR::U1(ir.Emit(opcode, {ReadU16AsU32(inst.src[0], signed_value),
|
||||
ReadU16AsU32(inst.src[1], signed_value)})));
|
||||
WriteCompareResult(inst.dst, IR::U1(ir.Emit(opcode, {ReadU16AsU32(inst.src0, signed_value),
|
||||
ReadU16AsU32(inst.src1, signed_value)})));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateFloatCompare(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateFloatCompare(const Decoder::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;
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_CMP_F_F32:
|
||||
WriteCompareResult(inst.dst, IR::U1(IR::Value(false)));
|
||||
return true;
|
||||
case Decoder::Opcode::V_CMP_TRU_F32:
|
||||
WriteCompareResult(inst.dst, IR::U1(IR::Value(true)));
|
||||
return true;
|
||||
case Decoder::Opcode::V_CMP_EQ_F32:
|
||||
case Decoder::Opcode::V_CMPX_EQ_F32: opcode = IR::ValueOpcode::FPOrdEqual32; break;
|
||||
case Decoder::Opcode::V_CMP_LG_F32:
|
||||
case Decoder::Opcode::V_CMPX_LG_F32: opcode = IR::ValueOpcode::FPOrdNotEqual32; break;
|
||||
case Decoder::Opcode::V_CMP_GT_F32:
|
||||
case Decoder::Opcode::V_CMPX_GT_F32: opcode = IR::ValueOpcode::FPOrdGreaterThan32; break;
|
||||
case Decoder::Opcode::V_CMP_GE_F32:
|
||||
case Decoder::Opcode::V_CMPX_GE_F32:
|
||||
opcode = IR::ValueOpcode::FPOrdGreaterThanEqual32;
|
||||
break;
|
||||
case IR::Opcode::CompareUnordGeF32:
|
||||
case IR::Opcode::CompareMaskUnordGeF32:
|
||||
case Decoder::Opcode::V_CMP_LT_F32:
|
||||
case Decoder::Opcode::V_CMPX_LT_F32: opcode = IR::ValueOpcode::FPOrdLessThan32; break;
|
||||
case Decoder::Opcode::V_CMP_LE_F32:
|
||||
case Decoder::Opcode::V_CMPX_LE_F32: opcode = IR::ValueOpcode::FPOrdLessThanEqual32; break;
|
||||
case Decoder::Opcode::V_CMP_NLG_F32:
|
||||
case Decoder::Opcode::V_CMPX_NLG_F32: opcode = IR::ValueOpcode::FPUnordEqual32; break;
|
||||
case Decoder::Opcode::V_CMP_NEQ_F32:
|
||||
case Decoder::Opcode::V_CMPX_NEQ_F32: opcode = IR::ValueOpcode::FPUnordNotEqual32; break;
|
||||
case Decoder::Opcode::V_CMP_NLE_F32:
|
||||
case Decoder::Opcode::V_CMPX_NLE_F32: opcode = IR::ValueOpcode::FPUnordGreaterThan32; break;
|
||||
case Decoder::Opcode::V_CMP_NLT_F32:
|
||||
case Decoder::Opcode::V_CMPX_NLT_F32:
|
||||
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:
|
||||
case Decoder::Opcode::V_CMP_NGE_F32:
|
||||
case Decoder::Opcode::V_CMPX_NGE_F32: opcode = IR::ValueOpcode::FPUnordLessThan32; break;
|
||||
case Decoder::Opcode::V_CMP_NGT_F32:
|
||||
case Decoder::Opcode::V_CMPX_NGT_F32:
|
||||
opcode = IR::ValueOpcode::FPUnordLessThanEqual32;
|
||||
break;
|
||||
case IR::Opcode::CompareEqF16:
|
||||
case IR::Opcode::CompareMaskEqF16:
|
||||
case Decoder::Opcode::V_CMP_EQ_F16:
|
||||
case Decoder::Opcode::V_CMPX_EQ_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case IR::Opcode::CompareNeF16:
|
||||
case IR::Opcode::CompareMaskNeF16:
|
||||
case Decoder::Opcode::V_CMP_LG_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdNotEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case IR::Opcode::CompareGtF16:
|
||||
case IR::Opcode::CompareMaskGtF16:
|
||||
case Decoder::Opcode::V_CMP_GT_F16:
|
||||
case Decoder::Opcode::V_CMPX_GT_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdGreaterThan32;
|
||||
half = true;
|
||||
break;
|
||||
case IR::Opcode::CompareGeF16:
|
||||
case IR::Opcode::CompareMaskGeF16:
|
||||
case Decoder::Opcode::V_CMP_GE_F16:
|
||||
case Decoder::Opcode::V_CMPX_GE_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdGreaterThanEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case IR::Opcode::CompareLtF16:
|
||||
case IR::Opcode::CompareMaskLtF16:
|
||||
case Decoder::Opcode::V_CMP_LT_F16:
|
||||
case Decoder::Opcode::V_CMPX_LT_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdLessThan32;
|
||||
half = true;
|
||||
break;
|
||||
case IR::Opcode::CompareLeF16:
|
||||
case IR::Opcode::CompareMaskLeF16:
|
||||
case Decoder::Opcode::V_CMP_LE_F16:
|
||||
case Decoder::Opcode::V_CMPX_LE_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdLessThanEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case IR::Opcode::CompareUnordNeF16:
|
||||
case IR::Opcode::CompareMaskUnordNeF16:
|
||||
case Decoder::Opcode::V_CMP_NEQ_F16:
|
||||
case Decoder::Opcode::V_CMPX_NEQ_F16:
|
||||
opcode = IR::ValueOpcode::FPUnordNotEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case IR::Opcode::CompareMaskUnordGeF16:
|
||||
case Decoder::Opcode::V_CMPX_NLT_F16:
|
||||
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));
|
||||
case Decoder::Opcode::V_CMP_O_F32:
|
||||
case Decoder::Opcode::V_CMP_U_F32: {
|
||||
const auto lhs = IR::F32(ReadOperand(inst.src0, IR::Type::F32));
|
||||
const auto rhs = IR::F32(ReadOperand(inst.src1, 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);
|
||||
inst.opcode == Decoder::Opcode::V_CMP_U_F32 ? 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);
|
||||
case Decoder::Opcode::V_CMP_CLASS_F32: {
|
||||
const auto value = ReadOperand(inst.src0, IR::Type::F32);
|
||||
const auto mask = ReadOperand(inst.src1, IR::Type::U32);
|
||||
WriteCompareResult(inst.dst,
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::FPCmpClass32, {value, mask})));
|
||||
return true;
|
||||
@@ -189,11 +212,11 @@ bool Translator::TranslateFloatCompare(const IR::Instruction& inst) {
|
||||
default: return false;
|
||||
}
|
||||
const auto lhs =
|
||||
half ? IR::Value(ReadF16AsF32(inst.src[0])) : ReadOperand(inst.src[0], IR::Type::F32);
|
||||
half ? IR::Value(ReadF16AsF32(inst.src0)) : ReadOperand(inst.src0, IR::Type::F32);
|
||||
const auto rhs =
|
||||
half ? IR::Value(ReadF16AsF32(inst.src[1])) : ReadOperand(inst.src[1], IR::Type::F32);
|
||||
half ? IR::Value(ReadF16AsF32(inst.src1)) : ReadOperand(inst.src1, IR::Type::F32);
|
||||
WriteCompareResult(inst.dst, IR::U1(ir.Emit(opcode, {lhs, rhs})));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
@@ -1,23 +1,52 @@
|
||||
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
namespace {
|
||||
|
||||
bool Translator::TranslateStateOperation(const IR::Instruction& inst) {
|
||||
bool IsExecOrVcc(const Decoder::Operand& operand) {
|
||||
switch (operand.kind) {
|
||||
case Decoder::OperandKind::ExecLo:
|
||||
case Decoder::OperandKind::ExecHi:
|
||||
case Decoder::OperandKind::VccLo:
|
||||
case Decoder::OperandKind::VccHi: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
Decoder::Operand ConditionOperand(Decoder::OperandKind kind) {
|
||||
Decoder::Operand operand;
|
||||
operand.kind = kind;
|
||||
return operand;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Translator::TranslateStateOperation(const Decoder::Instruction& inst) {
|
||||
const auto zero = IR::U32(IR::Value(0u));
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::SaveexecB32:
|
||||
case IR::Opcode::SaveexecB64: {
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_AND_SAVEEXEC_B32:
|
||||
case Decoder::Opcode::S_ANDN1_SAVEEXEC_B32:
|
||||
case Decoder::Opcode::S_AND_SAVEEXEC_B64:
|
||||
case Decoder::Opcode::S_ANDN1_SAVEEXEC_B64:
|
||||
case Decoder::Opcode::S_ORN2_SAVEEXEC_B64: {
|
||||
const auto old = ir.GetExec();
|
||||
const auto src = ReadMask(inst.src[0]);
|
||||
const auto src = ReadMask(inst.src0);
|
||||
IR::U1 result;
|
||||
switch (inst.saveexec_mode) {
|
||||
case IR::SaveexecMode::And: result = ir.LogicalAnd(old, src); break;
|
||||
case IR::SaveexecMode::Andn1:
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_AND_SAVEEXEC_B32:
|
||||
case Decoder::Opcode::S_AND_SAVEEXEC_B64: result = ir.LogicalAnd(old, src); break;
|
||||
case Decoder::Opcode::S_ANDN1_SAVEEXEC_B32:
|
||||
case Decoder::Opcode::S_ANDN1_SAVEEXEC_B64:
|
||||
result = ir.LogicalAnd(old, ir.LogicalNot(src));
|
||||
break;
|
||||
case IR::SaveexecMode::Orn2: result = ir.LogicalOr(ir.LogicalNot(old), src); break;
|
||||
case Decoder::Opcode::S_ORN2_SAVEEXEC_B64:
|
||||
result = ir.LogicalOr(ir.LogicalNot(old), src);
|
||||
break;
|
||||
default: EXIT("invalid saveexec opcode");
|
||||
}
|
||||
if (inst.op == IR::Opcode::SaveexecB64) {
|
||||
if (inst.opcode == Decoder::Opcode::S_AND_SAVEEXEC_B64 ||
|
||||
inst.opcode == Decoder::Opcode::S_ANDN1_SAVEEXEC_B64 ||
|
||||
inst.opcode == Decoder::Opcode::S_ORN2_SAVEEXEC_B64) {
|
||||
WriteMask64(inst.dst, old);
|
||||
} else {
|
||||
WriteMask(inst.dst, old);
|
||||
@@ -29,63 +58,75 @@ bool Translator::TranslateStateOperation(const IR::Instruction& inst) {
|
||||
ir.SetScc(result);
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ScalarAddCarryU32:
|
||||
case IR::Opcode::IAddCarryU32: {
|
||||
const auto lhs = ReadU32(inst.src[0]);
|
||||
const auto rhs = ReadU32(inst.src[1]);
|
||||
const auto carry_in = ConditionBit(inst.src[2]);
|
||||
case Decoder::Opcode::S_ADD_U32:
|
||||
case Decoder::Opcode::S_ADDC_U32:
|
||||
case Decoder::Opcode::V_ADD_I32:
|
||||
case Decoder::Opcode::V_ADDC_U32: {
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
const auto carry_in = inst.opcode == Decoder::Opcode::S_ADDC_U32
|
||||
? ConditionBit(ConditionOperand(Decoder::OperandKind::Scc))
|
||||
: inst.opcode == Decoder::Opcode::V_ADDC_U32
|
||||
? ConditionBit(inst.src2)
|
||||
: zero;
|
||||
const auto add0 = ir.Emit(IR::ValueOpcode::IAddCarry32, {lhs, rhs});
|
||||
const auto partial = ir.CompositeExtract(add0, 0);
|
||||
const auto carry0 = ir.CompositeExtract(add0, 1);
|
||||
const auto add1 = ir.Emit(IR::ValueOpcode::IAddCarry32, {partial, carry_in});
|
||||
const auto result = ir.CompositeExtract(add1, 0);
|
||||
const auto carry1 = ir.CompositeExtract(add1, 1);
|
||||
const auto carry = ir.INotEqual(ir.BitwiseOr(carry0, carry1), IR::U32(IR::Value(0u)));
|
||||
WriteOperand(inst.dst, result);
|
||||
if (inst.op == IR::Opcode::ScalarAddCarryU32) {
|
||||
const auto carry = ir.INotEqual(ir.BitwiseOr(carry0, carry1), zero);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
if (inst.opcode == Decoder::Opcode::S_ADD_U32 ||
|
||||
inst.opcode == Decoder::Opcode::S_ADDC_U32) {
|
||||
ir.SetScc(carry);
|
||||
} else {
|
||||
WriteMask(inst.dst2, ir.LogicalAnd(ir.GetExec(), carry));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ScalarSubBorrowU32:
|
||||
case IR::Opcode::ISubBorrowU32: {
|
||||
const auto lhs = ReadU32(inst.src[0]);
|
||||
const auto rhs = ReadU32(inst.src[1]);
|
||||
const auto result = ir.ISub(lhs, rhs);
|
||||
const auto borrow = ir.UGreaterThan(rhs, lhs);
|
||||
WriteOperand(inst.dst, result);
|
||||
if (inst.op == IR::Opcode::ScalarSubBorrowU32) {
|
||||
case Decoder::Opcode::S_SUB_U32:
|
||||
case Decoder::Opcode::V_SUB_I32:
|
||||
case Decoder::Opcode::V_SUBREV_I32: {
|
||||
const bool reverse = inst.opcode == Decoder::Opcode::V_SUBREV_I32;
|
||||
const auto lhs = ReadU32(reverse ? inst.src1 : inst.src0);
|
||||
const auto rhs = ReadU32(reverse ? inst.src0 : inst.src1);
|
||||
const auto result = ir.ISub(lhs, rhs);
|
||||
const auto borrow = ir.UGreaterThan(rhs, lhs);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
if (inst.opcode == Decoder::Opcode::S_SUB_U32) {
|
||||
ir.SetScc(borrow);
|
||||
} else {
|
||||
WriteMask(inst.dst2, ir.LogicalAnd(ir.GetExec(), borrow));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ScalarSubBorrowCarryU32:
|
||||
case IR::Opcode::ISubBorrowCarryU32: {
|
||||
const auto lhs = ReadU32(inst.src[0]);
|
||||
const auto rhs = ReadU32(inst.src[1]);
|
||||
const auto borrow_in = ConditionBit(inst.src[2]);
|
||||
case Decoder::Opcode::S_SUBB_U32:
|
||||
case Decoder::Opcode::V_SUBREV_CO_CI_U32: {
|
||||
const bool vector = inst.opcode == Decoder::Opcode::V_SUBREV_CO_CI_U32;
|
||||
const auto lhs = ReadU32(vector ? inst.src1 : inst.src0);
|
||||
const auto rhs = ReadU32(vector ? inst.src0 : inst.src1);
|
||||
const auto borrow_in = vector
|
||||
? ConditionBit(inst.src2)
|
||||
: ConditionBit(ConditionOperand(Decoder::OperandKind::Scc));
|
||||
const auto partial = ir.ISub(lhs, rhs);
|
||||
const auto result = ir.ISub(partial, borrow_in);
|
||||
const auto borrow0 = ir.UGreaterThan(rhs, lhs);
|
||||
const auto borrow1 = ir.UGreaterThan(borrow_in, partial);
|
||||
WriteOperand(inst.dst, result);
|
||||
const auto borrow = ir.LogicalOr(borrow0, borrow1);
|
||||
if (inst.op == IR::Opcode::ScalarSubBorrowCarryU32) {
|
||||
ir.SetScc(borrow);
|
||||
} else {
|
||||
const auto borrow = ir.LogicalOr(borrow0, borrow1);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
if (vector) {
|
||||
WriteMask(inst.dst2, ir.LogicalAnd(ir.GetExec(), borrow));
|
||||
} else {
|
||||
ir.SetScc(borrow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ScalarSignedAddOverflowI32:
|
||||
case IR::Opcode::ScalarSignedSubOverflowI32: {
|
||||
const auto lhs = ReadU32(inst.src[0]);
|
||||
const auto rhs = ReadU32(inst.src[1]);
|
||||
const bool subtract = inst.op == IR::Opcode::ScalarSignedSubOverflowI32;
|
||||
case Decoder::Opcode::S_ADD_I32:
|
||||
case Decoder::Opcode::S_SUB_I32: {
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
const bool subtract = inst.opcode == Decoder::Opcode::S_SUB_I32;
|
||||
const auto result = subtract ? ir.ISub(lhs, rhs) : ir.IAdd(lhs, rhs);
|
||||
const auto shift = IR::U32(IR::Value(31u));
|
||||
const auto lhs_sign = ir.ShiftRightLogical(lhs, shift);
|
||||
@@ -94,116 +135,201 @@ bool Translator::TranslateStateOperation(const IR::Instruction& inst) {
|
||||
const auto inputs =
|
||||
subtract ? ir.INotEqual(lhs_sign, rhs_sign) : ir.IEqual(lhs_sign, rhs_sign);
|
||||
const auto changed = ir.INotEqual(lhs_sign, out_sign);
|
||||
WriteOperand(inst.dst, result);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
ir.SetScc(ir.LogicalAnd(inputs, changed));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ScalarShiftLeftAddCarryU32: {
|
||||
const auto lhs = ReadU32(inst.src[0]);
|
||||
const auto shift = ReadU32(inst.src[1]);
|
||||
const auto rhs = ReadU32(inst.src[2]);
|
||||
const auto shifted = ir.ShiftLeftLogical(lhs, shift);
|
||||
const auto result = ir.IAdd(shifted, rhs);
|
||||
const auto add_carry = ir.ULessThan(result, shifted);
|
||||
const auto inverse_shift = ir.ISub(IR::U32(IR::Value(32u)), shift);
|
||||
const auto shifted_out = ir.ShiftRightLogical(lhs, inverse_shift);
|
||||
const auto shift_carry = ir.INotEqual(shifted_out, zero);
|
||||
WriteOperand(inst.dst, result);
|
||||
case Decoder::Opcode::S_LSHL1_ADD_U32:
|
||||
case Decoder::Opcode::S_LSHL2_ADD_U32:
|
||||
case Decoder::Opcode::S_LSHL3_ADD_U32:
|
||||
case Decoder::Opcode::S_LSHL4_ADD_U32: {
|
||||
const uint32_t shift_amount = 1u + static_cast<uint32_t>(inst.opcode) -
|
||||
static_cast<uint32_t>(Decoder::Opcode::S_LSHL1_ADD_U32);
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto shift = IR::U32(IR::Value(shift_amount));
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
const auto shifted = ir.ShiftLeftLogical(lhs, shift);
|
||||
const auto result = ir.IAdd(shifted, rhs);
|
||||
const auto add_carry = ir.ULessThan(result, shifted);
|
||||
const auto inverse_shift = ir.ISub(IR::U32(IR::Value(32u)), shift);
|
||||
const auto shifted_out = ir.ShiftRightLogical(lhs, inverse_shift);
|
||||
const auto shift_carry = ir.INotEqual(shifted_out, zero);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
ir.SetScc(ir.LogicalOr(add_carry, shift_carry));
|
||||
return true;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::TranslateControlOperation(const IR::Instruction& inst) {
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::ControlNop: ir.Emit(IR::ValueOpcode::ControlNop); return true;
|
||||
case IR::Opcode::Waitcnt: ir.Emit(IR::ValueOpcode::Waitcnt); return true;
|
||||
case IR::Opcode::Barrier: ir.Emit(IR::ValueOpcode::Barrier); return true;
|
||||
case IR::Opcode::Sendmsg: ir.Emit(IR::ValueOpcode::Sendmsg); return true;
|
||||
case IR::Opcode::TtraceData: ir.Emit(IR::ValueOpcode::TtraceData); return true;
|
||||
case IR::Opcode::InstPrefetch: ir.Emit(IR::ValueOpcode::InstPrefetch); return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::TranslateMove(const IR::Instruction& inst) {
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::MoveU32:
|
||||
if (inst.src[0].kind == IR::OperandKind::Register &&
|
||||
(inst.src[0].reg.file == IR::RegisterFile::Exec ||
|
||||
inst.src[0].reg.file == IR::RegisterFile::Vcc) &&
|
||||
inst.dst.kind == IR::OperandKind::Register &&
|
||||
(inst.dst.reg.file == IR::RegisterFile::Exec ||
|
||||
inst.dst.reg.file == IR::RegisterFile::Vcc)) {
|
||||
WriteMask(inst.dst, ReadMask(inst.src[0]));
|
||||
} else {
|
||||
WriteOperand(inst.dst, ReadOperand(inst.src[0], IR::Type::U32));
|
||||
case Decoder::Opcode::S_MIN_I32:
|
||||
case Decoder::Opcode::S_MAX_I32:
|
||||
case Decoder::Opcode::S_MIN_U32:
|
||||
case Decoder::Opcode::S_MAX_U32: {
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
IR::ValueOpcode value_opcode;
|
||||
IR::ValueOpcode compare_opcode;
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_MIN_I32:
|
||||
value_opcode = IR::ValueOpcode::SMin32;
|
||||
compare_opcode = IR::ValueOpcode::SLessThan32;
|
||||
break;
|
||||
case Decoder::Opcode::S_MAX_I32:
|
||||
value_opcode = IR::ValueOpcode::SMax32;
|
||||
compare_opcode = IR::ValueOpcode::SGreaterThan32;
|
||||
break;
|
||||
case Decoder::Opcode::S_MIN_U32:
|
||||
value_opcode = IR::ValueOpcode::UMin32;
|
||||
compare_opcode = IR::ValueOpcode::ULessThan32;
|
||||
break;
|
||||
case Decoder::Opcode::S_MAX_U32:
|
||||
value_opcode = IR::ValueOpcode::UMax32;
|
||||
compare_opcode = IR::ValueOpcode::UGreaterThan32;
|
||||
break;
|
||||
default: EXIT("invalid scalar min/max opcode");
|
||||
}
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(value_opcode, {lhs, rhs}));
|
||||
ir.SetScc(IR::U1(ir.Emit(compare_opcode, {lhs, rhs})));
|
||||
return true;
|
||||
case IR::Opcode::MoveF32Bits:
|
||||
WriteOperand(inst.dst, ReadOperand(inst.src[0], IR::Type::F32));
|
||||
return true;
|
||||
case IR::Opcode::MoveU64: {
|
||||
const auto is_exec_or_vcc = [](const IR::Operand& operand) {
|
||||
return operand.kind == IR::OperandKind::Register &&
|
||||
(operand.reg.file == IR::RegisterFile::Exec ||
|
||||
operand.reg.file == IR::RegisterFile::Vcc);
|
||||
};
|
||||
if (is_exec_or_vcc(inst.dst) || is_exec_or_vcc(inst.src[0])) {
|
||||
WriteMask64(inst.dst, ReadMask(inst.src[0]));
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::TranslateControlOperation(const Decoder::Instruction& inst) {
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_NOP: return true;
|
||||
case Decoder::Opcode::S_NOP:
|
||||
case Decoder::Opcode::S_SETREG_B32:
|
||||
case Decoder::Opcode::S_SLEEP:
|
||||
case Decoder::Opcode::S_TRAP: ir.Emit(IR::ValueOpcode::ControlNop); return true;
|
||||
case Decoder::Opcode::S_WAITCNT:
|
||||
case Decoder::Opcode::S_WAITCNT_DEPCTR: ir.Emit(IR::ValueOpcode::Waitcnt); return true;
|
||||
case Decoder::Opcode::S_BARRIER: ir.Emit(IR::ValueOpcode::Barrier); return true;
|
||||
case Decoder::Opcode::S_SENDMSG: ir.Emit(IR::ValueOpcode::Sendmsg); return true;
|
||||
case Decoder::Opcode::S_TTRACEDATA: ir.Emit(IR::ValueOpcode::TtraceData); return true;
|
||||
case Decoder::Opcode::S_INST_PREFETCH: ir.Emit(IR::ValueOpcode::InstPrefetch); return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::TranslateMove(const Decoder::Instruction& inst, std::string* error) {
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_GETPC_B64: {
|
||||
const auto base = IR::U64(ir.Emit(IR::ValueOpcode::GetShaderBase));
|
||||
const auto address = IR::U64(ir.Emit(
|
||||
IR::ValueOpcode::IAdd64, {base, IR::Value(static_cast<uint64_t>(inst.pc) + 4u)}));
|
||||
if (inst.dst.kind == Decoder::OperandKind::Null) {
|
||||
return true;
|
||||
}
|
||||
const bool scalar_copy = inst.dst.kind == IR::OperandKind::Register &&
|
||||
inst.src[0].kind == IR::OperandKind::Register &&
|
||||
inst.dst.reg.file == IR::RegisterFile::Scalar &&
|
||||
inst.src[0].reg.file == IR::RegisterFile::Scalar;
|
||||
IR::U1 source_mask;
|
||||
IR::U1 source_mask_valid;
|
||||
if (scalar_copy) {
|
||||
const auto src = static_cast<IR::ScalarReg>(inst.src[0].reg.index);
|
||||
source_mask = ir.GetThreadBitScalarReg(src);
|
||||
source_mask_valid = ir.GetScalarMaskTag(src);
|
||||
auto high = PlainOperand(inst.dst);
|
||||
switch (inst.dst.kind) {
|
||||
case Decoder::OperandKind::Sgpr:
|
||||
if (inst.dst.reg < 105u) {
|
||||
high.reg++;
|
||||
} else if (inst.dst.reg == 105u) {
|
||||
high.kind = Decoder::OperandKind::VccLo;
|
||||
high.reg = 0u;
|
||||
} else {
|
||||
if (error != nullptr) {
|
||||
*error = "S_GETPC_B64 destination does not name a valid scalar pair";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Decoder::OperandKind::VccLo: high.kind = Decoder::OperandKind::VccHi; break;
|
||||
case Decoder::OperandKind::M0: high.kind = Decoder::OperandKind::Null; break;
|
||||
case Decoder::OperandKind::ExecLo: high.kind = Decoder::OperandKind::ExecHi; break;
|
||||
default:
|
||||
if (error != nullptr) {
|
||||
*error = "S_GETPC_B64 destination does not name a valid scalar pair";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
WriteU32Pair(inst.dst, ReadU32Pair(inst.src[0]));
|
||||
if (scalar_copy) {
|
||||
ir.SetThreadBitScalarReg(static_cast<IR::ScalarReg>(inst.dst.reg.index),
|
||||
source_mask);
|
||||
ir.SetScalarMaskTag(static_cast<IR::ScalarReg>(inst.dst.reg.index),
|
||||
source_mask_valid);
|
||||
const auto words = ExtractU64(address);
|
||||
WriteOperand(inst.dst, words[0]);
|
||||
WriteOperand(high, words[1]);
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::S_CSELECT_B32: {
|
||||
const auto result = ir.Select(ir.GetScc(), ReadU32(inst.src0), ReadU32(inst.src1));
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::S_CSELECT_B64: {
|
||||
const auto condition = ir.GetScc();
|
||||
const auto lhs = ReadU32Pair(inst.src0);
|
||||
const auto rhs = ReadU32Pair(inst.src1);
|
||||
const auto selected_mask = IR::U1(ir.Emit(
|
||||
IR::ValueOpcode::SelectU1, {condition, ReadMask(inst.src0), ReadMask(inst.src1)}));
|
||||
const auto selected_mask_valid =
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1,
|
||||
{condition, ReadMaskValid(inst.src0), ReadMaskValid(inst.src1)}));
|
||||
if (IsExecOrVcc(inst.dst)) {
|
||||
WriteMask64(inst.dst, selected_mask);
|
||||
return true;
|
||||
}
|
||||
WriteU32Pair(inst.dst, {ir.Select(condition, lhs[0], rhs[0]),
|
||||
ir.Select(condition, lhs[1], rhs[1])});
|
||||
if (inst.dst.kind == Decoder::OperandKind::Sgpr) {
|
||||
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg);
|
||||
ir.SetThreadBitScalarReg(dst, selected_mask);
|
||||
ir.SetScalarMaskTag(dst, selected_mask_valid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::WqmB64: {
|
||||
const auto is_exec_or_vcc = [](const IR::Operand& operand) {
|
||||
return operand.kind == IR::OperandKind::Register &&
|
||||
(operand.reg.file == IR::RegisterFile::Exec ||
|
||||
operand.reg.file == IR::RegisterFile::Vcc);
|
||||
};
|
||||
if (!is_exec_or_vcc(inst.dst) && !is_exec_or_vcc(inst.src[0])) {
|
||||
const auto mask_valid = ReadMaskValid(inst.src[0]);
|
||||
case Decoder::Opcode::S_MOV_B32:
|
||||
case Decoder::Opcode::S_MOVK_I32:
|
||||
case Decoder::Opcode::V_MOV_B32:
|
||||
if (IsExecOrVcc(inst.src0) && IsExecOrVcc(inst.dst)) {
|
||||
WriteMask(inst.dst, ReadMask(inst.src0));
|
||||
} else if (inst.opcode == Decoder::Opcode::V_MOV_B32 &&
|
||||
(inst.src0.negate || inst.src0.absolute)) {
|
||||
WriteOperand(DestinationOperand(inst), ReadOperand(inst.src0, IR::Type::F32));
|
||||
} else {
|
||||
WriteOperand(DestinationOperand(inst), ReadOperand(inst.src0, IR::Type::U32));
|
||||
}
|
||||
return true;
|
||||
case Decoder::Opcode::S_MOV_B64: {
|
||||
if (IsExecOrVcc(inst.dst) || IsExecOrVcc(inst.src0)) {
|
||||
WriteMask64(inst.dst, ReadMask(inst.src0));
|
||||
return true;
|
||||
}
|
||||
const bool scalar_copy = inst.dst.kind == Decoder::OperandKind::Sgpr &&
|
||||
inst.src0.kind == Decoder::OperandKind::Sgpr;
|
||||
IR::U1 source_mask;
|
||||
IR::U1 source_mask_valid;
|
||||
if (scalar_copy) {
|
||||
source_mask = ir.GetThreadBitScalarReg(static_cast<IR::ScalarReg>(inst.src0.reg));
|
||||
source_mask_valid = ir.GetScalarMaskTag(static_cast<IR::ScalarReg>(inst.src0.reg));
|
||||
}
|
||||
WriteU32Pair(inst.dst, ReadU32Pair(inst.src0));
|
||||
if (scalar_copy) {
|
||||
ir.SetThreadBitScalarReg(static_cast<IR::ScalarReg>(inst.dst.reg), source_mask);
|
||||
ir.SetScalarMaskTag(static_cast<IR::ScalarReg>(inst.dst.reg), source_mask_valid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::S_WQM_B64: {
|
||||
if (!IsExecOrVcc(inst.dst) && !IsExecOrVcc(inst.src0)) {
|
||||
const auto mask_valid = ReadMaskValid(inst.src0);
|
||||
const auto invocation_result =
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::WqmMask, {ReadMask(inst.src[0])}));
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::WqmMask, {ReadMask(inst.src0)}));
|
||||
const auto result = IR::U64(
|
||||
ir.Emit(IR::ValueOpcode::WqmU64, {ReadOperand(inst.src[0], IR::Type::U64)}));
|
||||
WriteOperand(inst.dst, result);
|
||||
if (inst.dst.kind == IR::OperandKind::Register &&
|
||||
inst.dst.reg.file == IR::RegisterFile::Scalar) {
|
||||
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg.index);
|
||||
ir.Emit(IR::ValueOpcode::WqmU64, {ReadOperand(inst.src0, IR::Type::U64)}));
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
if (inst.dst.kind == Decoder::OperandKind::Sgpr) {
|
||||
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg);
|
||||
ir.SetThreadBitScalarReg(dst, invocation_result);
|
||||
ir.SetScalarMaskTag(dst, mask_valid);
|
||||
const auto raw_nonzero = IR::U1(
|
||||
ir.Emit(IR::ValueOpcode::INotEqual64, {result, IR::Value(uint64_t {0})}));
|
||||
ir.SetScc(IR::U1(ir.Emit(
|
||||
IR::ValueOpcode::SelectU1, {mask_valid, invocation_result, raw_nonzero})));
|
||||
ir.SetScc(IR::U1(ir.Emit(IR::ValueOpcode::SelectU1,
|
||||
{mask_valid, invocation_result, raw_nonzero})));
|
||||
} else {
|
||||
ir.SetScc(IR::U1(
|
||||
ir.Emit(IR::ValueOpcode::INotEqual64, {result, IR::Value(uint64_t {0})})));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const auto result = IR::U1(ir.Emit(IR::ValueOpcode::WqmMask, {ReadMask(inst.src[0])}));
|
||||
const auto result = IR::U1(ir.Emit(IR::ValueOpcode::WqmMask, {ReadMask(inst.src0)}));
|
||||
WriteMask64(inst.dst, result);
|
||||
ir.SetScc(result);
|
||||
return true;
|
||||
@@ -212,29 +338,56 @@ bool Translator::TranslateMove(const IR::Instruction& inst) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::TranslateLaneOperation(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateLaneOperation(const Decoder::Instruction& inst, std::string* error) {
|
||||
const auto lane_mask = IR::U32(IR::Value(current_wave_size == 32u ? 31u : 63u));
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::MoveRelSourceU32: {
|
||||
EXIT_IF(inst.src[0].kind != IR::OperandKind::Register ||
|
||||
inst.src[0].reg.file != IR::RegisterFile::Vector);
|
||||
const auto base = inst.src[0].reg.index;
|
||||
const auto m0 = ir.BitwiseAnd(ReadU32(inst.src[1]), IR::U32(IR::Value(0xffu)));
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_MOVRELS_B32: {
|
||||
if (inst.dst.kind != Decoder::OperandKind::Vgpr ||
|
||||
inst.src0.kind != Decoder::OperandKind::Vgpr) {
|
||||
if (error != nullptr) {
|
||||
*error = "V_MOVRELS_B32 requires VGPR source and destination";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (inst.dst.sdwa_sel != 6u || inst.dst.omod != 0u || inst.dst.clamp ||
|
||||
inst.src0.sdwa_sel != 6u || inst.src0.sdwa_sext || inst.src0.negate ||
|
||||
inst.src0.absolute || inst.src0.dpp) {
|
||||
if (error != nullptr) {
|
||||
*error = "V_MOVRELS_B32 modifiers are not implemented";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const auto base = inst.src0.reg;
|
||||
const auto m0 = ir.BitwiseAnd(ReadU32(ConditionOperand(Decoder::OperandKind::M0)),
|
||||
IR::U32(IR::Value(0xffu)));
|
||||
auto selected = ir.GetVectorReg(static_cast<IR::VectorReg>(base));
|
||||
for (uint32_t index = base + 1u; index < current_vector_limit; index++) {
|
||||
const auto match = ir.IEqual(m0, IR::U32(IR::Value(index - base)));
|
||||
selected =
|
||||
ir.Select(match, ir.GetVectorReg(static_cast<IR::VectorReg>(index)), selected);
|
||||
}
|
||||
WriteOperand(inst.dst, selected);
|
||||
WriteOperand(DestinationOperand(inst), selected);
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::MoveRelDestU32: {
|
||||
EXIT_IF(inst.dst.kind != IR::OperandKind::Register ||
|
||||
inst.dst.reg.file != IR::RegisterFile::Vector);
|
||||
const auto base = inst.dst.reg.index;
|
||||
const auto value = ReadU32(inst.src[0]);
|
||||
const auto m0 = ir.BitwiseAnd(ReadU32(inst.src[1]), IR::U32(IR::Value(0xffu)));
|
||||
case Decoder::Opcode::V_MOVRELD_B32: {
|
||||
if (inst.dst.kind != Decoder::OperandKind::Vgpr) {
|
||||
if (error != nullptr) {
|
||||
*error = "V_MOVRELD_B32 requires VGPR destination";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (inst.dst.sdwa_sel != 6u || inst.dst.omod != 0u || inst.dst.clamp ||
|
||||
inst.src0.sdwa_sel != 6u || inst.src0.sdwa_sext || inst.src0.negate ||
|
||||
inst.src0.absolute || inst.src0.dpp) {
|
||||
if (error != nullptr) {
|
||||
*error = "V_MOVRELD_B32 modifiers are not implemented";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const auto base = inst.dst.reg;
|
||||
const auto value = ReadU32(inst.src0);
|
||||
const auto m0 = ir.BitwiseAnd(ReadU32(ConditionOperand(Decoder::OperandKind::M0)),
|
||||
IR::U32(IR::Value(0xffu)));
|
||||
for (uint32_t index = base; index < current_vector_limit; index++) {
|
||||
const auto reg = static_cast<IR::VectorReg>(index);
|
||||
const auto match = ir.IEqual(m0, IR::U32(IR::Value(index - base)));
|
||||
@@ -243,41 +396,38 @@ bool Translator::TranslateLaneOperation(const IR::Instruction& inst) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ReadFirstLaneU32: {
|
||||
case Decoder::Opcode::V_READFIRSTLANE_B32: {
|
||||
const auto result =
|
||||
ir.Emit(IR::ValueOpcode::ReadFirstLane, {ReadU32(inst.src[0]), ir.GetExec()});
|
||||
WriteOperand(inst.dst, result);
|
||||
ir.Emit(IR::ValueOpcode::ReadFirstLane, {ReadU32(inst.src0), ir.GetExec()});
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ReadLaneU32: {
|
||||
const auto lane = ir.BitwiseAnd(ReadU32(inst.src[1]), lane_mask);
|
||||
WriteOperand(inst.dst,
|
||||
ir.Emit(IR::ValueOpcode::ReadLane, {ReadU32(inst.src[0]), lane}));
|
||||
case Decoder::Opcode::V_READLANE_B32: {
|
||||
const auto lane = ir.BitwiseAnd(ReadU32(inst.src1), lane_mask);
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::ReadLane, {ReadU32(inst.src0), lane}));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::WriteLaneU32: {
|
||||
EXIT_IF(inst.dst.kind != IR::OperandKind::Register ||
|
||||
inst.dst.reg.file != IR::RegisterFile::Vector);
|
||||
const auto reg = static_cast<IR::VectorReg>(inst.dst.reg.index);
|
||||
const auto lane = ir.BitwiseAnd(ReadU32(inst.src[1]), lane_mask);
|
||||
const auto result = IR::U32(ir.Emit(
|
||||
IR::ValueOpcode::WriteLane, {ir.GetVectorReg(reg), ReadU32(inst.src[0]), lane}));
|
||||
// V_WRITELANE_B32 ignores EXEC; bypass the ordinary VGPR destination path.
|
||||
case Decoder::Opcode::V_WRITELANE_B32: {
|
||||
EXIT_IF(inst.dst.kind != Decoder::OperandKind::Vgpr);
|
||||
const auto reg = static_cast<IR::VectorReg>(inst.dst.reg);
|
||||
const auto lane = ir.BitwiseAnd(ReadU32(inst.src1), lane_mask);
|
||||
const auto result = IR::U32(ir.Emit(IR::ValueOpcode::WriteLane,
|
||||
{ir.GetVectorReg(reg), ReadU32(inst.src0), lane}));
|
||||
ir.SetVectorReg(reg, result);
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::Permlane16B32:
|
||||
case IR::Opcode::Permlanex16B32: {
|
||||
case Decoder::Opcode::V_PERMLANE16_B32:
|
||||
case Decoder::Opcode::V_PERMLANEX16_B32: {
|
||||
const IR::PermlaneFlags flags {
|
||||
.x16 = inst.op == IR::Opcode::Permlanex16B32,
|
||||
.x16 = inst.opcode == Decoder::Opcode::V_PERMLANEX16_B32,
|
||||
.fetch_inactive = inst.dst.op_sel,
|
||||
.bound_control = inst.dst.op_sel_hi,
|
||||
};
|
||||
const auto result = ir.Emit(
|
||||
IR::ValueOpcode::Permlane16U32,
|
||||
{ReadU32(inst.src[0]), ReadU32(inst.src[1]), ReadU32(inst.src[2]), ir.GetExec()},
|
||||
flags);
|
||||
auto dst = inst.dst;
|
||||
{ReadU32(inst.src0), ReadU32(inst.src1), ReadU32(inst.src2), ir.GetExec()}, flags);
|
||||
auto dst = DestinationOperand(inst);
|
||||
dst.op_sel = false;
|
||||
dst.op_sel_hi = false;
|
||||
WriteOperand(dst, result);
|
||||
@@ -287,4 +437,4 @@ bool Translator::TranslateLaneOperation(const IR::Instruction& inst) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
IR::F32 Translator::SelectF32(IR::U1 condition, IR::F32 true_value, IR::F32 false_value) {
|
||||
return IR::F32(ir.Emit(IR::ValueOpcode::SelectF32, {condition, true_value, false_value}));
|
||||
@@ -38,11 +38,11 @@ IR::U32 Translator::ConvertF32ToI32Saturated(IR::F32 value, float lower_bound, f
|
||||
return ir.Select(nan, IR::U32(IR::Value(0u)), clamped);
|
||||
}
|
||||
|
||||
bool Translator::TranslateConversion(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateConversion(const Decoder::Instruction& inst) {
|
||||
const auto f32 = [&](uint32_t index) {
|
||||
return IR::F32(ReadOperand(inst.src[index], IR::Type::F32));
|
||||
return IR::F32(ReadOperand(SourceAt(inst, index), IR::Type::F32));
|
||||
};
|
||||
const auto u32 = [&](uint32_t index) { return ReadU32(inst.src[index]); };
|
||||
const auto u32 = [&](uint32_t index) { return ReadU32(SourceAt(inst, index)); };
|
||||
const auto convert_u32 = [&](IR::F32 value) {
|
||||
return ConvertF32ToU32Saturated(value, 4294967296.0f, 4294967040.0f, 0xffffffffu);
|
||||
};
|
||||
@@ -51,65 +51,77 @@ bool Translator::TranslateConversion(const IR::Instruction& inst) {
|
||||
0x80000000u, 0x7fffffffu);
|
||||
};
|
||||
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::ConvertByteU32ToF32: {
|
||||
const auto index =
|
||||
inst.src[1].kind == IR::OperandKind::ImmediateU32 ? inst.src[1].imm & 3u : 0u;
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_CVT_F32_UBYTE0:
|
||||
case Decoder::Opcode::V_CVT_F32_UBYTE1:
|
||||
case Decoder::Opcode::V_CVT_F32_UBYTE2:
|
||||
case Decoder::Opcode::V_CVT_F32_UBYTE3: {
|
||||
const auto index = static_cast<uint32_t>(inst.opcode) -
|
||||
static_cast<uint32_t>(Decoder::Opcode::V_CVT_F32_UBYTE0);
|
||||
const auto byte =
|
||||
ir.BitwiseAnd(ir.ShiftRightLogical(u32(0), IR::U32(IR::Value(index * 8u))),
|
||||
IR::U32(IR::Value(0xffu)));
|
||||
WriteOperand(inst.dst, ir.Emit(IR::ValueOpcode::ConvertF32U32, {byte}));
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(IR::ValueOpcode::ConvertF32U32, {byte}));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ConvertU32ToF32:
|
||||
WriteOperand(inst.dst, ir.Emit(IR::ValueOpcode::ConvertF32U32, {u32(0)}));
|
||||
case Decoder::Opcode::V_CVT_F32_U32:
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::ConvertF32U32, {u32(0)}));
|
||||
return true;
|
||||
case IR::Opcode::ConvertI32ToF32:
|
||||
WriteOperand(inst.dst, ir.Emit(IR::ValueOpcode::ConvertF32S32, {u32(0)}));
|
||||
case Decoder::Opcode::V_CVT_F32_I32:
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::ConvertF32S32, {u32(0)}));
|
||||
return true;
|
||||
case IR::Opcode::ConvertF32ToU32: WriteOperand(inst.dst, convert_u32(f32(0))); return true;
|
||||
case IR::Opcode::ConvertF32ToI32: WriteOperand(inst.dst, convert_i32(f32(0))); return true;
|
||||
case IR::Opcode::ConvertF32ToF16: WriteF16(inst.dst, f32(0)); return true;
|
||||
case IR::Opcode::ConvertF16ToF32:
|
||||
WriteOperand(inst.dst, ReadF16AsF32(inst.src[0]));
|
||||
case Decoder::Opcode::V_CVT_U32_F32:
|
||||
WriteOperand(DestinationOperand(inst), convert_u32(f32(0)));
|
||||
return true;
|
||||
case IR::Opcode::ConvertU16ToF16: {
|
||||
const auto value = IR::F32(
|
||||
ir.Emit(IR::ValueOpcode::ConvertF32U32, {ReadU16AsU32(inst.src[0], false)}));
|
||||
WriteF16(inst.dst, value);
|
||||
case Decoder::Opcode::V_CVT_I32_F32:
|
||||
WriteOperand(DestinationOperand(inst), convert_i32(f32(0)));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ConvertI16ToF16: {
|
||||
case Decoder::Opcode::V_CVT_F16_F32:
|
||||
WriteF16(DestinationOperand(inst), f32(0));
|
||||
return true;
|
||||
case Decoder::Opcode::V_CVT_F32_F16:
|
||||
WriteOperand(DestinationOperand(inst), ReadF16AsF32(inst.src0));
|
||||
return true;
|
||||
case Decoder::Opcode::V_CVT_F16_U16: {
|
||||
const auto value =
|
||||
IR::F32(ir.Emit(IR::ValueOpcode::ConvertF32S32, {ReadU16AsU32(inst.src[0], true)}));
|
||||
WriteF16(inst.dst, value);
|
||||
IR::F32(ir.Emit(IR::ValueOpcode::ConvertF32U32, {ReadU16AsU32(inst.src0, false)}));
|
||||
WriteF16(DestinationOperand(inst), value);
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ConvertF16ToU16: {
|
||||
case Decoder::Opcode::V_CVT_F16_I16: {
|
||||
const auto value =
|
||||
IR::F32(ir.Emit(IR::ValueOpcode::ConvertF32S32, {ReadU16AsU32(inst.src0, true)}));
|
||||
WriteF16(DestinationOperand(inst), value);
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::V_CVT_U16_F16: {
|
||||
const auto converted =
|
||||
ConvertF32ToU32Saturated(ReadF16AsF32(inst.src[0]), 65536.0f, 65535.0f, 0xffffu);
|
||||
WriteU16(inst.dst, converted);
|
||||
ConvertF32ToU32Saturated(ReadF16AsF32(inst.src0), 65536.0f, 65535.0f, 0xffffu);
|
||||
WriteU16(DestinationOperand(inst), converted);
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ConvertF16ToI16: {
|
||||
case Decoder::Opcode::V_CVT_I16_F16: {
|
||||
const auto converted = ConvertF32ToI32Saturated(
|
||||
ReadF16AsF32(inst.src[0]), -32768.0f, 32768.0f, 32767.0f, 0xffff8000u, 0x7fffu);
|
||||
WriteU16(inst.dst, ir.BitwiseAnd(converted, IR::U32(IR::Value(0xffffu))));
|
||||
ReadF16AsF32(inst.src0), -32768.0f, 32768.0f, 32767.0f, 0xffff8000u, 0x7fffu);
|
||||
WriteU16(DestinationOperand(inst),
|
||||
ir.BitwiseAnd(converted, IR::U32(IR::Value(0xffffu))));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ConvertRoundPlusInfF32ToI32: {
|
||||
case Decoder::Opcode::V_CVT_RPI_I32_F32: {
|
||||
const auto biased =
|
||||
IR::F32(ir.Emit(IR::ValueOpcode::FPAdd32, {f32(0), IR::Value::F32(0.5f)}));
|
||||
const auto rounded = IR::F32(ir.Emit(IR::ValueOpcode::FPFloor32, {biased}));
|
||||
WriteOperand(inst.dst, convert_i32(rounded));
|
||||
WriteOperand(DestinationOperand(inst), convert_i32(rounded));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ConvertFloorF32ToI32: {
|
||||
case Decoder::Opcode::V_CVT_FLR_I32_F32: {
|
||||
const auto rounded = IR::F32(ir.Emit(IR::ValueOpcode::FPFloor32, {f32(0)}));
|
||||
WriteOperand(inst.dst, convert_i32(rounded));
|
||||
WriteOperand(DestinationOperand(inst), convert_i32(rounded));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::FrexpExpI32F32: {
|
||||
case Decoder::Opcode::V_FREXP_EXP_I32_F32: {
|
||||
const auto bits = ir.BitCastU32(f32(0));
|
||||
const auto exponent = IR::U32(
|
||||
ir.Emit(IR::ValueOpcode::BitFieldUExtract, {bits, IR::Value(23u), IR::Value(8u)}));
|
||||
@@ -123,43 +135,45 @@ bool Translator::TranslateConversion(const IR::Instruction& inst) {
|
||||
ir.INotEqual(exponent, IR::U32(IR::Value(0xffu))),
|
||||
ir.Select(ir.INotEqual(exponent, IR::U32(IR::Value(0u))), normal, denormal),
|
||||
IR::U32(IR::Value(0u)));
|
||||
WriteOperand(inst.dst, finite);
|
||||
WriteOperand(DestinationOperand(inst), finite);
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::ConvertI4ToOffsetF32: {
|
||||
case Decoder::Opcode::V_CVT_OFF_F32_I4: {
|
||||
const auto nibble = IR::U32(
|
||||
ir.Emit(IR::ValueOpcode::BitFieldSExtract, {u32(0), IR::Value(0u), IR::Value(4u)}));
|
||||
const auto value = IR::F32(ir.Emit(IR::ValueOpcode::ConvertF32S32, {nibble}));
|
||||
WriteOperand(inst.dst,
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::FPMul32, {value, IR::Value::F32(1.0f / 16.0f)}));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::PackF32ToF16Rtz:
|
||||
WriteOperand(inst.dst, ir.Emit(IR::ValueOpcode::PackFloat2x16Rtz, {f32(0), f32(1)}));
|
||||
case Decoder::Opcode::V_CVT_PKRTZ_F16_F32:
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::PackFloat2x16Rtz, {f32(0), f32(1)}));
|
||||
return true;
|
||||
case IR::Opcode::PackSnorm2x16F32:
|
||||
case IR::Opcode::PackUnorm2x16F32: {
|
||||
case Decoder::Opcode::V_CVT_PKNORM_I16_F32:
|
||||
case Decoder::Opcode::V_CVT_PKNORM_U16_F32: {
|
||||
const auto pair = ir.Emit(IR::ValueOpcode::CompositeConstructF32x2, {f32(0), f32(1)});
|
||||
const auto opcode = inst.op == IR::Opcode::PackSnorm2x16F32
|
||||
const auto opcode = inst.opcode == Decoder::Opcode::V_CVT_PKNORM_I16_F32
|
||||
? IR::ValueOpcode::PackSnorm2x16
|
||||
: IR::ValueOpcode::PackUnorm2x16;
|
||||
WriteOperand(inst.dst, ir.Emit(opcode, {pair}));
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(opcode, {pair}));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::PackU8F32: {
|
||||
case Decoder::Opcode::V_CVT_PK_U8_F32: {
|
||||
const auto byte = ConvertF32ToU32Saturated(f32(0), 255.0f, 255.0f, 255u);
|
||||
const auto index = ir.BitwiseAnd(u32(1), IR::U32(IR::Value(3u)));
|
||||
const auto shift = ir.ShiftLeftLogical(index, IR::U32(IR::Value(3u)));
|
||||
const auto mask = ir.ShiftLeftLogical(IR::U32(IR::Value(0xffu)), shift);
|
||||
const auto base = ir.BitwiseAnd(u32(2), ir.BitwiseNot(mask));
|
||||
WriteOperand(inst.dst, ir.BitwiseOr(base, ir.ShiftLeftLogical(byte, shift)));
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.BitwiseOr(base, ir.ShiftLeftLogical(byte, shift)));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::PackB32F16: {
|
||||
const auto low = ReadF16LaneBits(inst.src[0], false);
|
||||
case Decoder::Opcode::V_PACK_B32_F16: {
|
||||
const auto low = ReadF16LaneBits(inst.src0, false);
|
||||
const auto high =
|
||||
ir.ShiftLeftLogical(ReadF16LaneBits(inst.src[1], false), IR::U32(IR::Value(16u)));
|
||||
WriteOperand(inst.dst, ir.BitwiseOr(low, high));
|
||||
ir.ShiftLeftLogical(ReadF16LaneBits(inst.src1, false), IR::U32(IR::Value(16u)));
|
||||
WriteOperand(DestinationOperand(inst), ir.BitwiseOr(low, high));
|
||||
return true;
|
||||
}
|
||||
default: return false;
|
||||
@@ -172,4 +186,4 @@ IR::U32 Translator::PackU16Lanes(IR::U32 low, IR::U32 high) {
|
||||
ir.ShiftLeftLogical(ir.BitwiseAnd(high, mask), IR::U32(IR::Value(16u))));
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
@@ -1,57 +1,73 @@
|
||||
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
bool Translator::TranslateU64MaskOperation(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateU64MaskOperation(const Decoder::Instruction& inst) {
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_AND_B64:
|
||||
case Decoder::Opcode::S_ANDN2_B64:
|
||||
case Decoder::Opcode::S_OR_B64:
|
||||
case Decoder::Opcode::S_ORN2_B64:
|
||||
case Decoder::Opcode::S_XOR_B64:
|
||||
case Decoder::Opcode::S_NAND_B64:
|
||||
case Decoder::Opcode::S_NOR_B64:
|
||||
case Decoder::Opcode::S_XNOR_B64:
|
||||
case Decoder::Opcode::S_NOT_B64: break;
|
||||
default: return false;
|
||||
}
|
||||
const auto invocation_result = EvaluateU64Mask(inst);
|
||||
const auto is_exec_or_vcc = [](const IR::Operand& operand) {
|
||||
return operand.kind == IR::OperandKind::Register &&
|
||||
(operand.reg.file == IR::RegisterFile::Exec ||
|
||||
operand.reg.file == IR::RegisterFile::Vcc);
|
||||
const auto is_exec_or_vcc = [](const Decoder::Operand& operand) {
|
||||
switch (operand.kind) {
|
||||
case Decoder::OperandKind::ExecLo:
|
||||
case Decoder::OperandKind::ExecHi:
|
||||
case Decoder::OperandKind::VccLo:
|
||||
case Decoder::OperandKind::VccHi: return true;
|
||||
default: return false;
|
||||
}
|
||||
};
|
||||
if (is_exec_or_vcc(inst.dst) || is_exec_or_vcc(inst.src[0]) ||
|
||||
(inst.src_count > 1u && is_exec_or_vcc(inst.src[1]))) {
|
||||
if (is_exec_or_vcc(inst.dst) || is_exec_or_vcc(inst.src0) ||
|
||||
(inst.src_count > 1u && is_exec_or_vcc(inst.src1))) {
|
||||
WriteMask64(inst.dst, invocation_result);
|
||||
ir.SetScc(invocation_result);
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto lhs = ReadU32Pair(inst.src[0]);
|
||||
auto mask_valid = ReadMaskValid(inst.src[0]);
|
||||
const auto lhs = ReadU32Pair(inst.src0);
|
||||
auto mask_valid = ReadMaskValid(inst.src0);
|
||||
if (inst.src_count > 1u) {
|
||||
mask_valid = ir.LogicalAnd(mask_valid, ReadMaskValid(inst.src[1]));
|
||||
mask_valid = ir.LogicalAnd(mask_valid, ReadMaskValid(inst.src1));
|
||||
}
|
||||
std::array<IR::U32, 2> result;
|
||||
if (inst.op == IR::Opcode::BitwiseNotU64) {
|
||||
if (inst.opcode == Decoder::Opcode::S_NOT_B64) {
|
||||
result = {ir.BitwiseNot(lhs[0]), ir.BitwiseNot(lhs[1])};
|
||||
} else {
|
||||
const auto rhs = ReadU32Pair(inst.src[1]);
|
||||
const auto rhs = ReadU32Pair(inst.src1);
|
||||
for (uint32_t component = 0; component < 2u; component++) {
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::BitwiseAndU64:
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_AND_B64:
|
||||
result[component] = ir.BitwiseAnd(lhs[component], rhs[component]);
|
||||
break;
|
||||
case IR::Opcode::BitwiseAndNotU64:
|
||||
case Decoder::Opcode::S_ANDN2_B64:
|
||||
result[component] =
|
||||
ir.BitwiseAnd(lhs[component], ir.BitwiseNot(rhs[component]));
|
||||
break;
|
||||
case IR::Opcode::BitwiseOrU64:
|
||||
case Decoder::Opcode::S_OR_B64:
|
||||
result[component] = ir.BitwiseOr(lhs[component], rhs[component]);
|
||||
break;
|
||||
case IR::Opcode::BitwiseOrNotU64:
|
||||
case Decoder::Opcode::S_ORN2_B64:
|
||||
result[component] = ir.BitwiseOr(lhs[component], ir.BitwiseNot(rhs[component]));
|
||||
break;
|
||||
case IR::Opcode::BitwiseXorU64:
|
||||
case Decoder::Opcode::S_XOR_B64:
|
||||
result[component] = ir.BitwiseXor(lhs[component], rhs[component]);
|
||||
break;
|
||||
case IR::Opcode::BitwiseNandU64:
|
||||
case Decoder::Opcode::S_NAND_B64:
|
||||
result[component] =
|
||||
ir.BitwiseNot(ir.BitwiseAnd(lhs[component], rhs[component]));
|
||||
break;
|
||||
case IR::Opcode::BitwiseNorU64:
|
||||
case Decoder::Opcode::S_NOR_B64:
|
||||
result[component] = ir.BitwiseNot(ir.BitwiseOr(lhs[component], rhs[component]));
|
||||
break;
|
||||
case IR::Opcode::BitwiseXnorU64:
|
||||
case Decoder::Opcode::S_XNOR_B64:
|
||||
result[component] =
|
||||
ir.BitwiseNot(ir.BitwiseXor(lhs[component], rhs[component]));
|
||||
break;
|
||||
@@ -60,9 +76,8 @@ bool Translator::TranslateU64MaskOperation(const IR::Instruction& inst) {
|
||||
}
|
||||
}
|
||||
WriteU32Pair(inst.dst, result);
|
||||
if (inst.dst.kind == IR::OperandKind::Register &&
|
||||
inst.dst.reg.file == IR::RegisterFile::Scalar) {
|
||||
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg.index);
|
||||
if (inst.dst.kind == Decoder::OperandKind::Sgpr) {
|
||||
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg);
|
||||
ir.SetThreadBitScalarReg(dst, invocation_result);
|
||||
ir.SetScalarMaskTag(dst, mask_valid);
|
||||
const auto raw_nonzero =
|
||||
@@ -75,29 +90,68 @@ bool Translator::TranslateU64MaskOperation(const IR::Instruction& inst) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateInstruction(const IR::Instruction& inst) {
|
||||
switch (IR::GetOpcodeInfo(inst.op).lowering_class) {
|
||||
case IR::LoweringClass::Control: return TranslateControlOperation(inst);
|
||||
case IR::LoweringClass::Move: return TranslateMove(inst);
|
||||
case IR::LoweringClass::Lane: return TranslateLaneOperation(inst);
|
||||
case IR::LoweringClass::State: return TranslateStateOperation(inst);
|
||||
case IR::LoweringClass::Memory: return TranslateMemoryOperation(inst);
|
||||
case IR::LoweringClass::Attribute: return TranslateAttributeOperation(inst);
|
||||
case IR::LoweringClass::IntegerCompare: return TranslateIntegerCompare(inst);
|
||||
case IR::LoweringClass::Integer16Compare: return TranslateInteger16Compare(inst);
|
||||
case IR::LoweringClass::FloatCompare: return TranslateFloatCompare(inst);
|
||||
case IR::LoweringClass::Conversion: return TranslateConversion(inst);
|
||||
case IR::LoweringClass::Integer16: return TranslateInteger16Operation(inst);
|
||||
case IR::LoweringClass::PackedInteger16: return TranslatePackedInteger16(inst);
|
||||
case IR::LoweringClass::PackedFloat16: return TranslatePackedFloat16(inst);
|
||||
case IR::LoweringClass::Float16: return TranslateFloat16Operation(inst);
|
||||
case IR::LoweringClass::Float: return TranslateFloatOperation(inst);
|
||||
case IR::LoweringClass::U64Mask: return TranslateU64MaskOperation(inst);
|
||||
case IR::LoweringClass::SimpleInteger: return TranslateSimpleInteger(inst);
|
||||
case IR::LoweringClass::ComposedInteger: return TranslateComposedInteger(inst);
|
||||
case IR::LoweringClass::ExtendedInteger: return TranslateExtendedInteger(inst);
|
||||
bool Translator::TranslateInstruction(const Decoder::Instruction& inst, std::string* error) {
|
||||
current_opcode = inst.opcode;
|
||||
current_pc = inst.pc;
|
||||
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::UNKNOWN:
|
||||
case Decoder::Opcode::COUNT:
|
||||
if (error != nullptr) {
|
||||
*error = "decoded opcode has no IR translation";
|
||||
}
|
||||
return false;
|
||||
case Decoder::Opcode::UNSUPPORTED:
|
||||
if (error != nullptr) {
|
||||
*error = "unsupported decoded instruction: " + Decoder::InstructionToString(inst);
|
||||
}
|
||||
return false;
|
||||
case Decoder::Opcode::S_GETPC_B64: return TranslateMove(inst, error);
|
||||
case Decoder::Opcode::V_MOVRELS_B32:
|
||||
case Decoder::Opcode::V_MOVRELD_B32: return TranslateLaneOperation(inst, error);
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
|
||||
switch (inst.family) {
|
||||
case Decoder::Family::SMEM:
|
||||
case Decoder::Family::MUBUF:
|
||||
case Decoder::Family::MTBUF:
|
||||
case Decoder::Family::FLAT:
|
||||
case Decoder::Family::DS:
|
||||
case Decoder::Family::MIMG: return TranslateMemoryOperation(inst, error);
|
||||
case Decoder::Family::EXP: return TranslateAttributeOperation(inst, error);
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_INTERP_P1_F32:
|
||||
case Decoder::Opcode::V_INTERP_P2_F32:
|
||||
case Decoder::Opcode::V_INTERP_MOV_F32: return TranslateAttributeOperation(inst, error);
|
||||
case Decoder::Opcode::S_BRANCH:
|
||||
case Decoder::Opcode::S_CBRANCH_SCC0:
|
||||
case Decoder::Opcode::S_CBRANCH_SCC1:
|
||||
case Decoder::Opcode::S_CBRANCH_VCCZ:
|
||||
case Decoder::Opcode::S_CBRANCH_VCCNZ:
|
||||
case Decoder::Opcode::S_CBRANCH_EXECZ:
|
||||
case Decoder::Opcode::S_CBRANCH_EXECNZ:
|
||||
case Decoder::Opcode::S_SETPC_B64:
|
||||
case Decoder::Opcode::S_ENDPGM: return true;
|
||||
default: break;
|
||||
}
|
||||
|
||||
const bool translated = TranslateControlOperation(inst) || TranslateStateOperation(inst) ||
|
||||
TranslateMove(inst, error) || TranslateLaneOperation(inst, error) ||
|
||||
TranslateIntegerCompare(inst) || TranslateInteger16Compare(inst) ||
|
||||
TranslateFloatCompare(inst) || TranslateConversion(inst) ||
|
||||
TranslateInteger16Operation(inst) || TranslatePackedInteger16(inst) ||
|
||||
TranslatePackedFloat16(inst) || TranslateFloat16Operation(inst) ||
|
||||
TranslateFloatOperation(inst) || TranslateU64MaskOperation(inst) ||
|
||||
TranslateSimpleInteger(inst) || TranslateComposedInteger(inst) ||
|
||||
TranslateExtendedInteger(inst);
|
||||
if (!translated && error != nullptr) {
|
||||
*error = "decoded opcode has no IR translation";
|
||||
}
|
||||
return translated;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
@@ -3,36 +3,39 @@
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
bool Translator::TranslatePackedFloat16(const IR::Instruction& inst) {
|
||||
bool Translator::TranslatePackedFloat16(const Decoder::Instruction& inst) {
|
||||
IR::ValueOpcode opcode;
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::PackedAddF16: opcode = IR::ValueOpcode::FPAdd32; break;
|
||||
case IR::Opcode::PackedMulF16: opcode = IR::ValueOpcode::FPMul32; break;
|
||||
case IR::Opcode::PackedMinF16: opcode = IR::ValueOpcode::FPMin32; break;
|
||||
case IR::Opcode::PackedMaxF16: opcode = IR::ValueOpcode::FPMax32; break;
|
||||
case IR::Opcode::PackedFmaF16: opcode = IR::ValueOpcode::FPFma32; break;
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_PK_ADD_F16: opcode = IR::ValueOpcode::FPAdd32; break;
|
||||
case Decoder::Opcode::V_PK_MUL_F16: opcode = IR::ValueOpcode::FPMul32; break;
|
||||
case Decoder::Opcode::V_PK_MIN_F16: opcode = IR::ValueOpcode::FPMin32; break;
|
||||
case Decoder::Opcode::V_PK_MAX_F16: opcode = IR::ValueOpcode::FPMax32; break;
|
||||
case Decoder::Opcode::V_PK_FMA_F16: opcode = IR::ValueOpcode::FPFma32; break;
|
||||
case Decoder::Opcode::V_PK_FMAC_F16: opcode = IR::ValueOpcode::FPFma32; break;
|
||||
default: return false;
|
||||
}
|
||||
const auto translate_lane = [&](bool high) {
|
||||
const auto lhs = ReadF16LaneAsF32(inst.src[0], high, true);
|
||||
const auto rhs = ReadF16LaneAsF32(inst.src[1], high, true);
|
||||
const auto lhs = ReadF16LaneAsF32(inst.src0, high, true);
|
||||
const auto rhs = ReadF16LaneAsF32(inst.src1, high, true);
|
||||
IR::F32 result;
|
||||
if (inst.src_count == 3u) {
|
||||
result = IR::F32(
|
||||
ir.Emit(opcode, {lhs, rhs, ReadF16LaneAsF32(inst.src[2], high, true)}));
|
||||
if (inst.opcode == Decoder::Opcode::V_PK_FMAC_F16) {
|
||||
result = IR::F32(ir.Emit(opcode, {lhs, rhs, ReadF16LaneAsF32(inst.dst, high, true)}));
|
||||
} else if (inst.src_count == 3u) {
|
||||
result = IR::F32(ir.Emit(opcode, {lhs, rhs, ReadF16LaneAsF32(inst.src2, high, true)}));
|
||||
} else {
|
||||
result = IR::F32(ir.Emit(opcode, {lhs, rhs}));
|
||||
}
|
||||
return ApplyF32ResultModifiers(inst.dst, result);
|
||||
};
|
||||
auto raw = inst.dst;
|
||||
auto raw = DestinationOperand(inst);
|
||||
raw.omod = 0u;
|
||||
raw.clamp = false;
|
||||
auto result = PackHalf2x16(translate_lane(false), translate_lane(true));
|
||||
if (inst.op == IR::Opcode::PackedMinF16 || inst.op == IR::Opcode::PackedMaxF16) {
|
||||
const auto quiet_snan = [&](const IR::Operand& operand, bool high) {
|
||||
if (inst.opcode == Decoder::Opcode::V_PK_MIN_F16 ||
|
||||
inst.opcode == Decoder::Opcode::V_PK_MAX_F16) {
|
||||
const auto quiet_snan = [&](const Decoder::Operand& operand, bool high) {
|
||||
const auto bits = ReadU16LaneAsU32(operand, high, false);
|
||||
const auto exponent = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x7c00u)));
|
||||
const auto payload = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x01ffu)));
|
||||
@@ -41,8 +44,8 @@ bool Translator::TranslatePackedFloat16(const IR::Instruction& inst) {
|
||||
return std::pair {snan, ir.BitwiseOr(bits, IR::U32(IR::Value(0x0200u)))};
|
||||
};
|
||||
const auto override_lane = [&](bool high) {
|
||||
const auto [lhs_snan, lhs_quiet] = quiet_snan(inst.src[0], high);
|
||||
const auto [rhs_snan, rhs_quiet] = quiet_snan(inst.src[1], high);
|
||||
const auto [lhs_snan, lhs_quiet] = quiet_snan(inst.src0, high);
|
||||
const auto [rhs_snan, rhs_quiet] = quiet_snan(inst.src1, high);
|
||||
const auto normal = high ? ir.ShiftRightLogical(result, IR::U32(IR::Value(16u)))
|
||||
: ir.BitwiseAnd(result, IR::U32(IR::Value(0xffffu)));
|
||||
return ir.Select(lhs_snan, lhs_quiet, ir.Select(rhs_snan, rhs_quiet, normal));
|
||||
@@ -53,59 +56,71 @@ bool Translator::TranslatePackedFloat16(const IR::Instruction& inst) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateFloat16Operation(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateFloat16Operation(const Decoder::Instruction& inst) {
|
||||
IR::ValueOpcode opcode;
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::AddF16: opcode = IR::ValueOpcode::FPAdd32; break;
|
||||
case IR::Opcode::SubF16: opcode = IR::ValueOpcode::FPSub32; break;
|
||||
case IR::Opcode::MulF16: opcode = IR::ValueOpcode::FPMul32; break;
|
||||
case IR::Opcode::MinF16: opcode = IR::ValueOpcode::FPMin32; break;
|
||||
case IR::Opcode::MaxF16: opcode = IR::ValueOpcode::FPMax32; break;
|
||||
case IR::Opcode::FmaF16:
|
||||
case IR::Opcode::MadMixF16: opcode = IR::ValueOpcode::FPFma32; break;
|
||||
case IR::Opcode::RcpF16: opcode = IR::ValueOpcode::FPRecip32; break;
|
||||
case IR::Opcode::SqrtF16: opcode = IR::ValueOpcode::FPSqrt; break;
|
||||
case IR::Opcode::InverseSqrtF16: opcode = IR::ValueOpcode::FPRecipSqrt32; break;
|
||||
case IR::Opcode::Log2F16: opcode = IR::ValueOpcode::FPLog2; break;
|
||||
case IR::Opcode::Exp2F16: opcode = IR::ValueOpcode::FPExp2; break;
|
||||
case IR::Opcode::FloorF16: opcode = IR::ValueOpcode::FPFloor32; break;
|
||||
case IR::Opcode::CeilF16: opcode = IR::ValueOpcode::FPCeil32; break;
|
||||
case IR::Opcode::TruncF16: opcode = IR::ValueOpcode::FPTrunc32; break;
|
||||
case IR::Opcode::RoundEvenF16: opcode = IR::ValueOpcode::FPRoundEven32; break;
|
||||
case IR::Opcode::Min3F16: opcode = IR::ValueOpcode::FPMinTri32; break;
|
||||
case IR::Opcode::Max3F16: opcode = IR::ValueOpcode::FPMaxTri32; break;
|
||||
case IR::Opcode::Med3F16: opcode = IR::ValueOpcode::FPMedTri32; break;
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_ADD_F16: opcode = IR::ValueOpcode::FPAdd32; break;
|
||||
case Decoder::Opcode::V_SUB_F16: opcode = IR::ValueOpcode::FPSub32; break;
|
||||
case Decoder::Opcode::V_SUBREV_F16: opcode = IR::ValueOpcode::FPSub32; break;
|
||||
case Decoder::Opcode::V_MUL_F16: opcode = IR::ValueOpcode::FPMul32; break;
|
||||
case Decoder::Opcode::V_MIN_F16: opcode = IR::ValueOpcode::FPMin32; break;
|
||||
case Decoder::Opcode::V_MAX_F16: opcode = IR::ValueOpcode::FPMax32; break;
|
||||
case Decoder::Opcode::V_FMAC_F16:
|
||||
case Decoder::Opcode::V_FMAMK_F16:
|
||||
case Decoder::Opcode::V_FMAAK_F16:
|
||||
case Decoder::Opcode::V_FMA_F16:
|
||||
case Decoder::Opcode::V_MAD_MIXLO_F16: opcode = IR::ValueOpcode::FPFma32; break;
|
||||
case Decoder::Opcode::V_MAD_MIXHI_F16: opcode = IR::ValueOpcode::FPFma32; break;
|
||||
case Decoder::Opcode::V_RCP_F16: opcode = IR::ValueOpcode::FPRecip32; break;
|
||||
case Decoder::Opcode::V_SQRT_F16: opcode = IR::ValueOpcode::FPSqrt; break;
|
||||
case Decoder::Opcode::V_RSQ_F16: opcode = IR::ValueOpcode::FPRecipSqrt32; break;
|
||||
case Decoder::Opcode::V_LOG_F16: opcode = IR::ValueOpcode::FPLog2; break;
|
||||
case Decoder::Opcode::V_EXP_F16: opcode = IR::ValueOpcode::FPExp2; break;
|
||||
case Decoder::Opcode::V_FLOOR_F16: opcode = IR::ValueOpcode::FPFloor32; break;
|
||||
case Decoder::Opcode::V_CEIL_F16: opcode = IR::ValueOpcode::FPCeil32; break;
|
||||
case Decoder::Opcode::V_TRUNC_F16: opcode = IR::ValueOpcode::FPTrunc32; break;
|
||||
case Decoder::Opcode::V_RNDNE_F16: opcode = IR::ValueOpcode::FPRoundEven32; break;
|
||||
case Decoder::Opcode::V_MIN3_F16: opcode = IR::ValueOpcode::FPMinTri32; break;
|
||||
case Decoder::Opcode::V_MAX3_F16: opcode = IR::ValueOpcode::FPMaxTri32; break;
|
||||
case Decoder::Opcode::V_MED3_F16: opcode = IR::ValueOpcode::FPMedTri32; break;
|
||||
default: return false;
|
||||
}
|
||||
const bool accumulator = inst.opcode == Decoder::Opcode::V_FMAC_F16;
|
||||
const uint32_t source_count = accumulator ? 3u : inst.src_count;
|
||||
std::array<IR::Value, 3> args;
|
||||
for (uint32_t index = 0; index < inst.src_count; index++) {
|
||||
args[index] = inst.op == IR::Opcode::MadMixF16 ? IR::Value(ReadMixF32(inst.src[index]))
|
||||
: IR::Value(ReadF16AsF32(inst.src[index]));
|
||||
for (uint32_t index = 0; index < source_count; index++) {
|
||||
auto operand = accumulator && index == 2u ? inst.dst : SourceAt(inst, index);
|
||||
if (inst.opcode == Decoder::Opcode::V_SUBREV_F16 && index < 2u) {
|
||||
operand = SourceAt(inst, 1u - index);
|
||||
}
|
||||
const bool mix = inst.opcode == Decoder::Opcode::V_MAD_MIXLO_F16 ||
|
||||
inst.opcode == Decoder::Opcode::V_MAD_MIXHI_F16;
|
||||
args[index] = mix ? IR::Value(ReadMixF32(operand)) : IR::Value(ReadF16AsF32(operand));
|
||||
}
|
||||
IR::F32 result;
|
||||
switch (inst.src_count) {
|
||||
switch (source_count) {
|
||||
case 1: result = IR::F32(ir.Emit(opcode, {args[0]})); break;
|
||||
case 2: result = IR::F32(ir.Emit(opcode, {args[0], args[1]})); break;
|
||||
case 3: result = IR::F32(ir.Emit(opcode, {args[0], args[1], args[2]})); break;
|
||||
default: EXIT("invalid half-float source count: %u", inst.src_count);
|
||||
}
|
||||
if (inst.op == IR::Opcode::SqrtF16 || inst.op == IR::Opcode::InverseSqrtF16 ||
|
||||
inst.op == IR::Opcode::Log2F16) {
|
||||
const auto negative = IR::U1(
|
||||
ir.Emit(IR::ValueOpcode::FPOrdLessThan32, {args[0], IR::Value::F32(0.0f)}));
|
||||
result = ApplyF32ResultModifiers(inst.dst, result);
|
||||
const auto bits = PackHalf2x16(result, IR::F32(IR::Value::F32(0.0f)));
|
||||
if (inst.opcode == Decoder::Opcode::V_SQRT_F16 || inst.opcode == Decoder::Opcode::V_RSQ_F16 ||
|
||||
inst.opcode == Decoder::Opcode::V_LOG_F16) {
|
||||
const auto negative =
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::FPOrdLessThan32, {args[0], IR::Value::F32(0.0f)}));
|
||||
result = ApplyF32ResultModifiers(inst.dst, result);
|
||||
const auto bits = PackHalf2x16(result, IR::F32(IR::Value::F32(0.0f)));
|
||||
const auto invalid = IR::U32(IR::Value(inst.dst.clamp ? 0u : 0xfe00u));
|
||||
WriteU16(inst.dst, ir.Select(negative, invalid, bits));
|
||||
WriteU16(DestinationOperand(inst), ir.Select(negative, invalid, bits));
|
||||
return true;
|
||||
}
|
||||
WriteF16(inst.dst, result);
|
||||
WriteF16(DestinationOperand(inst), result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateFloatOperation(const IR::Instruction& inst) {
|
||||
if (inst.op == IR::Opcode::FrexpMantF32) {
|
||||
const auto bits = ReadU32(inst.src[0]);
|
||||
bool Translator::TranslateFloatOperation(const Decoder::Instruction& inst) {
|
||||
if (inst.opcode == Decoder::Opcode::V_FREXP_MANT_F32) {
|
||||
const auto bits = ReadU32(inst.src0);
|
||||
const auto exponent = IR::U32(
|
||||
ir.Emit(IR::ValueOpcode::BitFieldUExtract, {bits, IR::Value(23u), IR::Value(8u)}));
|
||||
const auto mantissa = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x007fffffu)));
|
||||
@@ -121,84 +136,99 @@ bool Translator::TranslateFloatOperation(const IR::Instruction& inst) {
|
||||
const auto finite = ir.Select(ir.INotEqual(exponent, IR::U32(IR::Value(0u))), normal,
|
||||
ir.Select(zero, bits, subnormal));
|
||||
const auto result = ir.Select(ir.IEqual(exponent, IR::U32(IR::Value(0xffu))), bits, finite);
|
||||
WriteOperand(inst.dst, ir.BitCastF32(result));
|
||||
WriteOperand(DestinationOperand(inst), ir.BitCastF32(result));
|
||||
return true;
|
||||
}
|
||||
IR::ValueOpcode opcode {};
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::RcpF32: opcode = IR::ValueOpcode::FPRecip32; break;
|
||||
case IR::Opcode::RcpIflagF32: opcode = IR::ValueOpcode::FPRecipIFlag32; break;
|
||||
case IR::Opcode::FractF32: opcode = IR::ValueOpcode::FPFract32; break;
|
||||
case IR::Opcode::TruncF32: opcode = IR::ValueOpcode::FPTrunc32; break;
|
||||
case IR::Opcode::CeilF32: opcode = IR::ValueOpcode::FPCeil32; break;
|
||||
case IR::Opcode::RoundEvenF32: opcode = IR::ValueOpcode::FPRoundEven32; break;
|
||||
case IR::Opcode::FloorF32: opcode = IR::ValueOpcode::FPFloor32; break;
|
||||
case IR::Opcode::Exp2F32: opcode = IR::ValueOpcode::FPExp2; break;
|
||||
case IR::Opcode::Log2F32: opcode = IR::ValueOpcode::FPLog2; break;
|
||||
case IR::Opcode::InverseSqrtF32: opcode = IR::ValueOpcode::FPRecipSqrt32; break;
|
||||
case IR::Opcode::SqrtF32: opcode = IR::ValueOpcode::FPSqrt; break;
|
||||
case IR::Opcode::SinF32: opcode = IR::ValueOpcode::FPSin; break;
|
||||
case IR::Opcode::CosF32: opcode = IR::ValueOpcode::FPCos; break;
|
||||
case IR::Opcode::FAddF32: opcode = IR::ValueOpcode::FPAdd32; break;
|
||||
case IR::Opcode::FSubF32: opcode = IR::ValueOpcode::FPSub32; break;
|
||||
case IR::Opcode::FMulF32: opcode = IR::ValueOpcode::FPMul32; break;
|
||||
case IR::Opcode::FMinF32: opcode = IR::ValueOpcode::FPMin32; break;
|
||||
case IR::Opcode::FMaxF32: opcode = IR::ValueOpcode::FPMax32; break;
|
||||
case IR::Opcode::FMadF32: opcode = IR::ValueOpcode::FPFma32; break;
|
||||
case IR::Opcode::FMin3F32: opcode = IR::ValueOpcode::FPMinTri32; break;
|
||||
case IR::Opcode::FMax3F32: opcode = IR::ValueOpcode::FPMaxTri32; break;
|
||||
case IR::Opcode::FMed3F32: opcode = IR::ValueOpcode::FPMedTri32; break;
|
||||
case IR::Opcode::LdexpF32: opcode = IR::ValueOpcode::FPLdexp; break;
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_RCP_F32: opcode = IR::ValueOpcode::FPRecip32; break;
|
||||
case Decoder::Opcode::V_RCP_IFLAG_F32: opcode = IR::ValueOpcode::FPRecipIFlag32; break;
|
||||
case Decoder::Opcode::V_FRACT_F32: opcode = IR::ValueOpcode::FPFract32; break;
|
||||
case Decoder::Opcode::V_TRUNC_F32: opcode = IR::ValueOpcode::FPTrunc32; break;
|
||||
case Decoder::Opcode::V_CEIL_F32: opcode = IR::ValueOpcode::FPCeil32; break;
|
||||
case Decoder::Opcode::V_RNDNE_F32: opcode = IR::ValueOpcode::FPRoundEven32; break;
|
||||
case Decoder::Opcode::V_FLOOR_F32: opcode = IR::ValueOpcode::FPFloor32; break;
|
||||
case Decoder::Opcode::V_EXP_F32: opcode = IR::ValueOpcode::FPExp2; break;
|
||||
case Decoder::Opcode::V_LOG_F32: opcode = IR::ValueOpcode::FPLog2; break;
|
||||
case Decoder::Opcode::V_RSQ_F32: opcode = IR::ValueOpcode::FPRecipSqrt32; break;
|
||||
case Decoder::Opcode::V_SQRT_F32: opcode = IR::ValueOpcode::FPSqrt; break;
|
||||
case Decoder::Opcode::V_SIN_F32: opcode = IR::ValueOpcode::FPSin; break;
|
||||
case Decoder::Opcode::V_COS_F32: opcode = IR::ValueOpcode::FPCos; break;
|
||||
case Decoder::Opcode::V_ADD_F32: opcode = IR::ValueOpcode::FPAdd32; break;
|
||||
case Decoder::Opcode::V_SUB_F32: opcode = IR::ValueOpcode::FPSub32; break;
|
||||
case Decoder::Opcode::V_SUBREV_F32: opcode = IR::ValueOpcode::FPSub32; break;
|
||||
case Decoder::Opcode::V_MUL_F32: opcode = IR::ValueOpcode::FPMul32; break;
|
||||
case Decoder::Opcode::V_MIN_F32: opcode = IR::ValueOpcode::FPMin32; break;
|
||||
case Decoder::Opcode::V_MAX_F32: opcode = IR::ValueOpcode::FPMax32; break;
|
||||
case Decoder::Opcode::V_MAC_F32: opcode = IR::ValueOpcode::FPFma32; break;
|
||||
case Decoder::Opcode::V_MADMK_F32:
|
||||
case Decoder::Opcode::V_MADAK_F32:
|
||||
case Decoder::Opcode::V_MAD_F32:
|
||||
case Decoder::Opcode::V_FMA_F32: opcode = IR::ValueOpcode::FPFma32; break;
|
||||
case Decoder::Opcode::V_MIN3_F32: opcode = IR::ValueOpcode::FPMinTri32; break;
|
||||
case Decoder::Opcode::V_MAX3_F32: opcode = IR::ValueOpcode::FPMaxTri32; break;
|
||||
case Decoder::Opcode::V_MED3_F32: opcode = IR::ValueOpcode::FPMedTri32; break;
|
||||
case Decoder::Opcode::V_LDEXP_F32: opcode = IR::ValueOpcode::FPLdexp; break;
|
||||
default: break;
|
||||
}
|
||||
if (opcode != IR::ValueOpcode {}) {
|
||||
const bool accumulator = inst.opcode == Decoder::Opcode::V_MAC_F32;
|
||||
const bool fused = accumulator || inst.opcode == Decoder::Opcode::V_MADMK_F32 ||
|
||||
inst.opcode == Decoder::Opcode::V_MADAK_F32 ||
|
||||
inst.opcode == Decoder::Opcode::V_MAD_F32 ||
|
||||
inst.opcode == Decoder::Opcode::V_FMA_F32;
|
||||
const uint32_t source_count = accumulator ? 3u : inst.src_count;
|
||||
std::array<IR::Value, 3> args;
|
||||
for (uint32_t index = 0; index < inst.src_count; index++) {
|
||||
for (uint32_t index = 0; index < source_count; index++) {
|
||||
const auto arg_type = IR::ArgTypeOf(opcode, index);
|
||||
args[index] =
|
||||
arg_type == IR::Type::F32
|
||||
? (inst.op == IR::Opcode::FMadF32 ? IR::Value(ReadMixF32(inst.src[index]))
|
||||
: ReadOperand(inst.src[index], IR::Type::F32))
|
||||
: ReadOperand(inst.src[index], arg_type);
|
||||
auto operand = accumulator && index == 2u ? inst.dst : SourceAt(inst, index);
|
||||
if (inst.opcode == Decoder::Opcode::V_SUBREV_F32 && index < 2u) {
|
||||
operand = SourceAt(inst, 1u - index);
|
||||
}
|
||||
args[index] = arg_type == IR::Type::F32 ? (fused ? IR::Value(ReadMixF32(operand))
|
||||
: ReadOperand(operand, IR::Type::F32))
|
||||
: ReadOperand(operand, arg_type);
|
||||
}
|
||||
IR::Value result;
|
||||
switch (inst.src_count) {
|
||||
switch (source_count) {
|
||||
case 1: result = ir.Emit(opcode, {args[0]}); break;
|
||||
case 2: result = ir.Emit(opcode, {args[0], args[1]}); break;
|
||||
case 3: result = ir.Emit(opcode, {args[0], args[1], args[2]}); break;
|
||||
default: EXIT("invalid floating-point source count: %u", inst.src_count);
|
||||
}
|
||||
WriteOperand(inst.dst, result);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
return true;
|
||||
}
|
||||
|
||||
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}));
|
||||
};
|
||||
if (inst.op == IR::Opcode::Dot2AccF32F16) {
|
||||
auto a = inst.src[0];
|
||||
if (inst.opcode == Decoder::Opcode::V_DOT2C_F32_F16) {
|
||||
auto a = inst.src0;
|
||||
a.op_sel = false;
|
||||
a.op_sel_hi = true;
|
||||
auto b = inst.src[1];
|
||||
auto b = inst.src1;
|
||||
b.op_sel = false;
|
||||
b.op_sel_hi = true;
|
||||
const auto a_lo = ReadF16LaneAsF32(a, false);
|
||||
const auto a_hi = ReadF16LaneAsF32(a, true);
|
||||
const auto b_lo = ReadF16LaneAsF32(b, false);
|
||||
const auto b_hi = ReadF16LaneAsF32(b, true);
|
||||
const auto acc = ReadMixF32(inst.src[2]);
|
||||
const auto acc = ReadMixF32(inst.dst);
|
||||
const auto lo = IR::F32(ir.Emit(IR::ValueOpcode::FPFma32, {a_lo, b_lo, acc}));
|
||||
WriteOperand(inst.dst, ir.Emit(IR::ValueOpcode::FPFma32, {a_hi, b_hi, lo}));
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(IR::ValueOpcode::FPFma32, {a_hi, b_hi, lo}));
|
||||
return true;
|
||||
}
|
||||
if (inst.op != IR::Opcode::CubeIdF32 && inst.op != IR::Opcode::CubeScF32 &&
|
||||
inst.op != IR::Opcode::CubeTcF32 && inst.op != IR::Opcode::CubeMaF32) {
|
||||
if (inst.opcode != Decoder::Opcode::V_CUBEID_F32 &&
|
||||
inst.opcode != Decoder::Opcode::V_CUBESC_F32 &&
|
||||
inst.opcode != Decoder::Opcode::V_CUBETC_F32 &&
|
||||
inst.opcode != Decoder::Opcode::V_CUBEMA_F32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto x = ReadMixF32(inst.src[0]);
|
||||
const auto y = ReadMixF32(inst.src[1]);
|
||||
const auto z = ReadMixF32(inst.src[2]);
|
||||
const auto x = ReadMixF32(inst.src0);
|
||||
const auto y = ReadMixF32(inst.src1);
|
||||
const auto z = ReadMixF32(inst.src2);
|
||||
const auto nx = IR::F32(ir.Emit(IR::ValueOpcode::FPNeg32, {x}));
|
||||
const auto ny = IR::F32(ir.Emit(IR::ValueOpcode::FPNeg32, {y}));
|
||||
const auto nz = IR::F32(ir.Emit(IR::ValueOpcode::FPNeg32, {z}));
|
||||
@@ -216,18 +246,20 @@ bool Translator::TranslateFloatOperation(const IR::Instruction& inst) {
|
||||
return select_f32(z_face, z_value, select_f32(y_face, y_value, x_value));
|
||||
};
|
||||
IR::F32 result;
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::CubeIdF32:
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_CUBEID_F32:
|
||||
result = select_face(
|
||||
select_f32(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))),
|
||||
select_f32(z_neg, IR::F32(IR::Value::F32(5.0f)), IR::F32(IR::Value::F32(4.0f))));
|
||||
break;
|
||||
case IR::Opcode::CubeScF32:
|
||||
case Decoder::Opcode::V_CUBESC_F32:
|
||||
result = select_face(select_f32(x_neg, z, nz), x, select_f32(z_neg, nx, x));
|
||||
break;
|
||||
case IR::Opcode::CubeTcF32: result = select_face(ny, select_f32(y_neg, nz, z), ny); break;
|
||||
case IR::Opcode::CubeMaF32: {
|
||||
case Decoder::Opcode::V_CUBETC_F32:
|
||||
result = select_face(ny, select_f32(y_neg, nz, z), ny);
|
||||
break;
|
||||
case Decoder::Opcode::V_CUBEMA_F32: {
|
||||
const auto two = IR::F32(IR::Value::F32(2.0f));
|
||||
result = select_face(IR::F32(ir.Emit(IR::ValueOpcode::FPMul32, {x, two})),
|
||||
IR::F32(ir.Emit(IR::ValueOpcode::FPMul32, {y, two})),
|
||||
@@ -236,8 +268,8 @@ bool Translator::TranslateFloatOperation(const IR::Instruction& inst) {
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
WriteOperand(inst.dst, result);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
@@ -2,22 +2,22 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
bool Translator::TranslateInteger16Operation(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateInteger16Operation(const Decoder::Instruction& inst) {
|
||||
const auto mask16 = [&](IR::U32 value) {
|
||||
return ir.BitwiseAnd(value, IR::U32(IR::Value(0xffffu)));
|
||||
};
|
||||
IR::Value result;
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::ShiftLeftLogicalU16:
|
||||
case IR::Opcode::ShiftRightLogicalU16:
|
||||
case IR::Opcode::ShiftRightArithmeticI16: {
|
||||
const bool arithmetic = inst.op == IR::Opcode::ShiftRightArithmeticI16;
|
||||
const auto value = ReadU16AsU32(inst.src[0], arithmetic);
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_LSHLREV_B16:
|
||||
case Decoder::Opcode::V_LSHRREV_B16:
|
||||
case Decoder::Opcode::V_ASHRREV_I16: {
|
||||
const bool arithmetic = inst.opcode == Decoder::Opcode::V_ASHRREV_I16;
|
||||
const auto value = ReadU16AsU32(inst.src1, arithmetic);
|
||||
const auto count =
|
||||
ir.BitwiseAnd(ReadU16AsU32(inst.src[1], false), IR::U32(IR::Value(15u)));
|
||||
if (inst.op == IR::Opcode::ShiftLeftLogicalU16) {
|
||||
ir.BitwiseAnd(ReadU16AsU32(inst.src0, false), IR::U32(IR::Value(15u)));
|
||||
if (inst.opcode == Decoder::Opcode::V_LSHLREV_B16) {
|
||||
result = ir.ShiftLeftLogical(value, count);
|
||||
} else if (arithmetic) {
|
||||
result = ir.ShiftRightArithmetic(value, count);
|
||||
@@ -26,176 +26,207 @@ bool Translator::TranslateInteger16Operation(const IR::Instruction& inst) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::IAddU16:
|
||||
result = ir.IAdd(ReadU16AsU32(inst.src[0], false), ReadU16AsU32(inst.src[1], false));
|
||||
case Decoder::Opcode::V_ADD_NC_U16:
|
||||
case Decoder::Opcode::V_ADD_NC_I16:
|
||||
result = ir.IAdd(ReadU16AsU32(inst.src0, false), ReadU16AsU32(inst.src1, false));
|
||||
break;
|
||||
case IR::Opcode::ISubI16:
|
||||
result = ir.ISub(ReadU16AsU32(inst.src[0], false), ReadU16AsU32(inst.src[1], false));
|
||||
case Decoder::Opcode::V_SUB_NC_U16:
|
||||
case Decoder::Opcode::V_SUB_NC_I16:
|
||||
result = ir.ISub(ReadU16AsU32(inst.src0, false), ReadU16AsU32(inst.src1, false));
|
||||
break;
|
||||
case IR::Opcode::IMed3I16:
|
||||
case Decoder::Opcode::V_MED3_I16:
|
||||
result = ir.Emit(IR::ValueOpcode::SMedTri32,
|
||||
{ReadU16AsU32(inst.src[0], true), ReadU16AsU32(inst.src[1], true),
|
||||
ReadU16AsU32(inst.src[2], true)});
|
||||
{ReadU16AsU32(inst.src0, true), ReadU16AsU32(inst.src1, true),
|
||||
ReadU16AsU32(inst.src2, true)});
|
||||
break;
|
||||
case IR::Opcode::IMinI16:
|
||||
case IR::Opcode::IMaxI16:
|
||||
case IR::Opcode::UMinU16:
|
||||
case IR::Opcode::UMaxU16: {
|
||||
const bool sign = inst.op == IR::Opcode::IMinI16 || inst.op == IR::Opcode::IMaxI16;
|
||||
case Decoder::Opcode::V_MIN_I16:
|
||||
case Decoder::Opcode::V_MAX_I16:
|
||||
case Decoder::Opcode::V_MIN_U16:
|
||||
case Decoder::Opcode::V_MAX_U16: {
|
||||
const bool sign = inst.opcode == Decoder::Opcode::V_MIN_I16 ||
|
||||
inst.opcode == Decoder::Opcode::V_MAX_I16;
|
||||
IR::ValueOpcode opcode;
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::IMinI16: opcode = IR::ValueOpcode::SMin32; break;
|
||||
case IR::Opcode::IMaxI16: opcode = IR::ValueOpcode::SMax32; break;
|
||||
case IR::Opcode::UMinU16: opcode = IR::ValueOpcode::UMin32; break;
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_MIN_I16: opcode = IR::ValueOpcode::SMin32; break;
|
||||
case Decoder::Opcode::V_MAX_I16: opcode = IR::ValueOpcode::SMax32; break;
|
||||
case Decoder::Opcode::V_MIN_U16: opcode = IR::ValueOpcode::UMin32; break;
|
||||
default: opcode = IR::ValueOpcode::UMax32; break;
|
||||
}
|
||||
result =
|
||||
ir.Emit(opcode, {ReadU16AsU32(inst.src[0], sign), ReadU16AsU32(inst.src[1], sign)});
|
||||
ir.Emit(opcode, {ReadU16AsU32(inst.src0, sign), ReadU16AsU32(inst.src1, sign)});
|
||||
break;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
WriteU16(inst.dst, mask16(IR::U32(result)));
|
||||
WriteU16(DestinationOperand(inst), mask16(IR::U32(result)));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslatePackedInteger16(const IR::Instruction& inst) {
|
||||
const auto lane = [&](const IR::Operand& operand, bool high, bool sign) {
|
||||
bool Translator::TranslatePackedInteger16(const Decoder::Instruction& inst) {
|
||||
const auto lane = [&](const Decoder::Operand& operand, bool high, bool sign) {
|
||||
return ReadU16LaneAsU32(operand, high, sign);
|
||||
};
|
||||
const auto mask_count = [&](IR::U32 value) {
|
||||
return ir.BitwiseAnd(value, IR::U32(IR::Value(15u)));
|
||||
};
|
||||
const auto translate_lane = [&](bool high) -> IR::U32 {
|
||||
if (inst.op == IR::Opcode::PackedLshlrevB16 || inst.op == IR::Opcode::PackedLshrrevB16 ||
|
||||
inst.op == IR::Opcode::PackedAshrrevI16) {
|
||||
const auto count = mask_count(lane(inst.src[0], high, false));
|
||||
const bool arithmetic = inst.op == IR::Opcode::PackedAshrrevI16;
|
||||
const auto value = lane(inst.src[1], high, arithmetic);
|
||||
if (inst.op == IR::Opcode::PackedLshlrevB16) {
|
||||
if (inst.opcode == Decoder::Opcode::V_PK_LSHLREV_B16 ||
|
||||
inst.opcode == Decoder::Opcode::V_PK_LSHRREV_B16 ||
|
||||
inst.opcode == Decoder::Opcode::V_PK_ASHRREV_I16) {
|
||||
const auto count = mask_count(lane(inst.src0, high, false));
|
||||
const bool arithmetic = inst.opcode == Decoder::Opcode::V_PK_ASHRREV_I16;
|
||||
const auto value = lane(inst.src1, high, arithmetic);
|
||||
if (inst.opcode == Decoder::Opcode::V_PK_LSHLREV_B16) {
|
||||
return ir.ShiftLeftLogical(value, count);
|
||||
}
|
||||
return arithmetic ? ir.ShiftRightArithmetic(value, count)
|
||||
: ir.ShiftRightLogical(value, count);
|
||||
}
|
||||
|
||||
const bool signed_minmax =
|
||||
inst.op == IR::Opcode::PackedMaxI16 || inst.op == IR::Opcode::PackedMinI16;
|
||||
const auto lhs = lane(inst.src[0], high, signed_minmax);
|
||||
const auto rhs = lane(inst.src[1], high, signed_minmax);
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::PackedMadI16:
|
||||
case IR::Opcode::PackedMadU16:
|
||||
const bool signed_minmax = inst.opcode == Decoder::Opcode::V_PK_MAX_I16 ||
|
||||
inst.opcode == Decoder::Opcode::V_PK_MIN_I16;
|
||||
const auto lhs = lane(inst.src0, high, signed_minmax);
|
||||
const auto rhs = lane(inst.src1, high, signed_minmax);
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_PK_MAD_I16:
|
||||
case Decoder::Opcode::V_PK_MAD_U16:
|
||||
return ir.IAdd(ir.IMul(lhs, rhs),
|
||||
lane(inst.src[2], high, inst.op == IR::Opcode::PackedMadI16));
|
||||
case IR::Opcode::PackedMulLoU16: return ir.IMul(lhs, rhs);
|
||||
case IR::Opcode::PackedAddI16:
|
||||
case IR::Opcode::PackedAddU16: return ir.IAdd(lhs, rhs);
|
||||
case IR::Opcode::PackedSubI16:
|
||||
case IR::Opcode::PackedSubU16: return ir.ISub(lhs, rhs);
|
||||
case IR::Opcode::PackedMaxI16:
|
||||
lane(inst.src2, high, inst.opcode == Decoder::Opcode::V_PK_MAD_I16));
|
||||
case Decoder::Opcode::V_PK_MUL_LO_U16: return ir.IMul(lhs, rhs);
|
||||
case Decoder::Opcode::V_PK_ADD_I16:
|
||||
case Decoder::Opcode::V_PK_ADD_U16: return ir.IAdd(lhs, rhs);
|
||||
case Decoder::Opcode::V_PK_SUB_I16:
|
||||
case Decoder::Opcode::V_PK_SUB_U16: return ir.ISub(lhs, rhs);
|
||||
case Decoder::Opcode::V_PK_MAX_I16:
|
||||
return IR::U32(ir.Emit(IR::ValueOpcode::SMax32, {lhs, rhs}));
|
||||
case IR::Opcode::PackedMinI16:
|
||||
case Decoder::Opcode::V_PK_MIN_I16:
|
||||
return IR::U32(ir.Emit(IR::ValueOpcode::SMin32, {lhs, rhs}));
|
||||
case IR::Opcode::PackedMaxU16:
|
||||
case Decoder::Opcode::V_PK_MAX_U16:
|
||||
return IR::U32(ir.Emit(IR::ValueOpcode::UMax32, {lhs, rhs}));
|
||||
case IR::Opcode::PackedMinU16:
|
||||
case Decoder::Opcode::V_PK_MIN_U16:
|
||||
return IR::U32(ir.Emit(IR::ValueOpcode::UMin32, {lhs, rhs}));
|
||||
default: EXIT("invalid packed integer opcode");
|
||||
}
|
||||
};
|
||||
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::PackedMadI16:
|
||||
case IR::Opcode::PackedMulLoU16:
|
||||
case IR::Opcode::PackedAddI16:
|
||||
case IR::Opcode::PackedSubI16:
|
||||
case IR::Opcode::PackedLshlrevB16:
|
||||
case IR::Opcode::PackedLshrrevB16:
|
||||
case IR::Opcode::PackedAshrrevI16:
|
||||
case IR::Opcode::PackedMaxI16:
|
||||
case IR::Opcode::PackedMinI16:
|
||||
case IR::Opcode::PackedMadU16:
|
||||
case IR::Opcode::PackedAddU16:
|
||||
case IR::Opcode::PackedSubU16:
|
||||
case IR::Opcode::PackedMaxU16:
|
||||
case IR::Opcode::PackedMinU16:
|
||||
WriteOperand(inst.dst, PackU16Lanes(translate_lane(false), translate_lane(true)));
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_PK_MAD_I16:
|
||||
case Decoder::Opcode::V_PK_MUL_LO_U16:
|
||||
case Decoder::Opcode::V_PK_ADD_I16:
|
||||
case Decoder::Opcode::V_PK_SUB_I16:
|
||||
case Decoder::Opcode::V_PK_LSHLREV_B16:
|
||||
case Decoder::Opcode::V_PK_LSHRREV_B16:
|
||||
case Decoder::Opcode::V_PK_ASHRREV_I16:
|
||||
case Decoder::Opcode::V_PK_MAX_I16:
|
||||
case Decoder::Opcode::V_PK_MIN_I16:
|
||||
case Decoder::Opcode::V_PK_MAD_U16:
|
||||
case Decoder::Opcode::V_PK_ADD_U16:
|
||||
case Decoder::Opcode::V_PK_SUB_U16:
|
||||
case Decoder::Opcode::V_PK_MAX_U16:
|
||||
case Decoder::Opcode::V_PK_MIN_U16:
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
PackU16Lanes(translate_lane(false), translate_lane(true)));
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
IR::U1 Translator::EvaluateU64Mask(const IR::Instruction& inst) {
|
||||
const auto lhs = [&] { return ReadMask(inst.src[0]); };
|
||||
const auto rhs = [&] { return ReadMask(inst.src[1]); };
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::BitwiseAndU64: return ir.LogicalAnd(lhs(), rhs());
|
||||
case IR::Opcode::BitwiseOrU64: return ir.LogicalOr(lhs(), rhs());
|
||||
case IR::Opcode::BitwiseXorU64:
|
||||
IR::U1 Translator::EvaluateU64Mask(const Decoder::Instruction& inst) {
|
||||
const auto lhs = [&] { return ReadMask(inst.src0); };
|
||||
const auto rhs = [&] { return ReadMask(inst.src1); };
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_AND_B64: return ir.LogicalAnd(lhs(), rhs());
|
||||
case Decoder::Opcode::S_OR_B64: return ir.LogicalOr(lhs(), rhs());
|
||||
case Decoder::Opcode::S_XOR_B64:
|
||||
return IR::U1(ir.Emit(IR::ValueOpcode::LogicalXor, {lhs(), rhs()}));
|
||||
case IR::Opcode::BitwiseAndNotU64: return ir.LogicalAnd(lhs(), ir.LogicalNot(rhs()));
|
||||
case IR::Opcode::BitwiseOrNotU64: return ir.LogicalOr(lhs(), ir.LogicalNot(rhs()));
|
||||
case IR::Opcode::BitwiseNandU64: return ir.LogicalNot(ir.LogicalAnd(lhs(), rhs()));
|
||||
case IR::Opcode::BitwiseNorU64: return ir.LogicalNot(ir.LogicalOr(lhs(), rhs()));
|
||||
case IR::Opcode::BitwiseXnorU64:
|
||||
case Decoder::Opcode::S_ANDN2_B64: return ir.LogicalAnd(lhs(), ir.LogicalNot(rhs()));
|
||||
case Decoder::Opcode::S_ORN2_B64: return ir.LogicalOr(lhs(), ir.LogicalNot(rhs()));
|
||||
case Decoder::Opcode::S_NAND_B64: return ir.LogicalNot(ir.LogicalAnd(lhs(), rhs()));
|
||||
case Decoder::Opcode::S_NOR_B64: return ir.LogicalNot(ir.LogicalOr(lhs(), rhs()));
|
||||
case Decoder::Opcode::S_XNOR_B64:
|
||||
return ir.LogicalNot(IR::U1(ir.Emit(IR::ValueOpcode::LogicalXor, {lhs(), rhs()})));
|
||||
case IR::Opcode::BitwiseNotU64: return ir.LogicalNot(lhs());
|
||||
case Decoder::Opcode::S_NOT_B64: return ir.LogicalNot(lhs());
|
||||
default: EXIT("invalid 64-bit mask opcode");
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::TranslateSimpleInteger(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateSimpleInteger(const Decoder::Instruction& inst) {
|
||||
IR::ValueOpcode opcode {};
|
||||
IR::Type type = IR::Type::U32;
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::AbsI32: opcode = IR::ValueOpcode::IAbs32; break;
|
||||
case IR::Opcode::IAddU32: opcode = IR::ValueOpcode::IAdd32; break;
|
||||
case IR::Opcode::ISubU32: opcode = IR::ValueOpcode::ISub32; break;
|
||||
case IR::Opcode::IMulU32: opcode = IR::ValueOpcode::IMul32; break;
|
||||
case IR::Opcode::UMulHighU32: opcode = IR::ValueOpcode::UMulHi; break;
|
||||
case IR::Opcode::SMulHighI32: opcode = IR::ValueOpcode::SMulHi; break;
|
||||
case IR::Opcode::IMinI32: opcode = IR::ValueOpcode::SMin32; break;
|
||||
case IR::Opcode::IMaxI32: opcode = IR::ValueOpcode::SMax32; break;
|
||||
case IR::Opcode::UMinU32: opcode = IR::ValueOpcode::UMin32; break;
|
||||
case IR::Opcode::UMaxU32: opcode = IR::ValueOpcode::UMax32; break;
|
||||
case IR::Opcode::IMin3I32: opcode = IR::ValueOpcode::SMinTri32; break;
|
||||
case IR::Opcode::IMax3I32: opcode = IR::ValueOpcode::SMaxTri32; break;
|
||||
case IR::Opcode::IMed3I32: opcode = IR::ValueOpcode::SMedTri32; break;
|
||||
case IR::Opcode::UMin3U32: opcode = IR::ValueOpcode::UMinTri32; break;
|
||||
case IR::Opcode::UMax3U32: opcode = IR::ValueOpcode::UMaxTri32; break;
|
||||
case IR::Opcode::UMed3U32: opcode = IR::ValueOpcode::UMedTri32; break;
|
||||
case IR::Opcode::BitwiseAndU32: opcode = IR::ValueOpcode::BitwiseAnd32; break;
|
||||
case IR::Opcode::BitwiseOrU32: opcode = IR::ValueOpcode::BitwiseOr32; break;
|
||||
case IR::Opcode::BitwiseXorU32: opcode = IR::ValueOpcode::BitwiseXor32; break;
|
||||
case IR::Opcode::BitwiseNotU32: opcode = IR::ValueOpcode::BitwiseNot32; break;
|
||||
case IR::Opcode::BitReverseU32: opcode = IR::ValueOpcode::BitReverse32; break;
|
||||
case IR::Opcode::BitCountU32: opcode = IR::ValueOpcode::BitCount32; break;
|
||||
case IR::Opcode::BitCountU64:
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_ABS_I32: opcode = IR::ValueOpcode::IAbs32; break;
|
||||
case Decoder::Opcode::S_MUL_I32:
|
||||
case Decoder::Opcode::S_MULK_I32:
|
||||
case Decoder::Opcode::V_MUL_LO_U32:
|
||||
case Decoder::Opcode::V_MUL_LO_I32: opcode = IR::ValueOpcode::IMul32; break;
|
||||
case Decoder::Opcode::S_MUL_HI_U32:
|
||||
case Decoder::Opcode::V_MUL_HI_U32: opcode = IR::ValueOpcode::UMulHi; break;
|
||||
case Decoder::Opcode::V_MUL_HI_I32: opcode = IR::ValueOpcode::SMulHi; break;
|
||||
case Decoder::Opcode::V_ADD_NC_U32: opcode = IR::ValueOpcode::IAdd32; break;
|
||||
case Decoder::Opcode::V_SUB_NC_U32:
|
||||
case Decoder::Opcode::V_SUBREV_NC_U32: opcode = IR::ValueOpcode::ISub32; break;
|
||||
case Decoder::Opcode::V_MIN_I32: opcode = IR::ValueOpcode::SMin32; break;
|
||||
case Decoder::Opcode::V_MAX_I32: opcode = IR::ValueOpcode::SMax32; break;
|
||||
case Decoder::Opcode::V_MIN_U32: opcode = IR::ValueOpcode::UMin32; break;
|
||||
case Decoder::Opcode::V_MAX_U32: opcode = IR::ValueOpcode::UMax32; break;
|
||||
case Decoder::Opcode::V_MIN3_I32: opcode = IR::ValueOpcode::SMinTri32; break;
|
||||
case Decoder::Opcode::V_MAX3_I32: opcode = IR::ValueOpcode::SMaxTri32; break;
|
||||
case Decoder::Opcode::V_MED3_I32: opcode = IR::ValueOpcode::SMedTri32; break;
|
||||
case Decoder::Opcode::V_MIN3_U32: opcode = IR::ValueOpcode::UMinTri32; break;
|
||||
case Decoder::Opcode::V_MAX3_U32: opcode = IR::ValueOpcode::UMaxTri32; break;
|
||||
case Decoder::Opcode::V_MED3_U32: opcode = IR::ValueOpcode::UMedTri32; break;
|
||||
case Decoder::Opcode::S_AND_B32:
|
||||
case Decoder::Opcode::V_AND_B32: opcode = IR::ValueOpcode::BitwiseAnd32; break;
|
||||
case Decoder::Opcode::S_OR_B32:
|
||||
case Decoder::Opcode::V_OR_B32: opcode = IR::ValueOpcode::BitwiseOr32; break;
|
||||
case Decoder::Opcode::S_XOR_B32:
|
||||
case Decoder::Opcode::V_XOR_B32: opcode = IR::ValueOpcode::BitwiseXor32; break;
|
||||
case Decoder::Opcode::S_NOT_B32:
|
||||
case Decoder::Opcode::V_NOT_B32: opcode = IR::ValueOpcode::BitwiseNot32; break;
|
||||
case Decoder::Opcode::S_BREV_B32:
|
||||
case Decoder::Opcode::V_BFREV_B32: opcode = IR::ValueOpcode::BitReverse32; break;
|
||||
case Decoder::Opcode::S_BCNT1_I32_B32: opcode = IR::ValueOpcode::BitCount32; break;
|
||||
case Decoder::Opcode::S_BCNT1_I32_B64:
|
||||
opcode = IR::ValueOpcode::BitCount64;
|
||||
type = IR::Type::U64;
|
||||
break;
|
||||
case IR::Opcode::FindLsbU32: opcode = IR::ValueOpcode::FindILsb32; break;
|
||||
case IR::Opcode::ShiftLeftLogicalU32: opcode = IR::ValueOpcode::ShiftLeftLogical32; break;
|
||||
case IR::Opcode::ShiftRightLogicalU32: opcode = IR::ValueOpcode::ShiftRightLogical32; break;
|
||||
case IR::Opcode::ShiftRightArithmeticI32:
|
||||
case Decoder::Opcode::S_FF1_I32_B32:
|
||||
case Decoder::Opcode::V_FFBL_B32: opcode = IR::ValueOpcode::FindILsb32; break;
|
||||
case Decoder::Opcode::S_LSHL_B32:
|
||||
case Decoder::Opcode::V_LSHL_B32:
|
||||
case Decoder::Opcode::V_LSHLREV_B32: opcode = IR::ValueOpcode::ShiftLeftLogical32; break;
|
||||
case Decoder::Opcode::S_LSHR_B32:
|
||||
case Decoder::Opcode::V_LSHR_B32:
|
||||
case Decoder::Opcode::V_LSHRREV_B32: opcode = IR::ValueOpcode::ShiftRightLogical32; break;
|
||||
case Decoder::Opcode::S_ASHR_I32:
|
||||
case Decoder::Opcode::V_ASHR_I32:
|
||||
case Decoder::Opcode::V_ASHRREV_I32:
|
||||
opcode = IR::ValueOpcode::ShiftRightArithmetic32;
|
||||
break;
|
||||
case IR::Opcode::ShiftLeftLogicalU64:
|
||||
case Decoder::Opcode::S_LSHL_B64:
|
||||
case Decoder::Opcode::V_LSHLREV_B64:
|
||||
opcode = IR::ValueOpcode::ShiftLeftLogical64;
|
||||
type = IR::Type::U64;
|
||||
break;
|
||||
case IR::Opcode::ShiftRightLogicalU64:
|
||||
case Decoder::Opcode::S_LSHR_B64:
|
||||
case Decoder::Opcode::V_LSHRREV_B64:
|
||||
opcode = IR::ValueOpcode::ShiftRightLogical64;
|
||||
type = IR::Type::U64;
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
const bool reverse = inst.opcode == Decoder::Opcode::V_SUBREV_NC_U32 ||
|
||||
inst.opcode == Decoder::Opcode::V_LSHLREV_B32 ||
|
||||
inst.opcode == Decoder::Opcode::V_LSHRREV_B32 ||
|
||||
inst.opcode == Decoder::Opcode::V_ASHRREV_I32 ||
|
||||
inst.opcode == Decoder::Opcode::V_LSHLREV_B64 ||
|
||||
inst.opcode == Decoder::Opcode::V_LSHRREV_B64;
|
||||
std::array<IR::Value, 3> args;
|
||||
for (uint32_t index = 0; index < inst.src_count; index++) {
|
||||
const auto arg_type = IR::ArgTypeOf(opcode, index);
|
||||
args[index] = ReadOperand(inst.src[index], arg_type == IR::Type::Void ? type : arg_type);
|
||||
const auto operand = SourceAt(inst, reverse && index < 2u ? 1u - index : index);
|
||||
args[index] = ReadOperand(operand, arg_type == IR::Type::Void ? type : arg_type);
|
||||
if (index == 1u && (opcode == IR::ValueOpcode::ShiftLeftLogical32 ||
|
||||
opcode == IR::ValueOpcode::ShiftRightLogical32 ||
|
||||
opcode == IR::ValueOpcode::ShiftRightArithmetic32)) {
|
||||
@@ -209,56 +240,77 @@ bool Translator::TranslateSimpleInteger(const IR::Instruction& inst) {
|
||||
case 3: result = ir.Emit(opcode, {args[0], args[1], args[2]}); break;
|
||||
default: EXIT("invalid simple integer source count: %u", inst.src_count);
|
||||
}
|
||||
WriteOperand(inst.dst, result);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_ABS_I32:
|
||||
case Decoder::Opcode::S_BCNT1_I32_B32:
|
||||
case Decoder::Opcode::S_BCNT1_I32_B64:
|
||||
case Decoder::Opcode::S_AND_B32:
|
||||
case Decoder::Opcode::S_OR_B32:
|
||||
case Decoder::Opcode::S_XOR_B32:
|
||||
case Decoder::Opcode::S_NOT_B32:
|
||||
case Decoder::Opcode::S_LSHL_B32:
|
||||
case Decoder::Opcode::S_LSHR_B32:
|
||||
case Decoder::Opcode::S_ASHR_I32:
|
||||
ir.SetScc(ir.INotEqual(IR::U32(result), IR::U32(IR::Value(0u))));
|
||||
break;
|
||||
case Decoder::Opcode::S_LSHL_B64:
|
||||
case Decoder::Opcode::S_LSHR_B64:
|
||||
ir.SetScc(
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::INotEqual64, {result, IR::Value(uint64_t {0})})));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateComposedInteger(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateComposedInteger(const Decoder::Instruction& inst) {
|
||||
const auto binary_u32 = [&](auto operation) {
|
||||
const auto lhs = ReadU32(inst.src[0]);
|
||||
const auto rhs = ReadU32(inst.src[1]);
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
return operation(lhs, rhs);
|
||||
};
|
||||
|
||||
IR::Value result;
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::BitwiseAndNotU32:
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_ANDN2_B32:
|
||||
result = binary_u32(
|
||||
[&](IR::U32 lhs, IR::U32 rhs) { return ir.BitwiseAnd(lhs, ir.BitwiseNot(rhs)); });
|
||||
break;
|
||||
case IR::Opcode::BitwiseOrNotU32:
|
||||
case Decoder::Opcode::S_ORN2_B32:
|
||||
result = binary_u32(
|
||||
[&](IR::U32 lhs, IR::U32 rhs) { return ir.BitwiseOr(lhs, ir.BitwiseNot(rhs)); });
|
||||
break;
|
||||
case IR::Opcode::BitwiseNandU32:
|
||||
case Decoder::Opcode::S_NAND_B32:
|
||||
result = binary_u32(
|
||||
[&](IR::U32 lhs, IR::U32 rhs) { return ir.BitwiseNot(ir.BitwiseAnd(lhs, rhs)); });
|
||||
break;
|
||||
case IR::Opcode::BitwiseNorU32:
|
||||
case Decoder::Opcode::S_NOR_B32:
|
||||
result = binary_u32(
|
||||
[&](IR::U32 lhs, IR::U32 rhs) { return ir.BitwiseNot(ir.BitwiseOr(lhs, rhs)); });
|
||||
break;
|
||||
case IR::Opcode::BitwiseXnorU32:
|
||||
case Decoder::Opcode::S_XNOR_B32:
|
||||
case Decoder::Opcode::V_XNOR_B32:
|
||||
result = binary_u32(
|
||||
[&](IR::U32 lhs, IR::U32 rhs) { return ir.BitwiseNot(ir.BitwiseXor(lhs, rhs)); });
|
||||
break;
|
||||
case IR::Opcode::BitwiseAndOrU32: {
|
||||
const auto lhs = ReadU32(inst.src[0]);
|
||||
const auto rhs = ReadU32(inst.src[1]);
|
||||
const auto add = ReadU32(inst.src[2]);
|
||||
case Decoder::Opcode::V_AND_OR_B32: {
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
const auto add = ReadU32(inst.src2);
|
||||
result = ir.BitwiseOr(ir.BitwiseAnd(lhs, rhs), add);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitwiseOr3U32:
|
||||
result = ir.BitwiseOr(ir.BitwiseOr(ReadU32(inst.src[0]), ReadU32(inst.src[1])),
|
||||
ReadU32(inst.src[2]));
|
||||
case Decoder::Opcode::V_OR3_B32:
|
||||
result = ir.BitwiseOr(ir.BitwiseOr(ReadU32(inst.src0), ReadU32(inst.src1)),
|
||||
ReadU32(inst.src2));
|
||||
break;
|
||||
case IR::Opcode::BitwiseXor3U32:
|
||||
result = ir.BitwiseXor(ir.BitwiseXor(ReadU32(inst.src[0]), ReadU32(inst.src[1])),
|
||||
ReadU32(inst.src[2]));
|
||||
case Decoder::Opcode::V_XOR3_B32:
|
||||
result = ir.BitwiseXor(ir.BitwiseXor(ReadU32(inst.src0), ReadU32(inst.src1)),
|
||||
ReadU32(inst.src2));
|
||||
break;
|
||||
case IR::Opcode::FindLsbU64: {
|
||||
const auto source = ExtractU64(ReadU64(inst.src[0]));
|
||||
case Decoder::Opcode::S_FF1_I32_B64: {
|
||||
const auto source = ExtractU64(ReadU64(inst.src0));
|
||||
const auto low_lsb = IR::U32(ir.Emit(IR::ValueOpcode::FindILsb32, {source[0]}));
|
||||
const auto high_lsb = IR::U32(ir.Emit(IR::ValueOpcode::FindILsb32, {source[1]}));
|
||||
const auto high_position = ir.IAdd(high_lsb, IR::U32(IR::Value(32u)));
|
||||
@@ -267,16 +319,16 @@ bool Translator::TranslateComposedInteger(const IR::Instruction& inst) {
|
||||
high_position, IR::U32(IR::Value(0xffffffffu))));
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::FindMsbFromHighU32: {
|
||||
const auto source = ReadU32(inst.src[0]);
|
||||
case Decoder::Opcode::V_FFBH_U32: {
|
||||
const auto source = ReadU32(inst.src0);
|
||||
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {source}));
|
||||
const auto position = ir.ISub(IR::U32(IR::Value(31u)), msb);
|
||||
result = ir.Select(ir.INotEqual(source, IR::U32(IR::Value(0u))), position,
|
||||
IR::U32(IR::Value(0xffffffffu)));
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::FindMsbFromHighU64: {
|
||||
const auto source = ReadU64(inst.src[0]);
|
||||
case Decoder::Opcode::S_FLBIT_I32_B64: {
|
||||
const auto source = ReadU64(inst.src0);
|
||||
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb64, {source}));
|
||||
const auto position = ir.ISub(IR::U32(IR::Value(63u)), msb);
|
||||
const auto nonzero = IR::U1(
|
||||
@@ -287,11 +339,21 @@ bool Translator::TranslateComposedInteger(const IR::Instruction& inst) {
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
WriteOperand(inst.dst, result);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_ANDN2_B32:
|
||||
case Decoder::Opcode::S_ORN2_B32:
|
||||
case Decoder::Opcode::S_NAND_B32:
|
||||
case Decoder::Opcode::S_NOR_B32:
|
||||
case Decoder::Opcode::S_XNOR_B32:
|
||||
ir.SetScc(ir.INotEqual(IR::U32(result), IR::U32(IR::Value(0u))));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateExtendedInteger(const IR::Instruction& inst) {
|
||||
bool Translator::TranslateExtendedInteger(const Decoder::Instruction& inst) {
|
||||
const auto imm = [](uint32_t value) { return IR::U32(IR::Value(value)); };
|
||||
const auto mask = [&](IR::U32 value, uint32_t bits) { return ir.BitwiseAnd(value, imm(bits)); };
|
||||
const auto extract = [&](IR::U32 value, IR::U32 offset, IR::U32 width, bool sign) {
|
||||
@@ -312,26 +374,26 @@ bool Translator::TranslateExtendedInteger(const IR::Instruction& inst) {
|
||||
};
|
||||
|
||||
IR::Value result;
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::IMadI24U32:
|
||||
case IR::Opcode::UMadU24U32:
|
||||
case IR::Opcode::IMulI24U32:
|
||||
case IR::Opcode::UMulU24U32: {
|
||||
const bool sign =
|
||||
inst.op == IR::Opcode::IMadI24U32 || inst.op == IR::Opcode::IMulI24U32;
|
||||
const auto lhs = extract(ReadU32(inst.src[0]), imm(0), imm(24), sign);
|
||||
const auto rhs = extract(ReadU32(inst.src[1]), imm(0), imm(24), sign);
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_MAD_I32_I24:
|
||||
case Decoder::Opcode::V_MAD_U32_U24:
|
||||
case Decoder::Opcode::V_MUL_I32_I24:
|
||||
case Decoder::Opcode::V_MUL_U32_U24: {
|
||||
const bool sign = inst.opcode == Decoder::Opcode::V_MAD_I32_I24 ||
|
||||
inst.opcode == Decoder::Opcode::V_MUL_I32_I24;
|
||||
const auto lhs = extract(ReadU32(inst.src0), imm(0), imm(24), sign);
|
||||
const auto rhs = extract(ReadU32(inst.src1), imm(0), imm(24), sign);
|
||||
auto value = ir.IMul(lhs, rhs);
|
||||
if (inst.src_count == 3) {
|
||||
value = ir.IAdd(value, ReadU32(inst.src[2]));
|
||||
value = ir.IAdd(value, ReadU32(inst.src2));
|
||||
}
|
||||
result = value;
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::UMadU64U32: {
|
||||
const auto lhs = ReadU32(inst.src[0]);
|
||||
const auto rhs = ReadU32(inst.src[1]);
|
||||
const auto add = ExtractU64(ReadU64(inst.src[2]));
|
||||
case Decoder::Opcode::V_MAD_U64_U32: {
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
const auto add = ExtractU64(ReadU64(inst.src2));
|
||||
const auto mul_low = ir.IMul(lhs, rhs);
|
||||
const auto mul_high = IR::U32(ir.Emit(IR::ValueOpcode::UMulHi, {lhs, rhs}));
|
||||
const auto low = ir.IAdd(mul_low, add[0]);
|
||||
@@ -340,52 +402,52 @@ bool Translator::TranslateExtendedInteger(const IR::Instruction& inst) {
|
||||
const auto carry0 = ir.ULessThan(high0, mul_high);
|
||||
const auto high = ir.IAdd(high0, ir.Select(carry_low, imm(1), imm(0)));
|
||||
const auto carry1 = ir.ULessThan(high, high0);
|
||||
WriteOperand(inst.dst, ir.ConstructU64(low, high));
|
||||
if (inst.dst2.kind != IR::OperandKind::Null) {
|
||||
WriteOperand(DestinationOperand(inst), ir.ConstructU64(low, high));
|
||||
if (inst.dst2.kind != Decoder::OperandKind::Null &&
|
||||
inst.dst2.kind != Decoder::OperandKind::Unknown) {
|
||||
WriteMask(inst.dst2, ir.LogicalOr(carry0, carry1));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::SadU32: {
|
||||
const auto lhs = ReadU32(inst.src[0]);
|
||||
const auto rhs = ReadU32(inst.src[1]);
|
||||
case Decoder::Opcode::V_SAD_U32: {
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
const auto lo = IR::U32(ir.Emit(IR::ValueOpcode::UMin32, {lhs, rhs}));
|
||||
const auto hi = IR::U32(ir.Emit(IR::ValueOpcode::UMax32, {lhs, rhs}));
|
||||
result = ir.IAdd(ir.ISub(hi, lo), ReadU32(inst.src[2]));
|
||||
result = ir.IAdd(ir.ISub(hi, lo), ReadU32(inst.src2));
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::IAdd3U32:
|
||||
result =
|
||||
ir.IAdd(ir.IAdd(ReadU32(inst.src[0]), ReadU32(inst.src[1])), ReadU32(inst.src[2]));
|
||||
case Decoder::Opcode::V_ADD3_U32:
|
||||
result = ir.IAdd(ir.IAdd(ReadU32(inst.src0), ReadU32(inst.src1)), ReadU32(inst.src2));
|
||||
break;
|
||||
case IR::Opcode::BitClearU32:
|
||||
case IR::Opcode::BitSetU32: {
|
||||
const auto bit = ir.ShiftLeftLogical(imm(1), mask(ReadU32(inst.src[1]), 31u));
|
||||
result = inst.op == IR::Opcode::BitClearU32
|
||||
? IR::Value(ir.BitwiseAnd(ReadU32(inst.src[0]), ir.BitwiseNot(bit)))
|
||||
: IR::Value(ir.BitwiseOr(ReadU32(inst.src[0]), bit));
|
||||
case Decoder::Opcode::S_BITSET0_B32:
|
||||
case Decoder::Opcode::S_BITSET1_B32: {
|
||||
const auto bit = ir.ShiftLeftLogical(imm(1), mask(ReadU32(inst.src0), 31u));
|
||||
result = inst.opcode == Decoder::Opcode::S_BITSET0_B32
|
||||
? IR::Value(ir.BitwiseAnd(ReadU32(inst.dst), ir.BitwiseNot(bit)))
|
||||
: IR::Value(ir.BitwiseOr(ReadU32(inst.dst), bit));
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitCountAddU32:
|
||||
result = ir.IAdd(IR::U32(ir.Emit(IR::ValueOpcode::BitCount32, {ReadU32(inst.src[0])})),
|
||||
ReadU32(inst.src[1]));
|
||||
case Decoder::Opcode::V_BCNT_U32_B32:
|
||||
result = ir.IAdd(IR::U32(ir.Emit(IR::ValueOpcode::BitCount32, {ReadU32(inst.src0)})),
|
||||
ReadU32(inst.src1));
|
||||
break;
|
||||
case IR::Opcode::MaskedBitCountLowU32:
|
||||
case IR::Opcode::MaskedBitCountHighU32: {
|
||||
case Decoder::Opcode::V_MBCNT_LO_U32_B32:
|
||||
case Decoder::Opcode::V_MBCNT_HI_U32_B32: {
|
||||
const auto lane = IR::U32(ir.Emit(IR::ValueOpcode::LaneId));
|
||||
const auto local = mask(lane, 31u);
|
||||
const auto below = ir.ISub(ir.ShiftLeftLogical(imm(1), local), imm(1));
|
||||
const auto high_lane =
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::UGreaterThanEqual32, {lane, imm(32)}));
|
||||
const auto thread_mask = inst.op == IR::Opcode::MaskedBitCountLowU32
|
||||
const auto thread_mask = inst.opcode == Decoder::Opcode::V_MBCNT_LO_U32_B32
|
||||
? ir.Select(high_lane, imm(0xffffffffu), below)
|
||||
: ir.Select(high_lane, below, imm(0));
|
||||
const auto active = ir.BitwiseAnd(ReadU32(inst.src[0]), thread_mask);
|
||||
const auto active = ir.BitwiseAnd(ReadU32(inst.src0), thread_mask);
|
||||
result = ir.IAdd(IR::U32(ir.Emit(IR::ValueOpcode::BitCount32, {active})),
|
||||
ReadU32(inst.src[1]));
|
||||
ReadU32(inst.src1));
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitReplicateB64B32: {
|
||||
case Decoder::Opcode::S_BITREPLICATE_B64_B32: {
|
||||
const auto replicate = [&](IR::U32 value) {
|
||||
auto bits = ir.BitwiseOr(value, ir.ShiftLeftLogical(value, imm(8)));
|
||||
bits = ir.BitwiseAnd(bits, imm(0x00ff00ffu));
|
||||
@@ -397,12 +459,12 @@ bool Translator::TranslateExtendedInteger(const IR::Instruction& inst) {
|
||||
bits = ir.BitwiseAnd(bits, imm(0x55555555u));
|
||||
return ir.BitwiseOr(bits, ir.ShiftLeftLogical(bits, imm(1)));
|
||||
};
|
||||
const auto source = ReadU32(inst.src[0]);
|
||||
const auto source = ReadU32(inst.src0);
|
||||
result = ir.ConstructU64(replicate(mask(source, 0xffffu)),
|
||||
replicate(ir.ShiftRightLogical(source, imm(16))));
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::QuadmaskB64: {
|
||||
case Decoder::Opcode::S_QUADMASK_B64: {
|
||||
const auto compact = [&](IR::U32 value) {
|
||||
auto bits = ir.BitwiseOr(value, ir.ShiftRightLogical(value, imm(1)));
|
||||
bits = ir.BitwiseOr(bits, ir.ShiftRightLogical(bits, imm(2)));
|
||||
@@ -411,42 +473,43 @@ bool Translator::TranslateExtendedInteger(const IR::Instruction& inst) {
|
||||
bits = mask(ir.BitwiseOr(bits, ir.ShiftRightLogical(bits, imm(6))), 0x000f000fu);
|
||||
return mask(ir.BitwiseOr(bits, ir.ShiftRightLogical(bits, imm(12))), 0xffu);
|
||||
};
|
||||
const auto source = ReadU32Pair(inst.src[0]);
|
||||
const auto source = ReadU32Pair(inst.src0);
|
||||
const auto quads =
|
||||
ir.BitwiseOr(compact(source[0]), ir.ShiftLeftLogical(compact(source[1]), imm(8)));
|
||||
result = ir.ConstructU64(quads, imm(0));
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitFieldMaskU32: {
|
||||
const auto count = mask(ReadU32(inst.src[0]), 31u);
|
||||
const auto offset = mask(ReadU32(inst.src[1]), 31u);
|
||||
case Decoder::Opcode::S_BFM_B32:
|
||||
case Decoder::Opcode::V_BFM_B32: {
|
||||
const auto count = mask(ReadU32(inst.src0), 31u);
|
||||
const auto offset = mask(ReadU32(inst.src1), 31u);
|
||||
result =
|
||||
ir.Emit(IR::ValueOpcode::BitFieldInsert, {imm(0), imm(0xffffffffu), offset, count});
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitFieldMaskU64: {
|
||||
const auto count = mask(ReadU32(inst.src[0]), 63u);
|
||||
const auto offset = mask(ReadU32(inst.src[1]), 63u);
|
||||
case Decoder::Opcode::S_BFM_B64: {
|
||||
const auto count = mask(ReadU32(inst.src0), 63u);
|
||||
const auto offset = mask(ReadU32(inst.src1), 63u);
|
||||
result = ir.Emit(IR::ValueOpcode::ShiftLeftLogical64, {right_mask64(count), offset});
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitFieldExtractU32:
|
||||
case IR::Opcode::BitFieldExtractI32: {
|
||||
const auto source = ReadU32(inst.src[0]);
|
||||
const auto field = ReadU32(inst.src[1]);
|
||||
case Decoder::Opcode::S_BFE_U32:
|
||||
case Decoder::Opcode::S_BFE_I32: {
|
||||
const auto source = ReadU32(inst.src0);
|
||||
const auto field = ReadU32(inst.src1);
|
||||
const auto offset = extract(field, imm(0), imm(5), false);
|
||||
const auto count =
|
||||
IR::U32(ir.Emit(IR::ValueOpcode::UMin32, {extract(field, imm(16), imm(7), false),
|
||||
ir.ISub(imm(32), offset)}));
|
||||
const auto opcode = inst.op == IR::Opcode::BitFieldExtractI32
|
||||
const auto opcode = inst.opcode == Decoder::Opcode::S_BFE_I32
|
||||
? IR::ValueOpcode::BitFieldSExtract
|
||||
: IR::ValueOpcode::BitFieldUExtract;
|
||||
result = ir.Emit(opcode, {source, offset, count});
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitFieldExtractU64: {
|
||||
const auto source = ReadU64(inst.src[0]);
|
||||
const auto field = ReadU32(inst.src[1]);
|
||||
case Decoder::Opcode::S_BFE_U64: {
|
||||
const auto source = ReadU64(inst.src0);
|
||||
const auto field = ReadU32(inst.src1);
|
||||
const auto offset = extract(field, imm(0), imm(6), false);
|
||||
const auto raw_count = extract(field, imm(16), imm(7), false);
|
||||
const auto available = ir.ISub(imm(64), offset);
|
||||
@@ -456,49 +519,49 @@ bool Translator::TranslateExtendedInteger(const IR::Instruction& inst) {
|
||||
result = ir.Emit(IR::ValueOpcode::BitwiseAnd64, {shifted, right_mask64(count)});
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitFieldExtract3U32:
|
||||
case IR::Opcode::BitFieldExtract3I32: {
|
||||
const auto source = ReadU32(inst.src[0]);
|
||||
const auto offset = mask(ReadU32(inst.src[1]), 31u);
|
||||
case Decoder::Opcode::V_BFE_U32:
|
||||
case Decoder::Opcode::V_BFE_I32: {
|
||||
const auto source = ReadU32(inst.src0);
|
||||
const auto offset = mask(ReadU32(inst.src1), 31u);
|
||||
const auto count =
|
||||
IR::U32(ir.Emit(IR::ValueOpcode::UMin32,
|
||||
{mask(ReadU32(inst.src[2]), 31u), ir.ISub(imm(32), offset)}));
|
||||
const auto opcode = inst.op == IR::Opcode::BitFieldExtract3I32
|
||||
{mask(ReadU32(inst.src2), 31u), ir.ISub(imm(32), offset)}));
|
||||
const auto opcode = inst.opcode == Decoder::Opcode::V_BFE_I32
|
||||
? IR::ValueOpcode::BitFieldSExtract
|
||||
: IR::ValueOpcode::BitFieldUExtract;
|
||||
result = ir.Emit(opcode, {source, offset, count});
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitFieldInsertSelectU32: {
|
||||
const auto bits = ReadU32(inst.src[0]);
|
||||
const auto insert = ReadU32(inst.src[1]);
|
||||
const auto base = ReadU32(inst.src[2]);
|
||||
case Decoder::Opcode::V_BFI_B32: {
|
||||
const auto bits = ReadU32(inst.src0);
|
||||
const auto insert = ReadU32(inst.src1);
|
||||
const auto base = ReadU32(inst.src2);
|
||||
result =
|
||||
ir.BitwiseOr(ir.BitwiseAnd(bits, insert), ir.BitwiseAnd(ir.BitwiseNot(bits), base));
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitCompare0B32:
|
||||
case IR::Opcode::BitCompare1B32: {
|
||||
const auto value = ReadU32(inst.src[0]);
|
||||
const auto bit = extract(value, mask(ReadU32(inst.src[1]), 31u), imm(1), false);
|
||||
const auto expected = imm(inst.op == IR::Opcode::BitCompare1B32 ? 1u : 0u);
|
||||
WriteOperand(inst.dst, ir.IEqual(bit, expected));
|
||||
case Decoder::Opcode::S_BITCMP0_B32:
|
||||
case Decoder::Opcode::S_BITCMP1_B32: {
|
||||
const auto value = ReadU32(inst.src0);
|
||||
const auto bit = extract(value, mask(ReadU32(inst.src1), 31u), imm(1), false);
|
||||
const auto expected = imm(inst.opcode == Decoder::Opcode::S_BITCMP1_B32 ? 1u : 0u);
|
||||
WriteCompareResult(inst.dst, ir.IEqual(bit, expected));
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::AlignBitU32: {
|
||||
const auto hi = ReadU32(inst.src[0]);
|
||||
const auto lo = ReadU32(inst.src[1]);
|
||||
const auto shift = mask(ReadU32(inst.src[2]), 31u);
|
||||
case Decoder::Opcode::V_ALIGNBIT_B32: {
|
||||
const auto hi = ReadU32(inst.src0);
|
||||
const auto lo = ReadU32(inst.src1);
|
||||
const auto shift = mask(ReadU32(inst.src2), 31u);
|
||||
const auto lo_part = ir.ShiftRightLogical(lo, shift);
|
||||
const auto hi_part_raw = ir.ShiftLeftLogical(hi, mask(ir.ISub(imm(32), shift), 31u));
|
||||
const auto hi_part = ir.Select(ir.INotEqual(shift, imm(0)), hi_part_raw, imm(0));
|
||||
result = ir.BitwiseOr(lo_part, hi_part);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::AlignByteU32: {
|
||||
const auto hi = ReadU32(inst.src[0]);
|
||||
const auto lo = ReadU32(inst.src[1]);
|
||||
const auto byte_offset = mask(ReadU32(inst.src[2]), 31u);
|
||||
case Decoder::Opcode::V_ALIGNBYTE_B32: {
|
||||
const auto hi = ReadU32(inst.src0);
|
||||
const auto lo = ReadU32(inst.src1);
|
||||
const auto byte_offset = mask(ReadU32(inst.src2), 31u);
|
||||
const auto bit_offset = ir.ShiftLeftLogical(byte_offset, imm(3));
|
||||
const auto concatenated = ir.ConstructU64(lo, hi);
|
||||
const auto shifted = IR::U64(ir.Emit(IR::ValueOpcode::ShiftRightLogical64,
|
||||
@@ -508,85 +571,68 @@ bool Translator::TranslateExtendedInteger(const IR::Instruction& inst) {
|
||||
result = ir.Select(in_range, ExtractU64(shifted)[0], imm(0));
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::ShiftLeftAddU32:
|
||||
case Decoder::Opcode::V_LSHL_ADD_U32:
|
||||
result = ir.IAdd(ir.ShiftLeftLogical(ReadU32(inst.src0), mask(ReadU32(inst.src1), 31u)),
|
||||
ReadU32(inst.src2));
|
||||
break;
|
||||
case Decoder::Opcode::V_ADD_LSHL_U32:
|
||||
result = ir.ShiftLeftLogical(ir.IAdd(ReadU32(inst.src0), ReadU32(inst.src1)),
|
||||
mask(ReadU32(inst.src2), 31u));
|
||||
break;
|
||||
case Decoder::Opcode::V_XAD_U32:
|
||||
result =
|
||||
ir.IAdd(ir.ShiftLeftLogical(ReadU32(inst.src[0]), mask(ReadU32(inst.src[1]), 31u)),
|
||||
ReadU32(inst.src[2]));
|
||||
ir.IAdd(ir.BitwiseXor(ReadU32(inst.src0), ReadU32(inst.src1)), ReadU32(inst.src2));
|
||||
break;
|
||||
case IR::Opcode::AddShiftLeftU32:
|
||||
result = ir.ShiftLeftLogical(ir.IAdd(ReadU32(inst.src[0]), ReadU32(inst.src[1])),
|
||||
mask(ReadU32(inst.src[2]), 31u));
|
||||
break;
|
||||
case IR::Opcode::XorAddU32:
|
||||
result = ir.IAdd(ir.BitwiseXor(ReadU32(inst.src[0]), ReadU32(inst.src[1])),
|
||||
ReadU32(inst.src[2]));
|
||||
break;
|
||||
case IR::Opcode::ShiftLeftOrU32:
|
||||
result = ir.BitwiseOr(
|
||||
ir.ShiftLeftLogical(ReadU32(inst.src[0]), mask(ReadU32(inst.src[1]), 31u)),
|
||||
ReadU32(inst.src[2]));
|
||||
break;
|
||||
case IR::Opcode::SelectU32:
|
||||
case Decoder::Opcode::V_LSHL_OR_B32:
|
||||
result =
|
||||
ir.Select(ReadCondition(inst.src[0]), ReadU32(inst.src[1]), ReadU32(inst.src[2]));
|
||||
ir.BitwiseOr(ir.ShiftLeftLogical(ReadU32(inst.src0), mask(ReadU32(inst.src1), 31u)),
|
||||
ReadU32(inst.src2));
|
||||
break;
|
||||
case IR::Opcode::SelectMaskU32:
|
||||
result = ir.Select(ReadMask(inst.src[0]), ReadU32(inst.src[1]), ReadU32(inst.src[2]));
|
||||
break;
|
||||
case IR::Opcode::SelectF32Bits:
|
||||
case IR::Opcode::SelectMaskF32Bits: {
|
||||
const auto condition = inst.op == IR::Opcode::SelectMaskF32Bits
|
||||
? ReadMask(inst.src[0])
|
||||
: ReadCondition(inst.src[0]);
|
||||
result = ir.Emit(IR::ValueOpcode::SelectF32,
|
||||
{condition, ReadOperand(inst.src[1], IR::Type::F32),
|
||||
ReadOperand(inst.src[2], IR::Type::F32)});
|
||||
case Decoder::Opcode::V_CNDMASK_B32: {
|
||||
Decoder::Operand mask_operand;
|
||||
mask_operand.kind = Decoder::OperandKind::VccLo;
|
||||
if (inst.src_count >= 3u) {
|
||||
mask_operand = inst.src2;
|
||||
}
|
||||
const auto condition = ReadMask(mask_operand);
|
||||
if (inst.src0.negate || inst.src0.absolute || inst.src1.negate || inst.src1.absolute) {
|
||||
result = ir.Emit(IR::ValueOpcode::SelectF32,
|
||||
{condition, ReadOperand(inst.src1, IR::Type::F32),
|
||||
ReadOperand(inst.src0, IR::Type::F32)});
|
||||
} else {
|
||||
result = ir.Select(condition, ReadU32(inst.src1), ReadU32(inst.src0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::SelectU64: {
|
||||
const auto condition = ReadCondition(inst.src[0]);
|
||||
const auto selected_mask =
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1,
|
||||
{condition, ReadMask(inst.src[1]), ReadMask(inst.src[2])}));
|
||||
const auto selected_mask_valid =
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1, {condition, ReadMaskValid(inst.src[1]),
|
||||
ReadMaskValid(inst.src[2])}));
|
||||
if (inst.dst.kind == IR::OperandKind::Register &&
|
||||
(inst.dst.reg.file == IR::RegisterFile::Exec ||
|
||||
inst.dst.reg.file == IR::RegisterFile::Vcc)) {
|
||||
WriteMask64(inst.dst, selected_mask);
|
||||
return true;
|
||||
}
|
||||
const auto lhs = ReadU32Pair(inst.src[1]);
|
||||
const auto rhs = ReadU32Pair(inst.src[2]);
|
||||
WriteU32Pair(inst.dst, {ir.Select(condition, lhs[0], rhs[0]),
|
||||
ir.Select(condition, lhs[1], rhs[1])});
|
||||
if (inst.dst.kind == IR::OperandKind::Register &&
|
||||
inst.dst.reg.file == IR::RegisterFile::Scalar) {
|
||||
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg.index);
|
||||
ir.SetThreadBitScalarReg(dst, selected_mask);
|
||||
ir.SetScalarMaskTag(dst, selected_mask_valid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case IR::Opcode::PackLowLowU16:
|
||||
case IR::Opcode::PackLowHighU16:
|
||||
case IR::Opcode::PackHighHighU16:
|
||||
case IR::Opcode::PackU16U32: {
|
||||
const bool high0 = inst.op == IR::Opcode::PackHighHighU16;
|
||||
const bool high1 = inst.op == IR::Opcode::PackLowHighU16 || high0;
|
||||
case Decoder::Opcode::S_PACK_LL_B32_B16:
|
||||
case Decoder::Opcode::S_PACK_LH_B32_B16:
|
||||
case Decoder::Opcode::S_PACK_HH_B32_B16:
|
||||
case Decoder::Opcode::V_CVT_PK_U16_U32:
|
||||
case Decoder::Opcode::V_CVT_PK_I16_I32: {
|
||||
const bool high0 = inst.opcode == Decoder::Opcode::S_PACK_HH_B32_B16;
|
||||
const bool high1 = inst.opcode == Decoder::Opcode::S_PACK_LH_B32_B16 || high0;
|
||||
const auto lo =
|
||||
high0 ? ir.ShiftRightLogical(ReadU32(inst.src[0]), imm(16)) : ReadU32(inst.src[0]);
|
||||
high0 ? ir.ShiftRightLogical(ReadU32(inst.src0), imm(16)) : ReadU32(inst.src0);
|
||||
const auto hi =
|
||||
high1 ? ir.ShiftRightLogical(ReadU32(inst.src[1]), imm(16)) : ReadU32(inst.src[1]);
|
||||
high1 ? ir.ShiftRightLogical(ReadU32(inst.src1), imm(16)) : ReadU32(inst.src1);
|
||||
result =
|
||||
ir.BitwiseOr(mask(lo, 0xffffu), ir.ShiftLeftLogical(mask(hi, 0xffffu), imm(16)));
|
||||
break;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
WriteOperand(inst.dst, result);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_BFE_U32:
|
||||
case Decoder::Opcode::S_BFE_I32: ir.SetScc(ir.INotEqual(IR::U32(result), imm(0u))); break;
|
||||
case Decoder::Opcode::S_BFE_U64:
|
||||
case Decoder::Opcode::S_QUADMASK_B64:
|
||||
ir.SetScc(
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::INotEqual64, {result, IR::Value(uint64_t {0})})));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/recompiler/frontend/cfg/ShaderCFG.h"
|
||||
#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
bool TranslateProgram(const IR::Program& source, IR::ValueProgram& result,
|
||||
const ShaderVertexInputInfo* vertex_input_info,
|
||||
const ShaderPixelInputInfo* pixel_input_info,
|
||||
const ShaderComputeInputInfo* compute_input_info, std::string* error);
|
||||
struct EmbeddedFetchLoad {
|
||||
uint32_t pc = 0;
|
||||
int attrib_id = -1;
|
||||
uint32_t components = 0;
|
||||
std::vector<uint32_t> prolog_loads;
|
||||
};
|
||||
|
||||
struct EmbeddedFetchPlan {
|
||||
std::vector<EmbeddedFetchLoad> loads;
|
||||
int32_t vertex_offset_sgpr = -1;
|
||||
};
|
||||
|
||||
struct TranslateOptions {
|
||||
ShaderType stage = ShaderType::Unknown;
|
||||
uint32_t wave_size = 64;
|
||||
uint64_t shader_hash = 0;
|
||||
uint32_t user_data_base = 0;
|
||||
uint32_t user_data_count = 64;
|
||||
uint32_t scratch_dwords = 0;
|
||||
bool dispatcher_fallback = false;
|
||||
CFG::FailureKind cfg_failure_kind = CFG::FailureKind::None;
|
||||
std::string_view fallback_reason;
|
||||
const ShaderVertexInputInfo* vertex = nullptr;
|
||||
const ShaderPixelInputInfo* pixel = nullptr;
|
||||
const ShaderComputeInputInfo* compute = nullptr;
|
||||
const EmbeddedFetchPlan* embedded_fetch = nullptr;
|
||||
};
|
||||
|
||||
bool TranslateProgram(const Decoder::Program& decoded, const CFG::Graph& cfg,
|
||||
const TranslateOptions& options, IR::Program& result, std::string* error);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
@@ -5,58 +5,59 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
class Translator {
|
||||
public:
|
||||
Translator(IR::ValueProgram& program, IR::Block* block, uint32_t vector_limit,
|
||||
uint32_t wave_size)
|
||||
: value_program(program), ir(block), current_vector_limit(vector_limit),
|
||||
Translator(IR::Program& program, IR::Block* block, uint32_t vector_limit, uint32_t wave_size)
|
||||
: program(program), ir(block), current_vector_limit(vector_limit),
|
||||
current_wave_size(wave_size) {}
|
||||
|
||||
bool TranslateBlock(const IR::BasicBlock& source, std::string* error);
|
||||
bool AddBranchCondition(const IR::BasicBlock& source, IR::ValueBlockInfo& info,
|
||||
std::string* error);
|
||||
bool TranslateInstruction(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateEmbeddedFetch(const Decoder::Instruction& inst, uint32_t attribute,
|
||||
uint32_t component_count);
|
||||
bool AddBranchCondition(const CFG::BasicBlock& source, IR::BlockInfo& info, std::string* error);
|
||||
|
||||
private:
|
||||
IR::Operand OffsetOperand(const IR::Operand& operand, uint32_t offset);
|
||||
IR::Operand ScalarDestinationOperand(const IR::Operand& operand, uint32_t offset);
|
||||
IR::Operand PlainOperand(const IR::Operand& operand);
|
||||
IR::U32 ReadPcRelativeU32(const IR::Operand& operand);
|
||||
Decoder::Operand SourceAt(const Decoder::Instruction& inst, uint32_t index);
|
||||
Decoder::Operand DestinationOperand(const Decoder::Instruction& inst);
|
||||
Decoder::Operand OffsetOperand(const Decoder::Operand& operand, uint32_t offset);
|
||||
Decoder::Operand ScalarDestinationOperand(const Decoder::Operand& operand, uint32_t offset);
|
||||
Decoder::Operand PlainOperand(const Decoder::Operand& operand);
|
||||
std::array<IR::U32, 2> BallotMask(IR::U1 value);
|
||||
IR::U32 ReadRawU32(const IR::Operand& operand);
|
||||
IR::U32 ReadRawU32(const Decoder::Operand& operand);
|
||||
IR::U32 ReadScalarCode(uint32_t code);
|
||||
IR::U32 ApplyBitSourceModifiers(const IR::Operand& operand, IR::U32 value);
|
||||
IR::Value ReadOperand(const IR::Operand& operand, IR::Type type);
|
||||
IR::U32 ApplyBitSourceModifiers(const Decoder::Operand& operand, IR::U32 value);
|
||||
IR::Value ReadOperand(const Decoder::Operand& operand, IR::Type type);
|
||||
IR::U1 ThreadBit(IR::U32 low);
|
||||
void WriteRawU32(const IR::Operand& operand, IR::U32 value);
|
||||
IR::F32 ApplyF32ResultModifiers(const IR::Operand& operand, IR::F32 value);
|
||||
void WriteOperand(const IR::Operand& operand, IR::Value value);
|
||||
void WriteRawU32(const Decoder::Operand& operand, IR::U32 value);
|
||||
IR::F32 ApplyF32ResultModifiers(const Decoder::Operand& operand, IR::F32 value);
|
||||
void WriteOperand(const Decoder::Operand& operand, IR::Value value);
|
||||
IR::U32 PackHalf2x16(IR::F32 low, IR::F32 high);
|
||||
void WriteF16(const IR::Operand& operand, IR::F32 value);
|
||||
void WriteU16(const IR::Operand& operand, IR::U32 value);
|
||||
IR::U32 ReadU32(const IR::Operand& operand);
|
||||
std::array<IR::U32, 2> ReadU32Pair(const IR::Operand& operand);
|
||||
IR::U64 ReadU64(const IR::Operand& operand);
|
||||
IR::F32 ReadF16LaneAsF32(const IR::Operand& operand, bool high_lane, bool packed = false);
|
||||
IR::F32 ReadF16AsF32(const IR::Operand& operand);
|
||||
IR::F32 ReadMixF32(const IR::Operand& operand);
|
||||
IR::U32 ReadU16LaneRaw(const IR::Operand& operand, bool high_lane);
|
||||
IR::U32 ReadU16LaneAsU32(const IR::Operand& operand, bool high_lane, bool sign_extend);
|
||||
IR::U32 ReadU16AsU32(const IR::Operand& operand, bool sign_extend);
|
||||
IR::U32 ReadF16LaneBits(const IR::Operand& operand, bool high_lane);
|
||||
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);
|
||||
std::array<IR::U32, 2> ReadU32Pair(const Decoder::Operand& operand);
|
||||
IR::U64 ReadU64(const Decoder::Operand& operand);
|
||||
IR::F32 ReadF16LaneAsF32(const Decoder::Operand& operand, bool high_lane, bool packed = false);
|
||||
IR::F32 ReadF16AsF32(const Decoder::Operand& operand);
|
||||
IR::F32 ReadMixF32(const Decoder::Operand& operand);
|
||||
IR::U32 ReadU16LaneRaw(const Decoder::Operand& operand, bool high_lane);
|
||||
IR::U32 ReadU16LaneAsU32(const Decoder::Operand& operand, bool high_lane, bool sign_extend);
|
||||
IR::U32 ReadU16AsU32(const Decoder::Operand& operand, bool sign_extend);
|
||||
IR::U32 ReadF16LaneBits(const Decoder::Operand& operand, bool high_lane);
|
||||
std::array<IR::U32, 2> ExtractU64(IR::U64 value);
|
||||
void WriteU32Pair(const IR::Operand& operand, const std::array<IR::U32, 2>& value);
|
||||
IR::U1 ReadCondition(const IR::Operand& operand);
|
||||
IR::U32 ConditionBit(const IR::Operand& operand);
|
||||
IR::U1 ReadMask(const IR::Operand& operand);
|
||||
IR::U1 ReadMaskValid(const IR::Operand& operand);
|
||||
void WriteMask(const IR::Operand& operand, IR::U1 value);
|
||||
void WriteMask64(const IR::Operand& operand, IR::U1 value);
|
||||
void WriteCompareResult(const IR::Operand& operand, IR::U1 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::U1 ReadMask(const Decoder::Operand& operand);
|
||||
IR::U1 ReadMaskValid(const Decoder::Operand& operand);
|
||||
void WriteMask(const Decoder::Operand& operand, IR::U1 value);
|
||||
void WriteMask64(const Decoder::Operand& operand, IR::U1 value);
|
||||
void WriteCompareResult(const Decoder::Operand& operand, IR::U1 value);
|
||||
|
||||
IR::MemoryFlags AddMemoryInfo(const IR::Instruction& inst);
|
||||
IR::ExportFlags AddExportInfo(const IR::Instruction& inst);
|
||||
IR::MemoryFlags AddMemoryInfo(const IR::MemoryInfo& memory, uint32_t pc);
|
||||
IR::ExportFlags AddExportInfo(const Decoder::Instruction& inst);
|
||||
struct AddressOperands {
|
||||
IR::Value resource;
|
||||
IR::Value low;
|
||||
@@ -67,31 +68,31 @@ private:
|
||||
IR::U32 offset;
|
||||
IR::U32 soffset;
|
||||
};
|
||||
AddressOperands ReadAddressOperands(const IR::Instruction& inst, uint32_t first_source);
|
||||
AddressOperands ReadAddressOperands(const Decoder::Instruction& inst, uint32_t first_source);
|
||||
IR::U32 GetResourceDword(uint32_t index, uint32_t dword);
|
||||
IR::Value GetBufferResource(const IR::MemoryInfo& memory);
|
||||
IR::Value GetAddressResource(IR::Value low, IR::Value high);
|
||||
IR::Value GetScalarAddressResource(uint32_t base);
|
||||
IR::Value GetImageResource(const IR::MemoryInfo& memory);
|
||||
IR::Value GetSamplerResource(const IR::MemoryInfo& memory);
|
||||
IR::Value MakeImageAddress(const IR::Instruction& inst, const IR::Operand& base);
|
||||
IR::Value ConstructU32x4(const IR::Operand& base, uint32_t count);
|
||||
void WriteImageComponents(const IR::Operand& dst, IR::Value value, const IR::MemoryInfo& memory,
|
||||
uint32_t component_limit);
|
||||
IR::ValueOpcode ImageAtomicOpcode(IR::Opcode opcode);
|
||||
BufferAddress ReadBufferAddress(const IR::Instruction& inst, uint32_t source_offset);
|
||||
IR::Value MakeImageAddress(const Decoder::Instruction& inst, const Decoder::Operand& base);
|
||||
IR::Value ConstructU32x4(const Decoder::Operand& base, uint32_t count);
|
||||
void WriteImageComponents(const Decoder::Operand& dst, IR::Value value,
|
||||
const IR::MemoryInfo& memory, uint32_t component_limit);
|
||||
IR::ValueOpcode ImageAtomicOpcode(Decoder::Opcode opcode);
|
||||
BufferAddress ReadBufferAddress(const Decoder::Instruction& inst, uint32_t source_offset);
|
||||
IR::U32 WidenSubdword(IR::Value value, uint32_t bits, bool sign);
|
||||
IR::Value NarrowSubdword(IR::U32 value, uint32_t bits);
|
||||
IR::ValueOpcode BufferAtomicOpcode(IR::Opcode opcode);
|
||||
IR::ValueOpcode SharedAtomicOpcode(IR::Opcode opcode);
|
||||
bool TranslateScalarMemory(const IR::Instruction& inst);
|
||||
bool TranslateBufferLoad(const IR::Instruction& inst);
|
||||
bool TranslateBufferStore(const IR::Instruction& inst);
|
||||
bool TranslateAtomicMemory(const IR::Instruction& inst);
|
||||
bool TranslateFlatLoad(const IR::Instruction& inst);
|
||||
bool TranslateFlatStore(const IR::Instruction& inst);
|
||||
bool TranslateImageMemory(const IR::Instruction& inst);
|
||||
bool TranslateSharedMemory(const IR::Instruction& inst);
|
||||
IR::ValueOpcode BufferAtomicOpcode(Decoder::Opcode opcode);
|
||||
IR::ValueOpcode SharedAtomicOpcode(Decoder::Opcode opcode);
|
||||
bool TranslateScalarMemory(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateBufferLoad(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateBufferStore(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateAtomicMemory(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateFlatLoad(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateFlatStore(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateImageMemory(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateSharedMemory(const Decoder::Instruction& inst, std::string* error);
|
||||
|
||||
IR::F32 SelectF32(IR::U1 condition, IR::F32 true_value, IR::F32 false_value);
|
||||
IR::U32 ConvertF32ToU32Saturated(IR::F32 value, float upper_bound, float safe_upper,
|
||||
@@ -101,34 +102,33 @@ private:
|
||||
uint32_t upper_result);
|
||||
IR::U32 PackU16Lanes(IR::U32 low, IR::U32 high);
|
||||
|
||||
bool TranslateInstruction(const IR::Instruction& inst);
|
||||
bool TranslateStateOperation(const IR::Instruction& inst);
|
||||
bool TranslateControlOperation(const IR::Instruction& inst);
|
||||
bool TranslateMove(const IR::Instruction& inst);
|
||||
bool TranslateLaneOperation(const IR::Instruction& inst);
|
||||
bool TranslateAttributeOperation(const IR::Instruction& inst);
|
||||
bool TranslateMemoryOperation(const IR::Instruction& inst);
|
||||
bool TranslateIntegerCompare(const IR::Instruction& inst);
|
||||
bool TranslateInteger16Compare(const IR::Instruction& inst);
|
||||
bool TranslateFloatCompare(const IR::Instruction& inst);
|
||||
bool TranslateConversion(const IR::Instruction& inst);
|
||||
bool TranslateInteger16Operation(const IR::Instruction& inst);
|
||||
bool TranslatePackedInteger16(const IR::Instruction& inst);
|
||||
bool TranslatePackedFloat16(const IR::Instruction& inst);
|
||||
bool TranslateFloat16Operation(const IR::Instruction& inst);
|
||||
bool TranslateFloatOperation(const IR::Instruction& inst);
|
||||
IR::U1 EvaluateU64Mask(const IR::Instruction& inst);
|
||||
bool TranslateU64MaskOperation(const IR::Instruction& inst);
|
||||
bool TranslateSimpleInteger(const IR::Instruction& inst);
|
||||
bool TranslateComposedInteger(const IR::Instruction& inst);
|
||||
bool TranslateExtendedInteger(const IR::Instruction& inst);
|
||||
bool TranslateStateOperation(const Decoder::Instruction& inst);
|
||||
bool TranslateControlOperation(const Decoder::Instruction& inst);
|
||||
bool TranslateMove(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateLaneOperation(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateAttributeOperation(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateMemoryOperation(const Decoder::Instruction& inst, std::string* error);
|
||||
bool TranslateIntegerCompare(const Decoder::Instruction& inst);
|
||||
bool TranslateInteger16Compare(const Decoder::Instruction& inst);
|
||||
bool TranslateFloatCompare(const Decoder::Instruction& inst);
|
||||
bool TranslateConversion(const Decoder::Instruction& inst);
|
||||
bool TranslateInteger16Operation(const Decoder::Instruction& inst);
|
||||
bool TranslatePackedInteger16(const Decoder::Instruction& inst);
|
||||
bool TranslatePackedFloat16(const Decoder::Instruction& inst);
|
||||
bool TranslateFloat16Operation(const Decoder::Instruction& inst);
|
||||
bool TranslateFloatOperation(const Decoder::Instruction& inst);
|
||||
IR::U1 EvaluateU64Mask(const Decoder::Instruction& inst);
|
||||
bool TranslateU64MaskOperation(const Decoder::Instruction& inst);
|
||||
bool TranslateSimpleInteger(const Decoder::Instruction& inst);
|
||||
bool TranslateComposedInteger(const Decoder::Instruction& inst);
|
||||
bool TranslateExtendedInteger(const Decoder::Instruction& inst);
|
||||
|
||||
IR::ValueProgram& value_program;
|
||||
IR::IREmitter ir;
|
||||
IR::Opcode current_opcode = IR::Opcode::ControlNop;
|
||||
uint32_t current_pc = 0;
|
||||
uint32_t current_vector_limit = 1;
|
||||
uint32_t current_wave_size = 64;
|
||||
IR::Program& program;
|
||||
IR::IREmitter ir;
|
||||
Decoder::Opcode current_opcode = Decoder::Opcode::UNKNOWN;
|
||||
uint32_t current_pc = 0;
|
||||
uint32_t current_vector_limit = 1;
|
||||
uint32_t current_wave_size = 64;
|
||||
};
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
Reference in New Issue
Block a user