shader_ir: Separate float-point comparisons in ordered and unordered
This allows us to use native SPIR-V instructions without having to manually check for NAN.
This commit is contained in:
parent
1121960f0e
commit
4e57f9d5cf
|
@ -168,18 +168,22 @@ enum class Pred : u64 {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class PredCondition : u64 {
|
enum class PredCondition : u64 {
|
||||||
LessThan = 1,
|
F = 0, // Always false
|
||||||
Equal = 2,
|
LT = 1, // Ordered less than
|
||||||
LessEqual = 3,
|
EQ = 2, // Ordered equal
|
||||||
GreaterThan = 4,
|
LE = 3, // Ordered less than or equal
|
||||||
NotEqual = 5,
|
GT = 4, // Ordered greater than
|
||||||
GreaterEqual = 6,
|
NE = 5, // Ordered not equal
|
||||||
LessThanWithNan = 9,
|
GE = 6, // Ordered greater than or equal
|
||||||
LessEqualWithNan = 11,
|
NUM = 7, // Ordered
|
||||||
GreaterThanWithNan = 12,
|
NAN_ = 8, // Unordered
|
||||||
NotEqualWithNan = 13,
|
LTU = 9, // Unordered less than
|
||||||
GreaterEqualWithNan = 14,
|
EQU = 10, // Unordered equal
|
||||||
// TODO(Subv): Other condition types
|
LEU = 11, // Unordered less than or equal
|
||||||
|
GTU = 12, // Unordered greater than
|
||||||
|
NEU = 13, // Unordered not equal
|
||||||
|
GEU = 14, // Unordered greater than or equal
|
||||||
|
T = 15, // Always true
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class PredOperation : u64 {
|
enum class PredOperation : u64 {
|
||||||
|
|
|
@ -1840,34 +1840,31 @@ private:
|
||||||
Type::HalfFloat};
|
Type::HalfFloat};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Type type>
|
template <const std::string_view& op, Type type, bool unordered = false>
|
||||||
Expression LogicalLessThan(Operation operation) {
|
Expression Comparison(Operation operation) {
|
||||||
return GenerateBinaryInfix(operation, "<", Type::Bool, type, type);
|
static_assert(!unordered || type == Type::Float);
|
||||||
|
|
||||||
|
const Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type);
|
||||||
|
if constexpr (!unordered) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
// Unordered comparisons are always true for NaN operands.
|
||||||
|
return {fmt::format("({} || isnan({}) || isnan({}))", expr.AsBool(),
|
||||||
|
VisitOperand(operation, 0).AsFloat(),
|
||||||
|
VisitOperand(operation, 1).AsFloat()),
|
||||||
|
Type::Bool};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Type type>
|
Expression FOrdered(Operation operation) {
|
||||||
Expression LogicalEqual(Operation operation) {
|
return {fmt::format("(!isnan({}) && !isnan({}))", VisitOperand(operation, 0).AsFloat(),
|
||||||
return GenerateBinaryInfix(operation, "==", Type::Bool, type, type);
|
VisitOperand(operation, 1).AsFloat()),
|
||||||
|
Type::Bool};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Type type>
|
Expression FUnordered(Operation operation) {
|
||||||
Expression LogicalLessEqual(Operation operation) {
|
return {fmt::format("(isnan({}) || isnan({}))", VisitOperand(operation, 0).AsFloat(),
|
||||||
return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type);
|
VisitOperand(operation, 1).AsFloat()),
|
||||||
}
|
Type::Bool};
|
||||||
|
|
||||||
template <Type type>
|
|
||||||
Expression LogicalGreaterThan(Operation operation) {
|
|
||||||
return GenerateBinaryInfix(operation, ">", Type::Bool, type, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <Type type>
|
|
||||||
Expression LogicalNotEqual(Operation operation) {
|
|
||||||
return GenerateBinaryInfix(operation, "!=", Type::Bool, type, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <Type type>
|
|
||||||
Expression LogicalGreaterEqual(Operation operation) {
|
|
||||||
return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression LogicalAddCarry(Operation operation) {
|
Expression LogicalAddCarry(Operation operation) {
|
||||||
|
@ -2324,6 +2321,13 @@ private:
|
||||||
Func() = delete;
|
Func() = delete;
|
||||||
~Func() = delete;
|
~Func() = delete;
|
||||||
|
|
||||||
|
static constexpr std::string_view LessThan = "<";
|
||||||
|
static constexpr std::string_view Equal = "==";
|
||||||
|
static constexpr std::string_view LessEqual = "<=";
|
||||||
|
static constexpr std::string_view GreaterThan = ">";
|
||||||
|
static constexpr std::string_view NotEqual = "!=";
|
||||||
|
static constexpr std::string_view GreaterEqual = ">=";
|
||||||
|
|
||||||
static constexpr std::string_view Add = "Add";
|
static constexpr std::string_view Add = "Add";
|
||||||
static constexpr std::string_view Min = "Min";
|
static constexpr std::string_view Min = "Min";
|
||||||
static constexpr std::string_view Max = "Max";
|
static constexpr std::string_view Max = "Max";
|
||||||
|
@ -2425,27 +2429,34 @@ private:
|
||||||
&GLSLDecompiler::LogicalPick2,
|
&GLSLDecompiler::LogicalPick2,
|
||||||
&GLSLDecompiler::LogicalAnd2,
|
&GLSLDecompiler::LogicalAnd2,
|
||||||
|
|
||||||
&GLSLDecompiler::LogicalLessThan<Type::Float>,
|
&GLSLDecompiler::Comparison<Func::LessThan, Type::Float, false>,
|
||||||
&GLSLDecompiler::LogicalEqual<Type::Float>,
|
&GLSLDecompiler::Comparison<Func::Equal, Type::Float, false>,
|
||||||
&GLSLDecompiler::LogicalLessEqual<Type::Float>,
|
&GLSLDecompiler::Comparison<Func::LessEqual, Type::Float, false>,
|
||||||
&GLSLDecompiler::LogicalGreaterThan<Type::Float>,
|
&GLSLDecompiler::Comparison<Func::GreaterThan, Type::Float, false>,
|
||||||
&GLSLDecompiler::LogicalNotEqual<Type::Float>,
|
&GLSLDecompiler::Comparison<Func::NotEqual, Type::Float, false>,
|
||||||
&GLSLDecompiler::LogicalGreaterEqual<Type::Float>,
|
&GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Float, false>,
|
||||||
&GLSLDecompiler::LogicalFIsNan,
|
&GLSLDecompiler::FOrdered,
|
||||||
|
&GLSLDecompiler::FUnordered,
|
||||||
|
&GLSLDecompiler::Comparison<Func::LessThan, Type::Float, true>,
|
||||||
|
&GLSLDecompiler::Comparison<Func::Equal, Type::Float, true>,
|
||||||
|
&GLSLDecompiler::Comparison<Func::LessEqual, Type::Float, true>,
|
||||||
|
&GLSLDecompiler::Comparison<Func::GreaterThan, Type::Float, true>,
|
||||||
|
&GLSLDecompiler::Comparison<Func::NotEqual, Type::Float, true>,
|
||||||
|
&GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Float, true>,
|
||||||
|
|
||||||
&GLSLDecompiler::LogicalLessThan<Type::Int>,
|
&GLSLDecompiler::Comparison<Func::LessThan, Type::Int>,
|
||||||
&GLSLDecompiler::LogicalEqual<Type::Int>,
|
&GLSLDecompiler::Comparison<Func::Equal, Type::Int>,
|
||||||
&GLSLDecompiler::LogicalLessEqual<Type::Int>,
|
&GLSLDecompiler::Comparison<Func::LessEqual, Type::Int>,
|
||||||
&GLSLDecompiler::LogicalGreaterThan<Type::Int>,
|
&GLSLDecompiler::Comparison<Func::GreaterThan, Type::Int>,
|
||||||
&GLSLDecompiler::LogicalNotEqual<Type::Int>,
|
&GLSLDecompiler::Comparison<Func::NotEqual, Type::Int>,
|
||||||
&GLSLDecompiler::LogicalGreaterEqual<Type::Int>,
|
&GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Int>,
|
||||||
|
|
||||||
&GLSLDecompiler::LogicalLessThan<Type::Uint>,
|
&GLSLDecompiler::Comparison<Func::LessThan, Type::Uint>,
|
||||||
&GLSLDecompiler::LogicalEqual<Type::Uint>,
|
&GLSLDecompiler::Comparison<Func::Equal, Type::Uint>,
|
||||||
&GLSLDecompiler::LogicalLessEqual<Type::Uint>,
|
&GLSLDecompiler::Comparison<Func::LessEqual, Type::Uint>,
|
||||||
&GLSLDecompiler::LogicalGreaterThan<Type::Uint>,
|
&GLSLDecompiler::Comparison<Func::GreaterThan, Type::Uint>,
|
||||||
&GLSLDecompiler::LogicalNotEqual<Type::Uint>,
|
&GLSLDecompiler::Comparison<Func::NotEqual, Type::Uint>,
|
||||||
&GLSLDecompiler::LogicalGreaterEqual<Type::Uint>,
|
&GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Uint>,
|
||||||
|
|
||||||
&GLSLDecompiler::LogicalAddCarry,
|
&GLSLDecompiler::LogicalAddCarry,
|
||||||
|
|
||||||
|
|
|
@ -1618,6 +1618,24 @@ private:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression LogicalFOrdered(Operation operation) {
|
||||||
|
// Emulate SPIR-V's OpOrdered
|
||||||
|
const Id op_a = AsFloat(Visit(operation[0]));
|
||||||
|
const Id op_b = AsFloat(Visit(operation[1]));
|
||||||
|
const Id is_num_a = OpFOrdEqual(t_bool, op_a, op_a);
|
||||||
|
const Id is_num_b = OpFOrdEqual(t_bool, op_b, op_b);
|
||||||
|
return {OpLogicalAnd(t_bool, is_num_a, is_num_b), Type::Bool};
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression LogicalFUnordered(Operation operation) {
|
||||||
|
// Emulate SPIR-V's OpUnordered
|
||||||
|
const Id op_a = AsFloat(Visit(operation[0]));
|
||||||
|
const Id op_b = AsFloat(Visit(operation[1]));
|
||||||
|
const Id is_nan_a = OpIsNan(t_bool, op_a);
|
||||||
|
const Id is_nan_b = OpIsNan(t_bool, op_b);
|
||||||
|
return {OpLogicalOr(t_bool, is_nan_a, is_nan_b), Type::Bool};
|
||||||
|
}
|
||||||
|
|
||||||
Id GetTextureSampler(Operation operation) {
|
Id GetTextureSampler(Operation operation) {
|
||||||
const auto& meta = std::get<MetaTexture>(operation.GetMeta());
|
const auto& meta = std::get<MetaTexture>(operation.GetMeta());
|
||||||
ASSERT(!meta.sampler.is_buffer);
|
ASSERT(!meta.sampler.is_buffer);
|
||||||
|
@ -2511,7 +2529,14 @@ private:
|
||||||
&SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::Float>,
|
&SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::Float>,
|
||||||
&SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, Type::Bool, Type::Float>,
|
&SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, Type::Bool, Type::Float>,
|
||||||
&SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThanEqual, Type::Bool, Type::Float>,
|
&SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThanEqual, Type::Bool, Type::Float>,
|
||||||
&SPIRVDecompiler::Unary<&Module::OpIsNan, Type::Bool, Type::Float>,
|
&SPIRVDecompiler::LogicalFOrdered,
|
||||||
|
&SPIRVDecompiler::LogicalFUnordered,
|
||||||
|
&SPIRVDecompiler::Binary<&Module::OpFUnordLessThan, Type::Bool, Type::Float>,
|
||||||
|
&SPIRVDecompiler::Binary<&Module::OpFUnordEqual, Type::Bool, Type::Float>,
|
||||||
|
&SPIRVDecompiler::Binary<&Module::OpFUnordLessThanEqual, Type::Bool, Type::Float>,
|
||||||
|
&SPIRVDecompiler::Binary<&Module::OpFUnordGreaterThan, Type::Bool, Type::Float>,
|
||||||
|
&SPIRVDecompiler::Binary<&Module::OpFUnordNotEqual, Type::Bool, Type::Float>,
|
||||||
|
&SPIRVDecompiler::Binary<&Module::OpFUnordGreaterThanEqual, Type::Bool, Type::Float>,
|
||||||
|
|
||||||
&SPIRVDecompiler::Binary<&Module::OpSLessThan, Type::Bool, Type::Int>,
|
&SPIRVDecompiler::Binary<&Module::OpSLessThan, Type::Bool, Type::Int>,
|
||||||
&SPIRVDecompiler::Binary<&Module::OpIEqual, Type::Bool, Type::Int>,
|
&SPIRVDecompiler::Binary<&Module::OpIEqual, Type::Bool, Type::Int>,
|
||||||
|
|
|
@ -255,7 +255,7 @@ void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) {
|
||||||
Node n = Operation(OperationCode::Branch, Immediate(branch_case.address));
|
Node n = Operation(OperationCode::Branch, Immediate(branch_case.address));
|
||||||
Node op_b = Immediate(branch_case.cmp_value);
|
Node op_b = Immediate(branch_case.cmp_value);
|
||||||
Node condition =
|
Node condition =
|
||||||
GetPredicateComparisonInteger(Tegra::Shader::PredCondition::Equal, false, op_a, op_b);
|
GetPredicateComparisonInteger(Tegra::Shader::PredCondition::EQ, false, op_a, op_b);
|
||||||
auto result = Conditional(condition, {n});
|
auto result = Conditional(condition, {n});
|
||||||
bb.push_back(result);
|
bb.push_back(result);
|
||||||
global_code.push_back(result);
|
global_code.push_back(result);
|
||||||
|
|
|
@ -97,19 +97,19 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
|
||||||
return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b);
|
return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b);
|
||||||
}
|
}
|
||||||
case Tegra::Shader::XmadMode::CSfu: {
|
case Tegra::Shader::XmadMode::CSfu: {
|
||||||
const Node comp_a = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_a,
|
const Node comp_a =
|
||||||
op_a, Immediate(0));
|
GetPredicateComparisonInteger(PredCondition::EQ, is_signed_a, op_a, Immediate(0));
|
||||||
const Node comp_b = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_b,
|
const Node comp_b =
|
||||||
op_b, Immediate(0));
|
GetPredicateComparisonInteger(PredCondition::EQ, is_signed_b, op_b, Immediate(0));
|
||||||
const Node comp = Operation(OperationCode::LogicalOr, comp_a, comp_b);
|
const Node comp = Operation(OperationCode::LogicalOr, comp_a, comp_b);
|
||||||
|
|
||||||
const Node comp_minus_a = GetPredicateComparisonInteger(
|
const Node comp_minus_a = GetPredicateComparisonInteger(
|
||||||
PredCondition::NotEqual, is_signed_a,
|
PredCondition::NE, is_signed_a,
|
||||||
SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a,
|
SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a,
|
||||||
Immediate(0x80000000)),
|
Immediate(0x80000000)),
|
||||||
Immediate(0));
|
Immediate(0));
|
||||||
const Node comp_minus_b = GetPredicateComparisonInteger(
|
const Node comp_minus_b = GetPredicateComparisonInteger(
|
||||||
PredCondition::NotEqual, is_signed_b,
|
PredCondition::NE, is_signed_b,
|
||||||
SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b,
|
SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b,
|
||||||
Immediate(0x80000000)),
|
Immediate(0x80000000)),
|
||||||
Immediate(0));
|
Immediate(0));
|
||||||
|
|
|
@ -110,13 +110,20 @@ enum class OperationCode {
|
||||||
LogicalPick2, /// (bool2 pair, uint index) -> bool
|
LogicalPick2, /// (bool2 pair, uint index) -> bool
|
||||||
LogicalAnd2, /// (bool2 a) -> bool
|
LogicalAnd2, /// (bool2 a) -> bool
|
||||||
|
|
||||||
LogicalFLessThan, /// (float a, float b) -> bool
|
LogicalFOrdLessThan, /// (float a, float b) -> bool
|
||||||
LogicalFEqual, /// (float a, float b) -> bool
|
LogicalFOrdEqual, /// (float a, float b) -> bool
|
||||||
LogicalFLessEqual, /// (float a, float b) -> bool
|
LogicalFOrdLessEqual, /// (float a, float b) -> bool
|
||||||
LogicalFGreaterThan, /// (float a, float b) -> bool
|
LogicalFOrdGreaterThan, /// (float a, float b) -> bool
|
||||||
LogicalFNotEqual, /// (float a, float b) -> bool
|
LogicalFOrdNotEqual, /// (float a, float b) -> bool
|
||||||
LogicalFGreaterEqual, /// (float a, float b) -> bool
|
LogicalFOrdGreaterEqual, /// (float a, float b) -> bool
|
||||||
LogicalFIsNan, /// (float a) -> bool
|
LogicalFOrdered, /// (float a, float b) -> bool
|
||||||
|
LogicalFUnordered, /// (float a, float b) -> bool
|
||||||
|
LogicalFUnordLessThan, /// (float a, float b) -> bool
|
||||||
|
LogicalFUnordEqual, /// (float a, float b) -> bool
|
||||||
|
LogicalFUnordLessEqual, /// (float a, float b) -> bool
|
||||||
|
LogicalFUnordGreaterThan, /// (float a, float b) -> bool
|
||||||
|
LogicalFUnordNotEqual, /// (float a, float b) -> bool
|
||||||
|
LogicalFUnordGreaterEqual, /// (float a, float b) -> bool
|
||||||
|
|
||||||
LogicalILessThan, /// (int a, int b) -> bool
|
LogicalILessThan, /// (int a, int b) -> bool
|
||||||
LogicalIEqual, /// (int a, int b) -> bool
|
LogicalIEqual, /// (int a, int b) -> bool
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "video_core/engines/shader_bytecode.h"
|
#include "video_core/engines/shader_bytecode.h"
|
||||||
|
#include "video_core/shader/node.h"
|
||||||
#include "video_core/shader/node_helper.h"
|
#include "video_core/shader/node_helper.h"
|
||||||
#include "video_core/shader/registry.h"
|
#include "video_core/shader/registry.h"
|
||||||
#include "video_core/shader/shader_ir.h"
|
#include "video_core/shader/shader_ir.h"
|
||||||
|
@ -243,56 +244,44 @@ Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) {
|
Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) {
|
||||||
static constexpr std::array comparison_table{
|
if (condition == PredCondition::T) {
|
||||||
std::pair{PredCondition::LessThan, OperationCode::LogicalFLessThan},
|
return GetPredicate(true);
|
||||||
std::pair{PredCondition::Equal, OperationCode::LogicalFEqual},
|
} else if (condition == PredCondition::F) {
|
||||||
std::pair{PredCondition::LessEqual, OperationCode::LogicalFLessEqual},
|
return GetPredicate(false);
|
||||||
std::pair{PredCondition::GreaterThan, OperationCode::LogicalFGreaterThan},
|
|
||||||
std::pair{PredCondition::NotEqual, OperationCode::LogicalFNotEqual},
|
|
||||||
std::pair{PredCondition::GreaterEqual, OperationCode::LogicalFGreaterEqual},
|
|
||||||
std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalFLessThan},
|
|
||||||
std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalFNotEqual},
|
|
||||||
std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalFLessEqual},
|
|
||||||
std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalFGreaterThan},
|
|
||||||
std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalFGreaterEqual},
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto comparison =
|
|
||||||
std::find_if(comparison_table.cbegin(), comparison_table.cend(),
|
|
||||||
[condition](const auto entry) { return condition == entry.first; });
|
|
||||||
UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
|
|
||||||
"Unknown predicate comparison operation");
|
|
||||||
|
|
||||||
Node predicate = Operation(comparison->second, NO_PRECISE, op_a, op_b);
|
|
||||||
|
|
||||||
if (condition == PredCondition::LessThanWithNan ||
|
|
||||||
condition == PredCondition::NotEqualWithNan ||
|
|
||||||
condition == PredCondition::LessEqualWithNan ||
|
|
||||||
condition == PredCondition::GreaterThanWithNan ||
|
|
||||||
condition == PredCondition::GreaterEqualWithNan) {
|
|
||||||
predicate = Operation(OperationCode::LogicalOr, predicate,
|
|
||||||
Operation(OperationCode::LogicalFIsNan, op_a));
|
|
||||||
predicate = Operation(OperationCode::LogicalOr, predicate,
|
|
||||||
Operation(OperationCode::LogicalFIsNan, op_b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return predicate;
|
static constexpr std::array comparison_table{
|
||||||
|
OperationCode(0),
|
||||||
|
OperationCode::LogicalFOrdLessThan, // LT
|
||||||
|
OperationCode::LogicalFOrdEqual, // EQ
|
||||||
|
OperationCode::LogicalFOrdLessEqual, // LE
|
||||||
|
OperationCode::LogicalFOrdGreaterThan, // GT
|
||||||
|
OperationCode::LogicalFOrdNotEqual, // NE
|
||||||
|
OperationCode::LogicalFOrdGreaterEqual, // GE
|
||||||
|
OperationCode::LogicalFOrdered, // NUM
|
||||||
|
OperationCode::LogicalFUnordered, // NAN
|
||||||
|
OperationCode::LogicalFUnordLessThan, // LTU
|
||||||
|
OperationCode::LogicalFUnordEqual, // EQU
|
||||||
|
OperationCode::LogicalFUnordLessEqual, // LEU
|
||||||
|
OperationCode::LogicalFUnordGreaterThan, // GTU
|
||||||
|
OperationCode::LogicalFUnordNotEqual, // NEU
|
||||||
|
OperationCode::LogicalFUnordGreaterEqual, // GEU
|
||||||
|
};
|
||||||
|
const std::size_t index = static_cast<std::size_t>(condition);
|
||||||
|
ASSERT_MSG(index < std::size(comparison_table), "Invalid condition={}", index);
|
||||||
|
|
||||||
|
return Operation(comparison_table[index], op_a, op_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a,
|
Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a,
|
||||||
Node op_b) {
|
Node op_b) {
|
||||||
static constexpr std::array comparison_table{
|
static constexpr std::array comparison_table{
|
||||||
std::pair{PredCondition::LessThan, OperationCode::LogicalILessThan},
|
std::pair{PredCondition::LT, OperationCode::LogicalILessThan},
|
||||||
std::pair{PredCondition::Equal, OperationCode::LogicalIEqual},
|
std::pair{PredCondition::EQ, OperationCode::LogicalIEqual},
|
||||||
std::pair{PredCondition::LessEqual, OperationCode::LogicalILessEqual},
|
std::pair{PredCondition::LE, OperationCode::LogicalILessEqual},
|
||||||
std::pair{PredCondition::GreaterThan, OperationCode::LogicalIGreaterThan},
|
std::pair{PredCondition::GT, OperationCode::LogicalIGreaterThan},
|
||||||
std::pair{PredCondition::NotEqual, OperationCode::LogicalINotEqual},
|
std::pair{PredCondition::NE, OperationCode::LogicalINotEqual},
|
||||||
std::pair{PredCondition::GreaterEqual, OperationCode::LogicalIGreaterEqual},
|
std::pair{PredCondition::GE, OperationCode::LogicalIGreaterEqual},
|
||||||
std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalILessThan},
|
|
||||||
std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalINotEqual},
|
|
||||||
std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalILessEqual},
|
|
||||||
std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalIGreaterThan},
|
|
||||||
std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalIGreaterEqual},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto comparison =
|
const auto comparison =
|
||||||
|
@ -301,32 +290,24 @@ Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_si
|
||||||
UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
|
UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
|
||||||
"Unknown predicate comparison operation");
|
"Unknown predicate comparison operation");
|
||||||
|
|
||||||
Node predicate = SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a),
|
return SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a),
|
||||||
std::move(op_b));
|
std::move(op_b));
|
||||||
|
|
||||||
UNIMPLEMENTED_IF_MSG(condition == PredCondition::LessThanWithNan ||
|
|
||||||
condition == PredCondition::NotEqualWithNan ||
|
|
||||||
condition == PredCondition::LessEqualWithNan ||
|
|
||||||
condition == PredCondition::GreaterThanWithNan ||
|
|
||||||
condition == PredCondition::GreaterEqualWithNan,
|
|
||||||
"NaN comparisons for integers are not implemented");
|
|
||||||
return predicate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a,
|
Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a,
|
||||||
Node op_b) {
|
Node op_b) {
|
||||||
static constexpr std::array comparison_table{
|
static constexpr std::array comparison_table{
|
||||||
std::pair{PredCondition::LessThan, OperationCode::Logical2HLessThan},
|
std::pair{PredCondition::LT, OperationCode::Logical2HLessThan},
|
||||||
std::pair{PredCondition::Equal, OperationCode::Logical2HEqual},
|
std::pair{PredCondition::EQ, OperationCode::Logical2HEqual},
|
||||||
std::pair{PredCondition::LessEqual, OperationCode::Logical2HLessEqual},
|
std::pair{PredCondition::LE, OperationCode::Logical2HLessEqual},
|
||||||
std::pair{PredCondition::GreaterThan, OperationCode::Logical2HGreaterThan},
|
std::pair{PredCondition::GT, OperationCode::Logical2HGreaterThan},
|
||||||
std::pair{PredCondition::NotEqual, OperationCode::Logical2HNotEqual},
|
std::pair{PredCondition::NE, OperationCode::Logical2HNotEqual},
|
||||||
std::pair{PredCondition::GreaterEqual, OperationCode::Logical2HGreaterEqual},
|
std::pair{PredCondition::GE, OperationCode::Logical2HGreaterEqual},
|
||||||
std::pair{PredCondition::LessThanWithNan, OperationCode::Logical2HLessThanWithNan},
|
std::pair{PredCondition::LTU, OperationCode::Logical2HLessThanWithNan},
|
||||||
std::pair{PredCondition::NotEqualWithNan, OperationCode::Logical2HNotEqualWithNan},
|
std::pair{PredCondition::LEU, OperationCode::Logical2HLessEqualWithNan},
|
||||||
std::pair{PredCondition::LessEqualWithNan, OperationCode::Logical2HLessEqualWithNan},
|
std::pair{PredCondition::GTU, OperationCode::Logical2HGreaterThanWithNan},
|
||||||
std::pair{PredCondition::GreaterThanWithNan, OperationCode::Logical2HGreaterThanWithNan},
|
std::pair{PredCondition::NEU, OperationCode::Logical2HNotEqualWithNan},
|
||||||
std::pair{PredCondition::GreaterEqualWithNan, OperationCode::Logical2HGreaterEqualWithNan},
|
std::pair{PredCondition::GEU, OperationCode::Logical2HGreaterEqualWithNan},
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto comparison =
|
const auto comparison =
|
||||||
|
@ -397,7 +378,7 @@ void ShaderIR::SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc
|
||||||
if (!sets_cc) {
|
if (!sets_cc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Node zerop = Operation(OperationCode::LogicalFEqual, std::move(value), Immediate(0.0f));
|
Node zerop = Operation(OperationCode::LogicalFOrdEqual, std::move(value), Immediate(0.0f));
|
||||||
SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
|
SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
|
||||||
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
|
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue