From 3f594dd86bd1ee1b178109132482c7d6b43e66dd Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sun, 4 Apr 2021 02:31:09 -0300
Subject: [PATCH] shader: Reimplement GetCbufU64 as GetCbufU32x2

It may generate better code on some compilers and it's easier to handle.
---
 src/shader_recompiler/backend/spirv/emit_context.cpp |  4 ++--
 src/shader_recompiler/backend/spirv/emit_context.h   |  2 +-
 src/shader_recompiler/backend/spirv/emit_spirv.h     |  2 +-
 .../backend/spirv/emit_spirv_context_get_set.cpp     |  4 ++--
 src/shader_recompiler/frontend/ir/ir_emitter.cpp     |  6 +++---
 src/shader_recompiler/frontend/ir/ir_emitter.h       |  4 ++--
 src/shader_recompiler/frontend/ir/opcodes.inc        |  2 +-
 .../maxwell/translate/impl/load_constant.cpp         | 12 ++++++------
 .../ir_opt/collect_shader_info_pass.cpp              |  7 +++----
 9 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 32f679f2a9..e70b78a284 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -308,8 +308,8 @@ void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
     if (True(info.used_constant_buffer_types & IR::Type::F32)) {
         DefineConstantBuffers(info, &UniformDefinitions::F32, binding, F32[1], 'f', sizeof(f32));
     }
-    if (True(info.used_constant_buffer_types & IR::Type::U64)) {
-        DefineConstantBuffers(info, &UniformDefinitions::U64, binding, U64, 'u', sizeof(u64));
+    if (True(info.used_constant_buffer_types & IR::Type::U32x2)) {
+        DefineConstantBuffers(info, &UniformDefinitions::U32x2, binding, U32[2], 'u', sizeof(u64));
     }
     for (const ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
         binding += desc.count;
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index f4715a709b..3a686a78c9 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -42,7 +42,7 @@ struct UniformDefinitions {
     Id S16{};
     Id U32{};
     Id F32{};
-    Id U64{};
+    Id U32x2{};
 };
 
 class EmitContext final : public Sirit::Module {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index 5d0f16b3ab..e066ba87d5 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -47,7 +47,7 @@ Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& o
 Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
 Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
 Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
-Id EmitGetCbufU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
+Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
 Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr);
 void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value);
 void EmitGetAttributeIndexed(EmitContext& ctx);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index caab9aa125..1bfc602945 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -153,8 +153,8 @@ Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& o
     return GetCbuf(ctx, ctx.F32[1], &UniformDefinitions::F32, sizeof(f32), binding, offset);
 }
 
-Id EmitGetCbufU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
-    return GetCbuf(ctx, ctx.U64, &UniformDefinitions::U64, sizeof(u64), binding, offset);
+Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
+    return GetCbuf(ctx, ctx.U32[2], &UniformDefinitions::U32x2, sizeof(u32[2]), binding, offset);
 }
 
 Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr) {
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index dbfc670b0d..dbd38a28b3 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -162,8 +162,8 @@ U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) {
     return Inst<U32>(Opcode::GetCbufU32, binding, byte_offset);
 }
 
-UAny IREmitter::GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
-                        bool is_signed) {
+Value IREmitter::GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
+                         bool is_signed) {
     switch (bitsize) {
     case 8:
         return Inst<U32>(is_signed ? Opcode::GetCbufS8 : Opcode::GetCbufU8, binding, byte_offset);
@@ -172,7 +172,7 @@ UAny IREmitter::GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsi
     case 32:
         return Inst<U32>(Opcode::GetCbufU32, binding, byte_offset);
     case 64:
-        return Inst<U64>(Opcode::GetCbufU64, binding, byte_offset);
+        return Inst(Opcode::GetCbufU32x2, binding, byte_offset);
     default:
         throw InvalidArgument("Invalid bit size {}", bitsize);
     }
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 14b743975d..81a57fefea 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -56,8 +56,8 @@ public:
     void SetIndirectBranchVariable(const U32& value);
 
     [[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset);
-    [[nodiscard]] UAny GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
-                               bool is_signed);
+    [[nodiscard]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
+                                bool is_signed);
     [[nodiscard]] F32 GetFloatCbuf(const U32& binding, const U32& byte_offset);
 
     [[nodiscard]] U1 GetZFlag();
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 3640a5d242..734f5328be 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -40,7 +40,7 @@ OPCODE(GetCbufU16,                                          U32,            U32,
 OPCODE(GetCbufS16,                                          U32,            U32,            U32,                                                            )
 OPCODE(GetCbufU32,                                          U32,            U32,            U32,                                                            )
 OPCODE(GetCbufF32,                                          F32,            U32,            U32,                                                            )
-OPCODE(GetCbufU64,                                          U64,            U32,            U32,                                                            )
+OPCODE(GetCbufU32x2,                                        U32x2,          U32,            U32,                                                            )
 OPCODE(GetAttribute,                                        F32,            Attribute,                                                                      )
 OPCODE(SetAttribute,                                        Void,           Attribute,      F32,                                                            )
 OPCODE(GetAttributeIndexed,                                 F32,            U32,                                                                            )
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_constant.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_constant.cpp
index 49ccb7d62a..ae3ecea325 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/load_constant.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_constant.cpp
@@ -30,25 +30,25 @@ void TranslatorVisitor::LDC(u64 insn) {
     const auto [index, offset]{Slot(ir, ldc.mode, imm_index, reg, imm)};
     switch (ldc.size) {
     case Size::U8:
-        X(ldc.dest_reg, ir.GetCbuf(index, offset, 8, false));
+        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 8, false)});
         break;
     case Size::S8:
-        X(ldc.dest_reg, ir.GetCbuf(index, offset, 8, true));
+        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 8, true)});
         break;
     case Size::U16:
-        X(ldc.dest_reg, ir.GetCbuf(index, offset, 16, false));
+        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 16, false)});
         break;
     case Size::S16:
-        X(ldc.dest_reg, ir.GetCbuf(index, offset, 16, true));
+        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 16, true)});
         break;
     case Size::B32:
-        X(ldc.dest_reg, ir.GetCbuf(index, offset, 32, false));
+        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 32, false)});
         break;
     case Size::B64: {
         if (!IR::IsAligned(ldc.dest_reg, 2)) {
             throw NotImplementedException("Unaligned destination register");
         }
-        const IR::Value vector{ir.UnpackUint2x32(ir.GetCbuf(index, offset, 64, false))};
+        const IR::Value vector{ir.GetCbuf(index, offset, 64, false)};
         for (int i = 0; i < 2; ++i) {
             X(ldc.dest_reg + i, IR::U32{ir.CompositeExtract(vector, i)});
         }
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
index 5c1b816380..07f031ea6a 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -271,7 +271,6 @@ void VisitUsages(Info& info, IR::Inst& inst) {
         break;
     }
     switch (inst.Opcode()) {
-    case IR::Opcode::GetCbufU64:
     case IR::Opcode::UndefU64:
     case IR::Opcode::LoadGlobalU8:
     case IR::Opcode::LoadGlobalS8:
@@ -349,7 +348,7 @@ void VisitUsages(Info& info, IR::Inst& inst) {
     case IR::Opcode::GetCbufS16:
     case IR::Opcode::GetCbufU32:
     case IR::Opcode::GetCbufF32:
-    case IR::Opcode::GetCbufU64: {
+    case IR::Opcode::GetCbufU32x2: {
         if (const IR::Value index{inst.Arg(0)}; index.IsImmediate()) {
             AddConstantBufferDescriptor(info, index.U32(), 1);
         } else {
@@ -370,8 +369,8 @@ void VisitUsages(Info& info, IR::Inst& inst) {
         case IR::Opcode::GetCbufF32:
             info.used_constant_buffer_types |= IR::Type::F32;
             break;
-        case IR::Opcode::GetCbufU64:
-            info.used_constant_buffer_types |= IR::Type::U64;
+        case IR::Opcode::GetCbufU32x2:
+            info.used_constant_buffer_types |= IR::Type::U32x2;
             break;
         default:
             break;