diff options
| author | 2021-02-19 18:10:18 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:22 -0400 | |
| commit | 6db69990da9f232e6d982cdcb69c2e27d93075cf (patch) | |
| tree | 9367909cd030622ea36c4cadccd2fabc6f28d471 /src/shader_recompiler/frontend | |
| parent | shader: Primitive Vulkan integration (diff) | |
| download | yuzu-6db69990da9f232e6d982cdcb69c2e27d93075cf.tar.gz yuzu-6db69990da9f232e6d982cdcb69c2e27d93075cf.tar.xz yuzu-6db69990da9f232e6d982cdcb69c2e27d93075cf.zip | |
spirv: Add lower fp16 to fp32 pass
Diffstat (limited to 'src/shader_recompiler/frontend')
9 files changed, 97 insertions, 55 deletions
diff --git a/src/shader_recompiler/frontend/ir/condition.h b/src/shader_recompiler/frontend/ir/condition.h index 16b4ae888..51c2f15cf 100644 --- a/src/shader_recompiler/frontend/ir/condition.h +++ b/src/shader_recompiler/frontend/ir/condition.h | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | #include <compare> | 7 | #include <compare> |
| 8 | #include <string> | ||
| 9 | 9 | ||
| 10 | #include <fmt/format.h> | 10 | #include <fmt/format.h> |
| 11 | 11 | ||
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index f42489d41..559ab9cca 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -547,11 +547,11 @@ F32 IREmitter::FPSqrt(const F32& value) { | |||
| 547 | 547 | ||
| 548 | F16F32F64 IREmitter::FPSaturate(const F16F32F64& value) { | 548 | F16F32F64 IREmitter::FPSaturate(const F16F32F64& value) { |
| 549 | switch (value.Type()) { | 549 | switch (value.Type()) { |
| 550 | case Type::U16: | 550 | case Type::F16: |
| 551 | return Inst<F16>(Opcode::FPSaturate16, value); | 551 | return Inst<F16>(Opcode::FPSaturate16, value); |
| 552 | case Type::U32: | 552 | case Type::F32: |
| 553 | return Inst<F32>(Opcode::FPSaturate32, value); | 553 | return Inst<F32>(Opcode::FPSaturate32, value); |
| 554 | case Type::U64: | 554 | case Type::F64: |
| 555 | return Inst<F64>(Opcode::FPSaturate64, value); | 555 | return Inst<F64>(Opcode::FPSaturate64, value); |
| 556 | default: | 556 | default: |
| 557 | ThrowInvalidType(value.Type()); | 557 | ThrowInvalidType(value.Type()); |
| @@ -560,11 +560,11 @@ F16F32F64 IREmitter::FPSaturate(const F16F32F64& value) { | |||
| 560 | 560 | ||
| 561 | F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value) { | 561 | F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value) { |
| 562 | switch (value.Type()) { | 562 | switch (value.Type()) { |
| 563 | case Type::U16: | 563 | case Type::F16: |
| 564 | return Inst<F16>(Opcode::FPRoundEven16, value); | 564 | return Inst<F16>(Opcode::FPRoundEven16, value); |
| 565 | case Type::U32: | 565 | case Type::F32: |
| 566 | return Inst<F32>(Opcode::FPRoundEven32, value); | 566 | return Inst<F32>(Opcode::FPRoundEven32, value); |
| 567 | case Type::U64: | 567 | case Type::F64: |
| 568 | return Inst<F64>(Opcode::FPRoundEven64, value); | 568 | return Inst<F64>(Opcode::FPRoundEven64, value); |
| 569 | default: | 569 | default: |
| 570 | ThrowInvalidType(value.Type()); | 570 | ThrowInvalidType(value.Type()); |
| @@ -573,11 +573,11 @@ F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value) { | |||
| 573 | 573 | ||
| 574 | F16F32F64 IREmitter::FPFloor(const F16F32F64& value) { | 574 | F16F32F64 IREmitter::FPFloor(const F16F32F64& value) { |
| 575 | switch (value.Type()) { | 575 | switch (value.Type()) { |
| 576 | case Type::U16: | 576 | case Type::F16: |
| 577 | return Inst<F16>(Opcode::FPFloor16, value); | 577 | return Inst<F16>(Opcode::FPFloor16, value); |
| 578 | case Type::U32: | 578 | case Type::F32: |
| 579 | return Inst<F32>(Opcode::FPFloor32, value); | 579 | return Inst<F32>(Opcode::FPFloor32, value); |
| 580 | case Type::U64: | 580 | case Type::F64: |
| 581 | return Inst<F64>(Opcode::FPFloor64, value); | 581 | return Inst<F64>(Opcode::FPFloor64, value); |
| 582 | default: | 582 | default: |
| 583 | ThrowInvalidType(value.Type()); | 583 | ThrowInvalidType(value.Type()); |
| @@ -586,11 +586,11 @@ F16F32F64 IREmitter::FPFloor(const F16F32F64& value) { | |||
| 586 | 586 | ||
| 587 | F16F32F64 IREmitter::FPCeil(const F16F32F64& value) { | 587 | F16F32F64 IREmitter::FPCeil(const F16F32F64& value) { |
| 588 | switch (value.Type()) { | 588 | switch (value.Type()) { |
| 589 | case Type::U16: | 589 | case Type::F16: |
| 590 | return Inst<F16>(Opcode::FPCeil16, value); | 590 | return Inst<F16>(Opcode::FPCeil16, value); |
| 591 | case Type::U32: | 591 | case Type::F32: |
| 592 | return Inst<F32>(Opcode::FPCeil32, value); | 592 | return Inst<F32>(Opcode::FPCeil32, value); |
| 593 | case Type::U64: | 593 | case Type::F64: |
| 594 | return Inst<F64>(Opcode::FPCeil64, value); | 594 | return Inst<F64>(Opcode::FPCeil64, value); |
| 595 | default: | 595 | default: |
| 596 | ThrowInvalidType(value.Type()); | 596 | ThrowInvalidType(value.Type()); |
| @@ -599,11 +599,11 @@ F16F32F64 IREmitter::FPCeil(const F16F32F64& value) { | |||
| 599 | 599 | ||
| 600 | F16F32F64 IREmitter::FPTrunc(const F16F32F64& value) { | 600 | F16F32F64 IREmitter::FPTrunc(const F16F32F64& value) { |
| 601 | switch (value.Type()) { | 601 | switch (value.Type()) { |
| 602 | case Type::U16: | 602 | case Type::F16: |
| 603 | return Inst<F16>(Opcode::FPTrunc16, value); | 603 | return Inst<F16>(Opcode::FPTrunc16, value); |
| 604 | case Type::U32: | 604 | case Type::F32: |
| 605 | return Inst<F32>(Opcode::FPTrunc32, value); | 605 | return Inst<F32>(Opcode::FPTrunc32, value); |
| 606 | case Type::U64: | 606 | case Type::F64: |
| 607 | return Inst<F64>(Opcode::FPTrunc64, value); | 607 | return Inst<F64>(Opcode::FPTrunc64, value); |
| 608 | default: | 608 | default: |
| 609 | ThrowInvalidType(value.Type()); | 609 | ThrowInvalidType(value.Type()); |
| @@ -729,33 +729,33 @@ U32U64 IREmitter::ConvertFToS(size_t bitsize, const F16F32F64& value) { | |||
| 729 | switch (bitsize) { | 729 | switch (bitsize) { |
| 730 | case 16: | 730 | case 16: |
| 731 | switch (value.Type()) { | 731 | switch (value.Type()) { |
| 732 | case Type::U16: | 732 | case Type::F16: |
| 733 | return Inst<U32>(Opcode::ConvertS16F16, value); | 733 | return Inst<U32>(Opcode::ConvertS16F16, value); |
| 734 | case Type::U32: | 734 | case Type::F32: |
| 735 | return Inst<U32>(Opcode::ConvertS16F32, value); | 735 | return Inst<U32>(Opcode::ConvertS16F32, value); |
| 736 | case Type::U64: | 736 | case Type::F64: |
| 737 | return Inst<U32>(Opcode::ConvertS16F64, value); | 737 | return Inst<U32>(Opcode::ConvertS16F64, value); |
| 738 | default: | 738 | default: |
| 739 | ThrowInvalidType(value.Type()); | 739 | ThrowInvalidType(value.Type()); |
| 740 | } | 740 | } |
| 741 | case 32: | 741 | case 32: |
| 742 | switch (value.Type()) { | 742 | switch (value.Type()) { |
| 743 | case Type::U16: | 743 | case Type::F16: |
| 744 | return Inst<U32>(Opcode::ConvertS32F16, value); | 744 | return Inst<U32>(Opcode::ConvertS32F16, value); |
| 745 | case Type::U32: | 745 | case Type::F32: |
| 746 | return Inst<U32>(Opcode::ConvertS32F32, value); | 746 | return Inst<U32>(Opcode::ConvertS32F32, value); |
| 747 | case Type::U64: | 747 | case Type::F64: |
| 748 | return Inst<U32>(Opcode::ConvertS32F64, value); | 748 | return Inst<U32>(Opcode::ConvertS32F64, value); |
| 749 | default: | 749 | default: |
| 750 | ThrowInvalidType(value.Type()); | 750 | ThrowInvalidType(value.Type()); |
| 751 | } | 751 | } |
| 752 | case 64: | 752 | case 64: |
| 753 | switch (value.Type()) { | 753 | switch (value.Type()) { |
| 754 | case Type::U16: | 754 | case Type::F16: |
| 755 | return Inst<U64>(Opcode::ConvertS64F16, value); | 755 | return Inst<U64>(Opcode::ConvertS64F16, value); |
| 756 | case Type::U32: | 756 | case Type::F32: |
| 757 | return Inst<U64>(Opcode::ConvertS64F32, value); | 757 | return Inst<U64>(Opcode::ConvertS64F32, value); |
| 758 | case Type::U64: | 758 | case Type::F64: |
| 759 | return Inst<U64>(Opcode::ConvertS64F64, value); | 759 | return Inst<U64>(Opcode::ConvertS64F64, value); |
| 760 | default: | 760 | default: |
| 761 | ThrowInvalidType(value.Type()); | 761 | ThrowInvalidType(value.Type()); |
| @@ -769,33 +769,33 @@ U32U64 IREmitter::ConvertFToU(size_t bitsize, const F16F32F64& value) { | |||
| 769 | switch (bitsize) { | 769 | switch (bitsize) { |
| 770 | case 16: | 770 | case 16: |
| 771 | switch (value.Type()) { | 771 | switch (value.Type()) { |
| 772 | case Type::U16: | 772 | case Type::F16: |
| 773 | return Inst<U32>(Opcode::ConvertU16F16, value); | 773 | return Inst<U32>(Opcode::ConvertU16F16, value); |
| 774 | case Type::U32: | 774 | case Type::F32: |
| 775 | return Inst<U32>(Opcode::ConvertU16F32, value); | 775 | return Inst<U32>(Opcode::ConvertU16F32, value); |
| 776 | case Type::U64: | 776 | case Type::F64: |
| 777 | return Inst<U32>(Opcode::ConvertU16F64, value); | 777 | return Inst<U32>(Opcode::ConvertU16F64, value); |
| 778 | default: | 778 | default: |
| 779 | ThrowInvalidType(value.Type()); | 779 | ThrowInvalidType(value.Type()); |
| 780 | } | 780 | } |
| 781 | case 32: | 781 | case 32: |
| 782 | switch (value.Type()) { | 782 | switch (value.Type()) { |
| 783 | case Type::U16: | 783 | case Type::F16: |
| 784 | return Inst<U32>(Opcode::ConvertU32F16, value); | 784 | return Inst<U32>(Opcode::ConvertU32F16, value); |
| 785 | case Type::U32: | 785 | case Type::F32: |
| 786 | return Inst<U32>(Opcode::ConvertU32F32, value); | 786 | return Inst<U32>(Opcode::ConvertU32F32, value); |
| 787 | case Type::U64: | 787 | case Type::F64: |
| 788 | return Inst<U32>(Opcode::ConvertU32F64, value); | 788 | return Inst<U32>(Opcode::ConvertU32F64, value); |
| 789 | default: | 789 | default: |
| 790 | ThrowInvalidType(value.Type()); | 790 | ThrowInvalidType(value.Type()); |
| 791 | } | 791 | } |
| 792 | case 64: | 792 | case 64: |
| 793 | switch (value.Type()) { | 793 | switch (value.Type()) { |
| 794 | case Type::U16: | 794 | case Type::F16: |
| 795 | return Inst<U64>(Opcode::ConvertU64F16, value); | 795 | return Inst<U64>(Opcode::ConvertU64F16, value); |
| 796 | case Type::U32: | 796 | case Type::F32: |
| 797 | return Inst<U64>(Opcode::ConvertU64F32, value); | 797 | return Inst<U64>(Opcode::ConvertU64F32, value); |
| 798 | case Type::U64: | 798 | case Type::F64: |
| 799 | return Inst<U64>(Opcode::ConvertU64F64, value); | 799 | return Inst<U64>(Opcode::ConvertU64F64, value); |
| 800 | default: | 800 | default: |
| 801 | ThrowInvalidType(value.Type()); | 801 | ThrowInvalidType(value.Type()); |
| @@ -829,10 +829,10 @@ U32U64 IREmitter::ConvertU(size_t result_bitsize, const U32U64& value) { | |||
| 829 | case 64: | 829 | case 64: |
| 830 | switch (value.Type()) { | 830 | switch (value.Type()) { |
| 831 | case Type::U32: | 831 | case Type::U32: |
| 832 | return Inst<U64>(Opcode::ConvertU64U32, value); | ||
| 833 | case Type::U64: | ||
| 832 | // Nothing to do | 834 | // Nothing to do |
| 833 | return value; | 835 | return value; |
| 834 | case Type::U64: | ||
| 835 | return Inst<U64>(Opcode::ConvertU64U32, value); | ||
| 836 | default: | 836 | default: |
| 837 | break; | 837 | break; |
| 838 | } | 838 | } |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index ee76db9ad..d6a9be87d 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -216,6 +216,10 @@ void Inst::ReplaceUsesWith(Value replacement) { | |||
| 216 | } | 216 | } |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | void Inst::ReplaceOpcode(IR::Opcode opcode) { | ||
| 220 | op = opcode; | ||
| 221 | } | ||
| 222 | |||
| 219 | void Inst::Use(const Value& value) { | 223 | void Inst::Use(const Value& value) { |
| 220 | Inst* const inst{value.Inst()}; | 224 | Inst* const inst{value.Inst()}; |
| 221 | ++inst->use_count; | 225 | ++inst->use_count; |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.h b/src/shader_recompiler/frontend/ir/microinstruction.h index 5b244fa0b..321393dd7 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.h +++ b/src/shader_recompiler/frontend/ir/microinstruction.h | |||
| @@ -86,6 +86,8 @@ public: | |||
| 86 | 86 | ||
| 87 | void ReplaceUsesWith(Value replacement); | 87 | void ReplaceUsesWith(Value replacement); |
| 88 | 88 | ||
| 89 | void ReplaceOpcode(IR::Opcode opcode); | ||
| 90 | |||
| 89 | template <typename FlagsType> | 91 | template <typename FlagsType> |
| 90 | requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>) | 92 | requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>) |
| 91 | [[nodiscard]] FlagsType Flags() const noexcept { | 93 | [[nodiscard]] FlagsType Flags() const noexcept { |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index ede5e20c2..50da77535 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -119,8 +119,10 @@ OPCODE(PackUint2x32, U64, U32x | |||
| 119 | OPCODE(UnpackUint2x32, U32x2, U64, ) | 119 | OPCODE(UnpackUint2x32, U32x2, U64, ) |
| 120 | OPCODE(PackFloat2x16, U32, F16x2, ) | 120 | OPCODE(PackFloat2x16, U32, F16x2, ) |
| 121 | OPCODE(UnpackFloat2x16, F16x2, U32, ) | 121 | OPCODE(UnpackFloat2x16, F16x2, U32, ) |
| 122 | OPCODE(PackDouble2x32, U64, U32x2, ) | 122 | OPCODE(PackHalf2x16, U32, F32x2, ) |
| 123 | OPCODE(UnpackDouble2x32, U32x2, U64, ) | 123 | OPCODE(UnpackHalf2x16, F32x2, U32, ) |
| 124 | OPCODE(PackDouble2x32, F64, U32x2, ) | ||
| 125 | OPCODE(UnpackDouble2x32, U32x2, F64, ) | ||
| 124 | 126 | ||
| 125 | // Pseudo-operation, handled specially at final emit | 127 | // Pseudo-operation, handled specially at final emit |
| 126 | OPCODE(GetZeroFromOp, U1, Opaque, ) | 128 | OPCODE(GetZeroFromOp, U1, Opaque, ) |
diff --git a/src/shader_recompiler/frontend/ir/program.cpp b/src/shader_recompiler/frontend/ir/program.cpp index 0ce99ef2a..8c301c3a1 100644 --- a/src/shader_recompiler/frontend/ir/program.cpp +++ b/src/shader_recompiler/frontend/ir/program.cpp | |||
| @@ -35,4 +35,4 @@ std::string DumpProgram(const Program& program) { | |||
| 35 | return ret; | 35 | return ret; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | } // namespace Shader::IR \ No newline at end of file | 38 | } // namespace Shader::IR |
diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp index 8c44ebb29..16cdc12e2 100644 --- a/src/shader_recompiler/frontend/maxwell/program.cpp +++ b/src/shader_recompiler/frontend/maxwell/program.cpp | |||
| @@ -56,6 +56,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 56 | .post_order_blocks{}, | 56 | .post_order_blocks{}, |
| 57 | }); | 57 | }); |
| 58 | } | 58 | } |
| 59 | Optimization::LowerFp16ToFp32(program); | ||
| 59 | for (IR::Function& function : functions) { | 60 | for (IR::Function& function : functions) { |
| 60 | function.post_order_blocks = PostOrder(function.blocks); | 61 | function.post_order_blocks = PostOrder(function.blocks); |
| 61 | Optimization::SsaRewritePass(function.post_order_blocks); | 62 | Optimization::SsaRewritePass(function.post_order_blocks); |
| @@ -69,6 +70,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 69 | Optimization::VerificationPass(function); | 70 | Optimization::VerificationPass(function); |
| 70 | } | 71 | } |
| 71 | Optimization::CollectShaderInfoPass(program); | 72 | Optimization::CollectShaderInfoPass(program); |
| 73 | |||
| 72 | fmt::print(stdout, "{}\n", IR::DumpProgram(program)); | 74 | fmt::print(stdout, "{}\n", IR::DumpProgram(program)); |
| 73 | return program; | 75 | return program; |
| 74 | } | 76 | } |
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 3d0c48457..ae2d37405 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 | |||
| @@ -34,7 +34,7 @@ union F2I { | |||
| 34 | BitField<8, 2, DestFormat> dest_format; | 34 | BitField<8, 2, DestFormat> dest_format; |
| 35 | BitField<10, 2, SrcFormat> src_format; | 35 | BitField<10, 2, SrcFormat> src_format; |
| 36 | BitField<12, 1, u64> is_signed; | 36 | BitField<12, 1, u64> is_signed; |
| 37 | BitField<39, 1, Rounding> rounding; | 37 | BitField<39, 2, Rounding> rounding; |
| 38 | BitField<49, 1, u64> half; | 38 | BitField<49, 1, u64> half; |
| 39 | BitField<44, 1, u64> ftz; | 39 | BitField<44, 1, u64> ftz; |
| 40 | BitField<45, 1, u64> abs; | 40 | BitField<45, 1, u64> abs; |
| @@ -55,6 +55,28 @@ size_t BitSize(DestFormat dest_format) { | |||
| 55 | } | 55 | } |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | IR::F64 UnpackCbuf(TranslatorVisitor& v, u64 insn) { | ||
| 59 | union { | ||
| 60 | u64 raw; | ||
| 61 | BitField<20, 14, s64> offset; | ||
| 62 | BitField<34, 5, u64> binding; | ||
| 63 | } const cbuf{insn}; | ||
| 64 | if (cbuf.binding >= 18) { | ||
| 65 | throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding); | ||
| 66 | } | ||
| 67 | if (cbuf.offset >= 0x4'000 || cbuf.offset < 0) { | ||
| 68 | throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset * 4); | ||
| 69 | } | ||
| 70 | if (cbuf.offset % 2 != 0) { | ||
| 71 | throw NotImplementedException("Unaligned F64 constant buffer offset {}", cbuf.offset * 4); | ||
| 72 | } | ||
| 73 | const IR::U32 binding{v.ir.Imm32(static_cast<u32>(cbuf.binding))}; | ||
| 74 | const IR::U32 byte_offset{v.ir.Imm32(static_cast<u32>(cbuf.offset) * 4 + 4)}; | ||
| 75 | const IR::U32 cbuf_data{v.ir.GetCbuf(binding, byte_offset)}; | ||
| 76 | const IR::Value vector{v.ir.CompositeConstruct(v.ir.Imm32(0U), cbuf_data)}; | ||
| 77 | return v.ir.PackDouble2x32(vector); | ||
| 78 | } | ||
| 79 | |||
| 58 | void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) { | 80 | void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) { |
| 59 | // 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 |
| 60 | const F2I f2i{insn}; | 82 | const F2I f2i{insn}; |
| @@ -82,19 +104,16 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) { | |||
| 82 | const size_t bitsize{BitSize(f2i.dest_format)}; | 104 | const size_t bitsize{BitSize(f2i.dest_format)}; |
| 83 | const IR::U16U32U64 result{v.ir.ConvertFToI(bitsize, is_signed, rounded_value)}; | 105 | const IR::U16U32U64 result{v.ir.ConvertFToI(bitsize, is_signed, rounded_value)}; |
| 84 | 106 | ||
| 85 | v.X(f2i.dest_reg, result); | 107 | if (bitsize == 64) { |
| 108 | const IR::Value vector{v.ir.UnpackUint2x32(result)}; | ||
| 109 | v.X(f2i.dest_reg + 0, IR::U32{v.ir.CompositeExtract(vector, 0)}); | ||
| 110 | v.X(f2i.dest_reg + 1, IR::U32{v.ir.CompositeExtract(vector, 1)}); | ||
| 111 | } else { | ||
| 112 | v.X(f2i.dest_reg, result); | ||
| 113 | } | ||
| 86 | 114 | ||
| 87 | if (f2i.cc != 0) { | 115 | if (f2i.cc != 0) { |
| 88 | v.SetZFlag(v.ir.GetZeroFromOp(result)); | 116 | throw NotImplementedException("F2I CC"); |
| 89 | if (is_signed) { | ||
| 90 | v.SetSFlag(v.ir.GetSignFromOp(result)); | ||
| 91 | } else { | ||
| 92 | v.ResetSFlag(); | ||
| 93 | } | ||
| 94 | v.ResetCFlag(); | ||
| 95 | |||
| 96 | // TODO: Investigate if out of bound conversions sets the overflow flag | ||
| 97 | v.ResetOFlag(); | ||
| 98 | } | 117 | } |
| 99 | } | 118 | } |
| 100 | } // Anonymous namespace | 119 | } // Anonymous namespace |
| @@ -118,12 +137,25 @@ void TranslatorVisitor::F2I_reg(u64 insn) { | |||
| 118 | f2i.base.src_format.Value()); | 137 | f2i.base.src_format.Value()); |
| 119 | } | 138 | } |
| 120 | }()}; | 139 | }()}; |
| 121 | |||
| 122 | TranslateF2I(*this, insn, op_a); | 140 | TranslateF2I(*this, insn, op_a); |
| 123 | } | 141 | } |
| 124 | 142 | ||
| 125 | void TranslatorVisitor::F2I_cbuf(u64) { | 143 | void TranslatorVisitor::F2I_cbuf(u64 insn) { |
| 126 | throw NotImplementedException("{}", Opcode::F2I_cbuf); | 144 | const F2I f2i{insn}; |
| 145 | const IR::F16F32F64 op_a{[&]() -> IR::F16F32F64 { | ||
| 146 | switch (f2i.src_format) { | ||
| 147 | case SrcFormat::F16: | ||
| 148 | return IR::F16{ir.CompositeExtract(ir.UnpackFloat2x16(GetCbuf(insn)), f2i.half)}; | ||
| 149 | case SrcFormat::F32: | ||
| 150 | return GetCbufF(insn); | ||
| 151 | case SrcFormat::F64: { | ||
| 152 | return UnpackCbuf(*this, insn); | ||
| 153 | } | ||
| 154 | default: | ||
| 155 | throw NotImplementedException("Invalid F2I source format {}", f2i.src_format.Value()); | ||
| 156 | } | ||
| 157 | }()}; | ||
| 158 | TranslateF2I(*this, insn, op_a); | ||
| 127 | } | 159 | } |
| 128 | 160 | ||
| 129 | void TranslatorVisitor::F2I_imm(u64) { | 161 | void TranslatorVisitor::F2I_imm(u64) { |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h index 8bd468244..27aba2cf8 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h | |||
| @@ -11,7 +11,7 @@ namespace Shader::Maxwell { | |||
| 11 | 11 | ||
| 12 | class TranslatorVisitor { | 12 | class TranslatorVisitor { |
| 13 | public: | 13 | public: |
| 14 | explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_} ,ir(block) {} | 14 | explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_}, ir(block) {} |
| 15 | 15 | ||
| 16 | Environment& env; | 16 | Environment& env; |
| 17 | IR::IREmitter ir; | 17 | IR::IREmitter ir; |