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:
ReinUsesLisp 2020-05-09 04:55:15 -03:00
parent 1121960f0e
commit 4e57f9d5cf
7 changed files with 163 additions and 135 deletions

View file

@ -255,7 +255,7 @@ void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) {
Node n = Operation(OperationCode::Branch, Immediate(branch_case.address));
Node op_b = Immediate(branch_case.cmp_value);
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});
bb.push_back(result);
global_code.push_back(result);

View file

@ -97,19 +97,19 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b);
}
case Tegra::Shader::XmadMode::CSfu: {
const Node comp_a = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_a,
op_a, Immediate(0));
const Node comp_b = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_b,
op_b, Immediate(0));
const Node comp_a =
GetPredicateComparisonInteger(PredCondition::EQ, is_signed_a, op_a, Immediate(0));
const Node comp_b =
GetPredicateComparisonInteger(PredCondition::EQ, is_signed_b, op_b, Immediate(0));
const Node comp = Operation(OperationCode::LogicalOr, comp_a, comp_b);
const Node comp_minus_a = GetPredicateComparisonInteger(
PredCondition::NotEqual, is_signed_a,
PredCondition::NE, is_signed_a,
SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a,
Immediate(0x80000000)),
Immediate(0));
const Node comp_minus_b = GetPredicateComparisonInteger(
PredCondition::NotEqual, is_signed_b,
PredCondition::NE, is_signed_b,
SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b,
Immediate(0x80000000)),
Immediate(0));

View file

@ -110,13 +110,20 @@ enum class OperationCode {
LogicalPick2, /// (bool2 pair, uint index) -> bool
LogicalAnd2, /// (bool2 a) -> bool
LogicalFLessThan, /// (float a, float b) -> bool
LogicalFEqual, /// (float a, float b) -> bool
LogicalFLessEqual, /// (float a, float b) -> bool
LogicalFGreaterThan, /// (float a, float b) -> bool
LogicalFNotEqual, /// (float a, float b) -> bool
LogicalFGreaterEqual, /// (float a, float b) -> bool
LogicalFIsNan, /// (float a) -> bool
LogicalFOrdLessThan, /// (float a, float b) -> bool
LogicalFOrdEqual, /// (float a, float b) -> bool
LogicalFOrdLessEqual, /// (float a, float b) -> bool
LogicalFOrdGreaterThan, /// (float a, float b) -> bool
LogicalFOrdNotEqual, /// (float a, float b) -> bool
LogicalFOrdGreaterEqual, /// (float a, float b) -> 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
LogicalIEqual, /// (int a, int b) -> bool

View file

@ -10,6 +10,7 @@
#include "common/common_types.h"
#include "common/logging/log.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/registry.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) {
static constexpr std::array comparison_table{
std::pair{PredCondition::LessThan, OperationCode::LogicalFLessThan},
std::pair{PredCondition::Equal, OperationCode::LogicalFEqual},
std::pair{PredCondition::LessEqual, OperationCode::LogicalFLessEqual},
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));
if (condition == PredCondition::T) {
return GetPredicate(true);
} else if (condition == PredCondition::F) {
return GetPredicate(false);
}
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 op_b) {
static constexpr std::array comparison_table{
std::pair{PredCondition::LessThan, OperationCode::LogicalILessThan},
std::pair{PredCondition::Equal, OperationCode::LogicalIEqual},
std::pair{PredCondition::LessEqual, OperationCode::LogicalILessEqual},
std::pair{PredCondition::GreaterThan, OperationCode::LogicalIGreaterThan},
std::pair{PredCondition::NotEqual, OperationCode::LogicalINotEqual},
std::pair{PredCondition::GreaterEqual, 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},
std::pair{PredCondition::LT, OperationCode::LogicalILessThan},
std::pair{PredCondition::EQ, OperationCode::LogicalIEqual},
std::pair{PredCondition::LE, OperationCode::LogicalILessEqual},
std::pair{PredCondition::GT, OperationCode::LogicalIGreaterThan},
std::pair{PredCondition::NE, OperationCode::LogicalINotEqual},
std::pair{PredCondition::GE, OperationCode::LogicalIGreaterEqual},
};
const auto comparison =
@ -301,32 +290,24 @@ Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_si
UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
"Unknown predicate comparison operation");
Node predicate = SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a),
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;
return SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a),
std::move(op_b));
}
Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a,
Node op_b) {
static constexpr std::array comparison_table{
std::pair{PredCondition::LessThan, OperationCode::Logical2HLessThan},
std::pair{PredCondition::Equal, OperationCode::Logical2HEqual},
std::pair{PredCondition::LessEqual, OperationCode::Logical2HLessEqual},
std::pair{PredCondition::GreaterThan, OperationCode::Logical2HGreaterThan},
std::pair{PredCondition::NotEqual, OperationCode::Logical2HNotEqual},
std::pair{PredCondition::GreaterEqual, OperationCode::Logical2HGreaterEqual},
std::pair{PredCondition::LessThanWithNan, OperationCode::Logical2HLessThanWithNan},
std::pair{PredCondition::NotEqualWithNan, OperationCode::Logical2HNotEqualWithNan},
std::pair{PredCondition::LessEqualWithNan, OperationCode::Logical2HLessEqualWithNan},
std::pair{PredCondition::GreaterThanWithNan, OperationCode::Logical2HGreaterThanWithNan},
std::pair{PredCondition::GreaterEqualWithNan, OperationCode::Logical2HGreaterEqualWithNan},
std::pair{PredCondition::LT, OperationCode::Logical2HLessThan},
std::pair{PredCondition::EQ, OperationCode::Logical2HEqual},
std::pair{PredCondition::LE, OperationCode::Logical2HLessEqual},
std::pair{PredCondition::GT, OperationCode::Logical2HGreaterThan},
std::pair{PredCondition::NE, OperationCode::Logical2HNotEqual},
std::pair{PredCondition::GE, OperationCode::Logical2HGreaterEqual},
std::pair{PredCondition::LTU, OperationCode::Logical2HLessThanWithNan},
std::pair{PredCondition::LEU, OperationCode::Logical2HLessEqualWithNan},
std::pair{PredCondition::GTU, OperationCode::Logical2HGreaterThanWithNan},
std::pair{PredCondition::NEU, OperationCode::Logical2HNotEqualWithNan},
std::pair{PredCondition::GEU, OperationCode::Logical2HGreaterEqualWithNan},
};
const auto comparison =
@ -397,7 +378,7 @@ void ShaderIR::SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc
if (!sets_cc) {
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));
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
}