Просмотр исходного кода

glasm: Fix register allocation when moving immediate on GLASM

ReinUsesLisp 5 лет назад
Родитель
Сommit
deda89372f

+ 39 - 11
src/shader_recompiler/backend/glasm/emit_glasm.cpp

@@ -39,14 +39,16 @@ struct Identity {
 };
 
 template <bool scalar>
-struct RegWrapper {
-    RegWrapper(EmitContext& ctx, Value value)
-        : reg_alloc{ctx.reg_alloc}, allocated{value.type != Type::Register} {
-        if (allocated) {
+class RegWrapper {
+public:
+    RegWrapper(EmitContext& ctx, const IR::Value& ir_value) : reg_alloc{ctx.reg_alloc} {
+        const Value value{reg_alloc.Peek(ir_value)};
+        if (value.type == Type::Register) {
+            inst = ir_value.InstRecursive();
+            reg = Register{value};
+        } else {
             const bool is_long{value.type == Type::F64 || value.type == Type::U64};
             reg = is_long ? reg_alloc.AllocLongReg() : reg_alloc.AllocReg();
-        } else {
-            reg = Register{value};
         }
         switch (value.type) {
         case Type::Register:
@@ -68,8 +70,11 @@ struct RegWrapper {
             break;
         }
     }
+
     ~RegWrapper() {
-        if (allocated) {
+        if (inst) {
+            reg_alloc.Unref(*inst);
+        } else {
             reg_alloc.FreeReg(reg);
         }
     }
@@ -78,19 +83,42 @@ struct RegWrapper {
         return std::conditional_t<scalar, ScalarRegister, Register>{Value{reg}};
     }
 
+private:
     RegAlloc& reg_alloc;
+    IR::Inst* inst{};
     Register reg{};
-    bool allocated{};
+};
+
+template <typename ArgType>
+class ValueWrapper {
+public:
+    ValueWrapper(EmitContext& ctx, const IR::Value& ir_value_)
+        : reg_alloc{ctx.reg_alloc}, ir_value{ir_value_}, value{reg_alloc.Peek(ir_value)} {}
+
+    ~ValueWrapper() {
+        if (!ir_value.IsImmediate()) {
+            reg_alloc.Unref(*ir_value.InstRecursive());
+        }
+    }
+
+    ArgType Extract() {
+        return value;
+    }
+
+private:
+    RegAlloc& reg_alloc;
+    const IR::Value& ir_value;
+    ArgType value;
 };
 
 template <typename ArgType>
 auto Arg(EmitContext& ctx, const IR::Value& arg) {
     if constexpr (std::is_same_v<ArgType, Register>) {
-        return RegWrapper<false>{ctx, ctx.reg_alloc.Consume(arg)};
+        return RegWrapper<false>{ctx, arg};
     } else if constexpr (std::is_same_v<ArgType, ScalarRegister>) {
-        return RegWrapper<true>{ctx, ctx.reg_alloc.Consume(arg)};
+        return RegWrapper<true>{ctx, arg};
     } else if constexpr (std::is_base_of_v<Value, ArgType>) {
-        return Identity{ArgType{ctx.reg_alloc.Consume(arg)}};
+        return ValueWrapper<ArgType>{ctx, arg};
     } else if constexpr (std::is_same_v<ArgType, const IR::Value&>) {
         return Identity{arg};
     } else if constexpr (std::is_same_v<ArgType, u32>) {

+ 41 - 30
src/shader_recompiler/backend/glasm/reg_alloc.cpp

@@ -21,10 +21,40 @@ Register RegAlloc::LongDefine(IR::Inst& inst) {
     return Define(inst, true);
 }
 
+Value RegAlloc::Peek(const IR::Value& value) {
+    return value.IsImmediate() ? MakeImm(value) : PeekInst(*value.InstRecursive());
+}
+
 Value RegAlloc::Consume(const IR::Value& value) {
-    if (!value.IsImmediate()) {
-        return Consume(*value.InstRecursive());
+    return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive());
+}
+
+void RegAlloc::Unref(IR::Inst& inst) {
+    inst.DestructiveRemoveUsage();
+    if (!inst.HasUses()) {
+        Free(inst.Definition<Id>());
     }
+}
+
+Register RegAlloc::AllocReg() {
+    Register ret;
+    ret.type = Type::Register;
+    ret.id = Alloc(false);
+    return ret;
+}
+
+Register RegAlloc::AllocLongReg() {
+    Register ret;
+    ret.type = Type::Register;
+    ret.id = Alloc(true);
+    return ret;
+}
+
+void RegAlloc::FreeReg(Register reg) {
+    Free(reg.id);
+}
+
+Value RegAlloc::MakeImm(const IR::Value& value) {
     Value ret;
     switch (value.Type()) {
     case IR::Type::U1:
@@ -53,43 +83,24 @@ Value RegAlloc::Consume(const IR::Value& value) {
     return ret;
 }
 
-Register RegAlloc::AllocReg() {
-    Register ret;
-    ret.type = Type::Register;
-    ret.id = Alloc(false);
-    return ret;
-}
-
-Register RegAlloc::AllocLongReg() {
-    Register ret;
-    ret.type = Type::Register;
-    ret.id = Alloc(true);
-    return ret;
-}
-
-void RegAlloc::FreeReg(Register reg) {
-    Free(reg.id);
+Register RegAlloc::Define(IR::Inst& inst, bool is_long) {
+    inst.SetDefinition<Id>(Alloc(is_long));
+    return Register{PeekInst(inst)};
 }
 
-Register RegAlloc::Define(IR::Inst& inst, bool is_long) {
-    const Id id{Alloc(is_long)};
-    inst.SetDefinition<Id>(id);
-    Register ret;
+Value RegAlloc::PeekInst(IR::Inst& inst) {
+    Value ret;
     ret.type = Type::Register;
-    ret.id = id;
+    ret.id = inst.Definition<Id>();
     return ret;
 }
 
-Value RegAlloc::Consume(IR::Inst& inst) {
-    const Id id{inst.Definition<Id>()};
+Value RegAlloc::ConsumeInst(IR::Inst& inst) {
     inst.DestructiveRemoveUsage();
     if (!inst.HasUses()) {
-        Free(id);
+        Free(inst.Definition<Id>());
     }
-    Value ret;
-    ret.type = Type::Register;
-    ret.id = id;
-    return ret;
+    return PeekInst(inst);
 }
 
 Id RegAlloc::Alloc(bool is_long) {

+ 9 - 1
src/shader_recompiler/backend/glasm/reg_alloc.h

@@ -99,8 +99,12 @@ public:
 
     Register LongDefine(IR::Inst& inst);
 
+    [[nodiscard]] Value Peek(const IR::Value& value);
+
     Value Consume(const IR::Value& value);
 
+    void Unref(IR::Inst& inst);
+
     [[nodiscard]] Register AllocReg();
 
     [[nodiscard]] Register AllocLongReg();
@@ -123,9 +127,13 @@ private:
     static constexpr size_t NUM_REGS = 4096;
     static constexpr size_t NUM_ELEMENTS = 4;
 
+    Value MakeImm(const IR::Value& value);
+
     Register Define(IR::Inst& inst, bool is_long);
 
-    Value Consume(IR::Inst& inst);
+    Value PeekInst(IR::Inst& inst);
+
+    Value ConsumeInst(IR::Inst& inst);
 
     Id Alloc(bool is_long);