Merge pull request #3899 from ReinUsesLisp/float-comparisons
shader_ir: Add separate instructions for ordered and unordered comparisons and fix NE on GLSL
This commit is contained in:
		@@ -168,18 +168,22 @@ enum class Pred : u64 {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class PredCondition : u64 {
 | 
			
		||||
    LessThan = 1,
 | 
			
		||||
    Equal = 2,
 | 
			
		||||
    LessEqual = 3,
 | 
			
		||||
    GreaterThan = 4,
 | 
			
		||||
    NotEqual = 5,
 | 
			
		||||
    GreaterEqual = 6,
 | 
			
		||||
    LessThanWithNan = 9,
 | 
			
		||||
    LessEqualWithNan = 11,
 | 
			
		||||
    GreaterThanWithNan = 12,
 | 
			
		||||
    NotEqualWithNan = 13,
 | 
			
		||||
    GreaterEqualWithNan = 14,
 | 
			
		||||
    // TODO(Subv): Other condition types
 | 
			
		||||
    F = 0,    // Always false
 | 
			
		||||
    LT = 1,   // Ordered less than
 | 
			
		||||
    EQ = 2,   // Ordered equal
 | 
			
		||||
    LE = 3,   // Ordered less than or equal
 | 
			
		||||
    GT = 4,   // Ordered greater than
 | 
			
		||||
    NE = 5,   // Ordered not equal
 | 
			
		||||
    GE = 6,   // Ordered greater than or equal
 | 
			
		||||
    NUM = 7,  // Ordered
 | 
			
		||||
    NAN_ = 8, // Unordered
 | 
			
		||||
    LTU = 9,  // Unordered less than
 | 
			
		||||
    EQU = 10, // Unordered equal
 | 
			
		||||
    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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -1840,34 +1840,40 @@ private:
 | 
			
		||||
                Type::HalfFloat};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <Type type>
 | 
			
		||||
    Expression LogicalLessThan(Operation operation) {
 | 
			
		||||
        return GenerateBinaryInfix(operation, "<", Type::Bool, type, type);
 | 
			
		||||
    template <const std::string_view& op, Type type, bool unordered = false>
 | 
			
		||||
    Expression Comparison(Operation operation) {
 | 
			
		||||
        static_assert(!unordered || type == Type::Float);
 | 
			
		||||
 | 
			
		||||
        const Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type);
 | 
			
		||||
 | 
			
		||||
        if constexpr (op.compare("!=") == 0 && type == Type::Float && !unordered) {
 | 
			
		||||
            // GLSL's operator!=(float, float) doesn't seem be ordered. This happens on both AMD's
 | 
			
		||||
            // and Nvidia's proprietary stacks. Manually force an ordered comparison.
 | 
			
		||||
            return {fmt::format("({} && !isnan({}) && !isnan({}))", expr.AsBool(),
 | 
			
		||||
                                VisitOperand(operation, 0).AsFloat(),
 | 
			
		||||
                                VisitOperand(operation, 1).AsFloat()),
 | 
			
		||||
                    Type::Bool};
 | 
			
		||||
        }
 | 
			
		||||
        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 LogicalEqual(Operation operation) {
 | 
			
		||||
        return GenerateBinaryInfix(operation, "==", Type::Bool, type, type);
 | 
			
		||||
    Expression FOrdered(Operation operation) {
 | 
			
		||||
        return {fmt::format("(!isnan({}) && !isnan({}))", VisitOperand(operation, 0).AsFloat(),
 | 
			
		||||
                            VisitOperand(operation, 1).AsFloat()),
 | 
			
		||||
                Type::Bool};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <Type type>
 | 
			
		||||
    Expression LogicalLessEqual(Operation operation) {
 | 
			
		||||
        return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 FUnordered(Operation operation) {
 | 
			
		||||
        return {fmt::format("(isnan({}) || isnan({}))", VisitOperand(operation, 0).AsFloat(),
 | 
			
		||||
                            VisitOperand(operation, 1).AsFloat()),
 | 
			
		||||
                Type::Bool};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Expression LogicalAddCarry(Operation operation) {
 | 
			
		||||
@@ -2324,6 +2330,13 @@ private:
 | 
			
		||||
        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 Min = "Min";
 | 
			
		||||
        static constexpr std::string_view Max = "Max";
 | 
			
		||||
@@ -2425,27 +2438,34 @@ private:
 | 
			
		||||
        &GLSLDecompiler::LogicalPick2,
 | 
			
		||||
        &GLSLDecompiler::LogicalAnd2,
 | 
			
		||||
 | 
			
		||||
        &GLSLDecompiler::LogicalLessThan<Type::Float>,
 | 
			
		||||
        &GLSLDecompiler::LogicalEqual<Type::Float>,
 | 
			
		||||
        &GLSLDecompiler::LogicalLessEqual<Type::Float>,
 | 
			
		||||
        &GLSLDecompiler::LogicalGreaterThan<Type::Float>,
 | 
			
		||||
        &GLSLDecompiler::LogicalNotEqual<Type::Float>,
 | 
			
		||||
        &GLSLDecompiler::LogicalGreaterEqual<Type::Float>,
 | 
			
		||||
        &GLSLDecompiler::LogicalFIsNan,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::LessThan, Type::Float, false>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::Equal, Type::Float, false>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::LessEqual, Type::Float, false>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Float, false>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::NotEqual, Type::Float, false>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Float, false>,
 | 
			
		||||
        &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::LogicalEqual<Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::LogicalLessEqual<Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::LogicalGreaterThan<Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::LogicalNotEqual<Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::LogicalGreaterEqual<Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::LessThan, Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::Equal, Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::LessEqual, Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::NotEqual, Type::Int>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Int>,
 | 
			
		||||
 | 
			
		||||
        &GLSLDecompiler::LogicalLessThan<Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::LogicalEqual<Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::LogicalLessEqual<Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::LogicalGreaterThan<Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::LogicalNotEqual<Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::LogicalGreaterEqual<Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::LessThan, Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::Equal, Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::LessEqual, Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::NotEqual, Type::Uint>,
 | 
			
		||||
        &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Uint>,
 | 
			
		||||
 | 
			
		||||
        &GLSLDecompiler::LogicalAddCarry,
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1618,6 +1618,24 @@ private:
 | 
			
		||||
        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) {
 | 
			
		||||
        const auto& meta = std::get<MetaTexture>(operation.GetMeta());
 | 
			
		||||
        ASSERT(!meta.sampler.is_buffer);
 | 
			
		||||
@@ -2511,7 +2529,14 @@ private:
 | 
			
		||||
        &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::Float>,
 | 
			
		||||
        &SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, 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::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 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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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));
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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");
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user