summaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp69
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp16
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp9
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp38
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp6
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp23
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp30
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_special.cpp8
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp6
12 files changed, 101 insertions, 112 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index b9e6d5655..214ef9c25 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -131,13 +131,13 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation,
131 case Stage::TessellationControl: 131 case Stage::TessellationControl:
132 case Stage::TessellationEval: 132 case Stage::TessellationEval:
133 if (per_invocation) { 133 if (per_invocation) {
134 type = ctx.TypeArray(type, ctx.Constant(ctx.U32[1], 32u)); 134 type = ctx.TypeArray(type, ctx.Const(32u));
135 } 135 }
136 break; 136 break;
137 case Stage::Geometry: 137 case Stage::Geometry:
138 if (per_invocation) { 138 if (per_invocation) {
139 const u32 num_vertices{NumVertices(ctx.profile.input_topology)}; 139 const u32 num_vertices{NumVertices(ctx.profile.input_topology)};
140 type = ctx.TypeArray(type, ctx.Constant(ctx.U32[1], num_vertices)); 140 type = ctx.TypeArray(type, ctx.Const(num_vertices));
141 } 141 }
142 break; 142 break;
143 default: 143 default:
@@ -149,7 +149,7 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation,
149Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations, 149Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations,
150 std::optional<spv::BuiltIn> builtin = std::nullopt) { 150 std::optional<spv::BuiltIn> builtin = std::nullopt) {
151 if (invocations && ctx.stage == Stage::TessellationControl) { 151 if (invocations && ctx.stage == Stage::TessellationControl) {
152 type = ctx.TypeArray(type, ctx.Constant(ctx.U32[1], *invocations)); 152 type = ctx.TypeArray(type, ctx.Const(*invocations));
153 } 153 }
154 return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); 154 return DefineVariable(ctx, type, builtin, spv::StorageClass::Output);
155} 155}
@@ -224,7 +224,7 @@ std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
224 224
225void DefineConstBuffers(EmitContext& ctx, const Info& info, Id UniformDefinitions::*member_type, 225void DefineConstBuffers(EmitContext& ctx, const Info& info, Id UniformDefinitions::*member_type,
226 u32 binding, Id type, char type_char, u32 element_size) { 226 u32 binding, Id type, char type_char, u32 element_size) {
227 const Id array_type{ctx.TypeArray(type, ctx.Constant(ctx.U32[1], 65536U / element_size))}; 227 const Id array_type{ctx.TypeArray(type, ctx.Const(65536U / element_size))};
228 ctx.Decorate(array_type, spv::Decoration::ArrayStride, element_size); 228 ctx.Decorate(array_type, spv::Decoration::ArrayStride, element_size);
229 229
230 const Id struct_type{ctx.TypeStruct(array_type)}; 230 const Id struct_type{ctx.TypeStruct(array_type)};
@@ -328,7 +328,7 @@ Id CasLoop(EmitContext& ctx, Operation operation, Id array_pointer, Id element_p
328 const bool is_struct{!is_shared || ctx.profile.support_explicit_workgroup_layout}; 328 const bool is_struct{!is_shared || ctx.profile.support_explicit_workgroup_layout};
329 const Id cas_func{CasFunction(ctx, operation, value_type)}; 329 const Id cas_func{CasFunction(ctx, operation, value_type)};
330 const Id zero{ctx.u32_zero_value}; 330 const Id zero{ctx.u32_zero_value};
331 const Id scope_id{ctx.Constant(ctx.U32[1], static_cast<u32>(scope))}; 331 const Id scope_id{ctx.Const(static_cast<u32>(scope))};
332 332
333 const Id loop_header{ctx.OpLabel()}; 333 const Id loop_header{ctx.OpLabel()};
334 const Id continue_block{ctx.OpLabel()}; 334 const Id continue_block{ctx.OpLabel()};
@@ -428,11 +428,11 @@ Id EmitContext::Def(const IR::Value& value) {
428 case IR::Type::U1: 428 case IR::Type::U1:
429 return value.U1() ? true_value : false_value; 429 return value.U1() ? true_value : false_value;
430 case IR::Type::U32: 430 case IR::Type::U32:
431 return Constant(U32[1], value.U32()); 431 return Const(value.U32());
432 case IR::Type::U64: 432 case IR::Type::U64:
433 return Constant(U64, value.U64()); 433 return Constant(U64, value.U64());
434 case IR::Type::F32: 434 case IR::Type::F32:
435 return Constant(F32[1], value.F32()); 435 return Const(value.F32());
436 case IR::Type::F64: 436 case IR::Type::F64:
437 return Constant(F64[1], value.F64()); 437 return Constant(F64[1], value.F64());
438 case IR::Type::Label: 438 case IR::Type::Label:
@@ -486,8 +486,8 @@ void EmitContext::DefineCommonTypes(const Info& info) {
486void EmitContext::DefineCommonConstants() { 486void EmitContext::DefineCommonConstants() {
487 true_value = ConstantTrue(U1); 487 true_value = ConstantTrue(U1);
488 false_value = ConstantFalse(U1); 488 false_value = ConstantFalse(U1);
489 u32_zero_value = Constant(U32[1], 0U); 489 u32_zero_value = Const(0U);
490 f32_zero_value = Constant(F32[1], 0.0f); 490 f32_zero_value = Const(0.0f);
491} 491}
492 492
493void EmitContext::DefineInterfaces(const IR::Program& program) { 493void EmitContext::DefineInterfaces(const IR::Program& program) {
@@ -500,7 +500,7 @@ void EmitContext::DefineLocalMemory(const IR::Program& program) {
500 return; 500 return;
501 } 501 }
502 const u32 num_elements{Common::DivCeil(program.local_memory_size, 4U)}; 502 const u32 num_elements{Common::DivCeil(program.local_memory_size, 4U)};
503 const Id type{TypeArray(U32[1], Constant(U32[1], num_elements))}; 503 const Id type{TypeArray(U32[1], Const(num_elements))};
504 const Id pointer{TypePointer(spv::StorageClass::Private, type)}; 504 const Id pointer{TypePointer(spv::StorageClass::Private, type)};
505 local_memory = AddGlobalVariable(pointer, spv::StorageClass::Private); 505 local_memory = AddGlobalVariable(pointer, spv::StorageClass::Private);
506 if (profile.supported_spirv >= 0x00010400) { 506 if (profile.supported_spirv >= 0x00010400) {
@@ -514,7 +514,7 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) {
514 } 514 }
515 const auto make{[&](Id element_type, u32 element_size) { 515 const auto make{[&](Id element_type, u32 element_size) {
516 const u32 num_elements{Common::DivCeil(program.shared_memory_size, element_size)}; 516 const u32 num_elements{Common::DivCeil(program.shared_memory_size, element_size)};
517 const Id array_type{TypeArray(element_type, Constant(U32[1], num_elements))}; 517 const Id array_type{TypeArray(element_type, Const(num_elements))};
518 Decorate(array_type, spv::Decoration::ArrayStride, element_size); 518 Decorate(array_type, spv::Decoration::ArrayStride, element_size);
519 519
520 const Id struct_type{TypeStruct(array_type)}; 520 const Id struct_type{TypeStruct(array_type)};
@@ -549,7 +549,7 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) {
549 return; 549 return;
550 } 550 }
551 const u32 num_elements{Common::DivCeil(program.shared_memory_size, 4U)}; 551 const u32 num_elements{Common::DivCeil(program.shared_memory_size, 4U)};
552 const Id type{TypeArray(U32[1], Constant(U32[1], num_elements))}; 552 const Id type{TypeArray(U32[1], Const(num_elements))};
553 shared_memory_u32_type = TypePointer(spv::StorageClass::Workgroup, type); 553 shared_memory_u32_type = TypePointer(spv::StorageClass::Workgroup, type);
554 554
555 shared_u32 = TypePointer(spv::StorageClass::Workgroup, U32[1]); 555 shared_u32 = TypePointer(spv::StorageClass::Workgroup, U32[1]);
@@ -569,10 +569,10 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) {
569 OpBranch(loop_header); 569 OpBranch(loop_header);
570 570
571 AddLabel(loop_header); 571 AddLabel(loop_header);
572 const Id word_offset{OpShiftRightArithmetic(U32[1], offset, Constant(U32[1], 2U))}; 572 const Id word_offset{OpShiftRightArithmetic(U32[1], offset, Const(2U))};
573 const Id shift_offset{OpShiftLeftLogical(U32[1], offset, Constant(U32[1], 3U))}; 573 const Id shift_offset{OpShiftLeftLogical(U32[1], offset, Const(3U))};
574 const Id bit_offset{OpBitwiseAnd(U32[1], shift_offset, Constant(U32[1], mask))}; 574 const Id bit_offset{OpBitwiseAnd(U32[1], shift_offset, Const(mask))};
575 const Id count{Constant(U32[1], size)}; 575 const Id count{Const(size)};
576 OpLoopMerge(merge_block, continue_block, spv::LoopControlMask::MaskNone); 576 OpLoopMerge(merge_block, continue_block, spv::LoopControlMask::MaskNone);
577 OpBranch(continue_block); 577 OpBranch(continue_block);
578 578
@@ -580,9 +580,8 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) {
580 const Id word_pointer{OpAccessChain(shared_u32, shared_memory_u32, word_offset)}; 580 const Id word_pointer{OpAccessChain(shared_u32, shared_memory_u32, word_offset)};
581 const Id old_value{OpLoad(U32[1], word_pointer)}; 581 const Id old_value{OpLoad(U32[1], word_pointer)};
582 const Id new_value{OpBitFieldInsert(U32[1], old_value, insert_value, bit_offset, count)}; 582 const Id new_value{OpBitFieldInsert(U32[1], old_value, insert_value, bit_offset, count)};
583 const Id atomic_res{OpAtomicCompareExchange(U32[1], word_pointer, Constant(U32[1], 1U), 583 const Id atomic_res{OpAtomicCompareExchange(U32[1], word_pointer, Const(1U), u32_zero_value,
584 u32_zero_value, u32_zero_value, new_value, 584 u32_zero_value, new_value, old_value)};
585 old_value)};
586 const Id success{OpIEqual(U1, atomic_res, old_value)}; 585 const Id success{OpIEqual(U1, atomic_res, old_value)};
587 OpBranchConditional(success, merge_block, loop_header); 586 OpBranchConditional(success, merge_block, loop_header);
588 587
@@ -623,9 +622,9 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
623 const Id vertex{is_array ? OpFunctionParameter(U32[1]) : Id{}}; 622 const Id vertex{is_array ? OpFunctionParameter(U32[1]) : Id{}};
624 623
625 AddLabel(); 624 AddLabel();
626 const Id base_index{OpShiftRightArithmetic(U32[1], offset, Constant(U32[1], 2U))}; 625 const Id base_index{OpShiftRightArithmetic(U32[1], offset, Const(2U))};
627 const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))}; 626 const Id masked_index{OpBitwiseAnd(U32[1], base_index, Const(3U))};
628 const Id compare_index{OpShiftRightArithmetic(U32[1], base_index, Constant(U32[1], 2U))}; 627 const Id compare_index{OpShiftRightArithmetic(U32[1], base_index, Const(2U))};
629 std::vector<Sirit::Literal> literals; 628 std::vector<Sirit::Literal> literals;
630 std::vector<Id> labels; 629 std::vector<Id> labels;
631 if (info.loads_position) { 630 if (info.loads_position) {
@@ -643,7 +642,7 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
643 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); 642 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone);
644 OpSwitch(compare_index, default_label, literals, labels); 643 OpSwitch(compare_index, default_label, literals, labels);
645 AddLabel(default_label); 644 AddLabel(default_label);
646 OpReturnValue(Constant(F32[1], 0.0f)); 645 OpReturnValue(Const(0.0f));
647 size_t label_index{0}; 646 size_t label_index{0};
648 if (info.loads_position) { 647 if (info.loads_position) {
649 AddLabel(labels[label_index]); 648 AddLabel(labels[label_index]);
@@ -661,7 +660,7 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
661 AddLabel(labels[label_index]); 660 AddLabel(labels[label_index]);
662 const auto type{AttrTypes(*this, static_cast<u32>(i))}; 661 const auto type{AttrTypes(*this, static_cast<u32>(i))};
663 if (!type) { 662 if (!type) {
664 OpReturnValue(Constant(F32[1], 0.0f)); 663 OpReturnValue(Const(0.0f));
665 ++label_index; 664 ++label_index;
666 continue; 665 continue;
667 } 666 }
@@ -688,9 +687,9 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
688 const Id offset{OpFunctionParameter(U32[1])}; 687 const Id offset{OpFunctionParameter(U32[1])};
689 const Id store_value{OpFunctionParameter(F32[1])}; 688 const Id store_value{OpFunctionParameter(F32[1])};
690 AddLabel(); 689 AddLabel();
691 const Id base_index{OpShiftRightArithmetic(U32[1], offset, Constant(U32[1], 2U))}; 690 const Id base_index{OpShiftRightArithmetic(U32[1], offset, Const(2U))};
692 const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))}; 691 const Id masked_index{OpBitwiseAnd(U32[1], base_index, Const(3U))};
693 const Id compare_index{OpShiftRightArithmetic(U32[1], base_index, Constant(U32[1], 2U))}; 692 const Id compare_index{OpShiftRightArithmetic(U32[1], base_index, Const(2U))};
694 std::vector<Sirit::Literal> literals; 693 std::vector<Sirit::Literal> literals;
695 std::vector<Id> labels; 694 std::vector<Id> labels;
696 if (info.stores_position) { 695 if (info.stores_position) {
@@ -744,7 +743,7 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
744 OpReturn(); 743 OpReturn();
745 ++label_index; 744 ++label_index;
746 AddLabel(labels[label_index]); 745 AddLabel(labels[label_index]);
747 const Id fixed_index{OpIAdd(U32[1], masked_index, Constant(U32[1], 4))}; 746 const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))};
748 const Id pointer2{OpAccessChain(output_f32, clip_distances, fixed_index)}; 747 const Id pointer2{OpAccessChain(output_f32, clip_distances, fixed_index)};
749 OpStore(pointer2, store_value); 748 OpStore(pointer2, store_value);
750 OpReturn(); 749 OpReturn();
@@ -1018,9 +1017,9 @@ void EmitContext::DefineInputs(const Info& info) {
1018 DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId); 1017 DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
1019 } 1018 }
1020 if (info.uses_fswzadd) { 1019 if (info.uses_fswzadd) {
1021 const Id f32_one{Constant(F32[1], 1.0f)}; 1020 const Id f32_one{Const(1.0f)};
1022 const Id f32_minus_one{Constant(F32[1], -1.0f)}; 1021 const Id f32_minus_one{Const(-1.0f)};
1023 const Id f32_zero{Constant(F32[1], 0.0f)}; 1022 const Id f32_zero{Const(0.0f)};
1024 fswzadd_lut_a = ConstantComposite(F32[4], f32_minus_one, f32_one, f32_minus_one, f32_zero); 1023 fswzadd_lut_a = ConstantComposite(F32[4], f32_minus_one, f32_one, f32_minus_one, f32_zero);
1025 fswzadd_lut_b = 1024 fswzadd_lut_b =
1026 ConstantComposite(F32[4], f32_minus_one, f32_minus_one, f32_one, f32_minus_one); 1025 ConstantComposite(F32[4], f32_minus_one, f32_minus_one, f32_one, f32_minus_one);
@@ -1118,7 +1117,7 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
1118 if (stage == Stage::Fragment) { 1117 if (stage == Stage::Fragment) {
1119 throw NotImplementedException("Storing ClipDistance in fragment stage"); 1118 throw NotImplementedException("Storing ClipDistance in fragment stage");
1120 } 1119 }
1121 const Id type{TypeArray(F32[1], Constant(U32[1], 8U))}; 1120 const Id type{TypeArray(F32[1], Const(8U))};
1122 clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); 1121 clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance);
1123 } 1122 }
1124 if (info.stores_layer && 1123 if (info.stores_layer &&
@@ -1136,7 +1135,7 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
1136 viewport_index = DefineOutput(*this, U32[1], invocations, spv::BuiltIn::ViewportIndex); 1135 viewport_index = DefineOutput(*this, U32[1], invocations, spv::BuiltIn::ViewportIndex);
1137 } 1136 }
1138 if (info.stores_viewport_mask && profile.support_viewport_mask) { 1137 if (info.stores_viewport_mask && profile.support_viewport_mask) {
1139 viewport_mask = DefineOutput(*this, TypeArray(U32[1], Constant(U32[1], 1u)), std::nullopt); 1138 viewport_mask = DefineOutput(*this, TypeArray(U32[1], Const(1u)), std::nullopt);
1140 } 1139 }
1141 for (size_t index = 0; index < info.stores_generics.size(); ++index) { 1140 for (size_t index = 0; index < info.stores_generics.size(); ++index) {
1142 if (info.stores_generics[index]) { 1141 if (info.stores_generics[index]) {
@@ -1146,13 +1145,13 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
1146 switch (stage) { 1145 switch (stage) {
1147 case Stage::TessellationControl: 1146 case Stage::TessellationControl:
1148 if (info.stores_tess_level_outer) { 1147 if (info.stores_tess_level_outer) {
1149 const Id type{TypeArray(F32[1], Constant(U32[1], 4))}; 1148 const Id type{TypeArray(F32[1], Const(4U))};
1150 output_tess_level_outer = 1149 output_tess_level_outer =
1151 DefineOutput(*this, type, std::nullopt, spv::BuiltIn::TessLevelOuter); 1150 DefineOutput(*this, type, std::nullopt, spv::BuiltIn::TessLevelOuter);
1152 Decorate(output_tess_level_outer, spv::Decoration::Patch); 1151 Decorate(output_tess_level_outer, spv::Decoration::Patch);
1153 } 1152 }
1154 if (info.stores_tess_level_inner) { 1153 if (info.stores_tess_level_inner) {
1155 const Id type{TypeArray(F32[1], Constant(U32[1], 2))}; 1154 const Id type{TypeArray(F32[1], Const(2U))};
1156 output_tess_level_inner = 1155 output_tess_level_inner =
1157 DefineOutput(*this, type, std::nullopt, spv::BuiltIn::TessLevelInner); 1156 DefineOutput(*this, type, std::nullopt, spv::BuiltIn::TessLevelInner);
1158 Decorate(output_tess_level_inner, spv::Decoration::Patch); 1157 Decorate(output_tess_level_inner, spv::Decoration::Patch);
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index 7567fdcac..ef8507367 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -114,7 +114,7 @@ public:
114 } 114 }
115 115
116 Id Const(u32 element_1, u32 element_2, u32 element_3, u32 element_4) { 116 Id Const(u32 element_1, u32 element_2, u32 element_3, u32 element_4) {
117 return ConstantComposite(U32[2], Const(element_1), Const(element_2), Const(element_3), 117 return ConstantComposite(U32[4], Const(element_1), Const(element_2), Const(element_3),
118 Const(element_4)); 118 Const(element_4));
119 } 119 }
120 120
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
index c2c879a6c..6e17d1c7e 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
@@ -7,10 +7,10 @@
7namespace Shader::Backend::SPIRV { 7namespace Shader::Backend::SPIRV {
8namespace { 8namespace {
9Id SharedPointer(EmitContext& ctx, Id offset, u32 index_offset = 0) { 9Id SharedPointer(EmitContext& ctx, Id offset, u32 index_offset = 0) {
10 const Id shift_id{ctx.Constant(ctx.U32[1], 2U)}; 10 const Id shift_id{ctx.Const(2U)};
11 Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)}; 11 Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
12 if (index_offset > 0) { 12 if (index_offset > 0) {
13 index = ctx.OpIAdd(ctx.U32[1], index, ctx.Constant(ctx.U32[1], index_offset)); 13 index = ctx.OpIAdd(ctx.U32[1], index, ctx.Const(index_offset));
14 } 14 }
15 return ctx.profile.support_explicit_workgroup_layout 15 return ctx.profile.support_explicit_workgroup_layout
16 ? ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, ctx.u32_zero_value, index) 16 ? ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, ctx.u32_zero_value, index)
@@ -20,14 +20,14 @@ Id SharedPointer(EmitContext& ctx, Id offset, u32 index_offset = 0) {
20Id StorageIndex(EmitContext& ctx, const IR::Value& offset, size_t element_size) { 20Id StorageIndex(EmitContext& ctx, const IR::Value& offset, size_t element_size) {
21 if (offset.IsImmediate()) { 21 if (offset.IsImmediate()) {
22 const u32 imm_offset{static_cast<u32>(offset.U32() / element_size)}; 22 const u32 imm_offset{static_cast<u32>(offset.U32() / element_size)};
23 return ctx.Constant(ctx.U32[1], imm_offset); 23 return ctx.Const(imm_offset);
24 } 24 }
25 const u32 shift{static_cast<u32>(std::countr_zero(element_size))}; 25 const u32 shift{static_cast<u32>(std::countr_zero(element_size))};
26 const Id index{ctx.Def(offset)}; 26 const Id index{ctx.Def(offset)};
27 if (shift == 0) { 27 if (shift == 0) {
28 return index; 28 return index;
29 } 29 }
30 const Id shift_id{ctx.Constant(ctx.U32[1], shift)}; 30 const Id shift_id{ctx.Const(shift)};
31 return ctx.OpShiftRightLogical(ctx.U32[1], index, shift_id); 31 return ctx.OpShiftRightLogical(ctx.U32[1], index, shift_id);
32} 32}
33 33
@@ -43,7 +43,7 @@ Id StoragePointer(EmitContext& ctx, const StorageTypeDefinition& type_def,
43} 43}
44 44
45std::pair<Id, Id> AtomicArgs(EmitContext& ctx) { 45std::pair<Id, Id> AtomicArgs(EmitContext& ctx) {
46 const Id scope{ctx.Constant(ctx.U32[1], static_cast<u32>(spv::Scope::Device))}; 46 const Id scope{ctx.Const(static_cast<u32>(spv::Scope::Device))};
47 const Id semantics{ctx.u32_zero_value}; 47 const Id semantics{ctx.u32_zero_value};
48 return {scope, semantics}; 48 return {scope, semantics};
49} 49}
@@ -103,13 +103,13 @@ Id EmitSharedAtomicUMax32(EmitContext& ctx, Id offset, Id value) {
103} 103}
104 104
105Id EmitSharedAtomicInc32(EmitContext& ctx, Id offset, Id value) { 105Id EmitSharedAtomicInc32(EmitContext& ctx, Id offset, Id value) {
106 const Id shift_id{ctx.Constant(ctx.U32[1], 2U)}; 106 const Id shift_id{ctx.Const(2U)};
107 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)}; 107 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
108 return ctx.OpFunctionCall(ctx.U32[1], ctx.increment_cas_shared, index, value); 108 return ctx.OpFunctionCall(ctx.U32[1], ctx.increment_cas_shared, index, value);
109} 109}
110 110
111Id EmitSharedAtomicDec32(EmitContext& ctx, Id offset, Id value) { 111Id EmitSharedAtomicDec32(EmitContext& ctx, Id offset, Id value) {
112 const Id shift_id{ctx.Constant(ctx.U32[1], 2U)}; 112 const Id shift_id{ctx.Const(2U)};
113 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)}; 113 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
114 return ctx.OpFunctionCall(ctx.U32[1], ctx.decrement_cas_shared, index, value); 114 return ctx.OpFunctionCall(ctx.U32[1], ctx.decrement_cas_shared, index, value);
115} 115}
@@ -132,7 +132,7 @@ Id EmitSharedAtomicExchange32(EmitContext& ctx, Id offset, Id value) {
132 132
133Id EmitSharedAtomicExchange64(EmitContext& ctx, Id offset, Id value) { 133Id EmitSharedAtomicExchange64(EmitContext& ctx, Id offset, Id value) {
134 if (ctx.profile.support_int64_atomics && ctx.profile.support_explicit_workgroup_layout) { 134 if (ctx.profile.support_int64_atomics && ctx.profile.support_explicit_workgroup_layout) {
135 const Id shift_id{ctx.Constant(ctx.U32[1], 3U)}; 135 const Id shift_id{ctx.Const(3U)};
136 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)}; 136 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
137 const Id pointer{ 137 const Id pointer{
138 ctx.OpAccessChain(ctx.shared_u64, ctx.shared_memory_u64, ctx.u32_zero_value, index)}; 138 ctx.OpAccessChain(ctx.shared_u64, ctx.shared_memory_u64, ctx.u32_zero_value, index)};
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp
index 366dc6a0c..705aebd81 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp
@@ -12,8 +12,7 @@ void MemoryBarrier(EmitContext& ctx, spv::Scope scope) {
12 spv::MemorySemanticsMask::AcquireRelease | spv::MemorySemanticsMask::UniformMemory | 12 spv::MemorySemanticsMask::AcquireRelease | spv::MemorySemanticsMask::UniformMemory |
13 spv::MemorySemanticsMask::WorkgroupMemory | spv::MemorySemanticsMask::AtomicCounterMemory | 13 spv::MemorySemanticsMask::WorkgroupMemory | spv::MemorySemanticsMask::AtomicCounterMemory |
14 spv::MemorySemanticsMask::ImageMemory}; 14 spv::MemorySemanticsMask::ImageMemory};
15 ctx.OpMemoryBarrier(ctx.Constant(ctx.U32[1], static_cast<u32>(scope)), 15 ctx.OpMemoryBarrier(ctx.Const(static_cast<u32>(scope)), ctx.Const(static_cast<u32>(semantics)));
16 ctx.Constant(ctx.U32[1], static_cast<u32>(semantics)));
17} 16}
18} // Anonymous namespace 17} // Anonymous namespace
19 18
@@ -22,9 +21,9 @@ void EmitBarrier(EmitContext& ctx) {
22 const auto memory{spv::Scope::Workgroup}; 21 const auto memory{spv::Scope::Workgroup};
23 const auto memory_semantics{spv::MemorySemanticsMask::AcquireRelease | 22 const auto memory_semantics{spv::MemorySemanticsMask::AcquireRelease |
24 spv::MemorySemanticsMask::WorkgroupMemory}; 23 spv::MemorySemanticsMask::WorkgroupMemory};
25 ctx.OpControlBarrier(ctx.Constant(ctx.U32[1], static_cast<u32>(execution)), 24 ctx.OpControlBarrier(ctx.Const(static_cast<u32>(execution)),
26 ctx.Constant(ctx.U32[1], static_cast<u32>(memory)), 25 ctx.Const(static_cast<u32>(memory)),
27 ctx.Constant(ctx.U32[1], static_cast<u32>(memory_semantics))); 26 ctx.Const(static_cast<u32>(memory_semantics)));
28} 27}
29 28
30void EmitWorkgroupMemoryBarrier(EmitContext& ctx) { 29void EmitWorkgroupMemoryBarrier(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 ed57e44a2..5cc9d0d39 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
@@ -69,7 +69,7 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
69 return info.id; 69 return info.id;
70 } else { 70 } else {
71 const u32 index_element{element - info.first_element}; 71 const u32 index_element{element - info.first_element};
72 const Id index_id{ctx.Constant(ctx.U32[1], index_element)}; 72 const Id index_id{ctx.Const(index_element)};
73 return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id); 73 return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id);
74 } 74 }
75 } 75 }
@@ -81,7 +81,7 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
81 case IR::Attribute::PositionZ: 81 case IR::Attribute::PositionZ:
82 case IR::Attribute::PositionW: { 82 case IR::Attribute::PositionW: {
83 const u32 element{static_cast<u32>(attr) % 4}; 83 const u32 element{static_cast<u32>(attr) % 4};
84 const Id element_id{ctx.Constant(ctx.U32[1], element)}; 84 const Id element_id{ctx.Const(element)};
85 return OutputAccessChain(ctx, ctx.output_f32, ctx.output_position, element_id); 85 return OutputAccessChain(ctx, ctx.output_f32, ctx.output_position, element_id);
86 } 86 }
87 case IR::Attribute::ClipDistance0: 87 case IR::Attribute::ClipDistance0:
@@ -94,7 +94,7 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
94 case IR::Attribute::ClipDistance7: { 94 case IR::Attribute::ClipDistance7: {
95 const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)}; 95 const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)};
96 const u32 index{static_cast<u32>(attr) - base}; 96 const u32 index{static_cast<u32>(attr) - base};
97 const Id clip_num{ctx.Constant(ctx.U32[1], index)}; 97 const Id clip_num{ctx.Const(index)};
98 return OutputAccessChain(ctx, ctx.output_f32, ctx.clip_distances, clip_num); 98 return OutputAccessChain(ctx, ctx.output_f32, ctx.clip_distances, clip_num);
99 } 99 }
100 case IR::Attribute::Layer: 100 case IR::Attribute::Layer:
@@ -131,7 +131,7 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr,
131 Id index{ctx.Def(offset)}; 131 Id index{ctx.Def(offset)};
132 if (element_size > 1) { 132 if (element_size > 1) {
133 const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))}; 133 const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))};
134 const Id shift{ctx.Constant(ctx.U32[1], log2_element_size)}; 134 const Id shift{ctx.Const(log2_element_size)};
135 index = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift); 135 index = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift);
136 } 136 }
137 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)}; 137 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)};
@@ -140,7 +140,7 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr,
140 if (offset.U32() % element_size != 0) { 140 if (offset.U32() % element_size != 0) {
141 throw NotImplementedException("Unaligned immediate constant buffer load"); 141 throw NotImplementedException("Unaligned immediate constant buffer load");
142 } 142 }
143 const Id imm_offset{ctx.Constant(ctx.U32[1], offset.U32() / element_size)}; 143 const Id imm_offset{ctx.Const(offset.U32() / element_size)};
144 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)}; 144 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)};
145 return ctx.OpLoad(result_type, access_chain); 145 return ctx.OpLoad(result_type, access_chain);
146} 146}
@@ -212,13 +212,13 @@ Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value&
212 212
213Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { 213Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
214 const u32 element{static_cast<u32>(attr) % 4}; 214 const u32 element{static_cast<u32>(attr) % 4};
215 const auto element_id{[&] { return ctx.Constant(ctx.U32[1], element); }}; 215 const auto element_id{[&] { return ctx.Const(element); }};
216 if (IR::IsGeneric(attr)) { 216 if (IR::IsGeneric(attr)) {
217 const u32 index{IR::GenericAttributeIndex(attr)}; 217 const u32 index{IR::GenericAttributeIndex(attr)};
218 const std::optional<AttrInfo> type{AttrTypes(ctx, index)}; 218 const std::optional<AttrInfo> type{AttrTypes(ctx, index)};
219 if (!type) { 219 if (!type) {
220 // Attribute is disabled 220 // Attribute is disabled
221 return ctx.Constant(ctx.F32[1], 0.0f); 221 return ctx.Const(0.0f);
222 } 222 }
223 const Id generic_id{ctx.input_generics.at(index)}; 223 const Id generic_id{ctx.input_generics.at(index)};
224 const Id pointer{AttrPointer(ctx, type->pointer, vertex, generic_id, element_id())}; 224 const Id pointer{AttrPointer(ctx, type->pointer, vertex, generic_id, element_id())};
@@ -252,20 +252,19 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
252 } 252 }
253 case IR::Attribute::FrontFace: 253 case IR::Attribute::FrontFace:
254 return ctx.OpSelect(ctx.U32[1], ctx.OpLoad(ctx.U1, ctx.front_face), 254 return ctx.OpSelect(ctx.U32[1], ctx.OpLoad(ctx.U1, ctx.front_face),
255 ctx.Constant(ctx.U32[1], std::numeric_limits<u32>::max()), 255 ctx.Const(std::numeric_limits<u32>::max()), ctx.u32_zero_value);
256 ctx.u32_zero_value);
257 case IR::Attribute::PointSpriteS: 256 case IR::Attribute::PointSpriteS:
258 return ctx.OpLoad(ctx.F32[1], 257 return ctx.OpLoad(ctx.F32[1],
259 ctx.OpAccessChain(ctx.input_f32, ctx.point_coord, ctx.u32_zero_value)); 258 ctx.OpAccessChain(ctx.input_f32, ctx.point_coord, ctx.u32_zero_value));
260 case IR::Attribute::PointSpriteT: 259 case IR::Attribute::PointSpriteT:
261 return ctx.OpLoad(ctx.F32[1], ctx.OpAccessChain(ctx.input_f32, ctx.point_coord, 260 return ctx.OpLoad(ctx.F32[1],
262 ctx.Constant(ctx.U32[1], 1U))); 261 ctx.OpAccessChain(ctx.input_f32, ctx.point_coord, ctx.Const(1U)));
263 case IR::Attribute::TessellationEvaluationPointU: 262 case IR::Attribute::TessellationEvaluationPointU:
264 return ctx.OpLoad(ctx.F32[1], 263 return ctx.OpLoad(ctx.F32[1],
265 ctx.OpAccessChain(ctx.input_f32, ctx.tess_coord, ctx.u32_zero_value)); 264 ctx.OpAccessChain(ctx.input_f32, ctx.tess_coord, ctx.u32_zero_value));
266 case IR::Attribute::TessellationEvaluationPointV: 265 case IR::Attribute::TessellationEvaluationPointV:
267 return ctx.OpLoad(ctx.F32[1], ctx.OpAccessChain(ctx.input_f32, ctx.tess_coord, 266 return ctx.OpLoad(ctx.F32[1],
268 ctx.Constant(ctx.U32[1], 1U))); 267 ctx.OpAccessChain(ctx.input_f32, ctx.tess_coord, ctx.Const(1U)));
269 268
270 default: 269 default:
271 throw NotImplementedException("Read attribute {}", attr); 270 throw NotImplementedException("Read attribute {}", attr);
@@ -303,7 +302,7 @@ Id EmitGetPatch(EmitContext& ctx, IR::Patch patch) {
303 throw NotImplementedException("Non-generic patch load"); 302 throw NotImplementedException("Non-generic patch load");
304 } 303 }
305 const u32 index{IR::GenericPatchIndex(patch)}; 304 const u32 index{IR::GenericPatchIndex(patch)};
306 const Id element{ctx.Constant(ctx.U32[1], IR::GenericPatchElement(patch))}; 305 const Id element{ctx.Const(IR::GenericPatchElement(patch))};
307 const Id pointer{ctx.OpAccessChain(ctx.input_f32, ctx.patches.at(index), element)}; 306 const Id pointer{ctx.OpAccessChain(ctx.input_f32, ctx.patches.at(index), element)};
308 return ctx.OpLoad(ctx.F32[1], pointer); 307 return ctx.OpLoad(ctx.F32[1], pointer);
309} 308}
@@ -312,7 +311,7 @@ void EmitSetPatch(EmitContext& ctx, IR::Patch patch, Id value) {
312 const Id pointer{[&] { 311 const Id pointer{[&] {
313 if (IR::IsGeneric(patch)) { 312 if (IR::IsGeneric(patch)) {
314 const u32 index{IR::GenericPatchIndex(patch)}; 313 const u32 index{IR::GenericPatchIndex(patch)};
315 const Id element{ctx.Constant(ctx.U32[1], IR::GenericPatchElement(patch))}; 314 const Id element{ctx.Const(IR::GenericPatchElement(patch))};
316 return ctx.OpAccessChain(ctx.output_f32, ctx.patches.at(index), element); 315 return ctx.OpAccessChain(ctx.output_f32, ctx.patches.at(index), element);
317 } 316 }
318 switch (patch) { 317 switch (patch) {
@@ -321,15 +320,14 @@ void EmitSetPatch(EmitContext& ctx, IR::Patch patch, Id value) {
321 case IR::Patch::TessellationLodTop: 320 case IR::Patch::TessellationLodTop:
322 case IR::Patch::TessellationLodBottom: { 321 case IR::Patch::TessellationLodBottom: {
323 const u32 index{static_cast<u32>(patch) - u32(IR::Patch::TessellationLodLeft)}; 322 const u32 index{static_cast<u32>(patch) - u32(IR::Patch::TessellationLodLeft)};
324 const Id index_id{ctx.Constant(ctx.U32[1], index)}; 323 const Id index_id{ctx.Const(index)};
325 return ctx.OpAccessChain(ctx.output_f32, ctx.output_tess_level_outer, index_id); 324 return ctx.OpAccessChain(ctx.output_f32, ctx.output_tess_level_outer, index_id);
326 } 325 }
327 case IR::Patch::TessellationLodInteriorU: 326 case IR::Patch::TessellationLodInteriorU:
328 return ctx.OpAccessChain(ctx.output_f32, ctx.output_tess_level_inner, 327 return ctx.OpAccessChain(ctx.output_f32, ctx.output_tess_level_inner,
329 ctx.u32_zero_value); 328 ctx.u32_zero_value);
330 case IR::Patch::TessellationLodInteriorV: 329 case IR::Patch::TessellationLodInteriorV:
331 return ctx.OpAccessChain(ctx.output_f32, ctx.output_tess_level_inner, 330 return ctx.OpAccessChain(ctx.output_f32, ctx.output_tess_level_inner, ctx.Const(1u));
332 ctx.Constant(ctx.U32[1], 1u));
333 default: 331 default:
334 throw NotImplementedException("Patch {}", patch); 332 throw NotImplementedException("Patch {}", patch);
335 } 333 }
@@ -338,7 +336,7 @@ void EmitSetPatch(EmitContext& ctx, IR::Patch patch, Id value) {
338} 336}
339 337
340void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) { 338void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) {
341 const Id component_id{ctx.Constant(ctx.U32[1], component)}; 339 const Id component_id{ctx.Const(component)};
342 const Id pointer{ctx.OpAccessChain(ctx.output_f32, ctx.frag_color.at(index), component_id)}; 340 const Id pointer{ctx.OpAccessChain(ctx.output_f32, ctx.frag_color.at(index), component_id)};
343 ctx.OpStore(pointer, value); 341 ctx.OpStore(pointer, value);
344} 342}
@@ -404,7 +402,7 @@ Id EmitIsHelperInvocation(EmitContext& ctx) {
404} 402}
405 403
406Id EmitYDirection(EmitContext& ctx) { 404Id EmitYDirection(EmitContext& ctx) {
407 return ctx.Constant(ctx.F32[1], ctx.profile.y_negate ? -1.0f : 1.0f); 405 return ctx.Const(ctx.profile.y_negate ? -1.0f : 1.0f);
408} 406}
409 407
410Id EmitLoadLocal(EmitContext& ctx, Id word_offset) { 408Id EmitLoadLocal(EmitContext& ctx, Id word_offset) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
index 24300af39..97d11cc63 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
@@ -117,7 +117,7 @@ Id EmitFPLog2(EmitContext& ctx, Id value) {
117} 117}
118 118
119Id EmitFPRecip32(EmitContext& ctx, Id value) { 119Id EmitFPRecip32(EmitContext& ctx, Id value) {
120 return ctx.OpFDiv(ctx.F32[1], ctx.Constant(ctx.F32[1], 1.0f), value); 120 return ctx.OpFDiv(ctx.F32[1], ctx.Const(1.0f), value);
121} 121}
122 122
123Id EmitFPRecip64(EmitContext& ctx, Id value) { 123Id EmitFPRecip64(EmitContext& ctx, Id value) {
@@ -143,8 +143,8 @@ Id EmitFPSaturate16(EmitContext& ctx, Id value) {
143} 143}
144 144
145Id EmitFPSaturate32(EmitContext& ctx, Id value) { 145Id EmitFPSaturate32(EmitContext& ctx, Id value) {
146 const Id zero{ctx.Constant(ctx.F32[1], f32{0.0})}; 146 const Id zero{ctx.Const(f32{0.0})};
147 const Id one{ctx.Constant(ctx.F32[1], f32{1.0})}; 147 const Id one{ctx.Const(f32{1.0})};
148 return Clamp(ctx, ctx.F32[1], value, zero, one); 148 return Clamp(ctx, ctx.F32[1], value, zero, one);
149} 149}
150 150
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 7a4388e7e..90817f161 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -45,16 +45,12 @@ public:
45 if (opcode != values[1]->GetOpcode() || opcode != IR::Opcode::CompositeConstructU32x4) { 45 if (opcode != values[1]->GetOpcode() || opcode != IR::Opcode::CompositeConstructU32x4) {
46 throw LogicError("Invalid PTP arguments"); 46 throw LogicError("Invalid PTP arguments");
47 } 47 }
48 auto read{[&](unsigned int a, unsigned int b) { 48 auto read{[&](unsigned int a, unsigned int b) { return values[a]->Arg(b).U32(); }};
49 return ctx.Constant(ctx.U32[1], values[a]->Arg(b).U32()); 49
50 }}; 50 const Id offsets{ctx.ConstantComposite(
51 51 ctx.TypeArray(ctx.U32[2], ctx.Const(4U)), ctx.Const(read(0, 0), read(0, 1)),
52 const Id offsets{ 52 ctx.Const(read(0, 2), read(0, 3)), ctx.Const(read(1, 0), read(1, 1)),
53 ctx.ConstantComposite(ctx.TypeArray(ctx.U32[2], ctx.Constant(ctx.U32[1], 4)), 53 ctx.Const(read(1, 2), read(1, 3)))};
54 ctx.ConstantComposite(ctx.U32[2], read(0, 0), read(0, 1)),
55 ctx.ConstantComposite(ctx.U32[2], read(0, 2), read(0, 3)),
56 ctx.ConstantComposite(ctx.U32[2], read(1, 0), read(1, 1)),
57 ctx.ConstantComposite(ctx.U32[2], read(1, 2), read(1, 3)))};
58 Add(spv::ImageOperandsMask::ConstOffsets, offsets); 54 Add(spv::ImageOperandsMask::ConstOffsets, offsets);
59 } 55 }
60 56
@@ -108,7 +104,7 @@ private:
108 return; 104 return;
109 } 105 }
110 if (offset.IsImmediate()) { 106 if (offset.IsImmediate()) {
111 Add(spv::ImageOperandsMask::ConstOffset, ctx.Constant(ctx.U32[1], offset.U32())); 107 Add(spv::ImageOperandsMask::ConstOffset, ctx.Const(offset.U32()));
112 return; 108 return;
113 } 109 }
114 IR::Inst* const inst{offset.InstRecursive()}; 110 IR::Inst* const inst{offset.InstRecursive()};
@@ -361,9 +357,8 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id
361 const auto info{inst->Flags<IR::TextureInstInfo>()}; 357 const auto info{inst->Flags<IR::TextureInstInfo>()};
362 const ImageOperands operands(ctx, offset, offset2); 358 const ImageOperands operands(ctx, offset, offset2);
363 return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst, 359 return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst,
364 ctx.F32[4], Texture(ctx, index), coords, 360 ctx.F32[4], Texture(ctx, index), coords, ctx.Const(info.gather_component),
365 ctx.Constant(ctx.U32[1], info.gather_component.Value()), operands.Mask(), 361 operands.Mask(), operands.Span());
366 operands.Span());
367} 362}
368 363
369Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 364Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
index 944f1e429..c12d0a513 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
@@ -44,7 +44,7 @@ Id EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
44 // https://stackoverflow.com/questions/55468823/how-to-detect-integer-overflow-in-c 44 // https://stackoverflow.com/questions/55468823/how-to-detect-integer-overflow-in-c
45 constexpr u32 s32_max{static_cast<u32>(std::numeric_limits<s32>::max())}; 45 constexpr u32 s32_max{static_cast<u32>(std::numeric_limits<s32>::max())};
46 const Id is_positive{ctx.OpSGreaterThanEqual(ctx.U1, a, ctx.u32_zero_value)}; 46 const Id is_positive{ctx.OpSGreaterThanEqual(ctx.U1, a, ctx.u32_zero_value)};
47 const Id sub_a{ctx.OpISub(ctx.U32[1], ctx.Constant(ctx.U32[1], s32_max), a)}; 47 const Id sub_a{ctx.OpISub(ctx.U32[1], ctx.Const(s32_max), a)};
48 48
49 const Id positive_test{ctx.OpSGreaterThan(ctx.U1, b, sub_a)}; 49 const Id positive_test{ctx.OpSGreaterThan(ctx.U1, b, sub_a)};
50 const Id negative_test{ctx.OpSLessThan(ctx.U1, b, sub_a)}; 50 const Id negative_test{ctx.OpSLessThan(ctx.U1, b, sub_a)};
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
index a8f2ea5a0..7bf828995 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
@@ -11,14 +11,14 @@ namespace {
11Id StorageIndex(EmitContext& ctx, const IR::Value& offset, size_t element_size) { 11Id StorageIndex(EmitContext& ctx, const IR::Value& offset, size_t element_size) {
12 if (offset.IsImmediate()) { 12 if (offset.IsImmediate()) {
13 const u32 imm_offset{static_cast<u32>(offset.U32() / element_size)}; 13 const u32 imm_offset{static_cast<u32>(offset.U32() / element_size)};
14 return ctx.Constant(ctx.U32[1], imm_offset); 14 return ctx.Const(imm_offset);
15 } 15 }
16 const u32 shift{static_cast<u32>(std::countr_zero(element_size))}; 16 const u32 shift{static_cast<u32>(std::countr_zero(element_size))};
17 const Id index{ctx.Def(offset)}; 17 const Id index{ctx.Def(offset)};
18 if (shift == 0) { 18 if (shift == 0) {
19 return index; 19 return index;
20 } 20 }
21 const Id shift_id{ctx.Constant(ctx.U32[1], shift)}; 21 const Id shift_id{ctx.Const(shift)};
22 return ctx.OpShiftRightLogical(ctx.U32[1], index, shift_id); 22 return ctx.OpShiftRightLogical(ctx.U32[1], index, shift_id);
23} 23}
24 24
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp
index fa2fc9ab4..710d1cd25 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp
@@ -7,22 +7,22 @@
7namespace Shader::Backend::SPIRV { 7namespace Shader::Backend::SPIRV {
8namespace { 8namespace {
9Id Pointer(EmitContext& ctx, Id pointer_type, Id array, Id offset, u32 shift) { 9Id Pointer(EmitContext& ctx, Id pointer_type, Id array, Id offset, u32 shift) {
10 const Id shift_id{ctx.Constant(ctx.U32[1], shift)}; 10 const Id shift_id{ctx.Const(shift)};
11 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)}; 11 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
12 return ctx.OpAccessChain(pointer_type, array, ctx.u32_zero_value, index); 12 return ctx.OpAccessChain(pointer_type, array, ctx.u32_zero_value, index);
13} 13}
14 14
15Id Word(EmitContext& ctx, Id offset) { 15Id Word(EmitContext& ctx, Id offset) {
16 const Id shift_id{ctx.Constant(ctx.U32[1], 2U)}; 16 const Id shift_id{ctx.Const(2U)};
17 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)}; 17 const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
18 const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)}; 18 const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)};
19 return ctx.OpLoad(ctx.U32[1], pointer); 19 return ctx.OpLoad(ctx.U32[1], pointer);
20} 20}
21 21
22std::pair<Id, Id> ExtractArgs(EmitContext& ctx, Id offset, u32 mask, u32 count) { 22std::pair<Id, Id> ExtractArgs(EmitContext& ctx, Id offset, u32 mask, u32 count) {
23 const Id shift{ctx.OpShiftLeftLogical(ctx.U32[1], offset, ctx.Constant(ctx.U32[1], 3U))}; 23 const Id shift{ctx.OpShiftLeftLogical(ctx.U32[1], offset, ctx.Const(3U))};
24 const Id bit{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Constant(ctx.U32[1], mask))}; 24 const Id bit{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Const(mask))};
25 const Id count_id{ctx.Constant(ctx.U32[1], count)}; 25 const Id count_id{ctx.Const(count)};
26 return {bit, count_id}; 26 return {bit, count_id};
27} 27}
28} // Anonymous namespace 28} // Anonymous namespace
@@ -83,9 +83,9 @@ Id EmitLoadSharedU64(EmitContext& ctx, Id offset) {
83 const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)}; 83 const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)};
84 return ctx.OpLoad(ctx.U32[2], pointer); 84 return ctx.OpLoad(ctx.U32[2], pointer);
85 } else { 85 } else {
86 const Id shift_id{ctx.Constant(ctx.U32[1], 2U)}; 86 const Id shift_id{ctx.Const(2U)};
87 const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)}; 87 const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
88 const Id next_index{ctx.OpIAdd(ctx.U32[1], base_index, ctx.Constant(ctx.U32[1], 1U))}; 88 const Id next_index{ctx.OpIAdd(ctx.U32[1], base_index, ctx.Const(1U))};
89 const Id lhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, base_index)}; 89 const Id lhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, base_index)};
90 const Id rhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, next_index)}; 90 const Id rhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, next_index)};
91 return ctx.OpCompositeConstruct(ctx.U32[2], ctx.OpLoad(ctx.U32[1], lhs_pointer), 91 return ctx.OpCompositeConstruct(ctx.U32[2], ctx.OpLoad(ctx.U32[1], lhs_pointer),
@@ -98,12 +98,11 @@ Id EmitLoadSharedU128(EmitContext& ctx, Id offset) {
98 const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)}; 98 const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)};
99 return ctx.OpLoad(ctx.U32[4], pointer); 99 return ctx.OpLoad(ctx.U32[4], pointer);
100 } 100 }
101 const Id shift_id{ctx.Constant(ctx.U32[1], 2U)}; 101 const Id shift_id{ctx.Const(2U)};
102 const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)}; 102 const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
103 std::array<Id, 4> values{}; 103 std::array<Id, 4> values{};
104 for (u32 i = 0; i < 4; ++i) { 104 for (u32 i = 0; i < 4; ++i) {
105 const Id index{i == 0 ? base_index 105 const Id index{i == 0 ? base_index : ctx.OpIAdd(ctx.U32[1], base_index, ctx.Const(i))};
106 : ctx.OpIAdd(ctx.U32[1], base_index, ctx.Constant(ctx.U32[1], i))};
107 const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)}; 106 const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)};
108 values[i] = ctx.OpLoad(ctx.U32[1], pointer); 107 values[i] = ctx.OpLoad(ctx.U32[1], pointer);
109 } 108 }
@@ -134,7 +133,7 @@ void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value) {
134 if (ctx.profile.support_explicit_workgroup_layout) { 133 if (ctx.profile.support_explicit_workgroup_layout) {
135 pointer = Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2); 134 pointer = Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2);
136 } else { 135 } else {
137 const Id shift{ctx.Constant(ctx.U32[1], 2U)}; 136 const Id shift{ctx.Const(2U)};
138 const Id word_offset{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)}; 137 const Id word_offset{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)};
139 pointer = ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, word_offset); 138 pointer = ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, word_offset);
140 } 139 }
@@ -147,9 +146,9 @@ void EmitWriteSharedU64(EmitContext& ctx, Id offset, Id value) {
147 ctx.OpStore(pointer, value); 146 ctx.OpStore(pointer, value);
148 return; 147 return;
149 } 148 }
150 const Id shift{ctx.Constant(ctx.U32[1], 2U)}; 149 const Id shift{ctx.Const(2U)};
151 const Id word_offset{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)}; 150 const Id word_offset{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)};
152 const Id next_offset{ctx.OpIAdd(ctx.U32[1], word_offset, ctx.Constant(ctx.U32[1], 1U))}; 151 const Id next_offset{ctx.OpIAdd(ctx.U32[1], word_offset, ctx.Const(1U))};
153 const Id lhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, word_offset)}; 152 const Id lhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, word_offset)};
154 const Id rhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, next_offset)}; 153 const Id rhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, next_offset)};
155 ctx.OpStore(lhs_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 0U)); 154 ctx.OpStore(lhs_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 0U));
@@ -162,11 +161,10 @@ void EmitWriteSharedU128(EmitContext& ctx, Id offset, Id value) {
162 ctx.OpStore(pointer, value); 161 ctx.OpStore(pointer, value);
163 return; 162 return;
164 } 163 }
165 const Id shift{ctx.Constant(ctx.U32[1], 2U)}; 164 const Id shift{ctx.Const(2U)};
166 const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)}; 165 const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)};
167 for (u32 i = 0; i < 4; ++i) { 166 for (u32 i = 0; i < 4; ++i) {
168 const Id index{i == 0 ? base_index 167 const Id index{i == 0 ? base_index : ctx.OpIAdd(ctx.U32[1], base_index, ctx.Const(i))};
169 : ctx.OpIAdd(ctx.U32[1], base_index, ctx.Constant(ctx.U32[1], i))};
170 const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)}; 168 const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)};
171 ctx.OpStore(pointer, ctx.OpCompositeExtract(ctx.U32[1], value, i)); 169 ctx.OpStore(pointer, ctx.OpCompositeExtract(ctx.U32[1], value, i));
172 } 170 }
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
index ae8b39f41..d5430e905 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
@@ -19,7 +19,7 @@ void ConvertDepthMode(EmitContext& ctx) {
19void SetFixedPipelinePointSize(EmitContext& ctx) { 19void SetFixedPipelinePointSize(EmitContext& ctx) {
20 if (ctx.profile.fixed_state_point_size) { 20 if (ctx.profile.fixed_state_point_size) {
21 const float point_size{*ctx.profile.fixed_state_point_size}; 21 const float point_size{*ctx.profile.fixed_state_point_size};
22 ctx.OpStore(ctx.output_point_size, ctx.Constant(ctx.F32[1], point_size)); 22 ctx.OpStore(ctx.output_point_size, ctx.Const(point_size));
23 } 23 }
24} 24}
25 25
@@ -75,7 +75,7 @@ void AlphaTest(EmitContext& ctx) {
75 75
76 const Id true_label{ctx.OpLabel()}; 76 const Id true_label{ctx.OpLabel()};
77 const Id discard_label{ctx.OpLabel()}; 77 const Id discard_label{ctx.OpLabel()};
78 const Id alpha_reference{ctx.Constant(ctx.F32[1], ctx.profile.alpha_test_reference)}; 78 const Id alpha_reference{ctx.Const(ctx.profile.alpha_test_reference)};
79 const Id condition{ComparisonFunction(ctx, comparison, alpha, alpha_reference)}; 79 const Id condition{ComparisonFunction(ctx, comparison, alpha, alpha_reference)};
80 80
81 ctx.OpSelectionMerge(true_label, spv::SelectionControlMask::MaskNone); 81 ctx.OpSelectionMerge(true_label, spv::SelectionControlMask::MaskNone);
@@ -88,8 +88,8 @@ void AlphaTest(EmitContext& ctx) {
88 88
89void EmitPrologue(EmitContext& ctx) { 89void EmitPrologue(EmitContext& ctx) {
90 if (ctx.stage == Stage::VertexB) { 90 if (ctx.stage == Stage::VertexB) {
91 const Id zero{ctx.Constant(ctx.F32[1], 0.0f)}; 91 const Id zero{ctx.Const(0.0f)};
92 const Id one{ctx.Constant(ctx.F32[1], 1.0f)}; 92 const Id one{ctx.Const(1.0f)};
93 const Id default_vector{ctx.ConstantComposite(ctx.F32[4], zero, zero, zero, one)}; 93 const Id default_vector{ctx.ConstantComposite(ctx.F32[4], zero, zero, zero, one)};
94 ctx.OpStore(ctx.output_position, default_vector); 94 ctx.OpStore(ctx.output_position, default_vector);
95 for (const auto& info : ctx.output_generics) { 95 for (const auto& info : ctx.output_generics) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
index a255f9ba7..239e2ecab 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
@@ -54,7 +54,7 @@ Id EmitLaneId(EmitContext& ctx) {
54 if (!ctx.profile.warp_size_potentially_larger_than_guest) { 54 if (!ctx.profile.warp_size_potentially_larger_than_guest) {
55 return id; 55 return id;
56 } 56 }
57 return ctx.OpBitwiseAnd(ctx.U32[1], id, ctx.Constant(ctx.U32[1], 31U)); 57 return ctx.OpBitwiseAnd(ctx.U32[1], id, ctx.Const(31U));
58} 58}
59 59
60Id EmitVoteAll(EmitContext& ctx, Id pred) { 60Id EmitVoteAll(EmitContext& ctx, Id pred) {
@@ -168,10 +168,10 @@ Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id
168} 168}
169 169
170Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle) { 170Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle) {
171 const Id three{ctx.Constant(ctx.U32[1], 3)}; 171 const Id three{ctx.Const(3U)};
172 Id mask{ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id)}; 172 Id mask{ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id)};
173 mask = ctx.OpBitwiseAnd(ctx.U32[1], mask, three); 173 mask = ctx.OpBitwiseAnd(ctx.U32[1], mask, three);
174 mask = ctx.OpShiftLeftLogical(ctx.U32[1], mask, ctx.Constant(ctx.U32[1], 1)); 174 mask = ctx.OpShiftLeftLogical(ctx.U32[1], mask, ctx.Const(1U));
175 mask = ctx.OpShiftRightLogical(ctx.U32[1], swizzle, mask); 175 mask = ctx.OpShiftRightLogical(ctx.U32[1], swizzle, mask);
176 mask = ctx.OpBitwiseAnd(ctx.U32[1], mask, three); 176 mask = ctx.OpBitwiseAnd(ctx.U32[1], mask, three);
177 177