mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
graphics: split shader translation into explicit opcode dispatchers
This commit is contained in:
@@ -57,46 +57,50 @@ bool Translator::TranslateEmbeddedFetch(const Decoder::Instruction& inst, uint32
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateAttributeOperation(const Decoder::Instruction& inst, std::string* error) {
|
||||
void Translator::V_INTERP_P1_F32() {}
|
||||
|
||||
void Translator::V_INTERP_P2_F32(const Decoder::Instruction& inst) {
|
||||
const auto value = ir.Emit(IR::ValueOpcode::GetAttribute,
|
||||
{IR::Value(inst.src1.value), IR::Value(inst.src2.value)});
|
||||
WriteOperand(inst.dst, value);
|
||||
}
|
||||
|
||||
bool Translator::V_INTERP_MOV_F32(const Decoder::Instruction& inst, std::string* error) {
|
||||
if (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 value = ir.Emit(
|
||||
IR::ValueOpcode::GetInterpolationParameter,
|
||||
{IR::Value(inst.src1.value), IR::Value(inst.src2.value), IR::Value(inst.src0.value)});
|
||||
WriteOperand(inst.dst, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::EXP(const Decoder::Instruction& inst, std::string* error) {
|
||||
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;
|
||||
}
|
||||
|
||||
bool Translator::EmitInterpolation(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;
|
||||
}
|
||||
case Decoder::Opcode::V_INTERP_P1_F32: V_INTERP_P1_F32(); return true;
|
||||
case Decoder::Opcode::V_INTERP_P2_F32: V_INTERP_P2_F32(inst); return true;
|
||||
case Decoder::Opcode::V_INTERP_MOV_F32: return V_INTERP_MOV_F32(inst, error);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,221 +2,64 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
bool Translator::TranslateIntegerCompare(const Decoder::Instruction& inst) {
|
||||
IR::ValueOpcode opcode {};
|
||||
IR::Type type = IR::Type::U32;
|
||||
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 Decoder::Opcode::V_CMP_T_I32:
|
||||
case Decoder::Opcode::V_CMP_T_U32:
|
||||
WriteCompareResult(inst.dst, IR::U1(IR::Value(true)));
|
||||
return true;
|
||||
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 Decoder::Opcode::V_CMP_GT_U64:
|
||||
opcode = IR::ValueOpcode::UGreaterThan64;
|
||||
type = IR::Type::U64;
|
||||
break;
|
||||
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;
|
||||
void Translator::EmitCompareResult(const Decoder::Instruction& inst, IR::U1 value, bool scalar,
|
||||
bool cmpx) {
|
||||
if (scalar) {
|
||||
ir.SetScc(value);
|
||||
return;
|
||||
}
|
||||
const auto masked = ir.LogicalAnd(ir.GetExec(), value);
|
||||
if (cmpx) {
|
||||
const auto mask = BallotMask(masked);
|
||||
ir.SetExec(masked);
|
||||
ir.SetExecLo(mask[0]);
|
||||
ir.SetExecHi(mask[1]);
|
||||
return;
|
||||
}
|
||||
WriteMask(inst.dst, masked);
|
||||
}
|
||||
|
||||
void Translator::EmitCompareConstant(const Decoder::Instruction& inst, bool value, bool scalar,
|
||||
bool cmpx) {
|
||||
EmitCompareResult(inst, IR::U1(IR::Value(value)), scalar, cmpx);
|
||||
}
|
||||
|
||||
void Translator::EmitIntegerCompare(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
IR::Type type, bool scalar, bool cmpx) {
|
||||
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;
|
||||
EmitCompareResult(inst, IR::U1(ir.Emit(opcode, {lhs, rhs})), scalar, cmpx);
|
||||
}
|
||||
|
||||
bool Translator::TranslateInteger16Compare(const Decoder::Instruction& inst) {
|
||||
IR::ValueOpcode opcode {};
|
||||
bool signed_value = false;
|
||||
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 Decoder::Opcode::V_CMP_GE_I16:
|
||||
opcode = IR::ValueOpcode::SGreaterThanEqual32;
|
||||
signed_value = true;
|
||||
break;
|
||||
case Decoder::Opcode::V_CMP_LT_I16:
|
||||
opcode = IR::ValueOpcode::SLessThan32;
|
||||
signed_value = true;
|
||||
break;
|
||||
case Decoder::Opcode::V_CMP_LE_I16:
|
||||
opcode = IR::ValueOpcode::SLessThanEqual32;
|
||||
signed_value = true;
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
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.src0, signed_value),
|
||||
ReadU16AsU32(inst.src1, signed_value)})));
|
||||
return true;
|
||||
void Translator::EmitInteger16Compare(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool signed_value, bool cmpx) {
|
||||
const auto lhs = ReadU16AsU32(inst.src0, signed_value);
|
||||
const auto rhs = ReadU16AsU32(inst.src1, signed_value);
|
||||
EmitCompareResult(inst, IR::U1(ir.Emit(opcode, {lhs, rhs})), false, cmpx);
|
||||
}
|
||||
|
||||
bool Translator::TranslateFloatCompare(const Decoder::Instruction& inst) {
|
||||
IR::ValueOpcode opcode {};
|
||||
bool half = false;
|
||||
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 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 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 Decoder::Opcode::V_CMP_EQ_F16:
|
||||
case Decoder::Opcode::V_CMPX_EQ_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case Decoder::Opcode::V_CMP_LG_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdNotEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case Decoder::Opcode::V_CMP_GT_F16:
|
||||
case Decoder::Opcode::V_CMPX_GT_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdGreaterThan32;
|
||||
half = true;
|
||||
break;
|
||||
case Decoder::Opcode::V_CMP_GE_F16:
|
||||
case Decoder::Opcode::V_CMPX_GE_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdGreaterThanEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case Decoder::Opcode::V_CMP_LT_F16:
|
||||
case Decoder::Opcode::V_CMPX_LT_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdLessThan32;
|
||||
half = true;
|
||||
break;
|
||||
case Decoder::Opcode::V_CMP_LE_F16:
|
||||
case Decoder::Opcode::V_CMPX_LE_F16:
|
||||
opcode = IR::ValueOpcode::FPOrdLessThanEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case Decoder::Opcode::V_CMP_NEQ_F16:
|
||||
case Decoder::Opcode::V_CMPX_NEQ_F16:
|
||||
opcode = IR::ValueOpcode::FPUnordNotEqual32;
|
||||
half = true;
|
||||
break;
|
||||
case Decoder::Opcode::V_CMPX_NLT_F16:
|
||||
opcode = IR::ValueOpcode::FPUnordGreaterThanEqual32;
|
||||
half = true;
|
||||
break;
|
||||
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.opcode == Decoder::Opcode::V_CMP_U_F32 ? unordered : ir.LogicalNot(unordered);
|
||||
WriteCompareResult(inst.dst, result);
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
void Translator::EmitFloatCompare(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool half, bool cmpx) {
|
||||
const auto lhs =
|
||||
half ? IR::Value(ReadF16AsF32(inst.src0)) : ReadOperand(inst.src0, IR::Type::F32);
|
||||
const auto rhs =
|
||||
half ? IR::Value(ReadF16AsF32(inst.src1)) : ReadOperand(inst.src1, IR::Type::F32);
|
||||
WriteCompareResult(inst.dst, IR::U1(ir.Emit(opcode, {lhs, rhs})));
|
||||
return true;
|
||||
EmitCompareResult(inst, IR::U1(ir.Emit(opcode, {lhs, rhs})), false, cmpx);
|
||||
}
|
||||
|
||||
void Translator::EmitFloatOrderedCompare(const Decoder::Instruction& inst, bool ordered) {
|
||||
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})));
|
||||
EmitCompareResult(inst, ordered ? ir.LogicalNot(unordered) : unordered, false, false);
|
||||
}
|
||||
|
||||
void Translator::V_CMP_CLASS_F32(const Decoder::Instruction& inst) {
|
||||
const auto value = ReadOperand(inst.src0, IR::Type::F32);
|
||||
const auto mask = ReadOperand(inst.src1, IR::Type::U32);
|
||||
EmitCompareResult(inst, IR::U1(ir.Emit(IR::ValueOpcode::FPCmpClass32, {value, mask})), false,
|
||||
false);
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
@@ -21,420 +21,350 @@ Decoder::Operand ConditionOperand(Decoder::OperandKind kind) {
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Translator::TranslateStateOperation(const Decoder::Instruction& inst) {
|
||||
const auto zero = IR::U32(IR::Value(0u));
|
||||
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.src0);
|
||||
IR::U1 result;
|
||||
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 Decoder::Opcode::S_ORN2_SAVEEXEC_B64:
|
||||
result = ir.LogicalOr(ir.LogicalNot(old), src);
|
||||
break;
|
||||
default: EXIT("invalid saveexec opcode");
|
||||
}
|
||||
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);
|
||||
}
|
||||
const auto mask = BallotMask(result);
|
||||
ir.SetExec(result);
|
||||
ir.SetExecLo(mask[0]);
|
||||
ir.SetExecHi(mask[1]);
|
||||
ir.SetScc(result);
|
||||
return true;
|
||||
}
|
||||
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), 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 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 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);
|
||||
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 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);
|
||||
const auto rhs_sign = ir.ShiftRightLogical(rhs, shift);
|
||||
const auto out_sign = ir.ShiftRightLogical(result, shift);
|
||||
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(DestinationOperand(inst), result);
|
||||
ir.SetScc(ir.LogicalAnd(inputs, changed));
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
default: return false;
|
||||
void Translator::S_SAVEEXEC(const Decoder::Instruction& inst, IR::ValueOpcode operation,
|
||||
bool negate_exec, bool negate_source, bool write_64) {
|
||||
const auto old = ir.GetExec();
|
||||
const auto src = ReadMask(inst.src0);
|
||||
const auto lhs = negate_exec ? ir.LogicalNot(old) : old;
|
||||
const auto rhs = negate_source ? ir.LogicalNot(src) : src;
|
||||
const auto result = IR::U1(ir.Emit(operation, {lhs, rhs}));
|
||||
if (write_64) {
|
||||
WriteMask64(inst.dst, old);
|
||||
} else {
|
||||
WriteMask(inst.dst, old);
|
||||
}
|
||||
const auto mask = BallotMask(result);
|
||||
ir.SetExec(result);
|
||||
ir.SetExecLo(mask[0]);
|
||||
ir.SetExecHi(mask[1]);
|
||||
ir.SetScc(result);
|
||||
}
|
||||
|
||||
void Translator::ADD_U32(const Decoder::Instruction& inst, bool vector, bool use_carry_in) {
|
||||
const auto zero = IR::U32(IR::Value(0u));
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
const auto carry_in = !use_carry_in ? zero
|
||||
: vector ? ConditionBit(inst.src2)
|
||||
: ConditionBit(ConditionOperand(Decoder::OperandKind::Scc));
|
||||
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), zero);
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
if (vector) {
|
||||
WriteMask(inst.dst2, ir.LogicalAnd(ir.GetExec(), carry));
|
||||
} else {
|
||||
ir.SetScc(carry);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
void Translator::SUB_U32(const Decoder::Instruction& inst, bool vector, bool reverse) {
|
||||
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 (vector) {
|
||||
WriteMask(inst.dst2, ir.LogicalAnd(ir.GetExec(), borrow));
|
||||
} else {
|
||||
ir.SetScc(borrow);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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 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));
|
||||
void Translator::SUBB_U32(const Decoder::Instruction& inst, bool vector) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::S_ADD_SUB_I32(const Decoder::Instruction& inst, bool subtract) {
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
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);
|
||||
const auto rhs_sign = ir.ShiftRightLogical(rhs, shift);
|
||||
const auto out_sign = ir.ShiftRightLogical(result, shift);
|
||||
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(DestinationOperand(inst), result);
|
||||
ir.SetScc(ir.LogicalAnd(inputs, changed));
|
||||
}
|
||||
|
||||
void Translator::S_LSHL_ADD_U32(const Decoder::Instruction& inst, uint32_t shift_amount) {
|
||||
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, IR::U32(IR::Value(0u)));
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
ir.SetScc(ir.LogicalOr(add_carry, shift_carry));
|
||||
}
|
||||
|
||||
void Translator::ScalarMinMax32(const Decoder::Instruction& inst, IR::ValueOpcode value_opcode,
|
||||
IR::ValueOpcode compare_opcode) {
|
||||
const auto lhs = ReadU32(inst.src0);
|
||||
const auto rhs = ReadU32(inst.src1);
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(value_opcode, {lhs, rhs}));
|
||||
ir.SetScc(IR::U1(ir.Emit(compare_opcode, {lhs, rhs})));
|
||||
}
|
||||
|
||||
void Translator::EmitControlNop() {
|
||||
ir.Emit(IR::ValueOpcode::ControlNop);
|
||||
}
|
||||
|
||||
void Translator::EmitWaitcnt() {
|
||||
ir.Emit(IR::ValueOpcode::Waitcnt);
|
||||
}
|
||||
|
||||
void Translator::S_BARRIER() {
|
||||
ir.Emit(IR::ValueOpcode::Barrier);
|
||||
}
|
||||
|
||||
void Translator::S_SENDMSG() {
|
||||
ir.Emit(IR::ValueOpcode::Sendmsg);
|
||||
}
|
||||
|
||||
void Translator::S_TTRACEDATA() {
|
||||
ir.Emit(IR::ValueOpcode::TtraceData);
|
||||
}
|
||||
|
||||
void Translator::S_INST_PREFETCH() {
|
||||
ir.Emit(IR::ValueOpcode::InstPrefetch);
|
||||
}
|
||||
|
||||
bool Translator::S_GETPC_B64(const Decoder::Instruction& inst, std::string* error) {
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
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.src0)}));
|
||||
const auto result = IR::U64(
|
||||
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})));
|
||||
} else {
|
||||
ir.SetScc(IR::U1(
|
||||
ir.Emit(IR::ValueOpcode::INotEqual64, {result, IR::Value(uint64_t {0})})));
|
||||
if (error != nullptr) {
|
||||
*error = "S_GETPC_B64 destination does not name a valid scalar pair";
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
const auto result = IR::U1(ir.Emit(IR::ValueOpcode::WqmMask, {ReadMask(inst.src0)}));
|
||||
WriteMask64(inst.dst, result);
|
||||
ir.SetScc(result);
|
||||
return true;
|
||||
}
|
||||
default: 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;
|
||||
}
|
||||
const auto words = ExtractU64(address);
|
||||
WriteOperand(inst.dst, words[0]);
|
||||
WriteOperand(high, words[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Translator::S_CSELECT_B32(const Decoder::Instruction& inst) {
|
||||
const auto result = ir.Select(ir.GetScc(), ReadU32(inst.src0), ReadU32(inst.src1));
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
}
|
||||
|
||||
void Translator::S_CSELECT_B64(const Decoder::Instruction& inst) {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::TranslateLaneOperation(const Decoder::Instruction& inst, std::string* error) {
|
||||
void Translator::MOV_B32(const Decoder::Instruction& inst, bool apply_float_modifiers) {
|
||||
if (IsExecOrVcc(inst.src0) && IsExecOrVcc(inst.dst)) {
|
||||
WriteMask(inst.dst, ReadMask(inst.src0));
|
||||
} else if (apply_float_modifiers && (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));
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::S_MOV_B64(const Decoder::Instruction& inst) {
|
||||
if (IsExecOrVcc(inst.dst) || IsExecOrVcc(inst.src0)) {
|
||||
WriteMask64(inst.dst, ReadMask(inst.src0));
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::S_WQM_B64(const Decoder::Instruction& inst) {
|
||||
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.src0)}));
|
||||
const auto result =
|
||||
IR::U64(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})));
|
||||
} else {
|
||||
ir.SetScc(
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::INotEqual64, {result, IR::Value(uint64_t {0})})));
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto result = IR::U1(ir.Emit(IR::ValueOpcode::WqmMask, {ReadMask(inst.src0)}));
|
||||
WriteMask64(inst.dst, result);
|
||||
ir.SetScc(result);
|
||||
}
|
||||
|
||||
bool Translator::V_MOVRELS_B32(const Decoder::Instruction& inst, std::string* error) {
|
||||
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(DestinationOperand(inst), selected);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::V_MOVRELD_B32(const Decoder::Instruction& inst, std::string* error) {
|
||||
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)));
|
||||
const auto write = ir.LogicalAnd(ir.GetExec(), match);
|
||||
ir.SetVectorReg(reg, ir.Select(write, value, ir.GetVectorReg(reg)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Translator::V_READFIRSTLANE_B32(const Decoder::Instruction& inst) {
|
||||
const auto result = ir.Emit(IR::ValueOpcode::ReadFirstLane, {ReadU32(inst.src0), ir.GetExec()});
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
}
|
||||
|
||||
void Translator::V_READLANE_B32(const Decoder::Instruction& inst) {
|
||||
const auto lane_mask = IR::U32(IR::Value(current_wave_size == 32u ? 31u : 63u));
|
||||
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(DestinationOperand(inst), selected);
|
||||
return true;
|
||||
}
|
||||
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)));
|
||||
const auto write = ir.LogicalAnd(ir.GetExec(), match);
|
||||
ir.SetVectorReg(reg, ir.Select(write, value, ir.GetVectorReg(reg)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::V_READFIRSTLANE_B32: {
|
||||
const auto result =
|
||||
ir.Emit(IR::ValueOpcode::ReadFirstLane, {ReadU32(inst.src0), ir.GetExec()});
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
return true;
|
||||
}
|
||||
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 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 Decoder::Opcode::V_PERMLANE16_B32:
|
||||
case Decoder::Opcode::V_PERMLANEX16_B32: {
|
||||
const IR::PermlaneFlags flags {
|
||||
.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.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);
|
||||
return true;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
const auto lane = ir.BitwiseAnd(ReadU32(inst.src1), lane_mask);
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::ReadLane, {ReadU32(inst.src0), lane}));
|
||||
}
|
||||
|
||||
void Translator::V_WRITELANE_B32(const Decoder::Instruction& inst) {
|
||||
EXIT_IF(inst.dst.kind != Decoder::OperandKind::Vgpr);
|
||||
const auto lane_mask = IR::U32(IR::Value(current_wave_size == 32u ? 31u : 63u));
|
||||
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);
|
||||
}
|
||||
|
||||
void Translator::V_PERMLANE16_B32(const Decoder::Instruction& inst, bool x16) {
|
||||
const IR::PermlaneFlags flags {
|
||||
.x16 = x16,
|
||||
.fetch_inactive = inst.dst.op_sel,
|
||||
.bound_control = inst.dst.op_sel_hi,
|
||||
};
|
||||
const auto result =
|
||||
ir.Emit(IR::ValueOpcode::Permlane16U32,
|
||||
{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);
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
|
||||
@@ -38,146 +38,136 @@ 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 Decoder::Instruction& inst) {
|
||||
const auto f32 = [&](uint32_t index) {
|
||||
return IR::F32(ReadOperand(SourceAt(inst, index), IR::Type::F32));
|
||||
};
|
||||
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);
|
||||
};
|
||||
const auto convert_i32 = [&](IR::F32 value) {
|
||||
return ConvertF32ToI32Saturated(value, -2147483648.0f, 2147483648.0f, 2147483520.0f,
|
||||
0x80000000u, 0x7fffffffu);
|
||||
};
|
||||
void Translator::V_CVT_F32_UBYTE(const Decoder::Instruction& inst, uint32_t byte_index) {
|
||||
const auto source = ReadU32(SourceAt(inst, 0));
|
||||
const auto byte =
|
||||
ir.BitwiseAnd(ir.ShiftRightLogical(source, IR::U32(IR::Value(byte_index * 8u))),
|
||||
IR::U32(IR::Value(0xffu)));
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(IR::ValueOpcode::ConvertF32U32, {byte}));
|
||||
}
|
||||
|
||||
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(DestinationOperand(inst), ir.Emit(IR::ValueOpcode::ConvertF32U32, {byte}));
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::V_CVT_F32_U32:
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::ConvertF32U32, {u32(0)}));
|
||||
return true;
|
||||
case Decoder::Opcode::V_CVT_F32_I32:
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::ConvertF32S32, {u32(0)}));
|
||||
return true;
|
||||
case Decoder::Opcode::V_CVT_U32_F32:
|
||||
WriteOperand(DestinationOperand(inst), convert_u32(f32(0)));
|
||||
return true;
|
||||
case Decoder::Opcode::V_CVT_I32_F32:
|
||||
WriteOperand(DestinationOperand(inst), convert_i32(f32(0)));
|
||||
return true;
|
||||
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::ConvertF32U32, {ReadU16AsU32(inst.src0, false)}));
|
||||
WriteF16(DestinationOperand(inst), value);
|
||||
return true;
|
||||
}
|
||||
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.src0), 65536.0f, 65535.0f, 0xffffu);
|
||||
WriteU16(DestinationOperand(inst), converted);
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::V_CVT_I16_F16: {
|
||||
const auto converted = ConvertF32ToI32Saturated(
|
||||
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 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(DestinationOperand(inst), convert_i32(rounded));
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::V_CVT_FLR_I32_F32: {
|
||||
const auto rounded = IR::F32(ir.Emit(IR::ValueOpcode::FPFloor32, {f32(0)}));
|
||||
WriteOperand(DestinationOperand(inst), convert_i32(rounded));
|
||||
return true;
|
||||
}
|
||||
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)}));
|
||||
const auto mantissa = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x007fffffu)));
|
||||
const auto normal = ir.ISub(exponent, IR::U32(IR::Value(126u)));
|
||||
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {mantissa}));
|
||||
const auto subnormal = ir.ISub(msb, IR::U32(IR::Value(148u)));
|
||||
const auto denormal = ir.Select(ir.INotEqual(mantissa, IR::U32(IR::Value(0u))),
|
||||
subnormal, IR::U32(IR::Value(0u)));
|
||||
const auto finite = ir.Select(
|
||||
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(DestinationOperand(inst), finite);
|
||||
return true;
|
||||
}
|
||||
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(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::FPMul32, {value, IR::Value::F32(1.0f / 16.0f)}));
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::V_CVT_PKRTZ_F16_F32:
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::PackFloat2x16Rtz, {f32(0), f32(1)}));
|
||||
return true;
|
||||
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.opcode == Decoder::Opcode::V_CVT_PKNORM_I16_F32
|
||||
? IR::ValueOpcode::PackSnorm2x16
|
||||
: IR::ValueOpcode::PackUnorm2x16;
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(opcode, {pair}));
|
||||
return true;
|
||||
}
|
||||
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(DestinationOperand(inst),
|
||||
ir.BitwiseOr(base, ir.ShiftLeftLogical(byte, shift)));
|
||||
return true;
|
||||
}
|
||||
case Decoder::Opcode::V_PACK_B32_F16: {
|
||||
const auto low = ReadF16LaneBits(inst.src0, false);
|
||||
const auto high =
|
||||
ir.ShiftLeftLogical(ReadF16LaneBits(inst.src1, false), IR::U32(IR::Value(16u)));
|
||||
WriteOperand(DestinationOperand(inst), ir.BitwiseOr(low, high));
|
||||
return true;
|
||||
}
|
||||
default: return false;
|
||||
void Translator::V_CVT_F32_U32(const Decoder::Instruction& inst) {
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::ConvertF32U32, {ReadU32(SourceAt(inst, 0))}));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_F32_I32(const Decoder::Instruction& inst) {
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::ConvertF32S32, {ReadU32(SourceAt(inst, 0))}));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_U32_F32(const Decoder::Instruction& inst) {
|
||||
const auto value = IR::F32(ReadOperand(SourceAt(inst, 0), IR::Type::F32));
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ConvertF32ToU32Saturated(value, 4294967296.0f, 4294967040.0f, 0xffffffffu));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_I32_F32(const Decoder::Instruction& inst) {
|
||||
const auto value = IR::F32(ReadOperand(SourceAt(inst, 0), IR::Type::F32));
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ConvertF32ToI32Saturated(value, -2147483648.0f, 2147483648.0f, 2147483520.0f,
|
||||
0x80000000u, 0x7fffffffu));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_F16_F32(const Decoder::Instruction& inst) {
|
||||
WriteF16(DestinationOperand(inst), IR::F32(ReadOperand(SourceAt(inst, 0), IR::Type::F32)));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_F32_F16(const Decoder::Instruction& inst) {
|
||||
WriteOperand(DestinationOperand(inst), ReadF16AsF32(inst.src0));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_F16_16(const Decoder::Instruction& inst, bool signed_value) {
|
||||
const auto value = IR::F32(
|
||||
ir.Emit(signed_value ? IR::ValueOpcode::ConvertF32S32 : IR::ValueOpcode::ConvertF32U32,
|
||||
{ReadU16AsU32(inst.src0, signed_value)}));
|
||||
WriteF16(DestinationOperand(inst), value);
|
||||
}
|
||||
|
||||
void Translator::V_CVT_16_F16(const Decoder::Instruction& inst, bool signed_value) {
|
||||
const auto value = ReadF16AsF32(inst.src0);
|
||||
if (signed_value) {
|
||||
const auto converted =
|
||||
ConvertF32ToI32Saturated(value, -32768.0f, 32768.0f, 32767.0f, 0xffff8000u, 0x7fffu);
|
||||
WriteU16(DestinationOperand(inst), ir.BitwiseAnd(converted, IR::U32(IR::Value(0xffffu))));
|
||||
return;
|
||||
}
|
||||
WriteU16(DestinationOperand(inst),
|
||||
ConvertF32ToU32Saturated(value, 65536.0f, 65535.0f, 0xffffu));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_RPI_I32_F32(const Decoder::Instruction& inst) {
|
||||
const auto source = IR::F32(ReadOperand(SourceAt(inst, 0), IR::Type::F32));
|
||||
const auto biased = IR::F32(ir.Emit(IR::ValueOpcode::FPAdd32, {source, IR::Value::F32(0.5f)}));
|
||||
const auto rounded = IR::F32(ir.Emit(IR::ValueOpcode::FPFloor32, {biased}));
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ConvertF32ToI32Saturated(rounded, -2147483648.0f, 2147483648.0f, 2147483520.0f,
|
||||
0x80000000u, 0x7fffffffu));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_FLR_I32_F32(const Decoder::Instruction& inst) {
|
||||
const auto source = IR::F32(ReadOperand(SourceAt(inst, 0), IR::Type::F32));
|
||||
const auto rounded = IR::F32(ir.Emit(IR::ValueOpcode::FPFloor32, {source}));
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ConvertF32ToI32Saturated(rounded, -2147483648.0f, 2147483648.0f, 2147483520.0f,
|
||||
0x80000000u, 0x7fffffffu));
|
||||
}
|
||||
|
||||
void Translator::V_FREXP_EXP_I32_F32(const Decoder::Instruction& inst) {
|
||||
const auto source = IR::F32(ReadOperand(SourceAt(inst, 0), IR::Type::F32));
|
||||
const auto bits = ir.BitCastU32(source);
|
||||
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)));
|
||||
const auto normal = ir.ISub(exponent, IR::U32(IR::Value(126u)));
|
||||
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {mantissa}));
|
||||
const auto subnormal = ir.ISub(msb, IR::U32(IR::Value(148u)));
|
||||
const auto denormal = ir.Select(ir.INotEqual(mantissa, IR::U32(IR::Value(0u))), subnormal,
|
||||
IR::U32(IR::Value(0u)));
|
||||
const auto finite =
|
||||
ir.Select(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(DestinationOperand(inst), finite);
|
||||
}
|
||||
|
||||
void Translator::V_CVT_OFF_F32_I4(const Decoder::Instruction& inst) {
|
||||
const auto nibble =
|
||||
IR::U32(ir.Emit(IR::ValueOpcode::BitFieldSExtract,
|
||||
{ReadU32(SourceAt(inst, 0)), IR::Value(0u), IR::Value(4u)}));
|
||||
const auto value = IR::F32(ir.Emit(IR::ValueOpcode::ConvertF32S32, {nibble}));
|
||||
WriteOperand(DestinationOperand(inst),
|
||||
ir.Emit(IR::ValueOpcode::FPMul32, {value, IR::Value::F32(1.0f / 16.0f)}));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_PKRTZ_F16_F32(const Decoder::Instruction& inst) {
|
||||
const auto lhs = ReadOperand(SourceAt(inst, 0), IR::Type::F32);
|
||||
const auto rhs = ReadOperand(SourceAt(inst, 1), IR::Type::F32);
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(IR::ValueOpcode::PackFloat2x16Rtz, {lhs, rhs}));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_PKNORM_F32(const Decoder::Instruction& inst, IR::ValueOpcode opcode) {
|
||||
const auto lhs = ReadOperand(SourceAt(inst, 0), IR::Type::F32);
|
||||
const auto rhs = ReadOperand(SourceAt(inst, 1), IR::Type::F32);
|
||||
const auto pair = ir.Emit(IR::ValueOpcode::CompositeConstructF32x2, {lhs, rhs});
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(opcode, {pair}));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_PK_U8_F32(const Decoder::Instruction& inst) {
|
||||
const auto source = IR::F32(ReadOperand(SourceAt(inst, 0), IR::Type::F32));
|
||||
const auto byte = ConvertF32ToU32Saturated(source, 255.0f, 255.0f, 255u);
|
||||
const auto index = ir.BitwiseAnd(ReadU32(SourceAt(inst, 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(ReadU32(SourceAt(inst, 2)), ir.BitwiseNot(mask));
|
||||
WriteOperand(DestinationOperand(inst), ir.BitwiseOr(base, ir.ShiftLeftLogical(byte, shift)));
|
||||
}
|
||||
|
||||
void Translator::V_PACK_B32_F16(const Decoder::Instruction& inst) {
|
||||
const auto low = ReadF16LaneBits(inst.src0, false);
|
||||
const auto high =
|
||||
ir.ShiftLeftLogical(ReadF16LaneBits(inst.src1, false), IR::U32(IR::Value(16u)));
|
||||
WriteOperand(DestinationOperand(inst), ir.BitwiseOr(low, high));
|
||||
}
|
||||
|
||||
IR::U32 Translator::PackU16Lanes(IR::U32 low, IR::U32 high) {
|
||||
|
||||
@@ -2,94 +2,6 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
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 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.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.src0);
|
||||
auto mask_valid = ReadMaskValid(inst.src0);
|
||||
if (inst.src_count > 1u) {
|
||||
mask_valid = ir.LogicalAnd(mask_valid, ReadMaskValid(inst.src1));
|
||||
}
|
||||
std::array<IR::U32, 2> result;
|
||||
if (inst.opcode == Decoder::Opcode::S_NOT_B64) {
|
||||
result = {ir.BitwiseNot(lhs[0]), ir.BitwiseNot(lhs[1])};
|
||||
} else {
|
||||
const auto rhs = ReadU32Pair(inst.src1);
|
||||
for (uint32_t component = 0; component < 2u; component++) {
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::S_AND_B64:
|
||||
result[component] = ir.BitwiseAnd(lhs[component], rhs[component]);
|
||||
break;
|
||||
case Decoder::Opcode::S_ANDN2_B64:
|
||||
result[component] =
|
||||
ir.BitwiseAnd(lhs[component], ir.BitwiseNot(rhs[component]));
|
||||
break;
|
||||
case Decoder::Opcode::S_OR_B64:
|
||||
result[component] = ir.BitwiseOr(lhs[component], rhs[component]);
|
||||
break;
|
||||
case Decoder::Opcode::S_ORN2_B64:
|
||||
result[component] = ir.BitwiseOr(lhs[component], ir.BitwiseNot(rhs[component]));
|
||||
break;
|
||||
case Decoder::Opcode::S_XOR_B64:
|
||||
result[component] = ir.BitwiseXor(lhs[component], rhs[component]);
|
||||
break;
|
||||
case Decoder::Opcode::S_NAND_B64:
|
||||
result[component] =
|
||||
ir.BitwiseNot(ir.BitwiseAnd(lhs[component], rhs[component]));
|
||||
break;
|
||||
case Decoder::Opcode::S_NOR_B64:
|
||||
result[component] = ir.BitwiseNot(ir.BitwiseOr(lhs[component], rhs[component]));
|
||||
break;
|
||||
case Decoder::Opcode::S_XNOR_B64:
|
||||
result[component] =
|
||||
ir.BitwiseNot(ir.BitwiseXor(lhs[component], rhs[component]));
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteU32Pair(inst.dst, 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.INotEqual(ir.BitwiseOr(result[0], result[1]), IR::U32(IR::Value(0u)));
|
||||
ir.SetScc(IR::U1(
|
||||
ir.Emit(IR::ValueOpcode::SelectU1, {mask_valid, invocation_result, raw_nonzero})));
|
||||
} else {
|
||||
ir.SetScc(ir.INotEqual(ir.BitwiseOr(result[0], result[1]), IR::U32(IR::Value(0u))));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateInstruction(const Decoder::Instruction& inst, std::string* error) {
|
||||
current_opcode = inst.opcode;
|
||||
current_pc = inst.pc;
|
||||
@@ -106,49 +18,33 @@ bool Translator::TranslateInstruction(const Decoder::Instruction& inst, std::str
|
||||
*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;
|
||||
}
|
||||
|
||||
bool translated = false;
|
||||
switch (inst.family) {
|
||||
case Decoder::Family::SOP1:
|
||||
case Decoder::Family::SOP2:
|
||||
case Decoder::Family::SOPK:
|
||||
case Decoder::Family::SOPC:
|
||||
case Decoder::Family::SOPP: translated = EmitScalar(inst, error); break;
|
||||
case Decoder::Family::VOP1:
|
||||
case Decoder::Family::VOP2:
|
||||
case Decoder::Family::VOP3:
|
||||
case Decoder::Family::VOP3P:
|
||||
case Decoder::Family::VOPC: translated = EmitVector(inst, error); break;
|
||||
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);
|
||||
case Decoder::Family::MIMG: translated = EmitMemory(inst, error); break;
|
||||
case Decoder::Family::VINTRP: translated = EmitInterpolation(inst, error); break;
|
||||
case Decoder::Family::EXP: translated = EXP(inst, error); break;
|
||||
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) {
|
||||
if (!translated && error != nullptr && error->empty()) {
|
||||
*error = "decoded opcode has no IR translation";
|
||||
}
|
||||
return translated;
|
||||
|
||||
@@ -5,22 +5,13 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
bool Translator::TranslatePackedFloat16(const Decoder::Instruction& inst) {
|
||||
IR::ValueOpcode opcode;
|
||||
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;
|
||||
}
|
||||
bool Translator::PackedFloat16(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool accumulator, bool quiet_snan) {
|
||||
const auto translate_lane = [&](bool high) {
|
||||
const auto lhs = ReadF16LaneAsF32(inst.src0, high, true);
|
||||
const auto rhs = ReadF16LaneAsF32(inst.src1, high, true);
|
||||
IR::F32 result;
|
||||
if (inst.opcode == Decoder::Opcode::V_PK_FMAC_F16) {
|
||||
if (accumulator) {
|
||||
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)}));
|
||||
@@ -33,9 +24,8 @@ bool Translator::TranslatePackedFloat16(const Decoder::Instruction& inst) {
|
||||
raw.omod = 0u;
|
||||
raw.clamp = false;
|
||||
auto result = PackHalf2x16(translate_lane(false), translate_lane(true));
|
||||
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) {
|
||||
if (quiet_snan) {
|
||||
const auto quiet_snan_lane = [&](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)));
|
||||
@@ -44,8 +34,8 @@ bool Translator::TranslatePackedFloat16(const Decoder::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.src0, high);
|
||||
const auto [rhs_snan, rhs_quiet] = quiet_snan(inst.src1, high);
|
||||
const auto [lhs_snan, lhs_quiet] = quiet_snan_lane(inst.src0, high);
|
||||
const auto [rhs_snan, rhs_quiet] = quiet_snan_lane(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));
|
||||
@@ -56,176 +46,130 @@ bool Translator::TranslatePackedFloat16(const Decoder::Instruction& inst) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::TranslateFloat16Operation(const Decoder::Instruction& inst) {
|
||||
IR::ValueOpcode opcode;
|
||||
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 < 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 (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.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(DestinationOperand(inst), ir.Select(negative, invalid, bits));
|
||||
bool Translator::Float16Unary(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool invalid_negative) {
|
||||
const auto argument = ReadF16AsF32(inst.src0);
|
||||
auto result = IR::F32(ir.Emit(opcode, {argument}));
|
||||
if (!invalid_negative) {
|
||||
WriteF16(DestinationOperand(inst), result);
|
||||
return true;
|
||||
}
|
||||
WriteF16(DestinationOperand(inst), result);
|
||||
const auto negative =
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::FPOrdLessThan32, {argument, 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(DestinationOperand(inst), ir.Select(negative, invalid, bits));
|
||||
return true;
|
||||
}
|
||||
|
||||
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)));
|
||||
const auto sign = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x80000000u)));
|
||||
const auto base = ir.BitwiseOr(sign, IR::U32(IR::Value(0x3f000000u)));
|
||||
const auto normal = ir.BitwiseOr(base, mantissa);
|
||||
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {mantissa}));
|
||||
const auto shift = ir.ISub(IR::U32(IR::Value(23u)), msb);
|
||||
const auto fraction =
|
||||
ir.BitwiseAnd(ir.ShiftLeftLogical(mantissa, shift), IR::U32(IR::Value(0x007fffffu)));
|
||||
const auto subnormal = ir.BitwiseOr(base, fraction);
|
||||
const auto zero = ir.IEqual(mantissa, IR::U32(IR::Value(0u)));
|
||||
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(DestinationOperand(inst), ir.BitCastF32(result));
|
||||
return true;
|
||||
}
|
||||
IR::ValueOpcode opcode {};
|
||||
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 < source_count; index++) {
|
||||
const auto arg_type = IR::ArgTypeOf(opcode, index);
|
||||
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 (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(DestinationOperand(inst), result);
|
||||
return true;
|
||||
}
|
||||
bool Translator::Float16Binary(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool reverse) {
|
||||
const auto lhs = ReadF16AsF32(reverse ? inst.src1 : inst.src0);
|
||||
const auto rhs = ReadF16AsF32(reverse ? inst.src0 : inst.src1);
|
||||
WriteF16(DestinationOperand(inst), IR::F32(ir.Emit(opcode, {lhs, rhs})));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::Float16Ternary(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool accumulator, bool mix) {
|
||||
std::array<IR::Value, 3> args;
|
||||
for (uint32_t index = 0; index < args.size(); index++) {
|
||||
const auto operand = accumulator && index == 2u ? inst.dst : SourceAt(inst, index);
|
||||
args[index] = mix ? IR::Value(ReadMixF32(operand)) : IR::Value(ReadF16AsF32(operand));
|
||||
}
|
||||
WriteF16(DestinationOperand(inst), IR::F32(ir.Emit(opcode, {args[0], args[1], args[2]})));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::FloatUnary(const Decoder::Instruction& inst, IR::ValueOpcode opcode) {
|
||||
const auto type = IR::ArgTypeOf(opcode, 0);
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(opcode, {ReadOperand(inst.src0, type)}));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::FloatBinary(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool reverse) {
|
||||
std::array<IR::Value, 2> args;
|
||||
for (uint32_t index = 0; index < args.size(); index++) {
|
||||
const auto operand = SourceAt(inst, reverse ? 1u - index : index);
|
||||
args[index] = ReadOperand(operand, IR::ArgTypeOf(opcode, index));
|
||||
}
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(opcode, {args[0], args[1]}));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::FloatTernary(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool accumulator, bool mix) {
|
||||
std::array<IR::Value, 3> args;
|
||||
for (uint32_t index = 0; index < args.size(); index++) {
|
||||
const auto operand = accumulator && index == 2u ? inst.dst : SourceAt(inst, index);
|
||||
const auto type = IR::ArgTypeOf(opcode, index);
|
||||
args[index] = type == IR::Type::F32 && mix ? IR::Value(ReadMixF32(operand))
|
||||
: ReadOperand(operand, type);
|
||||
}
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(opcode, {args[0], args[1], args[2]}));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::V_FREXP_MANT_F32(const Decoder::Instruction& inst) {
|
||||
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)));
|
||||
const auto sign = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x80000000u)));
|
||||
const auto base = ir.BitwiseOr(sign, IR::U32(IR::Value(0x3f000000u)));
|
||||
const auto normal = ir.BitwiseOr(base, mantissa);
|
||||
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {mantissa}));
|
||||
const auto shift = ir.ISub(IR::U32(IR::Value(23u)), msb);
|
||||
const auto fraction =
|
||||
ir.BitwiseAnd(ir.ShiftLeftLogical(mantissa, shift), IR::U32(IR::Value(0x007fffffu)));
|
||||
const auto subnormal = ir.BitwiseOr(base, fraction);
|
||||
const auto zero = ir.IEqual(mantissa, IR::U32(IR::Value(0u)));
|
||||
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(DestinationOperand(inst), ir.BitCastF32(result));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::V_DOT2C_F32_F16(const Decoder::Instruction& inst) {
|
||||
auto a = inst.src0;
|
||||
a.op_sel = false;
|
||||
a.op_sel_hi = true;
|
||||
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.dst);
|
||||
const auto lo = IR::F32(ir.Emit(IR::ValueOpcode::FPFma32, {a_lo, b_lo, acc}));
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(IR::ValueOpcode::FPFma32, {a_hi, b_hi, lo}));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::V_CUBEID_F32(const Decoder::Instruction& inst) {
|
||||
return FloatCube(inst, 0u);
|
||||
}
|
||||
|
||||
bool Translator::V_CUBESC_F32(const Decoder::Instruction& inst) {
|
||||
return FloatCube(inst, 1u);
|
||||
}
|
||||
|
||||
bool Translator::V_CUBETC_F32(const Decoder::Instruction& inst) {
|
||||
return FloatCube(inst, 2u);
|
||||
}
|
||||
|
||||
bool Translator::V_CUBEMA_F32(const Decoder::Instruction& inst) {
|
||||
return FloatCube(inst, 3u);
|
||||
}
|
||||
|
||||
bool Translator::FloatCube(const Decoder::Instruction& inst, uint32_t result_kind) {
|
||||
const auto select_f32 = [&](IR::U1 condition, IR::F32 true_value, IR::F32 false_value) {
|
||||
return IR::F32(ir.Emit(IR::ValueOpcode::SelectF32, {condition, true_value, false_value}));
|
||||
};
|
||||
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.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.dst);
|
||||
const auto lo = IR::F32(ir.Emit(IR::ValueOpcode::FPFma32, {a_lo, b_lo, acc}));
|
||||
WriteOperand(DestinationOperand(inst), ir.Emit(IR::ValueOpcode::FPFma32, {a_hi, b_hi, lo}));
|
||||
return true;
|
||||
}
|
||||
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.src0);
|
||||
const auto y = ReadMixF32(inst.src1);
|
||||
const auto z = ReadMixF32(inst.src2);
|
||||
@@ -246,27 +190,23 @@ bool Translator::TranslateFloatOperation(const Decoder::Instruction& inst) {
|
||||
return select_f32(z_face, z_value, select_f32(y_face, y_value, x_value));
|
||||
};
|
||||
IR::F32 result;
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::V_CUBEID_F32:
|
||||
switch (result_kind) {
|
||||
case 0u:
|
||||
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 Decoder::Opcode::V_CUBESC_F32:
|
||||
result = select_face(select_f32(x_neg, z, nz), x, select_f32(z_neg, nx, x));
|
||||
break;
|
||||
case Decoder::Opcode::V_CUBETC_F32:
|
||||
result = select_face(ny, select_f32(y_neg, nz, z), ny);
|
||||
break;
|
||||
case Decoder::Opcode::V_CUBEMA_F32: {
|
||||
case 1u: result = select_face(select_f32(x_neg, z, nz), x, select_f32(z_neg, nx, x)); break;
|
||||
case 2u: result = select_face(ny, select_f32(y_neg, nz, z), ny); break;
|
||||
case 3u: {
|
||||
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})),
|
||||
IR::F32(ir.Emit(IR::ValueOpcode::FPMul32, {z, two})));
|
||||
break;
|
||||
}
|
||||
default: return false;
|
||||
default: EXIT("invalid cube result kind");
|
||||
}
|
||||
WriteOperand(DestinationOperand(inst), result);
|
||||
return true;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,221 @@
|
||||
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
bool Translator::EmitScalar(const Decoder::Instruction& inst, std::string* error) {
|
||||
using O = Decoder::Opcode;
|
||||
switch (inst.opcode) {
|
||||
case O::S_MOV_B32:
|
||||
case O::S_MOVK_I32: MOV_B32(inst, false); return true;
|
||||
case O::S_MOV_B64: S_MOV_B64(inst); return true;
|
||||
case O::S_WQM_B64: S_WQM_B64(inst); return true;
|
||||
case O::S_GETPC_B64: return S_GETPC_B64(inst, error);
|
||||
case O::S_SETPC_B64: return true;
|
||||
case O::S_CSELECT_B32: S_CSELECT_B32(inst); return true;
|
||||
case O::S_CSELECT_B64: S_CSELECT_B64(inst); return true;
|
||||
case O::S_SETREG_B32: EmitControlNop(); return true;
|
||||
case O::S_WAITCNT: EmitWaitcnt(); return true;
|
||||
|
||||
case O::S_AND_SAVEEXEC_B32:
|
||||
S_SAVEEXEC(inst, IR::ValueOpcode::LogicalAnd, false, false, false);
|
||||
return true;
|
||||
case O::S_ANDN1_SAVEEXEC_B32:
|
||||
S_SAVEEXEC(inst, IR::ValueOpcode::LogicalAnd, false, true, false);
|
||||
return true;
|
||||
case O::S_AND_SAVEEXEC_B64:
|
||||
S_SAVEEXEC(inst, IR::ValueOpcode::LogicalAnd, false, false, true);
|
||||
return true;
|
||||
case O::S_ANDN1_SAVEEXEC_B64:
|
||||
S_SAVEEXEC(inst, IR::ValueOpcode::LogicalAnd, false, true, true);
|
||||
return true;
|
||||
case O::S_ORN2_SAVEEXEC_B64:
|
||||
S_SAVEEXEC(inst, IR::ValueOpcode::LogicalOr, true, false, true);
|
||||
return true;
|
||||
case O::S_ADD_U32: ADD_U32(inst, false, false); return true;
|
||||
case O::S_ADDC_U32: ADD_U32(inst, false, true); return true;
|
||||
case O::S_SUB_U32: SUB_U32(inst, false, false); return true;
|
||||
case O::S_SUBB_U32: SUBB_U32(inst, false); return true;
|
||||
case O::S_ADD_I32: S_ADD_SUB_I32(inst, false); return true;
|
||||
case O::S_SUB_I32: S_ADD_SUB_I32(inst, true); return true;
|
||||
case O::S_LSHL1_ADD_U32: S_LSHL_ADD_U32(inst, 1u); return true;
|
||||
case O::S_LSHL2_ADD_U32: S_LSHL_ADD_U32(inst, 2u); return true;
|
||||
case O::S_LSHL3_ADD_U32: S_LSHL_ADD_U32(inst, 3u); return true;
|
||||
case O::S_LSHL4_ADD_U32: S_LSHL_ADD_U32(inst, 4u); return true;
|
||||
case O::S_MIN_I32:
|
||||
ScalarMinMax32(inst, IR::ValueOpcode::SMin32, IR::ValueOpcode::SLessThan32);
|
||||
return true;
|
||||
case O::S_MAX_I32:
|
||||
ScalarMinMax32(inst, IR::ValueOpcode::SMax32, IR::ValueOpcode::SGreaterThan32);
|
||||
return true;
|
||||
case O::S_MIN_U32:
|
||||
ScalarMinMax32(inst, IR::ValueOpcode::UMin32, IR::ValueOpcode::ULessThan32);
|
||||
return true;
|
||||
case O::S_MAX_U32:
|
||||
ScalarMinMax32(inst, IR::ValueOpcode::UMax32, IR::ValueOpcode::UGreaterThan32);
|
||||
return true;
|
||||
|
||||
case O::S_CMP_EQ_U32:
|
||||
case O::S_CMP_EQ_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::IEqual32, IR::Type::U32, true, false);
|
||||
return true;
|
||||
case O::S_CMP_LG_U32:
|
||||
case O::S_CMP_LG_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::INotEqual32, IR::Type::U32, true, false);
|
||||
return true;
|
||||
case O::S_CMP_GT_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::UGreaterThan32, IR::Type::U32, true, false);
|
||||
return true;
|
||||
case O::S_CMP_GE_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::UGreaterThanEqual32, IR::Type::U32, true,
|
||||
false);
|
||||
return true;
|
||||
case O::S_CMP_LT_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::ULessThan32, IR::Type::U32, true, false);
|
||||
return true;
|
||||
case O::S_CMP_LE_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::ULessThanEqual32, IR::Type::U32, true, false);
|
||||
return true;
|
||||
case O::S_CMP_GT_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SGreaterThan32, IR::Type::U32, true, false);
|
||||
return true;
|
||||
case O::S_CMP_GE_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SGreaterThanEqual32, IR::Type::U32, true,
|
||||
false);
|
||||
return true;
|
||||
case O::S_CMP_LT_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SLessThan32, IR::Type::U32, true, false);
|
||||
return true;
|
||||
case O::S_CMP_LE_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SLessThanEqual32, IR::Type::U32, true, false);
|
||||
return true;
|
||||
case O::S_CMP_EQ_U64:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::IEqual64, IR::Type::U64, true, false);
|
||||
return true;
|
||||
case O::S_CMP_LG_U64:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::INotEqual64, IR::Type::U64, true, false);
|
||||
return true;
|
||||
|
||||
case O::S_AND_B64:
|
||||
return S_U64_MASK(inst, IR::ValueOpcode::LogicalAnd, IR::ValueOpcode::BitwiseAnd32,
|
||||
false, false, false);
|
||||
case O::S_ANDN2_B64:
|
||||
return S_U64_MASK(inst, IR::ValueOpcode::LogicalAnd, IR::ValueOpcode::BitwiseAnd32,
|
||||
true, false, false);
|
||||
case O::S_OR_B64:
|
||||
return S_U64_MASK(inst, IR::ValueOpcode::LogicalOr, IR::ValueOpcode::BitwiseOr32, false,
|
||||
false, false);
|
||||
case O::S_ORN2_B64:
|
||||
return S_U64_MASK(inst, IR::ValueOpcode::LogicalOr, IR::ValueOpcode::BitwiseOr32, true,
|
||||
false, false);
|
||||
case O::S_XOR_B64:
|
||||
return S_U64_MASK(inst, IR::ValueOpcode::LogicalXor, IR::ValueOpcode::BitwiseXor32,
|
||||
false, false, false);
|
||||
case O::S_NAND_B64:
|
||||
return S_U64_MASK(inst, IR::ValueOpcode::LogicalAnd, IR::ValueOpcode::BitwiseAnd32,
|
||||
false, true, false);
|
||||
case O::S_NOR_B64:
|
||||
return S_U64_MASK(inst, IR::ValueOpcode::LogicalOr, IR::ValueOpcode::BitwiseOr32, false,
|
||||
true, false);
|
||||
case O::S_XNOR_B64:
|
||||
return S_U64_MASK(inst, IR::ValueOpcode::LogicalXor, IR::ValueOpcode::BitwiseXor32,
|
||||
false, true, false);
|
||||
case O::S_NOT_B64:
|
||||
return S_U64_MASK(inst, IR::ValueOpcode::LogicalAnd, IR::ValueOpcode::BitwiseAnd32,
|
||||
false, false, true);
|
||||
|
||||
case O::S_ABS_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::IAbs32, IR::Type::U32, false, false, true);
|
||||
case O::S_MUL_I32:
|
||||
case O::S_MULK_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::IMul32, IR::Type::U32, false, false, false);
|
||||
case O::S_MUL_HI_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::UMulHi, IR::Type::U32, false, false, false);
|
||||
case O::S_AND_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitwiseAnd32, IR::Type::U32, false, false,
|
||||
true);
|
||||
case O::S_OR_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitwiseOr32, IR::Type::U32, false, false,
|
||||
true);
|
||||
case O::S_XOR_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitwiseXor32, IR::Type::U32, false, false,
|
||||
true);
|
||||
case O::S_NOT_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitwiseNot32, IR::Type::U32, false, false,
|
||||
true);
|
||||
case O::S_BREV_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitReverse32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::S_BCNT1_I32_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitCount32, IR::Type::U32, false, false,
|
||||
true);
|
||||
case O::S_BCNT1_I32_B64:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitCount64, IR::Type::U64, false, false,
|
||||
true);
|
||||
case O::S_FF1_I32_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::FindILsb32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::S_LSHL_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftLeftLogical32, IR::Type::U32, false,
|
||||
true, true);
|
||||
case O::S_LSHR_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightLogical32, IR::Type::U32, false,
|
||||
true, true);
|
||||
case O::S_ASHR_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightArithmetic32, IR::Type::U32,
|
||||
false, true, true);
|
||||
case O::S_LSHL_B64:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftLeftLogical64, IR::Type::U64, false,
|
||||
false, true);
|
||||
case O::S_LSHR_B64:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightLogical64, IR::Type::U64, false,
|
||||
false, true);
|
||||
|
||||
case O::S_ANDN2_B32:
|
||||
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseAnd32, true, false, true);
|
||||
case O::S_ORN2_B32:
|
||||
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseOr32, true, false, true);
|
||||
case O::S_NAND_B32:
|
||||
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseAnd32, false, true, true);
|
||||
case O::S_NOR_B32:
|
||||
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseOr32, false, true, true);
|
||||
case O::S_XNOR_B32:
|
||||
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseXor32, false, true, true);
|
||||
case O::S_FF1_I32_B64: return S_FF1_I32_B64(inst);
|
||||
case O::S_FLBIT_I32_B64: return S_FLBIT_I32_B64(inst);
|
||||
|
||||
case O::S_BITSET0_B32: return S_BITSET_B32(inst, false);
|
||||
case O::S_BITSET1_B32: return S_BITSET_B32(inst, true);
|
||||
case O::S_BITREPLICATE_B64_B32: return S_BITREPLICATE_B64_B32(inst);
|
||||
case O::S_QUADMASK_B64: return S_QUADMASK_B64(inst);
|
||||
case O::S_BFM_B32: return BFM_B32(inst);
|
||||
case O::S_BFM_B64: return S_BFM_B64(inst);
|
||||
case O::S_BFE_U32: return S_BFE_U32(inst, false);
|
||||
case O::S_BFE_I32: return S_BFE_U32(inst, true);
|
||||
case O::S_BFE_U64: return S_BFE_U64(inst);
|
||||
case O::S_BITCMP0_B32: return S_BITCMP_B32(inst, false);
|
||||
case O::S_BITCMP1_B32: return S_BITCMP_B32(inst, true);
|
||||
case O::S_PACK_LL_B32_B16: return PackB16(inst, false, false);
|
||||
case O::S_PACK_LH_B32_B16: return PackB16(inst, false, true);
|
||||
case O::S_PACK_HH_B32_B16: return PackB16(inst, true, true);
|
||||
|
||||
case O::S_NOP:
|
||||
case O::S_SLEEP:
|
||||
case O::S_TRAP: EmitControlNop(); return true;
|
||||
case O::S_WAITCNT_DEPCTR: EmitWaitcnt(); return true;
|
||||
case O::S_BARRIER: S_BARRIER(); return true;
|
||||
case O::S_SENDMSG: S_SENDMSG(); return true;
|
||||
case O::S_TTRACEDATA: S_TTRACEDATA(); return true;
|
||||
case O::S_INST_PREFETCH: S_INST_PREFETCH(); return true;
|
||||
case O::S_BRANCH:
|
||||
case O::S_CBRANCH_SCC0:
|
||||
case O::S_CBRANCH_SCC1:
|
||||
case O::S_CBRANCH_VCCZ:
|
||||
case O::S_CBRANCH_VCCNZ:
|
||||
case O::S_CBRANCH_EXECZ:
|
||||
case O::S_CBRANCH_EXECNZ:
|
||||
case O::S_ENDPGM: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
@@ -75,24 +75,40 @@ private:
|
||||
IR::Value GetScalarAddressResource(uint32_t base);
|
||||
IR::Value GetImageResource(const IR::MemoryInfo& memory);
|
||||
IR::Value GetSamplerResource(const IR::MemoryInfo& memory);
|
||||
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(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::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);
|
||||
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);
|
||||
bool S_LOAD(const Decoder::Instruction& inst, bool raw);
|
||||
bool BUFFER_LOAD(const Decoder::Instruction& inst);
|
||||
bool BUFFER_STORE(const Decoder::Instruction& inst);
|
||||
bool BUFFER_ATOMIC(const Decoder::Instruction& inst, IR::ValueOpcode opcode);
|
||||
bool IMAGE_ATOMIC(const Decoder::Instruction& inst, IR::ValueOpcode opcode);
|
||||
bool DS_ATOMIC(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool returns_value);
|
||||
bool FLAT_LOAD(const Decoder::Instruction& inst);
|
||||
bool FLAT_STORE(const Decoder::Instruction& inst);
|
||||
bool IMAGE_GET_RESINFO(const Decoder::Instruction& inst);
|
||||
bool IMAGE_GET_LOD(const Decoder::Instruction& inst);
|
||||
bool IMAGE_LOAD(const Decoder::Instruction& inst);
|
||||
bool IMAGE_STORE(const Decoder::Instruction& inst);
|
||||
bool IMAGE_SAMPLE(const Decoder::Instruction& inst);
|
||||
bool IMAGE_GATHER(const Decoder::Instruction& inst);
|
||||
IR::Value LoadSharedU32(uint32_t width, IR::U32 address, const IR::MemoryInfo& memory,
|
||||
uint32_t pc);
|
||||
IR::Value ExtractSharedU32(IR::Value value, uint32_t width, uint32_t index);
|
||||
void WriteSharedU32(uint32_t width, IR::U32 address, const std::array<IR::Value, 4>& values,
|
||||
const IR::MemoryInfo& memory, uint32_t pc);
|
||||
bool DS_READ(const Decoder::Instruction& inst);
|
||||
bool DS_READ2(const Decoder::Instruction& inst);
|
||||
bool DS_WRITE(const Decoder::Instruction& inst);
|
||||
bool DS_WRITE2(const Decoder::Instruction& inst);
|
||||
bool DS_MINMAX_F32(const Decoder::Instruction& inst, IR::ValueOpcode opcode);
|
||||
bool DS_APPEND_CONSUME(const Decoder::Instruction& inst, IR::ValueOpcode opcode);
|
||||
bool DS_ADDTID(const Decoder::Instruction& inst, bool write);
|
||||
bool DS_SWIZZLE_B32(const Decoder::Instruction& inst);
|
||||
|
||||
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,27 +117,136 @@ private:
|
||||
float safe_upper, uint32_t lower_result,
|
||||
uint32_t upper_result);
|
||||
IR::U32 PackU16Lanes(IR::U32 low, IR::U32 high);
|
||||
void EmitCompareResult(const Decoder::Instruction& inst, IR::U1 value, bool scalar, bool cmpx);
|
||||
void EmitCompareConstant(const Decoder::Instruction& inst, bool value, bool scalar, bool cmpx);
|
||||
void EmitIntegerCompare(const Decoder::Instruction& inst, IR::ValueOpcode opcode, IR::Type type,
|
||||
bool scalar, bool cmpx);
|
||||
void EmitInteger16Compare(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool signed_value, bool cmpx);
|
||||
void EmitFloatCompare(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool half,
|
||||
bool cmpx);
|
||||
void EmitFloatOrderedCompare(const Decoder::Instruction& inst, bool ordered);
|
||||
void V_CMP_CLASS_F32(const Decoder::Instruction& inst);
|
||||
void V_CVT_F32_UBYTE(const Decoder::Instruction& inst, uint32_t byte_index);
|
||||
void V_CVT_F32_U32(const Decoder::Instruction& inst);
|
||||
void V_CVT_F32_I32(const Decoder::Instruction& inst);
|
||||
void V_CVT_U32_F32(const Decoder::Instruction& inst);
|
||||
void V_CVT_I32_F32(const Decoder::Instruction& inst);
|
||||
void V_CVT_F16_F32(const Decoder::Instruction& inst);
|
||||
void V_CVT_F32_F16(const Decoder::Instruction& inst);
|
||||
void V_CVT_F16_16(const Decoder::Instruction& inst, bool signed_value);
|
||||
void V_CVT_16_F16(const Decoder::Instruction& inst, bool signed_value);
|
||||
void V_CVT_RPI_I32_F32(const Decoder::Instruction& inst);
|
||||
void V_CVT_FLR_I32_F32(const Decoder::Instruction& inst);
|
||||
void V_FREXP_EXP_I32_F32(const Decoder::Instruction& inst);
|
||||
void V_CVT_OFF_F32_I4(const Decoder::Instruction& inst);
|
||||
void V_CVT_PKRTZ_F16_F32(const Decoder::Instruction& inst);
|
||||
void V_CVT_PKNORM_F32(const Decoder::Instruction& inst, IR::ValueOpcode opcode);
|
||||
void V_CVT_PK_U8_F32(const Decoder::Instruction& inst);
|
||||
void V_PACK_B32_F16(const Decoder::Instruction& inst);
|
||||
bool PackedFloat16(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool accumulator,
|
||||
bool quiet_snan);
|
||||
bool Float16Unary(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool invalid_negative);
|
||||
bool Float16Binary(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool reverse);
|
||||
bool Float16Ternary(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool accumulator,
|
||||
bool mix);
|
||||
bool FloatUnary(const Decoder::Instruction& inst, IR::ValueOpcode opcode);
|
||||
bool FloatBinary(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool reverse);
|
||||
bool FloatTernary(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool accumulator,
|
||||
bool mix);
|
||||
bool V_FREXP_MANT_F32(const Decoder::Instruction& inst);
|
||||
bool V_DOT2C_F32_F16(const Decoder::Instruction& inst);
|
||||
bool V_CUBEID_F32(const Decoder::Instruction& inst);
|
||||
bool V_CUBESC_F32(const Decoder::Instruction& inst);
|
||||
bool V_CUBETC_F32(const Decoder::Instruction& inst);
|
||||
bool V_CUBEMA_F32(const Decoder::Instruction& inst);
|
||||
bool FloatCube(const Decoder::Instruction& inst, uint32_t result_kind);
|
||||
bool Integer16Shift(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool arithmetic);
|
||||
bool Integer16Binary(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool sign);
|
||||
bool V_MED3_I16(const Decoder::Instruction& inst);
|
||||
bool PackedInteger16Shift(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool arithmetic);
|
||||
bool PackedInteger16Binary(const Decoder::Instruction& inst, IR::ValueOpcode opcode);
|
||||
bool PackedInteger16Mad(const Decoder::Instruction& inst, bool sign);
|
||||
bool PackedInteger16MinMax(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool sign);
|
||||
bool S_U64_MASK(const Decoder::Instruction& inst, IR::ValueOpcode logical_opcode,
|
||||
IR::ValueOpcode bit_opcode, bool negate_rhs, bool negate_result, bool unary);
|
||||
IR::U1 U64MaskBinary(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool negate_rhs,
|
||||
bool negate_result);
|
||||
bool SimpleInteger(const Decoder::Instruction& inst, IR::ValueOpcode opcode, IR::Type type,
|
||||
bool reverse, bool mask_shift_count, bool update_scc);
|
||||
bool ComposedIntegerBinary(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||
bool negate_rhs, bool negate_result, bool update_scc);
|
||||
bool V_AND_OR_B32(const Decoder::Instruction& inst);
|
||||
bool V_OR3_B32(const Decoder::Instruction& inst);
|
||||
bool V_XOR3_B32(const Decoder::Instruction& inst);
|
||||
bool S_FF1_I32_B64(const Decoder::Instruction& inst);
|
||||
bool V_FFBH_U32(const Decoder::Instruction& inst);
|
||||
bool S_FLBIT_I32_B64(const Decoder::Instruction& inst);
|
||||
bool Integer24(const Decoder::Instruction& inst, bool sign, bool addend);
|
||||
bool V_MAD_U64_U32(const Decoder::Instruction& inst);
|
||||
bool V_SAD_U32(const Decoder::Instruction& inst);
|
||||
bool V_ADD3_U32(const Decoder::Instruction& inst);
|
||||
bool S_BITSET_B32(const Decoder::Instruction& inst, bool set);
|
||||
bool V_BCNT_U32_B32(const Decoder::Instruction& inst);
|
||||
bool V_MBCNT_U32_B32(const Decoder::Instruction& inst, bool low);
|
||||
bool S_BITREPLICATE_B64_B32(const Decoder::Instruction& inst);
|
||||
bool S_QUADMASK_B64(const Decoder::Instruction& inst);
|
||||
bool BFM_B32(const Decoder::Instruction& inst);
|
||||
IR::U32 RightMask32(IR::U32 count);
|
||||
IR::U64 RightMask64(IR::U32 count);
|
||||
bool S_BFM_B64(const Decoder::Instruction& inst);
|
||||
bool S_BFE_U32(const Decoder::Instruction& inst, bool sign);
|
||||
bool S_BFE_U64(const Decoder::Instruction& inst);
|
||||
bool V_BFE_U32(const Decoder::Instruction& inst, bool sign);
|
||||
bool V_BFI_B32(const Decoder::Instruction& inst);
|
||||
bool S_BITCMP_B32(const Decoder::Instruction& inst, bool expected);
|
||||
bool V_ALIGNBIT_B32(const Decoder::Instruction& inst);
|
||||
bool V_ALIGNBYTE_B32(const Decoder::Instruction& inst);
|
||||
bool V_LSHL_ADD_U32(const Decoder::Instruction& inst);
|
||||
bool V_ADD_LSHL_U32(const Decoder::Instruction& inst);
|
||||
bool V_XAD_U32(const Decoder::Instruction& inst);
|
||||
bool V_LSHL_OR_B32(const Decoder::Instruction& inst);
|
||||
bool V_CNDMASK_B32(const Decoder::Instruction& inst);
|
||||
bool PackB16(const Decoder::Instruction& inst, bool high0, bool high1);
|
||||
|
||||
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);
|
||||
void S_SAVEEXEC(const Decoder::Instruction& inst, IR::ValueOpcode operation, bool negate_exec,
|
||||
bool negate_source, bool write_64);
|
||||
void ADD_U32(const Decoder::Instruction& inst, bool vector, bool use_carry_in);
|
||||
void SUB_U32(const Decoder::Instruction& inst, bool vector, bool reverse);
|
||||
void SUBB_U32(const Decoder::Instruction& inst, bool vector);
|
||||
void S_ADD_SUB_I32(const Decoder::Instruction& inst, bool subtract);
|
||||
void S_LSHL_ADD_U32(const Decoder::Instruction& inst, uint32_t shift_amount);
|
||||
void ScalarMinMax32(const Decoder::Instruction& inst, IR::ValueOpcode value_opcode,
|
||||
IR::ValueOpcode compare_opcode);
|
||||
void EmitControlNop();
|
||||
void EmitWaitcnt();
|
||||
void S_BARRIER();
|
||||
void S_SENDMSG();
|
||||
void S_TTRACEDATA();
|
||||
void S_INST_PREFETCH();
|
||||
bool S_GETPC_B64(const Decoder::Instruction& inst, std::string* error);
|
||||
void S_CSELECT_B32(const Decoder::Instruction& inst);
|
||||
void S_CSELECT_B64(const Decoder::Instruction& inst);
|
||||
void MOV_B32(const Decoder::Instruction& inst, bool apply_float_modifiers);
|
||||
void S_MOV_B64(const Decoder::Instruction& inst);
|
||||
void S_WQM_B64(const Decoder::Instruction& inst);
|
||||
bool V_MOVRELS_B32(const Decoder::Instruction& inst, std::string* error);
|
||||
bool V_MOVRELD_B32(const Decoder::Instruction& inst, std::string* error);
|
||||
void V_READFIRSTLANE_B32(const Decoder::Instruction& inst);
|
||||
void V_READLANE_B32(const Decoder::Instruction& inst);
|
||||
void V_WRITELANE_B32(const Decoder::Instruction& inst);
|
||||
void V_PERMLANE16_B32(const Decoder::Instruction& inst, bool x16);
|
||||
void V_INTERP_P1_F32();
|
||||
void V_INTERP_P2_F32(const Decoder::Instruction& inst);
|
||||
bool V_INTERP_MOV_F32(const Decoder::Instruction& inst, std::string* error);
|
||||
bool EXP(const Decoder::Instruction& inst, std::string* error);
|
||||
|
||||
bool EmitScalar(const Decoder::Instruction& inst, std::string* error);
|
||||
bool EmitVector(const Decoder::Instruction& inst, std::string* error);
|
||||
bool EmitInterpolation(const Decoder::Instruction& inst, std::string* error);
|
||||
bool EmitMemory(const Decoder::Instruction& inst, std::string* error);
|
||||
|
||||
IR::Program& program;
|
||||
IR::IREmitter ir;
|
||||
|
||||
@@ -0,0 +1,514 @@
|
||||
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
bool Translator::EmitVector(const Decoder::Instruction& inst, std::string* error) {
|
||||
using O = Decoder::Opcode;
|
||||
switch (inst.opcode) {
|
||||
case O::V_NOP: return true;
|
||||
case O::V_ADD_I32: ADD_U32(inst, true, false); return true;
|
||||
case O::V_ADDC_U32: ADD_U32(inst, true, true); return true;
|
||||
case O::V_SUB_I32: SUB_U32(inst, true, false); return true;
|
||||
case O::V_SUBREV_I32: SUB_U32(inst, true, true); return true;
|
||||
case O::V_SUBREV_CO_CI_U32: SUBB_U32(inst, true); return true;
|
||||
|
||||
case O::V_MOV_B32: MOV_B32(inst, true); return true;
|
||||
case O::V_MOVRELS_B32: return V_MOVRELS_B32(inst, error);
|
||||
case O::V_MOVRELD_B32: return V_MOVRELD_B32(inst, error);
|
||||
case O::V_READFIRSTLANE_B32: V_READFIRSTLANE_B32(inst); return true;
|
||||
case O::V_READLANE_B32: V_READLANE_B32(inst); return true;
|
||||
case O::V_WRITELANE_B32: V_WRITELANE_B32(inst); return true;
|
||||
case O::V_PERMLANE16_B32: V_PERMLANE16_B32(inst, false); return true;
|
||||
case O::V_PERMLANEX16_B32: V_PERMLANE16_B32(inst, true); return true;
|
||||
|
||||
case O::V_CMP_F_I32:
|
||||
case O::V_CMP_F_U32: EmitCompareConstant(inst, false, false, false); return true;
|
||||
case O::V_CMP_T_I32:
|
||||
case O::V_CMP_T_U32: EmitCompareConstant(inst, true, false, false); return true;
|
||||
case O::V_CMP_EQ_U32:
|
||||
case O::V_CMP_EQ_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::IEqual32, IR::Type::U32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_EQ_U32:
|
||||
case O::V_CMPX_EQ_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::IEqual32, IR::Type::U32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_NE_U32:
|
||||
case O::V_CMP_NE_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::INotEqual32, IR::Type::U32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_NE_U32:
|
||||
case O::V_CMPX_NE_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::INotEqual32, IR::Type::U32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_GT_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::UGreaterThan32, IR::Type::U32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_GT_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::UGreaterThan32, IR::Type::U32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_GE_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::UGreaterThanEqual32, IR::Type::U32, false,
|
||||
false);
|
||||
return true;
|
||||
case O::V_CMPX_GE_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::UGreaterThanEqual32, IR::Type::U32, false,
|
||||
true);
|
||||
return true;
|
||||
case O::V_CMP_LT_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::ULessThan32, IR::Type::U32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_LT_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::ULessThan32, IR::Type::U32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_LE_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::ULessThanEqual32, IR::Type::U32, false,
|
||||
false);
|
||||
return true;
|
||||
case O::V_CMPX_LE_U32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::ULessThanEqual32, IR::Type::U32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_GT_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SGreaterThan32, IR::Type::U32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_GT_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SGreaterThan32, IR::Type::U32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_GE_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SGreaterThanEqual32, IR::Type::U32, false,
|
||||
false);
|
||||
return true;
|
||||
case O::V_CMPX_GE_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SGreaterThanEqual32, IR::Type::U32, false,
|
||||
true);
|
||||
return true;
|
||||
case O::V_CMP_LT_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SLessThan32, IR::Type::U32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_LT_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SLessThan32, IR::Type::U32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_LE_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SLessThanEqual32, IR::Type::U32, false,
|
||||
false);
|
||||
return true;
|
||||
case O::V_CMPX_LE_I32:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::SLessThanEqual32, IR::Type::U32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_EQ_I64:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::IEqual64, IR::Type::U64, false, false);
|
||||
return true;
|
||||
case O::V_CMP_GT_U64:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::UGreaterThan64, IR::Type::U64, false, false);
|
||||
return true;
|
||||
case O::V_CMP_NE_U64:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::INotEqual64, IR::Type::U64, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_NE_I64:
|
||||
case O::V_CMPX_NE_U64:
|
||||
EmitIntegerCompare(inst, IR::ValueOpcode::INotEqual64, IR::Type::U64, false, true);
|
||||
return true;
|
||||
|
||||
case O::V_CMP_EQ_U16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::IEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMP_EQ_I16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::IEqual32, true, false);
|
||||
return true;
|
||||
case O::V_CMP_NE_U16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::INotEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMP_NE_I16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::INotEqual32, true, false);
|
||||
return true;
|
||||
case O::V_CMP_GT_U16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::UGreaterThan32, false, false);
|
||||
return true;
|
||||
case O::V_CMP_GE_U16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::UGreaterThanEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMP_LT_U16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::ULessThan32, false, false);
|
||||
return true;
|
||||
case O::V_CMP_LE_U16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::ULessThanEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMP_GT_I16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::SGreaterThan32, true, false);
|
||||
return true;
|
||||
case O::V_CMP_GE_I16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::SGreaterThanEqual32, true, false);
|
||||
return true;
|
||||
case O::V_CMP_LT_I16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::SLessThan32, true, false);
|
||||
return true;
|
||||
case O::V_CMP_LE_I16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::SLessThanEqual32, true, false);
|
||||
return true;
|
||||
|
||||
case O::V_CMP_F_F32: EmitCompareConstant(inst, false, false, false); return true;
|
||||
case O::V_CMP_TRU_F32: EmitCompareConstant(inst, true, false, false); return true;
|
||||
case O::V_CMP_EQ_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_EQ_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdEqual32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_LG_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdNotEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_LG_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdNotEqual32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_GT_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdGreaterThan32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_GT_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdGreaterThan32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_GE_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdGreaterThanEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_GE_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdGreaterThanEqual32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_LT_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdLessThan32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_LT_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdLessThan32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_LE_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdLessThanEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_LE_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdLessThanEqual32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_NLG_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_NLG_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordEqual32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_NEQ_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordNotEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_NEQ_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordNotEqual32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_NLE_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordGreaterThan32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_NLE_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordGreaterThan32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_NLT_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordGreaterThanEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_NLT_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordGreaterThanEqual32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_NGE_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordLessThan32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_NGE_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordLessThan32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_NGT_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordLessThanEqual32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_NGT_F32:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordLessThanEqual32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_EQ_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdEqual32, true, false);
|
||||
return true;
|
||||
case O::V_CMPX_EQ_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdEqual32, true, true);
|
||||
return true;
|
||||
case O::V_CMP_LG_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdNotEqual32, true, false);
|
||||
return true;
|
||||
case O::V_CMP_GT_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdGreaterThan32, true, false);
|
||||
return true;
|
||||
case O::V_CMPX_GT_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdGreaterThan32, true, true);
|
||||
return true;
|
||||
case O::V_CMP_GE_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdGreaterThanEqual32, true, false);
|
||||
return true;
|
||||
case O::V_CMPX_GE_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdGreaterThanEqual32, true, true);
|
||||
return true;
|
||||
case O::V_CMP_LT_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdLessThan32, true, false);
|
||||
return true;
|
||||
case O::V_CMPX_LT_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdLessThan32, true, true);
|
||||
return true;
|
||||
case O::V_CMP_LE_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdLessThanEqual32, true, false);
|
||||
return true;
|
||||
case O::V_CMPX_LE_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdLessThanEqual32, true, true);
|
||||
return true;
|
||||
case O::V_CMP_NEQ_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordNotEqual32, true, false);
|
||||
return true;
|
||||
case O::V_CMPX_NEQ_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordNotEqual32, true, true);
|
||||
return true;
|
||||
case O::V_CMPX_NLT_F16:
|
||||
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordGreaterThanEqual32, true, true);
|
||||
return true;
|
||||
case O::V_CMP_O_F32: EmitFloatOrderedCompare(inst, true); return true;
|
||||
case O::V_CMP_U_F32: EmitFloatOrderedCompare(inst, false); return true;
|
||||
case O::V_CMP_CLASS_F32: V_CMP_CLASS_F32(inst); return true;
|
||||
|
||||
case O::V_CVT_F32_UBYTE0: V_CVT_F32_UBYTE(inst, 0); return true;
|
||||
case O::V_CVT_F32_UBYTE1: V_CVT_F32_UBYTE(inst, 1); return true;
|
||||
case O::V_CVT_F32_UBYTE2: V_CVT_F32_UBYTE(inst, 2); return true;
|
||||
case O::V_CVT_F32_UBYTE3: V_CVT_F32_UBYTE(inst, 3); return true;
|
||||
case O::V_CVT_F32_U32: V_CVT_F32_U32(inst); return true;
|
||||
case O::V_CVT_F32_I32: V_CVT_F32_I32(inst); return true;
|
||||
case O::V_CVT_U32_F32: V_CVT_U32_F32(inst); return true;
|
||||
case O::V_CVT_I32_F32: V_CVT_I32_F32(inst); return true;
|
||||
case O::V_CVT_F16_F32: V_CVT_F16_F32(inst); return true;
|
||||
case O::V_CVT_F32_F16: V_CVT_F32_F16(inst); return true;
|
||||
case O::V_CVT_F16_U16: V_CVT_F16_16(inst, false); return true;
|
||||
case O::V_CVT_F16_I16: V_CVT_F16_16(inst, true); return true;
|
||||
case O::V_CVT_U16_F16: V_CVT_16_F16(inst, false); return true;
|
||||
case O::V_CVT_I16_F16: V_CVT_16_F16(inst, true); return true;
|
||||
case O::V_CVT_RPI_I32_F32: V_CVT_RPI_I32_F32(inst); return true;
|
||||
case O::V_CVT_FLR_I32_F32: V_CVT_FLR_I32_F32(inst); return true;
|
||||
case O::V_FREXP_EXP_I32_F32: V_FREXP_EXP_I32_F32(inst); return true;
|
||||
case O::V_CVT_OFF_F32_I4: V_CVT_OFF_F32_I4(inst); return true;
|
||||
case O::V_CVT_PKRTZ_F16_F32: V_CVT_PKRTZ_F16_F32(inst); return true;
|
||||
case O::V_CVT_PKNORM_I16_F32:
|
||||
V_CVT_PKNORM_F32(inst, IR::ValueOpcode::PackSnorm2x16);
|
||||
return true;
|
||||
case O::V_CVT_PKNORM_U16_F32:
|
||||
V_CVT_PKNORM_F32(inst, IR::ValueOpcode::PackUnorm2x16);
|
||||
return true;
|
||||
case O::V_CVT_PK_U8_F32: V_CVT_PK_U8_F32(inst); return true;
|
||||
case O::V_PACK_B32_F16: V_PACK_B32_F16(inst); return true;
|
||||
case O::V_CVT_PK_U16_U32:
|
||||
case O::V_CVT_PK_I16_I32: return PackB16(inst, false, false);
|
||||
|
||||
case O::V_LSHLREV_B16:
|
||||
return Integer16Shift(inst, IR::ValueOpcode::ShiftLeftLogical32, false);
|
||||
case O::V_LSHRREV_B16:
|
||||
return Integer16Shift(inst, IR::ValueOpcode::ShiftRightLogical32, false);
|
||||
case O::V_ASHRREV_I16:
|
||||
return Integer16Shift(inst, IR::ValueOpcode::ShiftRightArithmetic32, true);
|
||||
case O::V_ADD_NC_U16:
|
||||
case O::V_ADD_NC_I16: return Integer16Binary(inst, IR::ValueOpcode::IAdd32, false);
|
||||
case O::V_SUB_NC_U16:
|
||||
case O::V_SUB_NC_I16: return Integer16Binary(inst, IR::ValueOpcode::ISub32, false);
|
||||
case O::V_MED3_I16: return V_MED3_I16(inst);
|
||||
case O::V_MIN_I16: return Integer16Binary(inst, IR::ValueOpcode::SMin32, true);
|
||||
case O::V_MAX_I16: return Integer16Binary(inst, IR::ValueOpcode::SMax32, true);
|
||||
case O::V_MIN_U16: return Integer16Binary(inst, IR::ValueOpcode::UMin32, false);
|
||||
case O::V_MAX_U16: return Integer16Binary(inst, IR::ValueOpcode::UMax32, false);
|
||||
|
||||
case O::V_PK_LSHLREV_B16:
|
||||
return PackedInteger16Shift(inst, IR::ValueOpcode::ShiftLeftLogical32, false);
|
||||
case O::V_PK_LSHRREV_B16:
|
||||
return PackedInteger16Shift(inst, IR::ValueOpcode::ShiftRightLogical32, false);
|
||||
case O::V_PK_ASHRREV_I16:
|
||||
return PackedInteger16Shift(inst, IR::ValueOpcode::ShiftRightArithmetic32, true);
|
||||
case O::V_PK_MAD_I16: return PackedInteger16Mad(inst, true);
|
||||
case O::V_PK_MAD_U16: return PackedInteger16Mad(inst, false);
|
||||
case O::V_PK_MUL_LO_U16: return PackedInteger16Binary(inst, IR::ValueOpcode::IMul32);
|
||||
case O::V_PK_ADD_I16:
|
||||
case O::V_PK_ADD_U16: return PackedInteger16Binary(inst, IR::ValueOpcode::IAdd32);
|
||||
case O::V_PK_SUB_I16:
|
||||
case O::V_PK_SUB_U16: return PackedInteger16Binary(inst, IR::ValueOpcode::ISub32);
|
||||
case O::V_PK_MAX_I16: return PackedInteger16MinMax(inst, IR::ValueOpcode::SMax32, true);
|
||||
case O::V_PK_MIN_I16: return PackedInteger16MinMax(inst, IR::ValueOpcode::SMin32, true);
|
||||
case O::V_PK_MAX_U16: return PackedInteger16MinMax(inst, IR::ValueOpcode::UMax32, false);
|
||||
case O::V_PK_MIN_U16: return PackedInteger16MinMax(inst, IR::ValueOpcode::UMin32, false);
|
||||
|
||||
case O::V_PK_ADD_F16: return PackedFloat16(inst, IR::ValueOpcode::FPAdd32, false, false);
|
||||
case O::V_PK_MUL_F16: return PackedFloat16(inst, IR::ValueOpcode::FPMul32, false, false);
|
||||
case O::V_PK_MIN_F16: return PackedFloat16(inst, IR::ValueOpcode::FPMin32, false, true);
|
||||
case O::V_PK_MAX_F16: return PackedFloat16(inst, IR::ValueOpcode::FPMax32, false, true);
|
||||
case O::V_PK_FMA_F16: return PackedFloat16(inst, IR::ValueOpcode::FPFma32, false, false);
|
||||
case O::V_PK_FMAC_F16: return PackedFloat16(inst, IR::ValueOpcode::FPFma32, true, false);
|
||||
|
||||
case O::V_ADD_F16: return Float16Binary(inst, IR::ValueOpcode::FPAdd32, false);
|
||||
case O::V_SUB_F16: return Float16Binary(inst, IR::ValueOpcode::FPSub32, false);
|
||||
case O::V_SUBREV_F16: return Float16Binary(inst, IR::ValueOpcode::FPSub32, true);
|
||||
case O::V_MUL_F16: return Float16Binary(inst, IR::ValueOpcode::FPMul32, false);
|
||||
case O::V_MIN_F16: return Float16Binary(inst, IR::ValueOpcode::FPMin32, false);
|
||||
case O::V_MAX_F16: return Float16Binary(inst, IR::ValueOpcode::FPMax32, false);
|
||||
case O::V_FMAC_F16: return Float16Ternary(inst, IR::ValueOpcode::FPFma32, true, false);
|
||||
case O::V_FMAMK_F16:
|
||||
case O::V_FMAAK_F16:
|
||||
case O::V_FMA_F16: return Float16Ternary(inst, IR::ValueOpcode::FPFma32, false, false);
|
||||
case O::V_MAD_MIXLO_F16:
|
||||
case O::V_MAD_MIXHI_F16: return Float16Ternary(inst, IR::ValueOpcode::FPFma32, false, true);
|
||||
case O::V_RCP_F16: return Float16Unary(inst, IR::ValueOpcode::FPRecip32, false);
|
||||
case O::V_SQRT_F16: return Float16Unary(inst, IR::ValueOpcode::FPSqrt, true);
|
||||
case O::V_RSQ_F16: return Float16Unary(inst, IR::ValueOpcode::FPRecipSqrt32, true);
|
||||
case O::V_LOG_F16: return Float16Unary(inst, IR::ValueOpcode::FPLog2, true);
|
||||
case O::V_EXP_F16: return Float16Unary(inst, IR::ValueOpcode::FPExp2, false);
|
||||
case O::V_FLOOR_F16: return Float16Unary(inst, IR::ValueOpcode::FPFloor32, false);
|
||||
case O::V_CEIL_F16: return Float16Unary(inst, IR::ValueOpcode::FPCeil32, false);
|
||||
case O::V_TRUNC_F16: return Float16Unary(inst, IR::ValueOpcode::FPTrunc32, false);
|
||||
case O::V_RNDNE_F16: return Float16Unary(inst, IR::ValueOpcode::FPRoundEven32, false);
|
||||
case O::V_MIN3_F16: return Float16Ternary(inst, IR::ValueOpcode::FPMinTri32, false, false);
|
||||
case O::V_MAX3_F16: return Float16Ternary(inst, IR::ValueOpcode::FPMaxTri32, false, false);
|
||||
case O::V_MED3_F16: return Float16Ternary(inst, IR::ValueOpcode::FPMedTri32, false, false);
|
||||
|
||||
case O::V_FREXP_MANT_F32: return V_FREXP_MANT_F32(inst);
|
||||
case O::V_RCP_F32: return FloatUnary(inst, IR::ValueOpcode::FPRecip32);
|
||||
case O::V_RCP_IFLAG_F32: return FloatUnary(inst, IR::ValueOpcode::FPRecipIFlag32);
|
||||
case O::V_FRACT_F32: return FloatUnary(inst, IR::ValueOpcode::FPFract32);
|
||||
case O::V_TRUNC_F32: return FloatUnary(inst, IR::ValueOpcode::FPTrunc32);
|
||||
case O::V_CEIL_F32: return FloatUnary(inst, IR::ValueOpcode::FPCeil32);
|
||||
case O::V_RNDNE_F32: return FloatUnary(inst, IR::ValueOpcode::FPRoundEven32);
|
||||
case O::V_FLOOR_F32: return FloatUnary(inst, IR::ValueOpcode::FPFloor32);
|
||||
case O::V_EXP_F32: return FloatUnary(inst, IR::ValueOpcode::FPExp2);
|
||||
case O::V_LOG_F32: return FloatUnary(inst, IR::ValueOpcode::FPLog2);
|
||||
case O::V_RSQ_F32: return FloatUnary(inst, IR::ValueOpcode::FPRecipSqrt32);
|
||||
case O::V_SQRT_F32: return FloatUnary(inst, IR::ValueOpcode::FPSqrt);
|
||||
case O::V_SIN_F32: return FloatUnary(inst, IR::ValueOpcode::FPSin);
|
||||
case O::V_COS_F32: return FloatUnary(inst, IR::ValueOpcode::FPCos);
|
||||
case O::V_ADD_F32: return FloatBinary(inst, IR::ValueOpcode::FPAdd32, false);
|
||||
case O::V_SUB_F32: return FloatBinary(inst, IR::ValueOpcode::FPSub32, false);
|
||||
case O::V_SUBREV_F32: return FloatBinary(inst, IR::ValueOpcode::FPSub32, true);
|
||||
case O::V_MUL_F32: return FloatBinary(inst, IR::ValueOpcode::FPMul32, false);
|
||||
case O::V_MIN_F32: return FloatBinary(inst, IR::ValueOpcode::FPMin32, false);
|
||||
case O::V_MAX_F32: return FloatBinary(inst, IR::ValueOpcode::FPMax32, false);
|
||||
case O::V_LDEXP_F32: return FloatBinary(inst, IR::ValueOpcode::FPLdexp, false);
|
||||
case O::V_MAC_F32: return FloatTernary(inst, IR::ValueOpcode::FPFma32, true, true);
|
||||
case O::V_MADMK_F32:
|
||||
case O::V_MADAK_F32:
|
||||
case O::V_MAD_F32:
|
||||
case O::V_FMA_F32: return FloatTernary(inst, IR::ValueOpcode::FPFma32, false, true);
|
||||
case O::V_MIN3_F32: return FloatTernary(inst, IR::ValueOpcode::FPMinTri32, false, false);
|
||||
case O::V_MAX3_F32: return FloatTernary(inst, IR::ValueOpcode::FPMaxTri32, false, false);
|
||||
case O::V_MED3_F32: return FloatTernary(inst, IR::ValueOpcode::FPMedTri32, false, false);
|
||||
case O::V_DOT2C_F32_F16: return V_DOT2C_F32_F16(inst);
|
||||
case O::V_CUBEID_F32: return V_CUBEID_F32(inst);
|
||||
case O::V_CUBESC_F32: return V_CUBESC_F32(inst);
|
||||
case O::V_CUBETC_F32: return V_CUBETC_F32(inst);
|
||||
case O::V_CUBEMA_F32: return V_CUBEMA_F32(inst);
|
||||
|
||||
case O::V_MUL_LO_U32:
|
||||
case O::V_MUL_LO_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::IMul32, IR::Type::U32, false, false, false);
|
||||
case O::V_MUL_HI_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::UMulHi, IR::Type::U32, false, false, false);
|
||||
case O::V_MUL_HI_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::SMulHi, IR::Type::U32, false, false, false);
|
||||
case O::V_ADD_NC_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::IAdd32, IR::Type::U32, false, false, false);
|
||||
case O::V_SUB_NC_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ISub32, IR::Type::U32, false, false, false);
|
||||
case O::V_SUBREV_NC_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ISub32, IR::Type::U32, true, false, false);
|
||||
case O::V_MIN_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::SMin32, IR::Type::U32, false, false, false);
|
||||
case O::V_MAX_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::SMax32, IR::Type::U32, false, false, false);
|
||||
case O::V_MIN_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::UMin32, IR::Type::U32, false, false, false);
|
||||
case O::V_MAX_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::UMax32, IR::Type::U32, false, false, false);
|
||||
case O::V_MIN3_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::SMinTri32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_MAX3_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::SMaxTri32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_MED3_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::SMedTri32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_MIN3_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::UMinTri32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_MAX3_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::UMaxTri32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_MED3_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::UMedTri32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_AND_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitwiseAnd32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_OR_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitwiseOr32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_XOR_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitwiseXor32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_NOT_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitwiseNot32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_BFREV_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitReverse32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_FFBL_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::FindILsb32, IR::Type::U32, false, false,
|
||||
false);
|
||||
case O::V_LSHL_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftLeftLogical32, IR::Type::U32, false,
|
||||
true, false);
|
||||
case O::V_LSHLREV_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftLeftLogical32, IR::Type::U32, true,
|
||||
true, false);
|
||||
case O::V_LSHR_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightLogical32, IR::Type::U32, false,
|
||||
true, false);
|
||||
case O::V_LSHRREV_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightLogical32, IR::Type::U32, true,
|
||||
true, false);
|
||||
case O::V_ASHR_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightArithmetic32, IR::Type::U32,
|
||||
false, true, false);
|
||||
case O::V_ASHRREV_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightArithmetic32, IR::Type::U32, true,
|
||||
true, false);
|
||||
case O::V_LSHLREV_B64:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftLeftLogical64, IR::Type::U64, true,
|
||||
false, false);
|
||||
case O::V_LSHRREV_B64:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightLogical64, IR::Type::U64, true,
|
||||
false, false);
|
||||
|
||||
case O::V_XNOR_B32:
|
||||
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseXor32, false, true, false);
|
||||
case O::V_AND_OR_B32: return V_AND_OR_B32(inst);
|
||||
case O::V_OR3_B32: return V_OR3_B32(inst);
|
||||
case O::V_XOR3_B32: return V_XOR3_B32(inst);
|
||||
case O::V_FFBH_U32: return V_FFBH_U32(inst);
|
||||
|
||||
case O::V_MAD_I32_I24: return Integer24(inst, true, true);
|
||||
case O::V_MAD_U32_U24: return Integer24(inst, false, true);
|
||||
case O::V_MUL_I32_I24: return Integer24(inst, true, false);
|
||||
case O::V_MUL_U32_U24: return Integer24(inst, false, false);
|
||||
case O::V_MAD_U64_U32: return V_MAD_U64_U32(inst);
|
||||
case O::V_SAD_U32: return V_SAD_U32(inst);
|
||||
case O::V_ADD3_U32: return V_ADD3_U32(inst);
|
||||
case O::V_BCNT_U32_B32: return V_BCNT_U32_B32(inst);
|
||||
case O::V_MBCNT_LO_U32_B32: return V_MBCNT_U32_B32(inst, true);
|
||||
case O::V_MBCNT_HI_U32_B32: return V_MBCNT_U32_B32(inst, false);
|
||||
case O::V_BFM_B32: return BFM_B32(inst);
|
||||
case O::V_BFE_U32: return V_BFE_U32(inst, false);
|
||||
case O::V_BFE_I32: return V_BFE_U32(inst, true);
|
||||
case O::V_BFI_B32: return V_BFI_B32(inst);
|
||||
case O::V_ALIGNBIT_B32: return V_ALIGNBIT_B32(inst);
|
||||
case O::V_ALIGNBYTE_B32: return V_ALIGNBYTE_B32(inst);
|
||||
case O::V_LSHL_ADD_U32: return V_LSHL_ADD_U32(inst);
|
||||
case O::V_ADD_LSHL_U32: return V_ADD_LSHL_U32(inst);
|
||||
case O::V_XAD_U32: return V_XAD_U32(inst);
|
||||
case O::V_LSHL_OR_B32: return V_LSHL_OR_B32(inst);
|
||||
case O::V_CNDMASK_B32: return V_CNDMASK_B32(inst);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||
Reference in New Issue
Block a user