diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/backend/glasm/emit_glasm.cpp | 50 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/glasm/reg_alloc.cpp | 71 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/glasm/reg_alloc.h | 10 |
3 files changed, 89 insertions, 42 deletions
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index 8e5d575a9..ad27b8b06 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp | |||
| @@ -39,14 +39,16 @@ struct Identity { | |||
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | template <bool scalar> | 41 | template <bool scalar> |
| 42 | struct RegWrapper { | 42 | class RegWrapper { |
| 43 | RegWrapper(EmitContext& ctx, Value value) | 43 | public: |
| 44 | : reg_alloc{ctx.reg_alloc}, allocated{value.type != Type::Register} { | 44 | RegWrapper(EmitContext& ctx, const IR::Value& ir_value) : reg_alloc{ctx.reg_alloc} { |
| 45 | if (allocated) { | 45 | const Value value{reg_alloc.Peek(ir_value)}; |
| 46 | if (value.type == Type::Register) { | ||
| 47 | inst = ir_value.InstRecursive(); | ||
| 48 | reg = Register{value}; | ||
| 49 | } else { | ||
| 46 | const bool is_long{value.type == Type::F64 || value.type == Type::U64}; | 50 | const bool is_long{value.type == Type::F64 || value.type == Type::U64}; |
| 47 | reg = is_long ? reg_alloc.AllocLongReg() : reg_alloc.AllocReg(); | 51 | reg = is_long ? reg_alloc.AllocLongReg() : reg_alloc.AllocReg(); |
| 48 | } else { | ||
| 49 | reg = Register{value}; | ||
| 50 | } | 52 | } |
| 51 | switch (value.type) { | 53 | switch (value.type) { |
| 52 | case Type::Register: | 54 | case Type::Register: |
| @@ -68,8 +70,11 @@ struct RegWrapper { | |||
| 68 | break; | 70 | break; |
| 69 | } | 71 | } |
| 70 | } | 72 | } |
| 73 | |||
| 71 | ~RegWrapper() { | 74 | ~RegWrapper() { |
| 72 | if (allocated) { | 75 | if (inst) { |
| 76 | reg_alloc.Unref(*inst); | ||
| 77 | } else { | ||
| 73 | reg_alloc.FreeReg(reg); | 78 | reg_alloc.FreeReg(reg); |
| 74 | } | 79 | } |
| 75 | } | 80 | } |
| @@ -78,19 +83,42 @@ struct RegWrapper { | |||
| 78 | return std::conditional_t<scalar, ScalarRegister, Register>{Value{reg}}; | 83 | return std::conditional_t<scalar, ScalarRegister, Register>{Value{reg}}; |
| 79 | } | 84 | } |
| 80 | 85 | ||
| 86 | private: | ||
| 81 | RegAlloc& reg_alloc; | 87 | RegAlloc& reg_alloc; |
| 88 | IR::Inst* inst{}; | ||
| 82 | Register reg{}; | 89 | Register reg{}; |
| 83 | bool allocated{}; | 90 | }; |
| 91 | |||
| 92 | template <typename ArgType> | ||
| 93 | class ValueWrapper { | ||
| 94 | public: | ||
| 95 | ValueWrapper(EmitContext& ctx, const IR::Value& ir_value_) | ||
| 96 | : reg_alloc{ctx.reg_alloc}, ir_value{ir_value_}, value{reg_alloc.Peek(ir_value)} {} | ||
| 97 | |||
| 98 | ~ValueWrapper() { | ||
| 99 | if (!ir_value.IsImmediate()) { | ||
| 100 | reg_alloc.Unref(*ir_value.InstRecursive()); | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | ArgType Extract() { | ||
| 105 | return value; | ||
| 106 | } | ||
| 107 | |||
| 108 | private: | ||
| 109 | RegAlloc& reg_alloc; | ||
| 110 | const IR::Value& ir_value; | ||
| 111 | ArgType value; | ||
| 84 | }; | 112 | }; |
| 85 | 113 | ||
| 86 | template <typename ArgType> | 114 | template <typename ArgType> |
| 87 | auto Arg(EmitContext& ctx, const IR::Value& arg) { | 115 | auto Arg(EmitContext& ctx, const IR::Value& arg) { |
| 88 | if constexpr (std::is_same_v<ArgType, Register>) { | 116 | if constexpr (std::is_same_v<ArgType, Register>) { |
| 89 | return RegWrapper<false>{ctx, ctx.reg_alloc.Consume(arg)}; | 117 | return RegWrapper<false>{ctx, arg}; |
| 90 | } else if constexpr (std::is_same_v<ArgType, ScalarRegister>) { | 118 | } else if constexpr (std::is_same_v<ArgType, ScalarRegister>) { |
| 91 | return RegWrapper<true>{ctx, ctx.reg_alloc.Consume(arg)}; | 119 | return RegWrapper<true>{ctx, arg}; |
| 92 | } else if constexpr (std::is_base_of_v<Value, ArgType>) { | 120 | } else if constexpr (std::is_base_of_v<Value, ArgType>) { |
| 93 | return Identity{ArgType{ctx.reg_alloc.Consume(arg)}}; | 121 | return ValueWrapper<ArgType>{ctx, arg}; |
| 94 | } else if constexpr (std::is_same_v<ArgType, const IR::Value&>) { | 122 | } else if constexpr (std::is_same_v<ArgType, const IR::Value&>) { |
| 95 | return Identity{arg}; | 123 | return Identity{arg}; |
| 96 | } else if constexpr (std::is_same_v<ArgType, u32>) { | 124 | } else if constexpr (std::is_same_v<ArgType, u32>) { |
diff --git a/src/shader_recompiler/backend/glasm/reg_alloc.cpp b/src/shader_recompiler/backend/glasm/reg_alloc.cpp index 1a65a5e7d..f556f3aee 100644 --- a/src/shader_recompiler/backend/glasm/reg_alloc.cpp +++ b/src/shader_recompiler/backend/glasm/reg_alloc.cpp | |||
| @@ -21,10 +21,40 @@ Register RegAlloc::LongDefine(IR::Inst& inst) { | |||
| 21 | return Define(inst, true); | 21 | return Define(inst, true); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | Value RegAlloc::Peek(const IR::Value& value) { | ||
| 25 | return value.IsImmediate() ? MakeImm(value) : PeekInst(*value.InstRecursive()); | ||
| 26 | } | ||
| 27 | |||
| 24 | Value RegAlloc::Consume(const IR::Value& value) { | 28 | Value RegAlloc::Consume(const IR::Value& value) { |
| 25 | if (!value.IsImmediate()) { | 29 | return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive()); |
| 26 | return Consume(*value.InstRecursive()); | 30 | } |
| 31 | |||
| 32 | void RegAlloc::Unref(IR::Inst& inst) { | ||
| 33 | inst.DestructiveRemoveUsage(); | ||
| 34 | if (!inst.HasUses()) { | ||
| 35 | Free(inst.Definition<Id>()); | ||
| 27 | } | 36 | } |
| 37 | } | ||
| 38 | |||
| 39 | Register RegAlloc::AllocReg() { | ||
| 40 | Register ret; | ||
| 41 | ret.type = Type::Register; | ||
| 42 | ret.id = Alloc(false); | ||
| 43 | return ret; | ||
| 44 | } | ||
| 45 | |||
| 46 | Register RegAlloc::AllocLongReg() { | ||
| 47 | Register ret; | ||
| 48 | ret.type = Type::Register; | ||
| 49 | ret.id = Alloc(true); | ||
| 50 | return ret; | ||
| 51 | } | ||
| 52 | |||
| 53 | void RegAlloc::FreeReg(Register reg) { | ||
| 54 | Free(reg.id); | ||
| 55 | } | ||
| 56 | |||
| 57 | Value RegAlloc::MakeImm(const IR::Value& value) { | ||
| 28 | Value ret; | 58 | Value ret; |
| 29 | switch (value.Type()) { | 59 | switch (value.Type()) { |
| 30 | case IR::Type::U1: | 60 | case IR::Type::U1: |
| @@ -53,43 +83,24 @@ Value RegAlloc::Consume(const IR::Value& value) { | |||
| 53 | return ret; | 83 | return ret; |
| 54 | } | 84 | } |
| 55 | 85 | ||
| 56 | Register RegAlloc::AllocReg() { | 86 | Register RegAlloc::Define(IR::Inst& inst, bool is_long) { |
| 57 | Register ret; | 87 | inst.SetDefinition<Id>(Alloc(is_long)); |
| 58 | ret.type = Type::Register; | 88 | return Register{PeekInst(inst)}; |
| 59 | ret.id = Alloc(false); | ||
| 60 | return ret; | ||
| 61 | } | ||
| 62 | |||
| 63 | Register RegAlloc::AllocLongReg() { | ||
| 64 | Register ret; | ||
| 65 | ret.type = Type::Register; | ||
| 66 | ret.id = Alloc(true); | ||
| 67 | return ret; | ||
| 68 | } | ||
| 69 | |||
| 70 | void RegAlloc::FreeReg(Register reg) { | ||
| 71 | Free(reg.id); | ||
| 72 | } | 89 | } |
| 73 | 90 | ||
| 74 | Register RegAlloc::Define(IR::Inst& inst, bool is_long) { | 91 | Value RegAlloc::PeekInst(IR::Inst& inst) { |
| 75 | const Id id{Alloc(is_long)}; | 92 | Value ret; |
| 76 | inst.SetDefinition<Id>(id); | ||
| 77 | Register ret; | ||
| 78 | ret.type = Type::Register; | 93 | ret.type = Type::Register; |
| 79 | ret.id = id; | 94 | ret.id = inst.Definition<Id>(); |
| 80 | return ret; | 95 | return ret; |
| 81 | } | 96 | } |
| 82 | 97 | ||
| 83 | Value RegAlloc::Consume(IR::Inst& inst) { | 98 | Value RegAlloc::ConsumeInst(IR::Inst& inst) { |
| 84 | const Id id{inst.Definition<Id>()}; | ||
| 85 | inst.DestructiveRemoveUsage(); | 99 | inst.DestructiveRemoveUsage(); |
| 86 | if (!inst.HasUses()) { | 100 | if (!inst.HasUses()) { |
| 87 | Free(id); | 101 | Free(inst.Definition<Id>()); |
| 88 | } | 102 | } |
| 89 | Value ret; | 103 | return PeekInst(inst); |
| 90 | ret.type = Type::Register; | ||
| 91 | ret.id = id; | ||
| 92 | return ret; | ||
| 93 | } | 104 | } |
| 94 | 105 | ||
| 95 | Id RegAlloc::Alloc(bool is_long) { | 106 | Id RegAlloc::Alloc(bool is_long) { |
diff --git a/src/shader_recompiler/backend/glasm/reg_alloc.h b/src/shader_recompiler/backend/glasm/reg_alloc.h index 8df73ca18..5742436cf 100644 --- a/src/shader_recompiler/backend/glasm/reg_alloc.h +++ b/src/shader_recompiler/backend/glasm/reg_alloc.h | |||
| @@ -99,8 +99,12 @@ public: | |||
| 99 | 99 | ||
| 100 | Register LongDefine(IR::Inst& inst); | 100 | Register LongDefine(IR::Inst& inst); |
| 101 | 101 | ||
| 102 | [[nodiscard]] Value Peek(const IR::Value& value); | ||
| 103 | |||
| 102 | Value Consume(const IR::Value& value); | 104 | Value Consume(const IR::Value& value); |
| 103 | 105 | ||
| 106 | void Unref(IR::Inst& inst); | ||
| 107 | |||
| 104 | [[nodiscard]] Register AllocReg(); | 108 | [[nodiscard]] Register AllocReg(); |
| 105 | 109 | ||
| 106 | [[nodiscard]] Register AllocLongReg(); | 110 | [[nodiscard]] Register AllocLongReg(); |
| @@ -123,9 +127,13 @@ private: | |||
| 123 | static constexpr size_t NUM_REGS = 4096; | 127 | static constexpr size_t NUM_REGS = 4096; |
| 124 | static constexpr size_t NUM_ELEMENTS = 4; | 128 | static constexpr size_t NUM_ELEMENTS = 4; |
| 125 | 129 | ||
| 130 | Value MakeImm(const IR::Value& value); | ||
| 131 | |||
| 126 | Register Define(IR::Inst& inst, bool is_long); | 132 | Register Define(IR::Inst& inst, bool is_long); |
| 127 | 133 | ||
| 128 | Value Consume(IR::Inst& inst); | 134 | Value PeekInst(IR::Inst& inst); |
| 135 | |||
| 136 | Value ConsumeInst(IR::Inst& inst); | ||
| 129 | 137 | ||
| 130 | Id Alloc(bool is_long); | 138 | Id Alloc(bool is_long); |
| 131 | 139 | ||