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

glasm: Fix aliased bitcasts ref counting

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

+ 4 - 6
src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp

@@ -12,12 +12,10 @@ static void Alias(IR::Inst& inst, const IR::Value& value) {
     if (value.IsImmediate()) {
     if (value.IsImmediate()) {
         return;
         return;
     }
     }
-    IR::Inst* const value_inst{value.InstRecursive()};
-    if (inst.GetOpcode() == IR::Opcode::Identity) {
-        value_inst->DestructiveAddUsage(inst.UseCount());
-        value_inst->DestructiveRemoveUsage();
-    }
-    inst.SetDefinition(value_inst->Definition<Id>());
+    IR::Inst& value_inst{RegAlloc::AliasInst(*value.Inst())};
+    value_inst.DestructiveAddUsage(inst.UseCount());
+    value_inst.DestructiveRemoveUsage();
+    inst.SetDefinition(value_inst.Definition<Id>());
 }
 }
 
 
 void EmitIdentity(EmitContext&, IR::Inst& inst, const IR::Value& value) {
 void EmitIdentity(EmitContext&, IR::Inst& inst, const IR::Value& value) {

+ 32 - 7
src/shader_recompiler/backend/glasm/reg_alloc.cpp

@@ -30,9 +30,10 @@ Value RegAlloc::Consume(const IR::Value& value) {
 }
 }
 
 
 void RegAlloc::Unref(IR::Inst& inst) {
 void RegAlloc::Unref(IR::Inst& inst) {
-    inst.DestructiveRemoveUsage();
-    if (!inst.HasUses()) {
-        Free(inst.Definition<Id>());
+    IR::Inst& value_inst{AliasInst(inst)};
+    value_inst.DestructiveRemoveUsage();
+    if (!value_inst.HasUses()) {
+        Free(value_inst.Definition<Id>());
     }
     }
 }
 }
 
 
@@ -99,10 +100,7 @@ Value RegAlloc::PeekInst(IR::Inst& inst) {
 }
 }
 
 
 Value RegAlloc::ConsumeInst(IR::Inst& inst) {
 Value RegAlloc::ConsumeInst(IR::Inst& inst) {
-    inst.DestructiveRemoveUsage();
-    if (!inst.HasUses()) {
-        Free(inst.Definition<Id>());
-    }
+    Unref(inst);
     return PeekInst(inst);
     return PeekInst(inst);
 }
 }
 
 
@@ -138,4 +136,31 @@ void RegAlloc::Free(Id id) {
     }
     }
 }
 }
 
 
+/*static*/ bool RegAlloc::IsAliased(const IR::Inst& inst) {
+    switch (inst.GetOpcode()) {
+    case IR::Opcode::Identity:
+    case IR::Opcode::BitCastU16F16:
+    case IR::Opcode::BitCastU32F32:
+    case IR::Opcode::BitCastU64F64:
+    case IR::Opcode::BitCastF16U16:
+    case IR::Opcode::BitCastF32U32:
+    case IR::Opcode::BitCastF64U64:
+        return true;
+    default:
+        return false;
+    }
+}
+
+/*static*/ IR::Inst& RegAlloc::AliasInst(IR::Inst& inst) {
+    IR::Inst* it{&inst};
+    while (IsAliased(*it)) {
+        const IR::Value arg{it->Arg(0)};
+        if (arg.IsImmediate()) {
+            break;
+        }
+        it = arg.InstRecursive();
+    }
+    return *it;
+}
+
 } // namespace Shader::Backend::GLASM
 } // namespace Shader::Backend::GLASM

+ 6 - 0
src/shader_recompiler/backend/glasm/reg_alloc.h

@@ -126,6 +126,12 @@ public:
         return num_used_long_registers;
         return num_used_long_registers;
     }
     }
 
 
+    /// Returns true if the instruction is expected to be aliased to another
+    static bool IsAliased(const IR::Inst& inst);
+
+    /// Returns the underlying value out of an alias sequence
+    static IR::Inst& AliasInst(IR::Inst& inst);
+
 private:
 private:
     static constexpr size_t NUM_REGS = 4096;
     static constexpr size_t NUM_REGS = 4096;
     static constexpr size_t NUM_ELEMENTS = 4;
     static constexpr size_t NUM_ELEMENTS = 4;