diff options
| author | 2021-03-10 22:42:17 -0500 | |
|---|---|---|
| committer | 2021-07-22 21:51:23 -0400 | |
| commit | ba8c1d2eb479d04b2b0d847efd67468b688765d4 (patch) | |
| tree | c92c17f08ed3b313bbdb66917767ef8074d43c92 /src/shader_recompiler/frontend | |
| parent | shader: Partial implementation of LDC (diff) | |
| download | yuzu-ba8c1d2eb479d04b2b0d847efd67468b688765d4.tar.gz yuzu-ba8c1d2eb479d04b2b0d847efd67468b688765d4.tar.xz yuzu-ba8c1d2eb479d04b2b0d847efd67468b688765d4.zip | |
shader: Implement FCMP
still need to configure some settings for NV denorm flush and intel NaN
Diffstat (limited to 'src/shader_recompiler/frontend')
5 files changed, 184 insertions, 49 deletions
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 33819dd36..5d475207e 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -697,93 +697,107 @@ F16F32F64 IREmitter::FPTrunc(const F16F32F64& value, FpControl control) { | |||
| 697 | } | 697 | } |
| 698 | } | 698 | } |
| 699 | 699 | ||
| 700 | U1 IREmitter::FPEqual(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered) { | 700 | U1 IREmitter::FPEqual(const F16F32F64& lhs, const F16F32F64& rhs, FpControl control, bool ordered) { |
| 701 | if (lhs.Type() != rhs.Type()) { | 701 | if (lhs.Type() != rhs.Type()) { |
| 702 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); | 702 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); |
| 703 | } | 703 | } |
| 704 | switch (lhs.Type()) { | 704 | switch (lhs.Type()) { |
| 705 | case Type::F16: | 705 | case Type::F16: |
| 706 | return Inst<U1>(ordered ? Opcode::FPOrdEqual16 : Opcode::FPUnordEqual16, lhs, rhs); | 706 | return Inst<U1>(ordered ? Opcode::FPOrdEqual16 : Opcode::FPUnordEqual16, Flags{control}, |
| 707 | lhs, rhs); | ||
| 707 | case Type::F32: | 708 | case Type::F32: |
| 708 | return Inst<U1>(ordered ? Opcode::FPOrdEqual32 : Opcode::FPUnordEqual32, lhs, rhs); | 709 | return Inst<U1>(ordered ? Opcode::FPOrdEqual32 : Opcode::FPUnordEqual32, Flags{control}, |
| 710 | lhs, rhs); | ||
| 709 | case Type::F64: | 711 | case Type::F64: |
| 710 | return Inst<U1>(ordered ? Opcode::FPOrdEqual64 : Opcode::FPUnordEqual64, lhs, rhs); | 712 | return Inst<U1>(ordered ? Opcode::FPOrdEqual64 : Opcode::FPUnordEqual64, Flags{control}, |
| 713 | lhs, rhs); | ||
| 711 | default: | 714 | default: |
| 712 | ThrowInvalidType(lhs.Type()); | 715 | ThrowInvalidType(lhs.Type()); |
| 713 | } | 716 | } |
| 714 | } | 717 | } |
| 715 | 718 | ||
| 716 | U1 IREmitter::FPNotEqual(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered) { | 719 | U1 IREmitter::FPNotEqual(const F16F32F64& lhs, const F16F32F64& rhs, FpControl control, |
| 720 | bool ordered) { | ||
| 717 | if (lhs.Type() != rhs.Type()) { | 721 | if (lhs.Type() != rhs.Type()) { |
| 718 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); | 722 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); |
| 719 | } | 723 | } |
| 720 | switch (lhs.Type()) { | 724 | switch (lhs.Type()) { |
| 721 | case Type::F16: | 725 | case Type::F16: |
| 722 | return Inst<U1>(ordered ? Opcode::FPOrdNotEqual16 : Opcode::FPUnordNotEqual16, lhs, rhs); | 726 | return Inst<U1>(ordered ? Opcode::FPOrdNotEqual16 : Opcode::FPUnordNotEqual16, |
| 727 | Flags{control}, lhs, rhs); | ||
| 723 | case Type::F32: | 728 | case Type::F32: |
| 724 | return Inst<U1>(ordered ? Opcode::FPOrdNotEqual32 : Opcode::FPUnordNotEqual32, lhs, rhs); | 729 | return Inst<U1>(ordered ? Opcode::FPOrdNotEqual32 : Opcode::FPUnordNotEqual32, |
| 730 | Flags{control}, lhs, rhs); | ||
| 725 | case Type::F64: | 731 | case Type::F64: |
| 726 | return Inst<U1>(ordered ? Opcode::FPOrdNotEqual64 : Opcode::FPUnordNotEqual64, lhs, rhs); | 732 | return Inst<U1>(ordered ? Opcode::FPOrdNotEqual64 : Opcode::FPUnordNotEqual64, |
| 733 | Flags{control}, lhs, rhs); | ||
| 727 | default: | 734 | default: |
| 728 | ThrowInvalidType(lhs.Type()); | 735 | ThrowInvalidType(lhs.Type()); |
| 729 | } | 736 | } |
| 730 | } | 737 | } |
| 731 | 738 | ||
| 732 | U1 IREmitter::FPLessThan(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered) { | 739 | U1 IREmitter::FPLessThan(const F16F32F64& lhs, const F16F32F64& rhs, FpControl control, |
| 740 | bool ordered) { | ||
| 733 | if (lhs.Type() != rhs.Type()) { | 741 | if (lhs.Type() != rhs.Type()) { |
| 734 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); | 742 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); |
| 735 | } | 743 | } |
| 736 | switch (lhs.Type()) { | 744 | switch (lhs.Type()) { |
| 737 | case Type::F16: | 745 | case Type::F16: |
| 738 | return Inst<U1>(ordered ? Opcode::FPOrdLessThan16 : Opcode::FPUnordLessThan16, lhs, rhs); | 746 | return Inst<U1>(ordered ? Opcode::FPOrdLessThan16 : Opcode::FPUnordLessThan16, |
| 747 | Flags{control}, lhs, rhs); | ||
| 739 | case Type::F32: | 748 | case Type::F32: |
| 740 | return Inst<U1>(ordered ? Opcode::FPOrdLessThan32 : Opcode::FPUnordLessThan32, lhs, rhs); | 749 | return Inst<U1>(ordered ? Opcode::FPOrdLessThan32 : Opcode::FPUnordLessThan32, |
| 750 | Flags{control}, lhs, rhs); | ||
| 741 | case Type::F64: | 751 | case Type::F64: |
| 742 | return Inst<U1>(ordered ? Opcode::FPOrdLessThan64 : Opcode::FPUnordLessThan64, lhs, rhs); | 752 | return Inst<U1>(ordered ? Opcode::FPOrdLessThan64 : Opcode::FPUnordLessThan64, |
| 753 | Flags{control}, lhs, rhs); | ||
| 743 | default: | 754 | default: |
| 744 | ThrowInvalidType(lhs.Type()); | 755 | ThrowInvalidType(lhs.Type()); |
| 745 | } | 756 | } |
| 746 | } | 757 | } |
| 747 | 758 | ||
| 748 | U1 IREmitter::FPGreaterThan(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered) { | 759 | U1 IREmitter::FPGreaterThan(const F16F32F64& lhs, const F16F32F64& rhs, FpControl control, |
| 760 | bool ordered) { | ||
| 749 | if (lhs.Type() != rhs.Type()) { | 761 | if (lhs.Type() != rhs.Type()) { |
| 750 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); | 762 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); |
| 751 | } | 763 | } |
| 752 | switch (lhs.Type()) { | 764 | switch (lhs.Type()) { |
| 753 | case Type::F16: | 765 | case Type::F16: |
| 754 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThan16 : Opcode::FPUnordGreaterThan16, lhs, | 766 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThan16 : Opcode::FPUnordGreaterThan16, |
| 755 | rhs); | 767 | Flags{control}, lhs, rhs); |
| 756 | case Type::F32: | 768 | case Type::F32: |
| 757 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThan32 : Opcode::FPUnordGreaterThan32, lhs, | 769 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThan32 : Opcode::FPUnordGreaterThan32, |
| 758 | rhs); | 770 | Flags{control}, lhs, rhs); |
| 759 | case Type::F64: | 771 | case Type::F64: |
| 760 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThan64 : Opcode::FPUnordGreaterThan64, lhs, | 772 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThan64 : Opcode::FPUnordGreaterThan64, |
| 761 | rhs); | 773 | Flags{control}, lhs, rhs); |
| 762 | default: | 774 | default: |
| 763 | ThrowInvalidType(lhs.Type()); | 775 | ThrowInvalidType(lhs.Type()); |
| 764 | } | 776 | } |
| 765 | } | 777 | } |
| 766 | 778 | ||
| 767 | U1 IREmitter::FPLessThanEqual(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered) { | 779 | U1 IREmitter::FPLessThanEqual(const F16F32F64& lhs, const F16F32F64& rhs, FpControl control, |
| 780 | bool ordered) { | ||
| 768 | if (lhs.Type() != rhs.Type()) { | 781 | if (lhs.Type() != rhs.Type()) { |
| 769 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); | 782 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); |
| 770 | } | 783 | } |
| 771 | switch (lhs.Type()) { | 784 | switch (lhs.Type()) { |
| 772 | case Type::F16: | 785 | case Type::F16: |
| 773 | return Inst<U1>(ordered ? Opcode::FPOrdLessThanEqual16 : Opcode::FPUnordLessThanEqual16, | 786 | return Inst<U1>(ordered ? Opcode::FPOrdLessThanEqual16 : Opcode::FPUnordLessThanEqual16, |
| 774 | lhs, rhs); | 787 | Flags{control}, lhs, rhs); |
| 775 | case Type::F32: | 788 | case Type::F32: |
| 776 | return Inst<U1>(ordered ? Opcode::FPOrdLessThanEqual32 : Opcode::FPUnordLessThanEqual32, | 789 | return Inst<U1>(ordered ? Opcode::FPOrdLessThanEqual32 : Opcode::FPUnordLessThanEqual32, |
| 777 | lhs, rhs); | 790 | Flags{control}, lhs, rhs); |
| 778 | case Type::F64: | 791 | case Type::F64: |
| 779 | return Inst<U1>(ordered ? Opcode::FPOrdLessThanEqual64 : Opcode::FPUnordLessThanEqual64, | 792 | return Inst<U1>(ordered ? Opcode::FPOrdLessThanEqual64 : Opcode::FPUnordLessThanEqual64, |
| 780 | lhs, rhs); | 793 | Flags{control}, lhs, rhs); |
| 781 | default: | 794 | default: |
| 782 | ThrowInvalidType(lhs.Type()); | 795 | ThrowInvalidType(lhs.Type()); |
| 783 | } | 796 | } |
| 784 | } | 797 | } |
| 785 | 798 | ||
| 786 | U1 IREmitter::FPGreaterThanEqual(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered) { | 799 | U1 IREmitter::FPGreaterThanEqual(const F16F32F64& lhs, const F16F32F64& rhs, FpControl control, |
| 800 | bool ordered) { | ||
| 787 | if (lhs.Type() != rhs.Type()) { | 801 | if (lhs.Type() != rhs.Type()) { |
| 788 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); | 802 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); |
| 789 | } | 803 | } |
| @@ -791,20 +805,32 @@ U1 IREmitter::FPGreaterThanEqual(const F16F32F64& lhs, const F16F32F64& rhs, boo | |||
| 791 | case Type::F16: | 805 | case Type::F16: |
| 792 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThanEqual16 | 806 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThanEqual16 |
| 793 | : Opcode::FPUnordGreaterThanEqual16, | 807 | : Opcode::FPUnordGreaterThanEqual16, |
| 794 | lhs, rhs); | 808 | Flags{control}, lhs, rhs); |
| 795 | case Type::F32: | 809 | case Type::F32: |
| 796 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThanEqual32 | 810 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThanEqual32 |
| 797 | : Opcode::FPUnordGreaterThanEqual32, | 811 | : Opcode::FPUnordGreaterThanEqual32, |
| 798 | lhs, rhs); | 812 | Flags{control}, lhs, rhs); |
| 799 | case Type::F64: | 813 | case Type::F64: |
| 800 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThanEqual64 | 814 | return Inst<U1>(ordered ? Opcode::FPOrdGreaterThanEqual64 |
| 801 | : Opcode::FPUnordGreaterThanEqual64, | 815 | : Opcode::FPUnordGreaterThanEqual64, |
| 802 | lhs, rhs); | 816 | Flags{control}, lhs, rhs); |
| 803 | default: | 817 | default: |
| 804 | ThrowInvalidType(lhs.Type()); | 818 | ThrowInvalidType(lhs.Type()); |
| 805 | } | 819 | } |
| 806 | } | 820 | } |
| 807 | 821 | ||
| 822 | U1 IREmitter::FPIsNan(const F32& value) { | ||
| 823 | return Inst<U1>(Opcode::FPIsNan32, value); | ||
| 824 | } | ||
| 825 | |||
| 826 | U1 IREmitter::FPOrdered(const F32& lhs, const F32& rhs) { | ||
| 827 | return LogicalAnd(LogicalNot(FPIsNan(lhs)), LogicalNot(FPIsNan(rhs))); | ||
| 828 | } | ||
| 829 | |||
| 830 | U1 IREmitter::FPUnordered(const F32& lhs, const F32& rhs) { | ||
| 831 | return LogicalOr(FPIsNan(lhs), FPIsNan(rhs)); | ||
| 832 | } | ||
| 833 | |||
| 808 | U32U64 IREmitter::IAdd(const U32U64& a, const U32U64& b) { | 834 | U32U64 IREmitter::IAdd(const U32U64& a, const U32U64& b) { |
| 809 | if (a.Type() != b.Type()) { | 835 | if (a.Type() != b.Type()) { |
| 810 | throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type()); | 836 | throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type()); |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index e4d110540..5cfe1a54a 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -140,14 +140,21 @@ public: | |||
| 140 | [[nodiscard]] F16F32F64 FPCeil(const F16F32F64& value, FpControl control = {}); | 140 | [[nodiscard]] F16F32F64 FPCeil(const F16F32F64& value, FpControl control = {}); |
| 141 | [[nodiscard]] F16F32F64 FPTrunc(const F16F32F64& value, FpControl control = {}); | 141 | [[nodiscard]] F16F32F64 FPTrunc(const F16F32F64& value, FpControl control = {}); |
| 142 | 142 | ||
| 143 | [[nodiscard]] U1 FPEqual(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered = true); | 143 | [[nodiscard]] U1 FPEqual(const F16F32F64& lhs, const F16F32F64& rhs, FpControl control = {}, |
| 144 | [[nodiscard]] U1 FPNotEqual(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered = true); | 144 | bool ordered = true); |
| 145 | [[nodiscard]] U1 FPLessThan(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered = true); | 145 | [[nodiscard]] U1 FPNotEqual(const F16F32F64& lhs, const F16F32F64& rhs, FpControl control = {}, |
| 146 | [[nodiscard]] U1 FPGreaterThan(const F16F32F64& lhs, const F16F32F64& rhs, bool ordered = true); | 146 | bool ordered = true); |
| 147 | [[nodiscard]] U1 FPLessThan(const F16F32F64& lhs, const F16F32F64& rhs, FpControl control = {}, | ||
| 148 | bool ordered = true); | ||
| 149 | [[nodiscard]] U1 FPGreaterThan(const F16F32F64& lhs, const F16F32F64& rhs, | ||
| 150 | FpControl control = {}, bool ordered = true); | ||
| 147 | [[nodiscard]] U1 FPLessThanEqual(const F16F32F64& lhs, const F16F32F64& rhs, | 151 | [[nodiscard]] U1 FPLessThanEqual(const F16F32F64& lhs, const F16F32F64& rhs, |
| 148 | bool ordered = true); | 152 | FpControl control = {}, bool ordered = true); |
| 149 | [[nodiscard]] U1 FPGreaterThanEqual(const F16F32F64& lhs, const F16F32F64& rhs, | 153 | [[nodiscard]] U1 FPGreaterThanEqual(const F16F32F64& lhs, const F16F32F64& rhs, |
| 150 | bool ordered = true); | 154 | FpControl control = {}, bool ordered = true); |
| 155 | [[nodiscard]] U1 FPIsNan(const F32& value); | ||
| 156 | [[nodiscard]] U1 FPOrdered(const F32& lhs, const F32& rhs); | ||
| 157 | [[nodiscard]] U1 FPUnordered(const F32& lhs, const F32& rhs); | ||
| 151 | 158 | ||
| 152 | [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b); | 159 | [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b); |
| 153 | [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b); | 160 | [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b); |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 64bd495ed..476281789 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -197,6 +197,7 @@ OPCODE(FPTrunc16, F16, F16, | |||
| 197 | OPCODE(FPTrunc32, F32, F32, ) | 197 | OPCODE(FPTrunc32, F32, F32, ) |
| 198 | OPCODE(FPTrunc64, F64, F64, ) | 198 | OPCODE(FPTrunc64, F64, F64, ) |
| 199 | 199 | ||
| 200 | <<<<<<< HEAD | ||
| 200 | OPCODE(FPOrdEqual16, U1, F16, F16, ) | 201 | OPCODE(FPOrdEqual16, U1, F16, F16, ) |
| 201 | OPCODE(FPOrdEqual32, U1, F32, F32, ) | 202 | OPCODE(FPOrdEqual32, U1, F32, F32, ) |
| 202 | OPCODE(FPOrdEqual64, U1, F64, F64, ) | 203 | OPCODE(FPOrdEqual64, U1, F64, F64, ) |
| @@ -233,6 +234,7 @@ OPCODE(FPOrdGreaterThanEqual64, U1, F64, | |||
| 233 | OPCODE(FPUnordGreaterThanEqual16, U1, F16, F16, ) | 234 | OPCODE(FPUnordGreaterThanEqual16, U1, F16, F16, ) |
| 234 | OPCODE(FPUnordGreaterThanEqual32, U1, F32, F32, ) | 235 | OPCODE(FPUnordGreaterThanEqual32, U1, F32, F32, ) |
| 235 | OPCODE(FPUnordGreaterThanEqual64, U1, F64, F64, ) | 236 | OPCODE(FPUnordGreaterThanEqual64, U1, F64, F64, ) |
| 237 | OPCODE(FPIsNan32, U1, F32, ) | ||
| 236 | 238 | ||
| 237 | // Integer operations | 239 | // Integer operations |
| 238 | OPCODE(IAdd32, U32, U32, U32, ) | 240 | OPCODE(IAdd32, U32, U32, U32, ) |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_compare.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_compare.cpp new file mode 100644 index 000000000..21cb80d67 --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_compare.cpp | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/bit_field.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 9 | |||
| 10 | namespace Shader::Maxwell { | ||
| 11 | namespace { | ||
| 12 | enum class FPCompareOp : u64 { | ||
| 13 | F, | ||
| 14 | LT, | ||
| 15 | EQ, | ||
| 16 | LE, | ||
| 17 | GT, | ||
| 18 | NE, | ||
| 19 | GE, | ||
| 20 | NUM, | ||
| 21 | Nan, | ||
| 22 | LTU, | ||
| 23 | EQU, | ||
| 24 | LEU, | ||
| 25 | GTU, | ||
| 26 | NEU, | ||
| 27 | GEU, | ||
| 28 | T, | ||
| 29 | }; | ||
| 30 | |||
| 31 | bool IsCompareOpOrdered(FPCompareOp op) { | ||
| 32 | switch (op) { | ||
| 33 | case FPCompareOp::LTU: | ||
| 34 | case FPCompareOp::EQU: | ||
| 35 | case FPCompareOp::LEU: | ||
| 36 | case FPCompareOp::GTU: | ||
| 37 | case FPCompareOp::NEU: | ||
| 38 | case FPCompareOp::GEU: | ||
| 39 | return false; | ||
| 40 | default: | ||
| 41 | return true; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | IR::U1 FloatingPointCompare(IR::IREmitter& ir, const IR::F32& operand_1, const IR::F32& operand_2, | ||
| 46 | FPCompareOp compare_op, IR::FpControl control) { | ||
| 47 | const bool ordered{IsCompareOpOrdered(compare_op)}; | ||
| 48 | switch (compare_op) { | ||
| 49 | case FPCompareOp::F: | ||
| 50 | return ir.Imm1(false); | ||
| 51 | case FPCompareOp::LT: | ||
| 52 | case FPCompareOp::LTU: | ||
| 53 | return ir.FPLessThan(operand_1, operand_2, control, ordered); | ||
| 54 | case FPCompareOp::EQ: | ||
| 55 | case FPCompareOp::EQU: | ||
| 56 | return ir.FPEqual(operand_1, operand_2, control, ordered); | ||
| 57 | case FPCompareOp::LE: | ||
| 58 | case FPCompareOp::LEU: | ||
| 59 | return ir.FPLessThanEqual(operand_1, operand_2, control, ordered); | ||
| 60 | case FPCompareOp::GT: | ||
| 61 | case FPCompareOp::GTU: | ||
| 62 | return ir.FPGreaterThan(operand_1, operand_2, control, ordered); | ||
| 63 | case FPCompareOp::NE: | ||
| 64 | case FPCompareOp::NEU: | ||
| 65 | return ir.FPNotEqual(operand_1, operand_2, control, ordered); | ||
| 66 | case FPCompareOp::GE: | ||
| 67 | case FPCompareOp::GEU: | ||
| 68 | return ir.FPGreaterThanEqual(operand_1, operand_2, control, ordered); | ||
| 69 | case FPCompareOp::NUM: | ||
| 70 | return ir.FPOrdered(operand_1, operand_2); | ||
| 71 | case FPCompareOp::Nan: | ||
| 72 | return ir.FPUnordered(operand_1, operand_2); | ||
| 73 | case FPCompareOp::T: | ||
| 74 | return ir.Imm1(true); | ||
| 75 | default: | ||
| 76 | throw NotImplementedException("Invalid compare op {}", compare_op); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | void FCMP(TranslatorVisitor& v, u64 insn, const IR::U32& src_a, const IR::F32& operand) { | ||
| 81 | union { | ||
| 82 | u64 insn; | ||
| 83 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 84 | BitField<8, 8, IR::Reg> src_reg; | ||
| 85 | BitField<47, 1, u64> ftz; | ||
| 86 | BitField<48, 4, FPCompareOp> compare_op; | ||
| 87 | } const fcmp{insn}; | ||
| 88 | |||
| 89 | const IR::F32 zero{v.ir.Imm32(0.0f)}; | ||
| 90 | const IR::F32 neg_zero{v.ir.Imm32(-0.0f)}; | ||
| 91 | IR::FpControl control{.fmz_mode{fcmp.ftz != 0 ? IR::FmzMode::FTZ : IR::FmzMode::None}}; | ||
| 92 | const IR::U1 cmp_result{FloatingPointCompare(v.ir, operand, zero, fcmp.compare_op, control)}; | ||
| 93 | const IR::U32 src_reg{v.X(fcmp.src_reg)}; | ||
| 94 | const IR::U32 result{v.ir.Select(cmp_result, src_reg, src_a)}; | ||
| 95 | |||
| 96 | v.X(fcmp.dest_reg, result); | ||
| 97 | } | ||
| 98 | } // Anonymous namespace | ||
| 99 | |||
| 100 | void TranslatorVisitor::FCMP_reg(u64 insn) { | ||
| 101 | FCMP(*this, insn, GetReg20(insn), GetFloatReg39(insn)); | ||
| 102 | } | ||
| 103 | |||
| 104 | void TranslatorVisitor::FCMP_rc(u64 insn) { | ||
| 105 | FCMP(*this, insn, GetReg39(insn), GetFloatCbuf(insn)); | ||
| 106 | } | ||
| 107 | |||
| 108 | void TranslatorVisitor::FCMP_cr(u64 insn) { | ||
| 109 | FCMP(*this, insn, GetCbuf(insn), GetFloatReg39(insn)); | ||
| 110 | } | ||
| 111 | |||
| 112 | void TranslatorVisitor::FCMP_imm(u64 insn) { | ||
| 113 | FCMP(*this, insn, GetReg39(insn), GetFloatImm20(insn)); | ||
| 114 | } | ||
| 115 | |||
| 116 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp index 5b153acff..e1904472f 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -201,22 +201,6 @@ void TranslatorVisitor::FCHK_imm(u64) { | |||
| 201 | ThrowNotImplemented(Opcode::FCHK_imm); | 201 | ThrowNotImplemented(Opcode::FCHK_imm); |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | void TranslatorVisitor::FCMP_reg(u64) { | ||
| 205 | ThrowNotImplemented(Opcode::FCMP_reg); | ||
| 206 | } | ||
| 207 | |||
| 208 | void TranslatorVisitor::FCMP_rc(u64) { | ||
| 209 | ThrowNotImplemented(Opcode::FCMP_rc); | ||
| 210 | } | ||
| 211 | |||
| 212 | void TranslatorVisitor::FCMP_cr(u64) { | ||
| 213 | ThrowNotImplemented(Opcode::FCMP_cr); | ||
| 214 | } | ||
| 215 | |||
| 216 | void TranslatorVisitor::FCMP_imm(u64) { | ||
| 217 | ThrowNotImplemented(Opcode::FCMP_imm); | ||
| 218 | } | ||
| 219 | |||
| 220 | void TranslatorVisitor::FMNMX_reg(u64) { | 204 | void TranslatorVisitor::FMNMX_reg(u64) { |
| 221 | ThrowNotImplemented(Opcode::FMNMX_reg); | 205 | ThrowNotImplemented(Opcode::FMNMX_reg); |
| 222 | } | 206 | } |