diff options
Diffstat (limited to 'src/shader_recompiler/frontend')
4 files changed, 49 insertions, 33 deletions
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 559ab9cca..8f120a2f6 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -558,53 +558,53 @@ F16F32F64 IREmitter::FPSaturate(const F16F32F64& value) { | |||
| 558 | } | 558 | } |
| 559 | } | 559 | } |
| 560 | 560 | ||
| 561 | F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value) { | 561 | F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value, FpControl control) { |
| 562 | switch (value.Type()) { | 562 | switch (value.Type()) { |
| 563 | case Type::F16: | 563 | case Type::F16: |
| 564 | return Inst<F16>(Opcode::FPRoundEven16, value); | 564 | return Inst<F16>(Opcode::FPRoundEven16, Flags{control}, value); |
| 565 | case Type::F32: | 565 | case Type::F32: |
| 566 | return Inst<F32>(Opcode::FPRoundEven32, value); | 566 | return Inst<F32>(Opcode::FPRoundEven32, Flags{control}, value); |
| 567 | case Type::F64: | 567 | case Type::F64: |
| 568 | return Inst<F64>(Opcode::FPRoundEven64, value); | 568 | return Inst<F64>(Opcode::FPRoundEven64, Flags{control}, value); |
| 569 | default: | 569 | default: |
| 570 | ThrowInvalidType(value.Type()); | 570 | ThrowInvalidType(value.Type()); |
| 571 | } | 571 | } |
| 572 | } | 572 | } |
| 573 | 573 | ||
| 574 | F16F32F64 IREmitter::FPFloor(const F16F32F64& value) { | 574 | F16F32F64 IREmitter::FPFloor(const F16F32F64& value, FpControl control) { |
| 575 | switch (value.Type()) { | 575 | switch (value.Type()) { |
| 576 | case Type::F16: | 576 | case Type::F16: |
| 577 | return Inst<F16>(Opcode::FPFloor16, value); | 577 | return Inst<F16>(Opcode::FPFloor16, Flags{control}, value); |
| 578 | case Type::F32: | 578 | case Type::F32: |
| 579 | return Inst<F32>(Opcode::FPFloor32, value); | 579 | return Inst<F32>(Opcode::FPFloor32, Flags{control}, value); |
| 580 | case Type::F64: | 580 | case Type::F64: |
| 581 | return Inst<F64>(Opcode::FPFloor64, value); | 581 | return Inst<F64>(Opcode::FPFloor64, Flags{control}, value); |
| 582 | default: | 582 | default: |
| 583 | ThrowInvalidType(value.Type()); | 583 | ThrowInvalidType(value.Type()); |
| 584 | } | 584 | } |
| 585 | } | 585 | } |
| 586 | 586 | ||
| 587 | F16F32F64 IREmitter::FPCeil(const F16F32F64& value) { | 587 | F16F32F64 IREmitter::FPCeil(const F16F32F64& value, FpControl control) { |
| 588 | switch (value.Type()) { | 588 | switch (value.Type()) { |
| 589 | case Type::F16: | 589 | case Type::F16: |
| 590 | return Inst<F16>(Opcode::FPCeil16, value); | 590 | return Inst<F16>(Opcode::FPCeil16, Flags{control}, value); |
| 591 | case Type::F32: | 591 | case Type::F32: |
| 592 | return Inst<F32>(Opcode::FPCeil32, value); | 592 | return Inst<F32>(Opcode::FPCeil32, Flags{control}, value); |
| 593 | case Type::F64: | 593 | case Type::F64: |
| 594 | return Inst<F64>(Opcode::FPCeil64, value); | 594 | return Inst<F64>(Opcode::FPCeil64, Flags{control}, value); |
| 595 | default: | 595 | default: |
| 596 | ThrowInvalidType(value.Type()); | 596 | ThrowInvalidType(value.Type()); |
| 597 | } | 597 | } |
| 598 | } | 598 | } |
| 599 | 599 | ||
| 600 | F16F32F64 IREmitter::FPTrunc(const F16F32F64& value) { | 600 | F16F32F64 IREmitter::FPTrunc(const F16F32F64& value, FpControl control) { |
| 601 | switch (value.Type()) { | 601 | switch (value.Type()) { |
| 602 | case Type::F16: | 602 | case Type::F16: |
| 603 | return Inst<F16>(Opcode::FPTrunc16, value); | 603 | return Inst<F16>(Opcode::FPTrunc16, Flags{control}, value); |
| 604 | case Type::F32: | 604 | case Type::F32: |
| 605 | return Inst<F32>(Opcode::FPTrunc32, value); | 605 | return Inst<F32>(Opcode::FPTrunc32, Flags{control}, value); |
| 606 | case Type::F64: | 606 | case Type::F64: |
| 607 | return Inst<F64>(Opcode::FPTrunc64, value); | 607 | return Inst<F64>(Opcode::FPTrunc64, Flags{control}, value); |
| 608 | default: | 608 | default: |
| 609 | ThrowInvalidType(value.Type()); | 609 | ThrowInvalidType(value.Type()); |
| 610 | } | 610 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 24b012a39..959f4f9da 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -129,10 +129,10 @@ public: | |||
| 129 | [[nodiscard]] F32 FPSinNotReduced(const F32& value); | 129 | [[nodiscard]] F32 FPSinNotReduced(const F32& value); |
| 130 | [[nodiscard]] F32 FPSqrt(const F32& value); | 130 | [[nodiscard]] F32 FPSqrt(const F32& value); |
| 131 | [[nodiscard]] F16F32F64 FPSaturate(const F16F32F64& value); | 131 | [[nodiscard]] F16F32F64 FPSaturate(const F16F32F64& value); |
| 132 | [[nodiscard]] F16F32F64 FPRoundEven(const F16F32F64& value); | 132 | [[nodiscard]] F16F32F64 FPRoundEven(const F16F32F64& value, FpControl control = {}); |
| 133 | [[nodiscard]] F16F32F64 FPFloor(const F16F32F64& value); | 133 | [[nodiscard]] F16F32F64 FPFloor(const F16F32F64& value, FpControl control = {}); |
| 134 | [[nodiscard]] F16F32F64 FPCeil(const F16F32F64& value); | 134 | [[nodiscard]] F16F32F64 FPCeil(const F16F32F64& value, FpControl control = {}); |
| 135 | [[nodiscard]] F16F32F64 FPTrunc(const F16F32F64& value); | 135 | [[nodiscard]] F16F32F64 FPTrunc(const F16F32F64& value, FpControl control = {}); |
| 136 | 136 | ||
| 137 | [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b); | 137 | [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b); |
| 138 | [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b); | 138 | [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b); |
diff --git a/src/shader_recompiler/frontend/ir/modifiers.h b/src/shader_recompiler/frontend/ir/modifiers.h index c288eede0..44652eae7 100644 --- a/src/shader_recompiler/frontend/ir/modifiers.h +++ b/src/shader_recompiler/frontend/ir/modifiers.h | |||
| @@ -4,25 +4,30 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 7 | namespace Shader::IR { | 9 | namespace Shader::IR { |
| 8 | 10 | ||
| 9 | enum class FmzMode : u8 { | 11 | enum class FmzMode : u8 { |
| 10 | None, // Denorms are not flushed, NAN is propagated (nouveau) | 12 | DontCare, // Not specified for this instruction |
| 11 | FTZ, // Flush denorms to zero, NAN is propagated (D3D11, NVN, GL, VK) | 13 | FTZ, // Flush denorms to zero, NAN is propagated (D3D11, NVN, GL, VK) |
| 12 | FMZ, // Flush denorms to zero, x * 0 == 0 (D3D9) | 14 | FMZ, // Flush denorms to zero, x * 0 == 0 (D3D9) |
| 15 | None, // Denorms are not flushed, NAN is propagated (nouveau) | ||
| 13 | }; | 16 | }; |
| 14 | 17 | ||
| 15 | enum class FpRounding : u8 { | 18 | enum class FpRounding : u8 { |
| 16 | RN, // Round to nearest even, | 19 | DontCare, // Not specified for this instruction |
| 17 | RM, // Round towards negative infinity | 20 | RN, // Round to nearest even, |
| 18 | RP, // Round towards positive infinity | 21 | RM, // Round towards negative infinity |
| 19 | RZ, // Round towards zero | 22 | RP, // Round towards positive infinity |
| 23 | RZ, // Round towards zero | ||
| 20 | }; | 24 | }; |
| 21 | 25 | ||
| 22 | struct FpControl { | 26 | struct FpControl { |
| 23 | bool no_contraction{false}; | 27 | bool no_contraction{false}; |
| 24 | FpRounding rounding{FpRounding::RN}; | 28 | FpRounding rounding{FpRounding::DontCare}; |
| 25 | FmzMode fmz_mode{FmzMode::FTZ}; | 29 | FmzMode fmz_mode{FmzMode::DontCare}; |
| 26 | }; | 30 | }; |
| 27 | static_assert(sizeof(FpControl) <= sizeof(u32)); | 31 | static_assert(sizeof(FpControl) <= sizeof(u32)); |
| 32 | |||
| 28 | } // namespace Shader::IR | 33 | } // namespace Shader::IR |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp index ae2d37405..4d82a0009 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp | |||
| @@ -81,17 +81,28 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) { | |||
| 81 | // F2I is used to convert from a floating point value to an integer | 81 | // F2I is used to convert from a floating point value to an integer |
| 82 | const F2I f2i{insn}; | 82 | const F2I f2i{insn}; |
| 83 | 83 | ||
| 84 | const bool denorm_cares{f2i.src_format != SrcFormat::F16 && f2i.src_format != SrcFormat::F64 && | ||
| 85 | f2i.dest_format != DestFormat::I64}; | ||
| 86 | IR::FmzMode fmz_mode{IR::FmzMode::DontCare}; | ||
| 87 | if (denorm_cares) { | ||
| 88 | fmz_mode = f2i.ftz != 0 ? IR::FmzMode::FTZ : IR::FmzMode::None; | ||
| 89 | } | ||
| 90 | const IR::FpControl fp_control{ | ||
| 91 | .no_contraction{true}, | ||
| 92 | .rounding{IR::FpRounding::DontCare}, | ||
| 93 | .fmz_mode{fmz_mode}, | ||
| 94 | }; | ||
| 84 | const IR::F16F32F64 op_a{v.ir.FPAbsNeg(src_a, f2i.abs != 0, f2i.neg != 0)}; | 95 | const IR::F16F32F64 op_a{v.ir.FPAbsNeg(src_a, f2i.abs != 0, f2i.neg != 0)}; |
| 85 | const IR::F16F32F64 rounded_value{[&] { | 96 | const IR::F16F32F64 rounded_value{[&] { |
| 86 | switch (f2i.rounding) { | 97 | switch (f2i.rounding) { |
| 87 | case Rounding::Round: | 98 | case Rounding::Round: |
| 88 | return v.ir.FPRoundEven(op_a); | 99 | return v.ir.FPRoundEven(op_a, fp_control); |
| 89 | case Rounding::Floor: | 100 | case Rounding::Floor: |
| 90 | return v.ir.FPFloor(op_a); | 101 | return v.ir.FPFloor(op_a, fp_control); |
| 91 | case Rounding::Ceil: | 102 | case Rounding::Ceil: |
| 92 | return v.ir.FPCeil(op_a); | 103 | return v.ir.FPCeil(op_a, fp_control); |
| 93 | case Rounding::Trunc: | 104 | case Rounding::Trunc: |
| 94 | return v.ir.FPTrunc(op_a); | 105 | return v.ir.FPTrunc(op_a, fp_control); |
| 95 | default: | 106 | default: |
| 96 | throw NotImplementedException("Invalid F2I rounding {}", f2i.rounding.Value()); | 107 | throw NotImplementedException("Invalid F2I rounding {}", f2i.rounding.Value()); |
| 97 | } | 108 | } |