From cfb5da28f04d8bd25ee4cc92360a3bfe92251526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Sat, 20 Jul 2019 10:42:04 -0700 Subject: [PATCH] Updated spirv-tools. --- 3rdparty/spirv-tools/Android.mk | 1 - 3rdparty/spirv-tools/BUILD.gn | 9 +- .../include/generated/build-version.inc | 2 +- .../include/spirv-tools/instrument.hpp | 5 + .../include/spirv-tools/optimizer.hpp | 14 - .../spirv-tools/source/opt/CMakeLists.txt | 2 - .../source/opt/common_uniform_elim_pass.cpp | 596 ----- .../source/opt/common_uniform_elim_pass.h | 213 -- .../spirv-tools/source/opt/inline_pass.cpp | 41 +- 3rdparty/spirv-tools/source/opt/inline_pass.h | 5 +- .../spirv-tools/source/opt/instruction.cpp | 10 +- 3rdparty/spirv-tools/source/opt/instruction.h | 7 +- .../source/opt/instrument_pass.cpp | 29 +- .../spirv-tools/source/opt/ir_context.cpp | 3 +- .../source/opt/merge_return_pass.cpp | 80 +- .../source/opt/merge_return_pass.h | 38 +- 3rdparty/spirv-tools/source/opt/optimizer.cpp | 11 - 3rdparty/spirv-tools/source/opt/passes.h | 1 - .../spirv-tools/source/val/validate_type.cpp | 37 + 3rdparty/spirv-tools/test/opt/CMakeLists.txt | 1 - .../test/opt/common_uniform_elim_test.cpp | 1479 ------------- 3rdparty/spirv-tools/test/opt/inline_test.cpp | 115 - .../test/opt/inst_bindless_check_test.cpp | 1944 +++++++++++++++++ .../spirv-tools/test/opt/optimizer_test.cpp | 1 - .../test/opt/pass_merge_return_test.cpp | 56 + 3rdparty/spirv-tools/test/tools/expect.py | 9 + 3rdparty/spirv-tools/test/tools/opt/flags.py | 45 +- 3rdparty/spirv-tools/test/val/val_id_test.cpp | 20 + 3rdparty/spirv-tools/tools/opt/opt.cpp | 34 +- 29 files changed, 2240 insertions(+), 2568 deletions(-) delete mode 100644 3rdparty/spirv-tools/source/opt/common_uniform_elim_pass.cpp delete mode 100644 3rdparty/spirv-tools/source/opt/common_uniform_elim_pass.h delete mode 100644 3rdparty/spirv-tools/test/opt/common_uniform_elim_test.cpp diff --git a/3rdparty/spirv-tools/Android.mk b/3rdparty/spirv-tools/Android.mk index 075dc61ef..82d977663 100644 --- a/3rdparty/spirv-tools/Android.mk +++ b/3rdparty/spirv-tools/Android.mk @@ -84,7 +84,6 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/ccp_pass.cpp \ source/opt/code_sink.cpp \ source/opt/combine_access_chains.cpp \ - source/opt/common_uniform_elim_pass.cpp \ source/opt/compact_ids_pass.cpp \ source/opt/composite.cpp \ source/opt/const_folding_rules.cpp \ diff --git a/3rdparty/spirv-tools/BUILD.gn b/3rdparty/spirv-tools/BUILD.gn index 3c2a9f6d5..70772b93a 100644 --- a/3rdparty/spirv-tools/BUILD.gn +++ b/3rdparty/spirv-tools/BUILD.gn @@ -469,8 +469,6 @@ static_library("spvtools_opt") { "source/opt/code_sink.h", "source/opt/combine_access_chains.cpp", "source/opt/combine_access_chains.h", - "source/opt/common_uniform_elim_pass.cpp", - "source/opt/common_uniform_elim_pass.h", "source/opt/compact_ids_pass.cpp", "source/opt/compact_ids_pass.h", "source/opt/composite.cpp", @@ -670,6 +668,7 @@ static_library("spvtools_link") { ] deps = [ ":spvtools", + ":spvtools_opt", ":spvtools_val", ] public_deps = [ @@ -736,6 +735,8 @@ static_library("spvtools_reduce") { "source/reduce/structured_loop_to_selection_reduction_opportunity.h", "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp", "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h", + "source/spirv_reducer_options.cpp", + "source/spirv_reducer_options.h", ] deps = [ ":spvtools", @@ -865,6 +866,7 @@ source_set("spvtools_software_version") { ] deps = [ ":spvtools_build_version", + ":spvtools_headers", ] configs += [ ":spvtools_internal_config" ] } @@ -949,12 +951,11 @@ if (!is_ios) { # iOS does not allow std::system calls which spirv-reduce requires executable("spirv-reduce") { sources = [ - "source/spirv_reducer_options.cpp", - "source/spirv_reducer_options.h", "tools/reduce/reduce.cpp", ] deps = [ ":spvtools", + ":spvtools_opt", ":spvtools_reduce", ":spvtools_software_version", ":spvtools_util_cli_consumer", diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 25ecd73e3..00c5d1c7a 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-82-g55adf4cf" +"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-90-g76b75c40" diff --git a/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp b/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp index 4d37e3f18..dfd6e358f 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp @@ -117,6 +117,11 @@ static const int kInstGeomOutPrimitiveId = kInstCommonOutCnt; static const int kInstGeomOutInvocationId = kInstCommonOutCnt + 1; static const int kInstGeomOutUnused = kInstCommonOutCnt + 2; +// Ray Tracing Shader Output Record Offsets +static const int kInstRayTracingOutLaunchIdX = kInstCommonOutCnt; +static const int kInstRayTracingOutLaunchIdY = kInstCommonOutCnt + 1; +static const int kInstRayTracingOutLaunchIdZ = kInstCommonOutCnt + 2; + // Size of Common and Stage-specific Members static const int kInstStageOutCnt = kInstCommonOutCnt + 2; static const int kInst2StageOutCnt = kInstCommonOutCnt + 3; diff --git a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp index 1d8d6e04c..4c668b4e4 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp @@ -492,20 +492,6 @@ Optimizer::PassToken CreateInsertExtractElimPass(); // inserts created by that pass. Optimizer::PassToken CreateDeadInsertElimPass(); -// Creates a pass to consolidate uniform references. -// For each entry point function in the module, first change all constant index -// access chain loads into equivalent composite extracts. Then consolidate -// identical uniform loads into one uniform load. Finally, consolidate -// identical uniform extracts into one uniform extract. This may require -// moving a load or extract to a point which dominates all uses. -// -// This pass requires a module to have structured control flow ie shader -// capability. It also requires logical addressing ie Addresses capability -// is not enabled. It also currently does not support any extensions. -// -// This pass currently only optimizes loads with a single index. -Optimizer::PassToken CreateCommonUniformElimPass(); - // Create aggressive dead code elimination pass // This pass eliminates unused code from the module. In addition, // it detects and eliminates code which may have spurious uses but which do diff --git a/3rdparty/spirv-tools/source/opt/CMakeLists.txt b/3rdparty/spirv-tools/source/opt/CMakeLists.txt index 4cd800106..3e1280e62 100644 --- a/3rdparty/spirv-tools/source/opt/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/opt/CMakeLists.txt @@ -22,7 +22,6 @@ set(SPIRV_TOOLS_OPT_SOURCES cfg.h code_sink.h combine_access_chains.h - common_uniform_elim_pass.h compact_ids_pass.h composite.h const_folding_rules.h @@ -123,7 +122,6 @@ set(SPIRV_TOOLS_OPT_SOURCES cfg.cpp code_sink.cpp combine_access_chains.cpp - common_uniform_elim_pass.cpp compact_ids_pass.cpp composite.cpp const_folding_rules.cpp diff --git a/3rdparty/spirv-tools/source/opt/common_uniform_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/common_uniform_elim_pass.cpp deleted file mode 100644 index 86889a66e..000000000 --- a/3rdparty/spirv-tools/source/opt/common_uniform_elim_pass.cpp +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright (c) 2017 The Khronos Group Inc. -// Copyright (c) 2017 Valve Corporation -// Copyright (c) 2017 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/opt/common_uniform_elim_pass.h" -#include "source/cfa.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace opt { - -namespace { - -const uint32_t kAccessChainPtrIdInIdx = 0; -const uint32_t kTypePointerStorageClassInIdx = 0; -const uint32_t kTypePointerTypeIdInIdx = 1; -const uint32_t kConstantValueInIdx = 0; -const uint32_t kExtractCompositeIdInIdx = 0; -const uint32_t kExtractIdx0InIdx = 1; -const uint32_t kStorePtrIdInIdx = 0; -const uint32_t kLoadPtrIdInIdx = 0; -const uint32_t kCopyObjectOperandInIdx = 0; -const uint32_t kTypeIntWidthInIdx = 0; - -} // anonymous namespace - -bool CommonUniformElimPass::IsNonPtrAccessChain(const SpvOp opcode) const { - return opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain; -} - -bool CommonUniformElimPass::IsSamplerOrImageType( - const Instruction* typeInst) const { - switch (typeInst->opcode()) { - case SpvOpTypeSampler: - case SpvOpTypeImage: - case SpvOpTypeSampledImage: - return true; - default: - break; - } - if (typeInst->opcode() != SpvOpTypeStruct) return false; - // Return true if any member is a sampler or image - return !typeInst->WhileEachInId([this](const uint32_t* tid) { - const Instruction* compTypeInst = get_def_use_mgr()->GetDef(*tid); - if (IsSamplerOrImageType(compTypeInst)) { - return false; - } - return true; - }); -} - -bool CommonUniformElimPass::IsSamplerOrImageVar(uint32_t varId) const { - const Instruction* varInst = get_def_use_mgr()->GetDef(varId); - assert(varInst->opcode() == SpvOpVariable); - const uint32_t varTypeId = varInst->type_id(); - const Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId); - const uint32_t varPteTypeId = - varTypeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx); - Instruction* varPteTypeInst = get_def_use_mgr()->GetDef(varPteTypeId); - return IsSamplerOrImageType(varPteTypeInst); -} - -Instruction* CommonUniformElimPass::GetPtr(Instruction* ip, uint32_t* objId) { - const SpvOp op = ip->opcode(); - assert(op == SpvOpStore || op == SpvOpLoad); - *objId = ip->GetSingleWordInOperand(op == SpvOpStore ? kStorePtrIdInIdx - : kLoadPtrIdInIdx); - Instruction* ptrInst = get_def_use_mgr()->GetDef(*objId); - while (ptrInst->opcode() == SpvOpCopyObject) { - *objId = ptrInst->GetSingleWordInOperand(kCopyObjectOperandInIdx); - ptrInst = get_def_use_mgr()->GetDef(*objId); - } - Instruction* objInst = ptrInst; - while (objInst->opcode() != SpvOpVariable && - objInst->opcode() != SpvOpFunctionParameter) { - if (IsNonPtrAccessChain(objInst->opcode())) { - *objId = objInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx); - } else { - assert(objInst->opcode() == SpvOpCopyObject); - *objId = objInst->GetSingleWordInOperand(kCopyObjectOperandInIdx); - } - objInst = get_def_use_mgr()->GetDef(*objId); - } - return ptrInst; -} - -bool CommonUniformElimPass::IsVolatileStruct(uint32_t type_id) { - assert(get_def_use_mgr()->GetDef(type_id)->opcode() == SpvOpTypeStruct); - return !get_decoration_mgr()->WhileEachDecoration( - type_id, SpvDecorationVolatile, [](const Instruction&) { return false; }); -} - -bool CommonUniformElimPass::IsAccessChainToVolatileStructType( - const Instruction& AccessChainInst) { - assert(AccessChainInst.opcode() == SpvOpAccessChain); - - uint32_t ptr_id = AccessChainInst.GetSingleWordInOperand(0); - const Instruction* ptr_inst = get_def_use_mgr()->GetDef(ptr_id); - uint32_t pointee_type_id = GetPointeeTypeId(ptr_inst); - const uint32_t num_operands = AccessChainInst.NumOperands(); - - // walk the type tree: - for (uint32_t idx = 3; idx < num_operands; ++idx) { - Instruction* pointee_type = get_def_use_mgr()->GetDef(pointee_type_id); - - switch (pointee_type->opcode()) { - case SpvOpTypeMatrix: - case SpvOpTypeVector: - case SpvOpTypeArray: - case SpvOpTypeRuntimeArray: - pointee_type_id = pointee_type->GetSingleWordOperand(1); - break; - case SpvOpTypeStruct: - // check for volatile decorations: - if (IsVolatileStruct(pointee_type_id)) return true; - - if (idx < num_operands - 1) { - const uint32_t index_id = AccessChainInst.GetSingleWordOperand(idx); - const Instruction* index_inst = get_def_use_mgr()->GetDef(index_id); - uint32_t index_value = index_inst->GetSingleWordOperand( - 2); // TODO: replace with GetUintValueFromConstant() - pointee_type_id = pointee_type->GetSingleWordInOperand(index_value); - } - break; - default: - assert(false && "Unhandled pointee type."); - } - } - return false; -} - -bool CommonUniformElimPass::IsVolatileLoad(const Instruction& loadInst) { - assert(loadInst.opcode() == SpvOpLoad); - // Check if this Load instruction has Volatile Memory Access flag - if (loadInst.NumOperands() == 4) { - uint32_t memory_access_mask = loadInst.GetSingleWordOperand(3); - if (memory_access_mask & SpvMemoryAccessVolatileMask) return true; - } - // If we load a struct directly (result type is struct), - // check if the struct is decorated volatile - uint32_t type_id = loadInst.type_id(); - if (get_def_use_mgr()->GetDef(type_id)->opcode() == SpvOpTypeStruct) - return IsVolatileStruct(type_id); - else - return false; -} - -bool CommonUniformElimPass::IsUniformVar(uint32_t varId) { - const Instruction* varInst = - get_def_use_mgr()->id_to_defs().find(varId)->second; - if (varInst->opcode() != SpvOpVariable) return false; - const uint32_t varTypeId = varInst->type_id(); - const Instruction* varTypeInst = - get_def_use_mgr()->id_to_defs().find(varTypeId)->second; - return varTypeInst->GetSingleWordInOperand(kTypePointerStorageClassInIdx) == - SpvStorageClassUniform || - varTypeInst->GetSingleWordInOperand(kTypePointerStorageClassInIdx) == - SpvStorageClassUniformConstant; -} - -bool CommonUniformElimPass::HasUnsupportedDecorates(uint32_t id) const { - return !get_def_use_mgr()->WhileEachUser(id, [this](Instruction* user) { - if (IsNonTypeDecorate(user->opcode())) return false; - return true; - }); -} - -bool CommonUniformElimPass::HasOnlyNamesAndDecorates(uint32_t id) const { - return get_def_use_mgr()->WhileEachUser(id, [this](Instruction* user) { - SpvOp op = user->opcode(); - if (op != SpvOpName && !IsNonTypeDecorate(op)) return false; - return true; - }); -} - -void CommonUniformElimPass::DeleteIfUseless(Instruction* inst) { - const uint32_t resId = inst->result_id(); - assert(resId != 0); - if (HasOnlyNamesAndDecorates(resId)) { - context()->KillInst(inst); - } -} - -Instruction* CommonUniformElimPass::ReplaceAndDeleteLoad(Instruction* loadInst, - uint32_t replId, - Instruction* ptrInst) { - const uint32_t loadId = loadInst->result_id(); - context()->KillNamesAndDecorates(loadId); - (void)context()->ReplaceAllUsesWith(loadId, replId); - // remove load instruction - Instruction* next_instruction = context()->KillInst(loadInst); - // if access chain, see if it can be removed as well - if (IsNonPtrAccessChain(ptrInst->opcode())) DeleteIfUseless(ptrInst); - return next_instruction; -} - -void CommonUniformElimPass::GenACLoadRepl( - const Instruction* ptrInst, - std::vector>* newInsts, uint32_t* resultId) { - // Build and append Load - const uint32_t ldResultId = TakeNextId(); - const uint32_t varId = - ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx); - const Instruction* varInst = get_def_use_mgr()->GetDef(varId); - assert(varInst->opcode() == SpvOpVariable); - const uint32_t varPteTypeId = GetPointeeTypeId(varInst); - std::vector load_in_operands; - load_in_operands.push_back(Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, - std::initializer_list{varId})); - std::unique_ptr newLoad(new Instruction( - context(), SpvOpLoad, varPteTypeId, ldResultId, load_in_operands)); - get_def_use_mgr()->AnalyzeInstDefUse(&*newLoad); - newInsts->emplace_back(std::move(newLoad)); - - // Build and append Extract - const uint32_t extResultId = TakeNextId(); - const uint32_t ptrPteTypeId = GetPointeeTypeId(ptrInst); - std::vector ext_in_opnds; - ext_in_opnds.push_back(Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, - std::initializer_list{ldResultId})); - uint32_t iidIdx = 0; - ptrInst->ForEachInId([&iidIdx, &ext_in_opnds, this](const uint32_t* iid) { - if (iidIdx > 0) { - const Instruction* cInst = get_def_use_mgr()->GetDef(*iid); - uint32_t val = cInst->GetSingleWordInOperand(kConstantValueInIdx); - ext_in_opnds.push_back( - Operand(spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, - std::initializer_list{val})); - } - ++iidIdx; - }); - std::unique_ptr newExt( - new Instruction(context(), SpvOpCompositeExtract, ptrPteTypeId, - extResultId, ext_in_opnds)); - get_def_use_mgr()->AnalyzeInstDefUse(&*newExt); - newInsts->emplace_back(std::move(newExt)); - *resultId = extResultId; -} - -bool CommonUniformElimPass::IsConstantIndexAccessChain(Instruction* acp) { - uint32_t inIdx = 0; - return acp->WhileEachInId([&inIdx, this](uint32_t* tid) { - if (inIdx > 0) { - Instruction* opInst = get_def_use_mgr()->GetDef(*tid); - if (opInst->opcode() != SpvOpConstant) return false; - } - ++inIdx; - return true; - }); -} - -bool CommonUniformElimPass::UniformAccessChainConvert(Function* func) { - bool modified = false; - for (auto bi = func->begin(); bi != func->end(); ++bi) { - for (Instruction* inst = &*bi->begin(); inst; inst = inst->NextNode()) { - if (inst->opcode() != SpvOpLoad) continue; - uint32_t varId; - Instruction* ptrInst = GetPtr(inst, &varId); - if (!IsNonPtrAccessChain(ptrInst->opcode())) continue; - // Do not convert nested access chains - if (ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx) != varId) - continue; - if (!IsUniformVar(varId)) continue; - if (!IsConstantIndexAccessChain(ptrInst)) continue; - if (HasUnsupportedDecorates(inst->result_id())) continue; - if (HasUnsupportedDecorates(ptrInst->result_id())) continue; - if (IsVolatileLoad(*inst)) continue; - if (IsAccessChainToVolatileStructType(*ptrInst)) continue; - std::vector> newInsts; - uint32_t replId; - GenACLoadRepl(ptrInst, &newInsts, &replId); - inst = ReplaceAndDeleteLoad(inst, replId, ptrInst); - assert(inst->opcode() != SpvOpPhi); - inst = inst->InsertBefore(std::move(newInsts)); - modified = true; - } - } - return modified; -} - -void CommonUniformElimPass::ComputeStructuredSuccessors(Function* func) { - block2structured_succs_.clear(); - for (auto& blk : *func) { - // If header, make merge block first successor. - uint32_t mbid = blk.MergeBlockIdIfAny(); - if (mbid != 0) { - block2structured_succs_[&blk].push_back(cfg()->block(mbid)); - uint32_t cbid = blk.ContinueBlockIdIfAny(); - if (cbid != 0) { - block2structured_succs_[&blk].push_back(cfg()->block(mbid)); - } - } - // add true successors - const auto& const_blk = blk; - const_blk.ForEachSuccessorLabel([&blk, this](const uint32_t sbid) { - block2structured_succs_[&blk].push_back(cfg()->block(sbid)); - }); - } -} - -void CommonUniformElimPass::ComputeStructuredOrder( - Function* func, std::list* order) { - // Compute structured successors and do DFS - ComputeStructuredSuccessors(func); - auto ignore_block = [](cbb_ptr) {}; - auto ignore_edge = [](cbb_ptr, cbb_ptr) {}; - auto get_structured_successors = [this](const BasicBlock* block) { - return &(block2structured_succs_[block]); - }; - // TODO(greg-lunarg): Get rid of const_cast by making moving const - // out of the cfa.h prototypes and into the invoking code. - auto post_order = [&](cbb_ptr b) { - order->push_front(const_cast(b)); - }; - - order->clear(); - CFA::DepthFirstTraversal(&*func->begin(), - get_structured_successors, ignore_block, - post_order, ignore_edge); -} - -bool CommonUniformElimPass::CommonUniformLoadElimination(Function* func) { - // Process all blocks in structured order. This is just one way (the - // simplest?) to keep track of the most recent block outside of control - // flow, used to copy common instructions, guaranteed to dominate all - // following load sites. - std::list structuredOrder; - ComputeStructuredOrder(func, &structuredOrder); - uniform2load_id_.clear(); - bool modified = false; - // Find insertion point in first block to copy non-dominating loads. - auto insertItr = func->begin()->begin(); - while (insertItr->opcode() == SpvOpVariable || - insertItr->opcode() == SpvOpNop) - ++insertItr; - // Update insertItr until it will not be removed. Without this code, - // ReplaceAndDeleteLoad() can set |insertItr| as a dangling pointer. - while (IsUniformLoadToBeRemoved(&*insertItr)) ++insertItr; - uint32_t mergeBlockId = 0; - for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) { - BasicBlock* bp = *bi; - // Check if we are exiting outermost control construct. If so, remember - // new load insertion point. Trying to keep register pressure down. - if (mergeBlockId == bp->id()) { - mergeBlockId = 0; - insertItr = bp->begin(); - while (insertItr->opcode() == SpvOpPhi) { - ++insertItr; - } - - // Update insertItr until it will not be removed. Without this code, - // ReplaceAndDeleteLoad() can set |insertItr| as a dangling pointer. - while (IsUniformLoadToBeRemoved(&*insertItr)) ++insertItr; - } - for (Instruction* inst = &*bp->begin(); inst; inst = inst->NextNode()) { - if (inst->opcode() != SpvOpLoad) continue; - uint32_t varId; - Instruction* ptrInst = GetPtr(inst, &varId); - if (ptrInst->opcode() != SpvOpVariable) continue; - if (!IsUniformVar(varId)) continue; - if (IsSamplerOrImageVar(varId)) continue; - if (HasUnsupportedDecorates(inst->result_id())) continue; - if (IsVolatileLoad(*inst)) continue; - uint32_t replId; - const auto uItr = uniform2load_id_.find(varId); - if (uItr != uniform2load_id_.end()) { - replId = uItr->second; - } else { - if (mergeBlockId == 0) { - // Load is in dominating block; just remember it - uniform2load_id_[varId] = inst->result_id(); - continue; - } else { - // Copy load into most recent dominating block and remember it - replId = TakeNextId(); - std::unique_ptr newLoad(new Instruction( - context(), SpvOpLoad, inst->type_id(), replId, - {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {varId}}})); - get_def_use_mgr()->AnalyzeInstDefUse(&*newLoad); - insertItr = insertItr.InsertBefore(std::move(newLoad)); - ++insertItr; - uniform2load_id_[varId] = replId; - } - } - inst = ReplaceAndDeleteLoad(inst, replId, ptrInst); - modified = true; - } - // If we are outside of any control construct and entering one, remember - // the id of the merge block - if (mergeBlockId == 0) { - mergeBlockId = bp->MergeBlockIdIfAny(); - } - } - return modified; -} - -bool CommonUniformElimPass::CommonUniformLoadElimBlock(Function* func) { - bool modified = false; - for (auto& blk : *func) { - uniform2load_id_.clear(); - for (Instruction* inst = &*blk.begin(); inst; inst = inst->NextNode()) { - if (inst->opcode() != SpvOpLoad) continue; - uint32_t varId; - Instruction* ptrInst = GetPtr(inst, &varId); - if (ptrInst->opcode() != SpvOpVariable) continue; - if (!IsUniformVar(varId)) continue; - if (!IsSamplerOrImageVar(varId)) continue; - if (HasUnsupportedDecorates(inst->result_id())) continue; - if (IsVolatileLoad(*inst)) continue; - uint32_t replId; - const auto uItr = uniform2load_id_.find(varId); - if (uItr != uniform2load_id_.end()) { - replId = uItr->second; - } else { - uniform2load_id_[varId] = inst->result_id(); - continue; - } - inst = ReplaceAndDeleteLoad(inst, replId, ptrInst); - modified = true; - } - } - return modified; -} - -bool CommonUniformElimPass::CommonExtractElimination(Function* func) { - // Find all composite ids with duplicate extracts. - for (auto bi = func->begin(); bi != func->end(); ++bi) { - for (auto ii = bi->begin(); ii != bi->end(); ++ii) { - if (ii->opcode() != SpvOpCompositeExtract) continue; - // TODO(greg-lunarg): Support multiple indices - if (ii->NumInOperands() > 2) continue; - if (HasUnsupportedDecorates(ii->result_id())) continue; - uint32_t compId = ii->GetSingleWordInOperand(kExtractCompositeIdInIdx); - uint32_t idx = ii->GetSingleWordInOperand(kExtractIdx0InIdx); - comp2idx2inst_[compId][idx].push_back(&*ii); - } - } - // For all defs of ids with duplicate extracts, insert new extracts - // after def, and replace and delete old extracts - bool modified = false; - for (auto bi = func->begin(); bi != func->end(); ++bi) { - for (auto ii = bi->begin(); ii != bi->end(); ++ii) { - const auto cItr = comp2idx2inst_.find(ii->result_id()); - if (cItr == comp2idx2inst_.end()) continue; - for (auto idxItr : cItr->second) { - if (idxItr.second.size() < 2) continue; - uint32_t replId = TakeNextId(); - std::unique_ptr newExtract( - idxItr.second.front()->Clone(context())); - newExtract->SetResultId(replId); - get_def_use_mgr()->AnalyzeInstDefUse(&*newExtract); - ++ii; - ii = ii.InsertBefore(std::move(newExtract)); - for (auto instItr : idxItr.second) { - uint32_t resId = instItr->result_id(); - context()->KillNamesAndDecorates(resId); - (void)context()->ReplaceAllUsesWith(resId, replId); - context()->KillInst(instItr); - } - modified = true; - } - } - } - return modified; -} - -bool CommonUniformElimPass::EliminateCommonUniform(Function* func) { - bool modified = false; - modified |= UniformAccessChainConvert(func); - modified |= CommonUniformLoadElimination(func); - modified |= CommonExtractElimination(func); - - modified |= CommonUniformLoadElimBlock(func); - return modified; -} - -void CommonUniformElimPass::Initialize() { - // Clear collections. - comp2idx2inst_.clear(); - - // Initialize extension whitelist - InitExtensions(); -} - -bool CommonUniformElimPass::AllExtensionsSupported() const { - // If any extension not in whitelist, return false - for (auto& ei : get_module()->extensions()) { - const char* extName = - reinterpret_cast(&ei.GetInOperand(0).words[0]); - if (extensions_whitelist_.find(extName) == extensions_whitelist_.end()) - return false; - } - return true; -} - -Pass::Status CommonUniformElimPass::ProcessImpl() { - // Assumes all control flow structured. - // TODO(greg-lunarg): Do SSA rewrite for non-structured control flow - if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) - return Status::SuccessWithoutChange; - // Assumes logical addressing only - // TODO(greg-lunarg): Add support for physical addressing - if (context()->get_feature_mgr()->HasCapability(SpvCapabilityAddresses)) - return Status::SuccessWithoutChange; - if (context()->get_feature_mgr()->HasCapability( - SpvCapabilityVariablePointersStorageBuffer)) - return Status::SuccessWithoutChange; - // Do not process if any disallowed extensions are enabled - if (!AllExtensionsSupported()) return Status::SuccessWithoutChange; - // Do not process if module contains OpGroupDecorate. Additional - // support required in KillNamesAndDecorates(). - // TODO(greg-lunarg): Add support for OpGroupDecorate - for (auto& ai : get_module()->annotations()) - if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange; - // If non-32-bit integer type in module, terminate processing - // TODO(): Handle non-32-bit integer constants in access chains - for (const Instruction& inst : get_module()->types_values()) - if (inst.opcode() == SpvOpTypeInt && - inst.GetSingleWordInOperand(kTypeIntWidthInIdx) != 32) - return Status::SuccessWithoutChange; - // Process entry point functions - ProcessFunction pfn = [this](Function* fp) { - return EliminateCommonUniform(fp); - }; - bool modified = context()->ProcessEntryPointCallTree(pfn); - return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; -} - -CommonUniformElimPass::CommonUniformElimPass() = default; - -Pass::Status CommonUniformElimPass::Process() { - Initialize(); - return ProcessImpl(); -} - -void CommonUniformElimPass::InitExtensions() { - extensions_whitelist_.clear(); - extensions_whitelist_.insert({ - "SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - // SPV_KHR_variable_pointers - // Currently do not support extended pointer expressions - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_GOOGLE_user_type", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_descriptor_indexing", - "SPV_NV_fragment_shader_barycentric", - "SPV_NV_compute_shader_derivatives", - "SPV_NV_shader_image_footprint", - "SPV_NV_shading_rate", - "SPV_NV_mesh_shader", - "SPV_NV_ray_tracing", - "SPV_EXT_fragment_invocation_density", - }); -} - -} // namespace opt -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/common_uniform_elim_pass.h b/3rdparty/spirv-tools/source/opt/common_uniform_elim_pass.h deleted file mode 100644 index e6ef69c5d..000000000 --- a/3rdparty/spirv-tools/source/opt/common_uniform_elim_pass.h +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) 2016 The Khronos Group Inc. -// Copyright (c) 2016 Valve Corporation -// Copyright (c) 2016 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_OPT_COMMON_UNIFORM_ELIM_PASS_H_ -#define SOURCE_OPT_COMMON_UNIFORM_ELIM_PASS_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "source/opt/basic_block.h" -#include "source/opt/decoration_manager.h" -#include "source/opt/def_use_manager.h" -#include "source/opt/ir_context.h" -#include "source/opt/module.h" -#include "source/opt/pass.h" - -namespace spvtools { -namespace opt { - -// See optimizer.hpp for documentation. -class CommonUniformElimPass : public Pass { - using cbb_ptr = const BasicBlock*; - - public: - using GetBlocksFunction = - std::function*(const BasicBlock*)>; - - CommonUniformElimPass(); - - const char* name() const override { return "eliminate-common-uniform"; } - Status Process() override; - - private: - // Returns true if |opcode| is a non-ptr access chain op - bool IsNonPtrAccessChain(const SpvOp opcode) const; - - // Returns true if |typeInst| is a sampler or image type or a struct - // containing one, recursively. - bool IsSamplerOrImageType(const Instruction* typeInst) const; - - // Returns true if |varId| is a variable containing a sampler or image. - bool IsSamplerOrImageVar(uint32_t varId) const; - - // Given a load or store pointed at by |ip|, return the top-most - // non-CopyObj in its pointer operand. Also return the base pointer - // in |objId|. - Instruction* GetPtr(Instruction* ip, uint32_t* objId); - - // Return true if variable is uniform - bool IsUniformVar(uint32_t varId); - - // Given the type id for a struct type, checks if the struct type - // or any struct member is volatile decorated - bool IsVolatileStruct(uint32_t type_id); - - // Given an OpAccessChain instruction, return true - // if the accessed variable belongs to a volatile - // decorated object or member of a struct type - bool IsAccessChainToVolatileStructType(const Instruction& AccessChainInst); - - // Given an OpLoad instruction, return true if - // OpLoad has a Volatile Memory Access flag or if - // the resulting type is a volatile decorated struct - bool IsVolatileLoad(const Instruction& loadInst); - - // Return true if any uses of |id| are decorate ops. - bool HasUnsupportedDecorates(uint32_t id) const; - - // Return true if all uses of |id| are only name or decorate ops. - bool HasOnlyNamesAndDecorates(uint32_t id) const; - - // Delete inst if it has no uses. Assumes inst has a resultId. - void DeleteIfUseless(Instruction* inst); - - // Replace all instances of load's id with replId and delete load - // and its access chain, if any - Instruction* ReplaceAndDeleteLoad(Instruction* loadInst, uint32_t replId, - Instruction* ptrInst); - - // For the (constant index) access chain ptrInst, create an - // equivalent load and extract - void GenACLoadRepl(const Instruction* ptrInst, - std::vector>* newInsts, - uint32_t* resultId); - - // Return true if all indices are constant - bool IsConstantIndexAccessChain(Instruction* acp); - - // Convert all uniform access chain loads into load/extract. - bool UniformAccessChainConvert(Function* func); - - // Compute structured successors for function |func|. - // A block's structured successors are the blocks it branches to - // together with its declared merge block if it has one. - // When order matters, the merge block always appears first. - // This assures correct depth first search in the presence of early - // returns and kills. If the successor vector contain duplicates - // if the merge block, they are safely ignored by DFS. - // - // TODO(dnovillo): This pass computes structured successors slightly different - // than the implementation in class Pass. Can this be re-factored? - void ComputeStructuredSuccessors(Function* func); - - // Compute structured block order for |func| into |structuredOrder|. This - // order has the property that dominators come before all blocks they - // dominate and merge blocks come after all blocks that are in the control - // constructs of their header. - // - // TODO(dnovillo): This pass computes structured order slightly different - // than the implementation in class Pass. Can this be re-factored? - void ComputeStructuredOrder(Function* func, std::list* order); - - // Eliminate loads of uniform variables which have previously been loaded. - // If first load is in control flow, move it to first block of function. - // Most effective if preceded by UniformAccessChainRemoval(). - bool CommonUniformLoadElimination(Function* func); - - // Eliminate loads of uniform sampler and image variables which have - // previously - // been loaded in the same block for types whose loads cannot cross blocks. - bool CommonUniformLoadElimBlock(Function* func); - - // Eliminate duplicated extracts of same id. Extract may be moved to same - // block as the id definition. This is primarily intended for extracts - // from uniform loads. Most effective if preceded by - // CommonUniformLoadElimination(). - bool CommonExtractElimination(Function* func); - - // For function |func|, first change all uniform constant index - // access chain loads into equivalent composite extracts. Then consolidate - // identical uniform loads into one uniform load. Finally, consolidate - // identical uniform extracts into one uniform extract. This may require - // moving a load or extract to a point which dominates all uses. - // Return true if func is modified. - // - // This pass requires the function to have structured control flow ie shader - // capability. It also requires logical addressing ie Addresses capability - // is not enabled. It also currently does not support any extensions. - // - // This function currently only optimizes loads with a single index. - bool EliminateCommonUniform(Function* func); - - // Initialize extensions whitelist - void InitExtensions(); - - // Return true if all extensions in this module are allowed by this pass. - bool AllExtensionsSupported() const; - - // Return true if |op| is a decorate for non-type instruction - inline bool IsNonTypeDecorate(uint32_t op) const { - return (op == SpvOpDecorate || op == SpvOpDecorateId); - } - - // Return true if |inst| is an instruction that loads uniform variable and - // can be replaced with other uniform load instruction. - bool IsUniformLoadToBeRemoved(Instruction* inst) { - if (inst->opcode() == SpvOpLoad) { - uint32_t varId; - Instruction* ptrInst = GetPtr(inst, &varId); - if (ptrInst->opcode() == SpvOpVariable && IsUniformVar(varId) && - !IsSamplerOrImageVar(varId) && - !HasUnsupportedDecorates(inst->result_id()) && !IsVolatileLoad(*inst)) - return true; - } - return false; - } - - void Initialize(); - Pass::Status ProcessImpl(); - - // Map from uniform variable id to its common load id - std::unordered_map uniform2load_id_; - - // Map of extract composite ids to map of indices to insts - // TODO(greg-lunarg): Consider std::vector. - std::unordered_map>> - comp2idx2inst_; - - // Extensions supported by this pass. - std::unordered_set extensions_whitelist_; - - // Map from block to its structured successor blocks. See - // ComputeStructuredSuccessors() for definition. - std::unordered_map> - block2structured_succs_; -}; - -} // namespace opt -} // namespace spvtools - -#endif // SOURCE_OPT_COMMON_UNIFORM_ELIM_PASS_H_ diff --git a/3rdparty/spirv-tools/source/opt/inline_pass.cpp b/3rdparty/spirv-tools/source/opt/inline_pass.cpp index 01ed5b88e..f348bbe3e 100644 --- a/3rdparty/spirv-tools/source/opt/inline_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/inline_pass.cpp @@ -629,39 +629,12 @@ bool InlinePass::GenInlineCode( return true; } -bool InlinePass::IsInlinableFunctionCall(Instruction* inst) { +bool InlinePass::IsInlinableFunctionCall(const Instruction* inst) { if (inst->opcode() != SpvOp::SpvOpFunctionCall) return false; const uint32_t calleeFnId = inst->GetSingleWordOperand(kSpvFunctionCallFunctionId); const auto ci = inlinable_.find(calleeFnId); - if (ci == inlinable_.cend()) { - return false; - } - - if (funcs_with_opkill_.count(calleeFnId) == 0) { - return true; - } - - // We cannot inline into a continue construct if the function has an OpKill. - auto* cfg_analysis = context()->GetStructuredCFGAnalysis(); - BasicBlock* bb = context()->get_instr_block(inst); - uint32_t loop_header_id = cfg_analysis->ContainingLoop(bb->id()); - if (loop_header_id == 0) { - // Not in a loop, so we can inline. - return true; - } - BasicBlock* loop_header_bb = context()->get_instr_block(loop_header_id); - uint32_t loop_continue = - loop_header_bb->GetLoopMergeInst()->GetSingleWordOperand(1); - - Function* caller_func = bb->GetParent(); - DominatorAnalysis* dom = context()->GetDominatorAnalysis(caller_func); - if (dom->Dominates(loop_continue, bb->id())) { - // The function call is the continue construct and the callee contains an - // OpKill. - return false; - } - return true; + return ci != inlinable_.cend(); } void InlinePass::UpdateSucceedingPhis( @@ -738,9 +711,6 @@ bool InlinePass::IsInlinableFunction(Function* func) { // the returns as a branch to the loop's merge block. However, this can only // done validly if the return was not in a loop in the original function. // Also remember functions with multiple (early) returns. - - // Do not inline functions with an OpKill because they may be inlined into a - // continue construct. AnalyzeReturns(func); if (no_return_in_loop_.find(func->result_id()) == no_return_in_loop_.cend()) { return false; @@ -771,13 +741,6 @@ void InlinePass::InitializeInline() { } // Compute inlinability if (IsInlinableFunction(&fn)) inlinable_.insert(fn.result_id()); - - bool has_opkill = !fn.WhileEachInst( - [](Instruction* inst) { return inst->opcode() != SpvOpKill; }); - - if (has_opkill) { - funcs_with_opkill_.insert(fn.result_id()); - } } } diff --git a/3rdparty/spirv-tools/source/opt/inline_pass.h b/3rdparty/spirv-tools/source/opt/inline_pass.h index e17dddb60..ecfe964f1 100644 --- a/3rdparty/spirv-tools/source/opt/inline_pass.h +++ b/3rdparty/spirv-tools/source/opt/inline_pass.h @@ -122,7 +122,7 @@ class InlinePass : public Pass { UptrVectorIterator call_block_itr); // Return true if |inst| is a function call that can be inlined. - bool IsInlinableFunctionCall(Instruction* inst); + bool IsInlinableFunctionCall(const Instruction* inst); // Return true if |func| does not have a return that is // nested in a structured if, switch or loop. @@ -159,9 +159,6 @@ class InlinePass : public Pass { // Set of ids of functions with no returns in loop std::set no_return_in_loop_; - // Set of ids of functions with no returns in loop - std::unordered_set funcs_with_opkill_; - // Set of ids of inlinable functions std::set inlinable_; diff --git a/3rdparty/spirv-tools/source/opt/instruction.cpp b/3rdparty/spirv-tools/source/opt/instruction.cpp index f8c837b0c..ec736406e 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.cpp +++ b/3rdparty/spirv-tools/source/opt/instruction.cpp @@ -372,6 +372,11 @@ uint32_t Instruction::GetTypeComponent(uint32_t element) const { return subtype; } +Instruction* Instruction::InsertBefore(std::unique_ptr&& i) { + i.get()->InsertBefore(this); + return i.release(); +} + Instruction* Instruction::InsertBefore( std::vector>&& list) { Instruction* first_node = list.front().get(); @@ -382,11 +387,6 @@ Instruction* Instruction::InsertBefore( return first_node; } -Instruction* Instruction::InsertBefore(std::unique_ptr&& i) { - i.get()->InsertBefore(this); - return i.release(); -} - bool Instruction::IsValidBasePointer() const { uint32_t tid = type_id(); if (tid == 0) { diff --git a/3rdparty/spirv-tools/source/opt/instruction.h b/3rdparty/spirv-tools/source/opt/instruction.h index 034da76f4..d507d6c3d 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.h +++ b/3rdparty/spirv-tools/source/opt/instruction.h @@ -398,8 +398,13 @@ class Instruction : public utils::IntrusiveNodeBase { inline bool operator!=(const Instruction&) const; inline bool operator<(const Instruction&) const; - Instruction* InsertBefore(std::vector>&& list); + // Takes ownership of the instruction owned by |i| and inserts it immediately + // before |this|. Returns the insterted instruction. Instruction* InsertBefore(std::unique_ptr&& i); + // Takes ownership of the instructions in |list| and inserts them in order + // immediately before |this|. Returns the first inserted instruction. + // Assumes the list is non-empty. + Instruction* InsertBefore(std::vector>&& list); using utils::IntrusiveNodeBase::InsertBefore; // Returns true if |this| is an instruction defining a constant, but not a diff --git a/3rdparty/spirv-tools/source/opt/instrument_pass.cpp b/3rdparty/spirv-tools/source/opt/instrument_pass.cpp index 36fe00e43..6645a2e3f 100644 --- a/3rdparty/spirv-tools/source/opt/instrument_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/instrument_pass.cpp @@ -264,6 +264,28 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, GenFragCoordEltDebugOutputCode( base_offset_id, uint_frag_coord_inst->result_id(), u, builder); } break; + case SpvExecutionModelRayGenerationNV: + case SpvExecutionModelIntersectionNV: + case SpvExecutionModelAnyHitNV: + case SpvExecutionModelClosestHitNV: + case SpvExecutionModelMissNV: + case SpvExecutionModelCallableNV: { + // Load and store LaunchIdNV. + uint32_t launch_id = GenVarLoad( + context()->GetBuiltinInputVarId(SpvBuiltInLaunchIdNV), builder); + Instruction* x_launch_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, launch_id, 0); + Instruction* y_launch_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, launch_id, 1); + Instruction* z_launch_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, launch_id, 2); + GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX, + x_launch_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY, + y_launch_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ, + z_launch_inst->result_id(), builder); + } break; default: { assert(false && "unsupported stage"); } break; } } @@ -843,7 +865,12 @@ bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) { stage != SpvExecutionModelGeometry && stage != SpvExecutionModelGLCompute && stage != SpvExecutionModelTessellationControl && - stage != SpvExecutionModelTessellationEvaluation) + stage != SpvExecutionModelTessellationEvaluation && + stage != SpvExecutionModelRayGenerationNV && + stage != SpvExecutionModelIntersectionNV && + stage != SpvExecutionModelAnyHitNV && + stage != SpvExecutionModelClosestHitNV && + stage != SpvExecutionModelMissNV && stage != SpvExecutionModelCallableNV) return false; // Add together the roots of all entry points std::queue roots; diff --git a/3rdparty/spirv-tools/source/opt/ir_context.cpp b/3rdparty/spirv-tools/source/opt/ir_context.cpp index 11146cfd4..20309ca52 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_context.cpp @@ -683,7 +683,8 @@ uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) { reg_type = type_mgr->GetRegisteredType(&uint_ty); break; } - case SpvBuiltInGlobalInvocationId: { + case SpvBuiltInGlobalInvocationId: + case SpvBuiltInLaunchIdNV: { analysis::Integer uint_ty(32, false); analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); analysis::Vector v3uint_ty(reg_uint_ty, 3); diff --git a/3rdparty/spirv-tools/source/opt/merge_return_pass.cpp b/3rdparty/spirv-tools/source/opt/merge_return_pass.cpp index 044633166..6e7284baf 100644 --- a/3rdparty/spirv-tools/source/opt/merge_return_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/merge_return_pass.cpp @@ -224,6 +224,7 @@ void MergeReturnPass::BranchToBlock(BasicBlock* block, uint32_t target) { return_inst->SetOpcode(SpvOpBranch); return_inst->ReplaceOperands({{SPV_OPERAND_TYPE_ID, {target}}}); context()->get_def_use_mgr()->AnalyzeInstDefUse(return_inst); + new_edges_[target_block].insert(block->id()); cfg()->AddEdge(block->id(), target); } @@ -236,28 +237,18 @@ void MergeReturnPass::UpdatePhiNodes(BasicBlock* new_source, context()->UpdateDefUse(inst); }); - const auto& target_pred = cfg()->preds(target->id()); - if (target_pred.size() == 1) { - MarkForNewPhiNodes(target, context()->get_instr_block(target_pred[0])); - } else { - // If the loop contained a break and a return, OpPhi instructions may be - // required starting from the dominator of the loop merge. - DominatorAnalysis* dom_tree = - context()->GetDominatorAnalysis(target->GetParent()); - auto idom = dom_tree->ImmediateDominator(target); - if (idom) { - MarkForNewPhiNodes(target, idom); - } - } + // Store the immediate dominator for this block in case new phi nodes will be + // needed later. + RecordImmediateDominator(target); } void MergeReturnPass::CreatePhiNodesForInst(BasicBlock* merge_block, Instruction& inst) { DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(merge_block->GetParent()); - BasicBlock* inst_bb = context()->get_instr_block(&inst); if (inst.result_id() != 0) { + BasicBlock* inst_bb = context()->get_instr_block(&inst); std::vector users_to_update; context()->get_def_use_mgr()->ForEachUser( &inst, @@ -295,12 +286,13 @@ void MergeReturnPass::CreatePhiNodesForInst(BasicBlock* merge_block, IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); uint32_t undef_id = Type2Undef(inst.type_id()); std::vector phi_operands; + const std::set& new_edges = new_edges_[merge_block]; // Add the OpPhi operands. If the predecessor is a return block use undef, // otherwise use |inst|'s id. std::vector preds = cfg()->preds(merge_block->id()); for (uint32_t pred_id : preds) { - if (return_blocks_.count(pred_id)) { + if (new_edges.count(pred_id)) { phi_operands.push_back(undef_id); } else { phi_operands.push_back(inst.result_id()); @@ -417,6 +409,8 @@ bool MergeReturnPass::BreakFromConstruct( auto old_body_id = TakeNextId(); BasicBlock* old_body = block->SplitBasicBlock(context(), old_body_id, iter); predicated->insert(old_body); + cfg()->AddEdges(old_body); + // If a return block is being split, mark the new body block also as a return // block. if (return_blocks_.count(block->id())) { @@ -456,14 +450,15 @@ bool MergeReturnPass::BreakFromConstruct( builder.AddConditionalBranch(load_id, merge_block->id(), old_body->id(), old_body->id()); - // 3. Update OpPhi instructions in |merge_block|. - BasicBlock* merge_original_pred = MarkedSinglePred(merge_block); - if (merge_original_pred == nullptr) { - UpdatePhiNodes(block, merge_block); - } else if (merge_original_pred == block) { - MarkForNewPhiNodes(merge_block, old_body); + if (!new_edges_[merge_block].insert(block->id()).second) { + // It is possible that we already inserted a new edge to the merge block. + // If so, that edge now goes from |old_body| to |merge_block|. + new_edges_[merge_block].insert(old_body->id()); } + // 3. Update OpPhi instructions in |merge_block|. + UpdatePhiNodes(block, merge_block); + // 4. Update the CFG. We do this after updating the OpPhi instructions // because |UpdatePhiNodes| assumes the edge from |block| has not been added // to the CFG yet. @@ -659,26 +654,37 @@ void MergeReturnPass::MergeReturnBlocks( } void MergeReturnPass::AddNewPhiNodes() { - DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(function_); std::list order; cfg()->ComputeStructuredOrder(function_, &*function_->begin(), &order); for (BasicBlock* bb : order) { - BasicBlock* dominator = dom_tree->ImmediateDominator(bb); - if (dominator) { - AddNewPhiNodes(bb, new_merge_nodes_[bb], dominator->id()); - } + AddNewPhiNodes(bb); } } -void MergeReturnPass::AddNewPhiNodes(BasicBlock* bb, BasicBlock* pred, - uint32_t header_id) { - DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(function_); - // Insert as a stopping point. We do not have to add anything in the block - // or above because the header dominates |bb|. +void MergeReturnPass::AddNewPhiNodes(BasicBlock* bb) { + // New phi nodes are needed for any id whose definition used to dominate |bb|, + // but no longer dominates |bb|. These are found by walking the dominator + // tree starting at the original immediate dominator of |bb| and ending at its + // current dominator. - BasicBlock* current_bb = pred; - while (current_bb != nullptr && current_bb->id() != header_id) { + // Because we are walking the updated dominator tree it is important that the + // new phi nodes for the original dominators of |bb| have already been added. + // Otherwise some ids might be missed. Consider the case where bb1 dominates + // bb2, and bb2 dominates bb3. Suppose there are changes such that bb1 no + // longer dominates bb2 and the same for bb2 and bb3. This algorithm will not + // look at the ids defined in bb1. However, calling |AddNewPhiNodes(bb2)| + // first will add a phi node in bb2 for that value. Then a call to + // |AddNewPhiNodes(bb3)| will process that value by processing the phi in bb2. + DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(function_); + + BasicBlock* dominator = dom_tree->ImmediateDominator(bb); + if (dominator == nullptr) { + return; + } + + BasicBlock* current_bb = new_merge_nodes_[bb]; + while (current_bb != nullptr && current_bb != dominator) { for (Instruction& inst : *current_bb) { CreatePhiNodesForInst(bb, inst); } @@ -686,9 +692,11 @@ void MergeReturnPass::AddNewPhiNodes(BasicBlock* bb, BasicBlock* pred, } } -void MergeReturnPass::MarkForNewPhiNodes(BasicBlock* block, - BasicBlock* single_original_pred) { - new_merge_nodes_[block] = single_original_pred; +void MergeReturnPass::RecordImmediateDominator(BasicBlock* block) { + DominatorAnalysis* dom_tree = + context()->GetDominatorAnalysis(block->GetParent()); + auto idom = dom_tree->ImmediateDominator(block); + new_merge_nodes_[block] = idom; } void MergeReturnPass::InsertAfterElement(BasicBlock* element, diff --git a/3rdparty/spirv-tools/source/opt/merge_return_pass.h b/3rdparty/spirv-tools/source/opt/merge_return_pass.h index 63094b798..d9eae39fd 100644 --- a/3rdparty/spirv-tools/source/opt/merge_return_pass.h +++ b/3rdparty/spirv-tools/source/opt/merge_return_pass.h @@ -251,31 +251,19 @@ class MergeReturnPass : public MemPass { // there are no unreachable blocks in the control flow graph. void AddNewPhiNodes(); - // Creates any new phi nodes that are needed in |bb| now that |pred| is no - // longer the only block that preceedes |bb|. |header_id| is the id of the - // basic block for the loop or selection construct that merges at |bb|. - void AddNewPhiNodes(BasicBlock* bb, BasicBlock* pred, uint32_t header_id); + // Creates any new phi nodes that are needed in |bb|. |AddNewPhiNodes| must + // have already been called on the original dominators of |bb|. + void AddNewPhiNodes(BasicBlock* bb); // Saves |block| to a list of basic block that will require OpPhi nodes to be // added by calling |AddNewPhiNodes|. It is assumed that |block| used to have // a single predecessor, |single_original_pred|, but now has more. - void MarkForNewPhiNodes(BasicBlock* block, BasicBlock* single_original_pred); - - // Return the original single predcessor of |block| if it was flagged as - // having a single predecessor. |nullptr| is returned otherwise. - BasicBlock* MarkedSinglePred(BasicBlock* block) { - auto it = new_merge_nodes_.find(block); - if (it != new_merge_nodes_.end()) { - return it->second; - } else { - return nullptr; - } - } + void RecordImmediateDominator(BasicBlock* block); // Modifies existing OpPhi instruction in |target| block to account for the // new edge from |new_source|. The value for that edge will be an Undef. If // |target| only had a single predecessor, then it is marked as needing new - // phi nodes. See |MarkForNewPhiNodes|. + // phi nodes. See |RecordImmediateDominator|. // // The CFG must not include the edge from |new_source| to |target| yet. void UpdatePhiNodes(BasicBlock* new_source, BasicBlock* target); @@ -301,6 +289,11 @@ class MergeReturnPass : public MemPass { // |merge_target| as the merge node. void CreateDummyLoop(BasicBlock* merge_target); + // Returns true if |function| has an unreachable block that is not a continue + // target that simply branches back to the header, or a merge block containing + // 1 instruction which is OpUnreachable. + bool HasNontrivialUnreachableBlocks(Function* function); + // A stack used to keep track of the innermost contain loop and selection // constructs. std::vector state_; @@ -324,12 +317,13 @@ class MergeReturnPass : public MemPass { // after processing the current function. BasicBlock* final_return_block_; - // This map contains the set of nodes that use to have a single predcessor, - // but now have more. They will need new OpPhi nodes. For each of the nodes, - // it is mapped to it original single predcessor. It is assumed there are no - // values that will need a phi on the new edges. + // This is a map from a node to its original immediate dominator. This is + // used to determine which values will require a new phi node. std::unordered_map new_merge_nodes_; - bool HasNontrivialUnreachableBlocks(Function* function); + + // A map from a basic block, bb, to the set of basic blocks which represent + // the new edges that reach |bb|. + std::unordered_map> new_edges_; // Contains all return blocks that are merged. This is set is populated while // processing structured blocks and used to properly construct OpPhi diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index 6206f6468..5c1e6cabf 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -186,8 +186,6 @@ Optimizer& Optimizer::RegisterPerformancePasses() { .RegisterPass(CreateDeadBranchElimPass()) .RegisterPass(CreateBlockMergePass()) .RegisterPass(CreateSimplificationPass()); - // Currently exposing driver bugs resulting in crashes (#946) - // .RegisterPass(CreateCommonUniformElimPass()) } Optimizer& Optimizer::RegisterSizePasses() { @@ -215,8 +213,6 @@ Optimizer& Optimizer::RegisterSizePasses() { .RegisterPass(CreateDeadInsertElimPass()) .RegisterPass(CreateRedundancyEliminationPass()) .RegisterPass(CreateCFGCleanupPass()) - // Currently exposing driver bugs resulting in crashes (#946) - // .RegisterPass(CreateCommonUniformElimPass()) .RegisterPass(CreateAggressiveDCEPass()); } @@ -340,8 +336,6 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateEliminateDeadFunctionsPass()); } else if (pass_name == "eliminate-local-multi-store") { RegisterPass(CreateLocalMultiStoreElimPass()); - } else if (pass_name == "eliminate-common-uniform") { - RegisterPass(CreateCommonUniformElimPass()); } else if (pass_name == "eliminate-dead-const") { RegisterPass(CreateEliminateDeadConstantPass()); } else if (pass_name == "eliminate-dead-inserts") { @@ -713,11 +707,6 @@ Optimizer::PassToken CreateRedundantLineInfoElimPass() { MakeUnique(opt::kLinesEliminateDeadLines)); } -Optimizer::PassToken CreateCommonUniformElimPass() { - return MakeUnique( - MakeUnique()); -} - Optimizer::PassToken CreateCompactIdsPass() { return MakeUnique( MakeUnique()); diff --git a/3rdparty/spirv-tools/source/opt/passes.h b/3rdparty/spirv-tools/source/opt/passes.h index b7a9cb070..0a348e4f5 100644 --- a/3rdparty/spirv-tools/source/opt/passes.h +++ b/3rdparty/spirv-tools/source/opt/passes.h @@ -23,7 +23,6 @@ #include "source/opt/cfg_cleanup_pass.h" #include "source/opt/code_sink.h" #include "source/opt/combine_access_chains.h" -#include "source/opt/common_uniform_elim_pass.h" #include "source/opt/compact_ids_pass.h" #include "source/opt/copy_prop_arrays.h" #include "source/opt/dead_branch_elim_pass.h" diff --git a/3rdparty/spirv-tools/source/val/validate_type.cpp b/3rdparty/spirv-tools/source/val/validate_type.cpp index e3c766292..afc065676 100644 --- a/3rdparty/spirv-tools/source/val/validate_type.cpp +++ b/3rdparty/spirv-tools/source/val/validate_type.cpp @@ -190,6 +190,35 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _, return SPV_SUCCESS; } +bool ContainsOpaqueType(ValidationState_t& _, const Instruction* str) { + const size_t elem_type_index = 1; + uint32_t elem_type_id; + Instruction* elem_type; + + if (spvOpcodeIsBaseOpaqueType(str->opcode())) { + return true; + } + + switch (str->opcode()) { + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + elem_type_id = str->GetOperandAs(elem_type_index); + elem_type = _.FindDef(elem_type_id); + return ContainsOpaqueType(_, elem_type); + case SpvOpTypeStruct: + for (size_t member_type_index = 1; + member_type_index < str->operands().size(); ++member_type_index) { + auto member_type_id = str->GetOperandAs(member_type_index); + auto member_type = _.FindDef(member_type_id); + if (ContainsOpaqueType(_, member_type)) return true; + } + break; + default: + break; + } + return false; +} + spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { const uint32_t struct_id = inst->GetOperandAs(0); for (size_t member_type_index = 1; @@ -289,6 +318,14 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { if (num_builtin_members > 0) { _.RegisterStructTypeWithBuiltInMember(struct_id); } + + if (spvIsVulkanEnv(_.context()->target_env) && + !_.options()->before_hlsl_legalization && ContainsOpaqueType(_, inst)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "In " << spvLogStringForEnv(_.context()->target_env) + << ", OpTypeStruct must not contain an opaque type."; + } + return SPV_SUCCESS; } diff --git a/3rdparty/spirv-tools/test/opt/CMakeLists.txt b/3rdparty/spirv-tools/test/opt/CMakeLists.txt index ba29cf8b6..246c11690 100644 --- a/3rdparty/spirv-tools/test/opt/CMakeLists.txt +++ b/3rdparty/spirv-tools/test/opt/CMakeLists.txt @@ -24,7 +24,6 @@ add_spvtools_unittest(TARGET opt cfg_test.cpp code_sink_test.cpp combine_access_chains_test.cpp - common_uniform_elim_test.cpp compact_ids_test.cpp constant_manager_test.cpp copy_prop_array_test.cpp diff --git a/3rdparty/spirv-tools/test/opt/common_uniform_elim_test.cpp b/3rdparty/spirv-tools/test/opt/common_uniform_elim_test.cpp deleted file mode 100644 index 923f78678..000000000 --- a/3rdparty/spirv-tools/test/opt/common_uniform_elim_test.cpp +++ /dev/null @@ -1,1479 +0,0 @@ -// Copyright (c) 2017 Valve Corporation -// Copyright (c) 2017 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "test/opt/pass_fixture.h" - -namespace spvtools { -namespace opt { -namespace { - -using CommonUniformElimTest = PassTest<::testing::Test>; - -TEST_F(CommonUniformElimTest, Basic1) { - // Note: This test exemplifies the following: - // - Common uniform (%_) load floated to nearest non-controlled block - // - Common extract (g_F) floated to non-controlled block - // - Non-common extract (g_F2) not floated, but common uniform load shared - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // - // layout(std140) uniform U_t - // { - // float g_F; - // float g_F2; - // } ; - // - // void main() - // { - // vec4 v = BaseColor; - // if (fi > 0) { - // v = v * g_F; - // } - // else { - // float f2 = g_F2 - g_F; - // v = v * f2; - // } - // gl_FragColor = v; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %fi "fi" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %f2 "f2" -OpName %gl_FragColor "gl_FragColor" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%11 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%U_t = OpTypeStruct %float %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Function_float = OpTypePointer Function %float -%int_1 = OpConstant %int 1 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string before = - R"(%main = OpFunction %void None %11 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpLoad %float %fi -%29 = OpFOrdGreaterThan %bool %28 %float_0 -OpSelectionMerge %30 None -OpBranchConditional %29 %31 %32 -%31 = OpLabel -%33 = OpLoad %v4float %v -%34 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%35 = OpLoad %float %34 -%36 = OpVectorTimesScalar %v4float %33 %35 -OpStore %v %36 -OpBranch %30 -%32 = OpLabel -%37 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%38 = OpLoad %float %37 -%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%40 = OpLoad %float %39 -%41 = OpFSub %float %38 %40 -OpStore %f2 %41 -%42 = OpLoad %v4float %v -%43 = OpLoad %float %f2 -%44 = OpVectorTimesScalar %v4float %42 %43 -OpStore %v %44 -OpBranch %30 -%30 = OpLabel -%45 = OpLoad %v4float %v -OpStore %gl_FragColor %45 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %11 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%52 = OpLoad %U_t %_ -%53 = OpCompositeExtract %float %52 0 -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpLoad %float %fi -%29 = OpFOrdGreaterThan %bool %28 %float_0 -OpSelectionMerge %30 None -OpBranchConditional %29 %31 %32 -%31 = OpLabel -%33 = OpLoad %v4float %v -%36 = OpVectorTimesScalar %v4float %33 %53 -OpStore %v %36 -OpBranch %30 -%32 = OpLabel -%49 = OpCompositeExtract %float %52 1 -%41 = OpFSub %float %49 %53 -OpStore %f2 %41 -%42 = OpLoad %v4float %v -%43 = OpLoad %float %f2 -%44 = OpVectorTimesScalar %v4float %42 %43 -OpStore %v %44 -OpBranch %30 -%30 = OpLabel -%45 = OpLoad %v4float %v -OpStore %gl_FragColor %45 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Basic2) { - // Note: This test exemplifies the following: - // - Common uniform (%_) load floated to nearest non-controlled block - // - Common extract (g_F) floated to non-controlled block - // - Non-common extract (g_F2) not floated, but common uniform load shared - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // in float fi2; - // - // layout(std140) uniform U_t - // { - // float g_F; - // float g_F2; - // } ; - // - // void main() - // { - // float f = fi; - // if (f < 0) - // f = -f; - // if (fi2 > 0) { - // f = f * g_F; - // } - // else { - // f = g_F2 - g_F; - // } - // gl_FragColor = f * BaseColor; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %fi %fi2 %gl_FragColor %BaseColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %f "f" -OpName %fi "fi" -OpName %fi2 "fi2" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %gl_FragColor "gl_FragColor" -OpName %BaseColor "BaseColor" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%11 = OpTypeFunction %void -%float = OpTypeFloat 32 -%_ptr_Function_float = OpTypePointer Function %float -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%fi2 = OpVariable %_ptr_Input_float Input -%U_t = OpTypeStruct %float %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%int_1 = OpConstant %int 1 -%v4float = OpTypeVector %float 4 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -)"; - - const std::string before = - R"(%main = OpFunction %void None %11 -%25 = OpLabel -%f = OpVariable %_ptr_Function_float Function -%26 = OpLoad %float %fi -OpStore %f %26 -%27 = OpLoad %float %f -%28 = OpFOrdLessThan %bool %27 %float_0 -OpSelectionMerge %29 None -OpBranchConditional %28 %30 %29 -%30 = OpLabel -%31 = OpLoad %float %f -%32 = OpFNegate %float %31 -OpStore %f %32 -OpBranch %29 -%29 = OpLabel -%33 = OpLoad %float %fi2 -%34 = OpFOrdGreaterThan %bool %33 %float_0 -OpSelectionMerge %35 None -OpBranchConditional %34 %36 %37 -%36 = OpLabel -%38 = OpLoad %float %f -%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%40 = OpLoad %float %39 -%41 = OpFMul %float %38 %40 -OpStore %f %41 -OpBranch %35 -%37 = OpLabel -%42 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%43 = OpLoad %float %42 -%44 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%45 = OpLoad %float %44 -%46 = OpFSub %float %43 %45 -OpStore %f %46 -OpBranch %35 -%35 = OpLabel -%47 = OpLoad %v4float %BaseColor -%48 = OpLoad %float %f -%49 = OpVectorTimesScalar %v4float %47 %48 -OpStore %gl_FragColor %49 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %11 -%25 = OpLabel -%f = OpVariable %_ptr_Function_float Function -%26 = OpLoad %float %fi -OpStore %f %26 -%27 = OpLoad %float %f -%28 = OpFOrdLessThan %bool %27 %float_0 -OpSelectionMerge %29 None -OpBranchConditional %28 %30 %29 -%30 = OpLabel -%31 = OpLoad %float %f -%32 = OpFNegate %float %31 -OpStore %f %32 -OpBranch %29 -%29 = OpLabel -%56 = OpLoad %U_t %_ -%57 = OpCompositeExtract %float %56 0 -%33 = OpLoad %float %fi2 -%34 = OpFOrdGreaterThan %bool %33 %float_0 -OpSelectionMerge %35 None -OpBranchConditional %34 %36 %37 -%36 = OpLabel -%38 = OpLoad %float %f -%41 = OpFMul %float %38 %57 -OpStore %f %41 -OpBranch %35 -%37 = OpLabel -%53 = OpCompositeExtract %float %56 1 -%46 = OpFSub %float %53 %57 -OpStore %f %46 -OpBranch %35 -%35 = OpLabel -%47 = OpLoad %v4float %BaseColor -%48 = OpLoad %float %f -%49 = OpVectorTimesScalar %v4float %47 %48 -OpStore %gl_FragColor %49 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Basic3) { - // Note: This test exemplifies the following: - // - Existing common uniform (%_) load kept in place and shared - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // - // layout(std140) uniform U_t - // { - // bool g_B; - // float g_F; - // } ; - // - // void main() - // { - // vec4 v = BaseColor; - // if (g_B) - // v = v * g_F; - // gl_FragColor = v; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor %fi -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_B" -OpMemberName %U_t 1 "g_F" -OpName %_ "" -OpName %gl_FragColor "gl_FragColor" -OpName %fi "fi" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%10 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%uint = OpTypeInt 32 0 -%U_t = OpTypeStruct %uint %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%bool = OpTypeBool -%uint_0 = OpConstant %uint 0 -%int_1 = OpConstant %int 1 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -)"; - - const std::string before = - R"(%main = OpFunction %void None %10 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 -%29 = OpLoad %uint %28 -%30 = OpINotEqual %bool %29 %uint_0 -OpSelectionMerge %31 None -OpBranchConditional %30 %32 %31 -%32 = OpLabel -%33 = OpLoad %v4float %v -%34 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%35 = OpLoad %float %34 -%36 = OpVectorTimesScalar %v4float %33 %35 -OpStore %v %36 -OpBranch %31 -%31 = OpLabel -%37 = OpLoad %v4float %v -OpStore %gl_FragColor %37 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %10 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%38 = OpLoad %U_t %_ -%39 = OpCompositeExtract %uint %38 0 -%30 = OpINotEqual %bool %39 %uint_0 -OpSelectionMerge %31 None -OpBranchConditional %30 %32 %31 -%32 = OpLabel -%33 = OpLoad %v4float %v -%41 = OpCompositeExtract %float %38 1 -%36 = OpVectorTimesScalar %v4float %33 %41 -OpStore %v %36 -OpBranch %31 -%31 = OpLabel -%37 = OpLoad %v4float %v -OpStore %gl_FragColor %37 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Loop) { - // Note: This test exemplifies the following: - // - Common extract (g_F) shared between two loops - // #version 140 - // in vec4 BC; - // in vec4 BC2; - // - // layout(std140) uniform U_t - // { - // float g_F; - // } ; - // - // void main() - // { - // vec4 v = BC; - // for (int i = 0; i < 4; i++) - // v[i] = v[i] / g_F; - // vec4 v2 = BC2; - // for (int i = 0; i < 4; i++) - // v2[i] = v2[i] * g_F; - // gl_FragColor = v + v2; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BC %BC2 %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BC "BC" -OpName %i "i" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpName %_ "" -OpName %v2 "v2" -OpName %BC2 "BC2" -OpName %i_0 "i" -OpName %gl_FragColor "gl_FragColor" -OpMemberDecorate %U_t 0 Offset 0 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%13 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BC = OpVariable %_ptr_Input_v4float Input -%int = OpTypeInt 32 1 -%_ptr_Function_int = OpTypePointer Function %int -%int_0 = OpConstant %int 0 -%int_4 = OpConstant %int 4 -%bool = OpTypeBool -%_ptr_Function_float = OpTypePointer Function %float -%U_t = OpTypeStruct %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%_ptr_Uniform_float = OpTypePointer Uniform %float -%int_1 = OpConstant %int 1 -%BC2 = OpVariable %_ptr_Input_v4float Input -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string before = - R"(%main = OpFunction %void None %13 -%28 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%i = OpVariable %_ptr_Function_int Function -%v2 = OpVariable %_ptr_Function_v4float Function -%i_0 = OpVariable %_ptr_Function_int Function -%29 = OpLoad %v4float %BC -OpStore %v %29 -OpStore %i %int_0 -OpBranch %30 -%30 = OpLabel -OpLoopMerge %31 %32 None -OpBranch %33 -%33 = OpLabel -%34 = OpLoad %int %i -%35 = OpSLessThan %bool %34 %int_4 -OpBranchConditional %35 %36 %31 -%36 = OpLabel -%37 = OpLoad %int %i -%38 = OpLoad %int %i -%39 = OpAccessChain %_ptr_Function_float %v %38 -%40 = OpLoad %float %39 -%41 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%42 = OpLoad %float %41 -%43 = OpFDiv %float %40 %42 -%44 = OpAccessChain %_ptr_Function_float %v %37 -OpStore %44 %43 -OpBranch %32 -%32 = OpLabel -%45 = OpLoad %int %i -%46 = OpIAdd %int %45 %int_1 -OpStore %i %46 -OpBranch %30 -%31 = OpLabel -%47 = OpLoad %v4float %BC2 -OpStore %v2 %47 -OpStore %i_0 %int_0 -OpBranch %48 -%48 = OpLabel -OpLoopMerge %49 %50 None -OpBranch %51 -%51 = OpLabel -%52 = OpLoad %int %i_0 -%53 = OpSLessThan %bool %52 %int_4 -OpBranchConditional %53 %54 %49 -%54 = OpLabel -%55 = OpLoad %int %i_0 -%56 = OpLoad %int %i_0 -%57 = OpAccessChain %_ptr_Function_float %v2 %56 -%58 = OpLoad %float %57 -%59 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%60 = OpLoad %float %59 -%61 = OpFMul %float %58 %60 -%62 = OpAccessChain %_ptr_Function_float %v2 %55 -OpStore %62 %61 -OpBranch %50 -%50 = OpLabel -%63 = OpLoad %int %i_0 -%64 = OpIAdd %int %63 %int_1 -OpStore %i_0 %64 -OpBranch %48 -%49 = OpLabel -%65 = OpLoad %v4float %v -%66 = OpLoad %v4float %v2 -%67 = OpFAdd %v4float %65 %66 -OpStore %gl_FragColor %67 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %13 -%28 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%i = OpVariable %_ptr_Function_int Function -%v2 = OpVariable %_ptr_Function_v4float Function -%i_0 = OpVariable %_ptr_Function_int Function -%72 = OpLoad %U_t %_ -%73 = OpCompositeExtract %float %72 0 -%29 = OpLoad %v4float %BC -OpStore %v %29 -OpStore %i %int_0 -OpBranch %30 -%30 = OpLabel -OpLoopMerge %31 %32 None -OpBranch %33 -%33 = OpLabel -%34 = OpLoad %int %i -%35 = OpSLessThan %bool %34 %int_4 -OpBranchConditional %35 %36 %31 -%36 = OpLabel -%37 = OpLoad %int %i -%38 = OpLoad %int %i -%39 = OpAccessChain %_ptr_Function_float %v %38 -%40 = OpLoad %float %39 -%43 = OpFDiv %float %40 %73 -%44 = OpAccessChain %_ptr_Function_float %v %37 -OpStore %44 %43 -OpBranch %32 -%32 = OpLabel -%45 = OpLoad %int %i -%46 = OpIAdd %int %45 %int_1 -OpStore %i %46 -OpBranch %30 -%31 = OpLabel -%47 = OpLoad %v4float %BC2 -OpStore %v2 %47 -OpStore %i_0 %int_0 -OpBranch %48 -%48 = OpLabel -OpLoopMerge %49 %50 None -OpBranch %51 -%51 = OpLabel -%52 = OpLoad %int %i_0 -%53 = OpSLessThan %bool %52 %int_4 -OpBranchConditional %53 %54 %49 -%54 = OpLabel -%55 = OpLoad %int %i_0 -%56 = OpLoad %int %i_0 -%57 = OpAccessChain %_ptr_Function_float %v2 %56 -%58 = OpLoad %float %57 -%61 = OpFMul %float %58 %73 -%62 = OpAccessChain %_ptr_Function_float %v2 %55 -OpStore %62 %61 -OpBranch %50 -%50 = OpLabel -%63 = OpLoad %int %i_0 -%64 = OpIAdd %int %63 %int_1 -OpStore %i_0 %64 -OpBranch %48 -%49 = OpLabel -%65 = OpLoad %v4float %v -%66 = OpLoad %v4float %v2 -%67 = OpFAdd %v4float %65 %66 -OpStore %gl_FragColor %67 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Volatile1) { - // Note: This test exemplifies the following: - // - Same test as Basic1 with the exception that - // the Load of g_F in else-branch is volatile - // - Common uniform (%_) load floated to nearest non-controlled block - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // - // layout(std140) uniform U_t - // { - // float g_F; - // float g_F2; - // } ; - // - // void main() - // { - // vec4 v = BaseColor; - // if (fi > 0) { - // v = v * g_F; - // } - // else { - // float f2 = g_F2 - g_F; - // v = v * f2; - // } - // gl_FragColor = v; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %fi "fi" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %f2 "f2" -OpName %gl_FragColor "gl_FragColor" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%11 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%U_t = OpTypeStruct %float %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Function_float = OpTypePointer Function %float -%int_1 = OpConstant %int 1 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string before = - R"(%main = OpFunction %void None %11 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpLoad %float %fi -%29 = OpFOrdGreaterThan %bool %28 %float_0 -OpSelectionMerge %30 None -OpBranchConditional %29 %31 %32 -%31 = OpLabel -%33 = OpLoad %v4float %v -%34 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%35 = OpLoad %float %34 -%36 = OpVectorTimesScalar %v4float %33 %35 -OpStore %v %36 -OpBranch %30 -%32 = OpLabel -%37 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%38 = OpLoad %float %37 -%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%40 = OpLoad %float %39 Volatile -%41 = OpFSub %float %38 %40 -OpStore %f2 %41 -%42 = OpLoad %v4float %v -%43 = OpLoad %float %f2 -%44 = OpVectorTimesScalar %v4float %42 %43 -OpStore %v %44 -OpBranch %30 -%30 = OpLabel -%45 = OpLoad %v4float %v -OpStore %gl_FragColor %45 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %11 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%50 = OpLoad %U_t %_ -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpLoad %float %fi -%29 = OpFOrdGreaterThan %bool %28 %float_0 -OpSelectionMerge %30 None -OpBranchConditional %29 %31 %32 -%31 = OpLabel -%33 = OpLoad %v4float %v -%47 = OpCompositeExtract %float %50 0 -%36 = OpVectorTimesScalar %v4float %33 %47 -OpStore %v %36 -OpBranch %30 -%32 = OpLabel -%49 = OpCompositeExtract %float %50 1 -%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%40 = OpLoad %float %39 Volatile -%41 = OpFSub %float %49 %40 -OpStore %f2 %41 -%42 = OpLoad %v4float %v -%43 = OpLoad %float %f2 -%44 = OpVectorTimesScalar %v4float %42 %43 -OpStore %v %44 -OpBranch %30 -%30 = OpLabel -%45 = OpLoad %v4float %v -OpStore %gl_FragColor %45 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Volatile2) { - // Note: This test exemplifies the following: - // - Same test as Basic1 with the exception that - // U_t is Volatile. - // - No optimizations are applied - // - // #version 430 - // in vec4 BaseColor; - // in float fi; - // - // layout(std430) volatile buffer U_t - // { - // float g_F; - // float g_F2; - // }; - // - // - // void main(void) - // { - // vec4 v = BaseColor; - // if (fi > 0) { - // v = v * g_F; - // } else { - // float f2 = g_F2 - g_F; - // v = v * f2; - // } - // } - - const std::string text = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %fi -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 430 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %fi "fi" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %f2 "f2" -OpDecorate %BaseColor Location 0 -OpDecorate %fi Location 0 -OpMemberDecorate %U_t 0 Volatile -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Volatile -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t BufferBlock -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%U_t = OpTypeStruct %float %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Function_float = OpTypePointer Function %float -%int_1 = OpConstant %int 1 -%main = OpFunction %void None %3 -%5 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%12 = OpLoad %v4float %BaseColor -OpStore %v %12 -%15 = OpLoad %float %fi -%18 = OpFOrdGreaterThan %bool %15 %float_0 -OpSelectionMerge %20 None -OpBranchConditional %18 %19 %31 -%19 = OpLabel -%21 = OpLoad %v4float %v -%28 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%29 = OpLoad %float %28 -%30 = OpVectorTimesScalar %v4float %21 %29 -OpStore %v %30 -OpBranch %20 -%31 = OpLabel -%35 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%36 = OpLoad %float %35 -%37 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%38 = OpLoad %float %37 -%39 = OpFSub %float %36 %38 -OpStore %f2 %39 -%40 = OpLoad %v4float %v -%41 = OpLoad %float %f2 -%42 = OpVectorTimesScalar %v4float %40 %41 -OpStore %v %42 -OpBranch %20 -%20 = OpLabel -OpReturn -OpFunctionEnd -)"; - - Pass::Status res = std::get<1>( - SinglePassRunAndDisassemble(text, true, false)); - EXPECT_EQ(res, Pass::Status::SuccessWithoutChange); -} - -TEST_F(CommonUniformElimTest, Volatile3) { - // Note: This test exemplifies the following: - // - Same test as Volatile2 with the exception that - // the nested struct S is volatile - // - No optimizations are applied - // - // #version 430 - // in vec4 BaseColor; - // in float fi; - // - // struct S { - // volatile float a; - // }; - // - // layout(std430) buffer U_t - // { - // S g_F; - // S g_F2; - // }; - // - // - // void main(void) - // { - // vec4 v = BaseColor; - // if (fi > 0) { - // v = v * g_F.a; - // } else { - // float f2 = g_F2.a - g_F.a; - // v = v * f2; - // } - // } - - const std::string text = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %fi -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 430 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %fi "fi" -OpName %S "S" -OpMemberName %S 0 "a" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %f2 "f2" -OpDecorate %BaseColor Location 0 -OpDecorate %fi Location 0 -OpMemberDecorate %S 0 Offset 0 -OpMemberDecorate %S 0 Volatile -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t BufferBlock -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%S = OpTypeStruct %float -%U_t = OpTypeStruct %S %S -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Function_float = OpTypePointer Function %float -%int_1 = OpConstant %int 1 -%main = OpFunction %void None %3 -%5 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%12 = OpLoad %v4float %BaseColor -OpStore %v %12 -%15 = OpLoad %float %fi -%18 = OpFOrdGreaterThan %bool %15 %float_0 -OpSelectionMerge %20 None -OpBranchConditional %18 %19 %32 -%19 = OpLabel -%21 = OpLoad %v4float %v -%29 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_0 -%30 = OpLoad %float %29 -%31 = OpVectorTimesScalar %v4float %21 %30 -OpStore %v %31 -OpBranch %20 -%32 = OpLabel -%36 = OpAccessChain %_ptr_Uniform_float %_ %int_1 %int_0 -%37 = OpLoad %float %36 -%38 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_0 -%39 = OpLoad %float %38 -%40 = OpFSub %float %37 %39 -OpStore %f2 %40 -%41 = OpLoad %v4float %v -%42 = OpLoad %float %f2 -%43 = OpVectorTimesScalar %v4float %41 %42 -OpStore %v %43 -OpBranch %20 -%20 = OpLabel -OpReturn -OpFunctionEnd -)"; - - Pass::Status res = std::get<1>( - SinglePassRunAndDisassemble(text, true, false)); - EXPECT_EQ(res, Pass::Status::SuccessWithoutChange); -} - -TEST_F(CommonUniformElimTest, IteratorDanglingPointer) { - // Note: This test exemplifies the following: - // - Existing common uniform (%_) load kept in place and shared - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // - // layout(std140) uniform U_t - // { - // bool g_B; - // float g_F; - // } ; - // - // uniform float alpha; - // uniform bool alpha_B; - // - // void main() - // { - // vec4 v = BaseColor; - // if (g_B) { - // v = v * g_F; - // if (alpha_B) - // v = v * alpha; - // else - // v = v * fi; - // } - // gl_FragColor = v; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor %fi -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_B" -OpMemberName %U_t 1 "g_F" -OpName %alpha "alpha" -OpName %alpha_B "alpha_B" -OpName %_ "" -OpName %gl_FragColor "gl_FragColor" -OpName %fi "fi" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%12 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%uint = OpTypeInt 32 0 -%U_t = OpTypeStruct %uint %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%bool = OpTypeBool -%uint_0 = OpConstant %uint 0 -%int_1 = OpConstant %int 1 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%alpha = OpVariable %_ptr_Uniform_float Uniform -%alpha_B = OpVariable %_ptr_Uniform_uint Uniform -)"; - - const std::string before = - R"(%main = OpFunction %void None %12 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 -%29 = OpLoad %uint %28 -%30 = OpINotEqual %bool %29 %uint_0 -OpSelectionMerge %31 None -OpBranchConditional %30 %31 %32 -%32 = OpLabel -%47 = OpLoad %v4float %v -OpStore %gl_FragColor %47 -OpReturn -%31 = OpLabel -%33 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%34 = OpLoad %float %33 -%35 = OpLoad %v4float %v -%36 = OpVectorTimesScalar %v4float %35 %34 -OpStore %v %36 -%37 = OpLoad %uint %alpha_B -%38 = OpIEqual %bool %37 %uint_0 -OpSelectionMerge %43 None -OpBranchConditional %38 %43 %39 -%39 = OpLabel -%40 = OpLoad %float %alpha -%41 = OpLoad %v4float %v -%42 = OpVectorTimesScalar %v4float %41 %40 -OpStore %v %42 -OpBranch %50 -%50 = OpLabel -%51 = OpLoad %v4float %v -OpStore %gl_FragColor %51 -OpReturn -%43 = OpLabel -%44 = OpLoad %float %fi -%45 = OpLoad %v4float %v -%46 = OpVectorTimesScalar %v4float %45 %44 -OpStore %v %46 -OpBranch %60 -%60 = OpLabel -%61 = OpLoad %v4float %v -OpStore %gl_FragColor %61 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %12 -%28 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%29 = OpLoad %v4float %BaseColor -OpStore %v %29 -%54 = OpLoad %U_t %_ -%55 = OpCompositeExtract %uint %54 0 -%32 = OpINotEqual %bool %55 %uint_0 -OpSelectionMerge %33 None -OpBranchConditional %32 %33 %34 -%34 = OpLabel -%35 = OpLoad %v4float %v -OpStore %gl_FragColor %35 -OpReturn -%33 = OpLabel -%58 = OpLoad %float %alpha -%57 = OpCompositeExtract %float %54 1 -%38 = OpLoad %v4float %v -%39 = OpVectorTimesScalar %v4float %38 %57 -OpStore %v %39 -%40 = OpLoad %uint %alpha_B -%41 = OpIEqual %bool %40 %uint_0 -OpSelectionMerge %42 None -OpBranchConditional %41 %42 %43 -%43 = OpLabel -%45 = OpLoad %v4float %v -%46 = OpVectorTimesScalar %v4float %45 %58 -OpStore %v %46 -OpBranch %47 -%47 = OpLabel -%48 = OpLoad %v4float %v -OpStore %gl_FragColor %48 -OpReturn -%42 = OpLabel -%49 = OpLoad %float %fi -%50 = OpLoad %v4float %v -%51 = OpVectorTimesScalar %v4float %50 %49 -OpStore %v %51 -OpBranch %52 -%52 = OpLabel -%53 = OpLoad %v4float %v -OpStore %gl_FragColor %53 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, MixedConstantAndNonConstantIndexes) { - const std::string text = R"( -; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform -; CHECK: %501 = OpLabel -; CHECK: [[ld:%\w+]] = OpLoad -; CHECK-NOT: OpCompositeExtract {{%\w+}} {{%\w+}} 0 2 484 -; CHECK: OpAccessChain {{%\w+}} [[var]] %int_0 %int_2 [[ld]] - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "ringeffectLayer_px" %gl_FragCoord %178 %182 - OpExecutionMode %4 OriginUpperLeft - OpSource HLSL 500 - OpDecorate %_arr_v4float_uint_10 ArrayStride 16 - OpMemberDecorate %_struct_20 0 Offset 0 - OpMemberDecorate %_struct_20 1 Offset 16 - OpMemberDecorate %_struct_20 2 Offset 32 - OpMemberDecorate %_struct_21 0 Offset 0 - OpDecorate %_struct_21 Block - OpDecorate %23 DescriptorSet 0 - OpDecorate %gl_FragCoord BuiltIn FragCoord - OpDecorate %178 Location 0 - OpDecorate %182 Location 0 - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 - %v2float = OpTypeVector %float 2 -%_ptr_Function_v2float = OpTypePointer Function %v2float - %uint = OpTypeInt 32 0 - %uint_10 = OpConstant %uint 10 -%_arr_v4float_uint_10 = OpTypeArray %v4float %uint_10 - %_struct_20 = OpTypeStruct %v4float %v4float %_arr_v4float_uint_10 - %_struct_21 = OpTypeStruct %_struct_20 -%_ptr_Uniform__struct_21 = OpTypePointer Uniform %_struct_21 - %23 = OpVariable %_ptr_Uniform__struct_21 Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 -%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float -%_ptr_Uniform_float = OpTypePointer Uniform %float - %uint_3 = OpConstant %uint 3 -%_ptr_Function_v4float = OpTypePointer Function %v4float - %float_0 = OpConstant %float 0 - %43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 -%_ptr_Function_int = OpTypePointer Function %int - %int_5 = OpConstant %int 5 - %bool = OpTypeBool - %int_1 = OpConstant %int 1 - %int_2 = OpConstant %int 2 - %uint_5 = OpConstant %uint 5 -%_arr_v2float_uint_5 = OpTypeArray %v2float %uint_5 -%_ptr_Function__arr_v2float_uint_5 = OpTypePointer Function %_arr_v2float_uint_5 - %82 = OpTypeImage %float 2D 0 0 0 1 Unknown -%_ptr_UniformConstant_82 = OpTypePointer UniformConstant %82 - %86 = OpTypeSampler -%_ptr_UniformConstant_86 = OpTypePointer UniformConstant %86 - %90 = OpTypeSampledImage %82 - %v3float = OpTypeVector %float 3 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%gl_FragCoord = OpVariable %_ptr_Input_v4float Input - %178 = OpVariable %_ptr_Input_v4float Input -%_ptr_Output_v4float = OpTypePointer Output %v4float - %182 = OpVariable %_ptr_Output_v4float Output - %4 = OpFunction %void None %3 - %5 = OpLabel - %483 = OpVariable %_ptr_Function_v4float Function - %484 = OpVariable %_ptr_Function_int Function - %486 = OpVariable %_ptr_Function__arr_v2float_uint_5 Function - %179 = OpLoad %v4float %178 - %493 = OpAccessChain %_ptr_Uniform_float %23 %int_0 %int_0 %uint_3 - %494 = OpLoad %float %493 - OpStore %483 %43 - OpStore %484 %int_0 - OpBranch %495 - %495 = OpLabel - OpLoopMerge %496 %497 None - OpBranch %498 - %498 = OpLabel - %499 = OpLoad %int %484 - %500 = OpSLessThan %bool %499 %int_5 - OpBranchConditional %500 %501 %496 - %501 = OpLabel - %504 = OpVectorShuffle %v2float %179 %179 0 1 - %505 = OpLoad %int %484 - %506 = OpAccessChain %_ptr_Uniform_v4float %23 %int_0 %int_2 %505 - %507 = OpLoad %v4float %506 - %508 = OpVectorShuffle %v2float %507 %507 0 1 - %509 = OpFAdd %v2float %504 %508 - %512 = OpAccessChain %_ptr_Uniform_v4float %23 %int_0 %int_1 - %513 = OpLoad %v4float %512 - %514 = OpVectorShuffle %v2float %513 %513 0 1 - %517 = OpVectorShuffle %v2float %513 %513 2 3 - %518 = OpExtInst %v2float %1 FClamp %509 %514 %517 - %519 = OpAccessChain %_ptr_Function_v2float %486 %505 - OpStore %519 %518 - OpBranch %497 - %497 = OpLabel - %520 = OpLoad %int %484 - %521 = OpIAdd %int %520 %int_1 - OpStore %484 %521 - OpBranch %495 - %496 = OpLabel - OpReturn - OpFunctionEnd -)"; - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true); -} - -TEST_F(CommonUniformElimTest, LoadPlacedAfterPhi) { - const std::string text = R"( -; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform -; CHECK: OpSelectionMerge [[merge:%\w+]] -; CHECK: [[merge]] = OpLabel -; CHECK-NEXT: OpPhi -; CHECK-NEXT: OpLoad {{%\w+}} [[var]] - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %2 "main" - OpExecutionMode %2 OriginUpperLeft - OpSource ESSL 310 - OpMemberDecorate %_struct_3 0 Offset 0 - OpDecorate %_struct_3 Block - OpDecorate %4 DescriptorSet 0 - OpDecorate %4 Binding 0 - %void = OpTypeVoid - %6 = OpTypeFunction %void - %bool = OpTypeBool - %false = OpConstantFalse %bool - %uint = OpTypeInt 32 0 - %v2uint = OpTypeVector %uint 2 - %_struct_3 = OpTypeStruct %v2uint -%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3 - %4 = OpVariable %_ptr_Uniform__struct_3 Uniform - %uint_0 = OpConstant %uint 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint - %uint_2 = OpConstant %uint 2 - %2 = OpFunction %void None %6 - %15 = OpLabel - OpSelectionMerge %16 None - OpBranchConditional %false %17 %16 - %17 = OpLabel - OpBranch %16 - %16 = OpLabel - %18 = OpPhi %bool %false %15 %false %17 - OpSelectionMerge %19 None - OpBranchConditional %false %20 %21 - %20 = OpLabel - %22 = OpAccessChain %_ptr_Uniform_uint %4 %uint_0 %uint_0 - %23 = OpLoad %uint %22 - OpBranch %19 - %21 = OpLabel - OpBranch %19 - %19 = OpLabel - OpReturn - OpFunctionEnd -)"; - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true); -} - -TEST_F(CommonUniformElimTest, TestVariablePointer) { - // Same test a basic1 except the variable pointers capability has been added. - // This should stop the transformation from running. - const std::string test = - R"(OpCapability Shader -OpCapability VariablePointers -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %fi "fi" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %f2 "f2" -OpName %gl_FragColor "gl_FragColor" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%11 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%U_t = OpTypeStruct %float %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Function_float = OpTypePointer Function %float -%int_1 = OpConstant %int 1 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -%main = OpFunction %void None %11 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpLoad %float %fi -%29 = OpFOrdGreaterThan %bool %28 %float_0 -OpSelectionMerge %30 None -OpBranchConditional %29 %31 %32 -%31 = OpLabel -%33 = OpLoad %v4float %v -%34 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%35 = OpLoad %float %34 -%36 = OpVectorTimesScalar %v4float %33 %35 -OpStore %v %36 -OpBranch %30 -%32 = OpLabel -%37 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%38 = OpLoad %float %37 -%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%40 = OpLoad %float %39 -%41 = OpFSub %float %38 %40 -OpStore %f2 %41 -%42 = OpLoad %v4float %v -%43 = OpLoad %float %f2 -%44 = OpVectorTimesScalar %v4float %42 %43 -OpStore %v %44 -OpBranch %30 -%30 = OpLabel -%45 = OpLoad %v4float %v -OpStore %gl_FragColor %45 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(test, test, true, true); -} - -// TODO(greg-lunarg): Add tests to verify handling of these cases: -// -// Disqualifying cases: extensions, decorations, non-logical addressing, -// non-structured control flow -// Others? - -} // namespace -} // namespace opt -} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/opt/inline_test.cpp b/3rdparty/spirv-tools/test/opt/inline_test.cpp index fd38e4776..717081210 100644 --- a/3rdparty/spirv-tools/test/opt/inline_test.cpp +++ b/3rdparty/spirv-tools/test/opt/inline_test.cpp @@ -3112,121 +3112,6 @@ OpFunctionEnd SinglePassRunAndCheck(test, test, false, true); } -TEST_F(InlineTest, DontInlineFuncWithOpKill) { - const std::string test = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 330 -OpName %main "main" -OpName %kill_ "kill(" -%void = OpTypeVoid -%3 = OpTypeFunction %void -%bool = OpTypeBool -%true = OpConstantTrue %bool -%main = OpFunction %void None %3 -%5 = OpLabel -OpBranch %9 -%9 = OpLabel -OpLoopMerge %11 %12 None -OpBranch %13 -%13 = OpLabel -OpBranchConditional %true %10 %11 -%10 = OpLabel -OpBranch %12 -%12 = OpLabel -%16 = OpFunctionCall %void %kill_ -OpBranch %9 -%11 = OpLabel -OpReturn -OpFunctionEnd -%kill_ = OpFunction %void None %3 -%7 = OpLabel -OpKill -OpFunctionEnd -)"; - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndCheck(test, test, false, true); -} - -TEST_F(InlineTest, InlineFuncWithOpKill) { - const std::string before = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 330 -OpName %main "main" -OpName %kill_ "kill(" -%void = OpTypeVoid -%3 = OpTypeFunction %void -%bool = OpTypeBool -%true = OpConstantTrue %bool -%main = OpFunction %void None %3 -%5 = OpLabel -OpBranch %9 -%9 = OpLabel -OpLoopMerge %11 %12 None -OpBranch %13 -%13 = OpLabel -OpBranchConditional %true %10 %11 -%10 = OpLabel -%16 = OpFunctionCall %void %kill_ -OpBranch %12 -%12 = OpLabel -OpBranch %9 -%11 = OpLabel -OpReturn -OpFunctionEnd -%kill_ = OpFunction %void None %3 -%7 = OpLabel -OpKill -OpFunctionEnd -)"; - const std::string after = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 330 -OpName %main "main" -OpName %kill_ "kill(" -%void = OpTypeVoid -%3 = OpTypeFunction %void -%bool = OpTypeBool -%true = OpConstantTrue %bool -%main = OpFunction %void None %3 -%5 = OpLabel -OpBranch %9 -%9 = OpLabel -OpLoopMerge %11 %12 None -OpBranch %13 -%13 = OpLabel -OpBranchConditional %true %10 %11 -%10 = OpLabel -OpKill -%17 = OpLabel -OpBranch %12 -%12 = OpLabel -OpBranch %9 -%11 = OpLabel -OpReturn -OpFunctionEnd -%kill_ = OpFunction %void None %3 -%7 = OpLabel -OpKill -OpFunctionEnd -)"; - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndCheck(before, after, false, true); -} - // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Empty modules diff --git a/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp b/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp index 0848deb3c..25f0baa15 100644 --- a/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp +++ b/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp @@ -8598,6 +8598,1950 @@ OpFunctionEnd true, 7u, 23u, true, true, 2u); } +TEST_F(InstBindlessTest, + InstBoundsRayGenerationInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint RayGenerationNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint RayGenerationNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5313 = OpConstant %uint 5313 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5313 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, + InstBoundsIntersectionInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint IntersectionNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint IntersectionNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5314 = OpConstant %uint 5314 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5314 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, + InstBoundsAnyHitInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint AnyHitNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint AnyHitNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5315 = OpConstant %uint 5315 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5315 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, + InstBoundsClosestHitInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint ClosestHitNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint ClosestHitNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5316 = OpConstant %uint 5316 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5316 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, + InstBoundsMissInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint MissNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint MissNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5317 = OpConstant %uint 5317 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5317 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + +TEST_F(InstBindlessTest, + InstBoundsCallableInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint CallableNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArrayEXT +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint CallableNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5318 = OpConstant %uint 5318 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5318 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true, 2u); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Compute shader diff --git a/3rdparty/spirv-tools/test/opt/optimizer_test.cpp b/3rdparty/spirv-tools/test/opt/optimizer_test.cpp index b4278046b..ee6e949b4 100644 --- a/3rdparty/spirv-tools/test/opt/optimizer_test.cpp +++ b/3rdparty/spirv-tools/test/opt/optimizer_test.cpp @@ -163,7 +163,6 @@ TEST(Optimizer, CanRegisterPassesFromFlags) { "--eliminate-dead-branches", "--eliminate-dead-functions", "--eliminate-local-multi-store", - "--eliminate-common-uniform", "--eliminate-dead-const", "--eliminate-dead-inserts", "--eliminate-dead-variables", diff --git a/3rdparty/spirv-tools/test/opt/pass_merge_return_test.cpp b/3rdparty/spirv-tools/test/opt/pass_merge_return_test.cpp index 423e81d94..f6b30de7c 100644 --- a/3rdparty/spirv-tools/test/opt/pass_merge_return_test.cpp +++ b/3rdparty/spirv-tools/test/opt/pass_merge_return_test.cpp @@ -1724,6 +1724,62 @@ OpFunctionEnd SinglePassRunAndMatch(predefs + caller + callee, true); } +TEST_F(MergeReturnPassTest, MergeToMergeBranch) { + const std::string text = + R"( +; CHECK: [[new_undef:%\w+]] = OpUndef %uint +; CHECK: OpLoopMerge +; CHECK: OpLoopMerge [[merge1:%\w+]] +; CHECK: OpLoopMerge [[merge2:%\w+]] +; CHECK: [[merge1]] = OpLabel +; CHECK-NEXT: OpPhi %uint [[new_undef]] [[merge2]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 100 1 1 + OpSource ESSL 310 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %bool = OpTypeBool + %false = OpConstantFalse %bool + %uint_0 = OpConstant %uint 0 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %13 = OpUndef %bool + %2 = OpFunction %void None %4 + %14 = OpLabel + OpBranch %15 + %15 = OpLabel + OpLoopMerge %16 %17 None + OpBranch %18 + %18 = OpLabel + OpLoopMerge %19 %20 None + OpBranchConditional %13 %21 %19 + %21 = OpLabel + OpReturn + %20 = OpLabel + OpBranch %18 + %19 = OpLabel + %22 = OpUndef %uint + OpBranch %23 + %23 = OpLabel + OpBranch %16 + %17 = OpLabel + OpBranch %15 + %16 = OpLabel + %24 = OpCopyObject %uint %22 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/tools/expect.py b/3rdparty/spirv-tools/test/tools/expect.py index 56ddaec97..e21a0c4fe 100755 --- a/3rdparty/spirv-tools/test/tools/expect.py +++ b/3rdparty/spirv-tools/test/tools/expect.py @@ -79,6 +79,15 @@ class ReturnCodeIsZero(SpirvTest): return True, '' +class ReturnCodeIsNonZero(SpirvTest): + """Mixin class for checking that the return code is not zero.""" + + def check_return_code_is_nonzero(self, status): + if not status.returncode: + return False, 'return code is 0' + return True, '' + + class NoOutputOnStdout(SpirvTest): """Mixin class for checking that there is no output on stdout.""" diff --git a/3rdparty/spirv-tools/test/tools/opt/flags.py b/3rdparty/spirv-tools/test/tools/opt/flags.py index ca873c768..a89477cc3 100644 --- a/3rdparty/spirv-tools/test/tools/opt/flags.py +++ b/3rdparty/spirv-tools/test/tools/opt/flags.py @@ -59,7 +59,7 @@ class TestValidPassFlags(expect.ValidObjectFile1_4, flags = [ '--ccp', '--cfg-cleanup', '--combine-access-chains', '--compact-ids', '--convert-local-access-chains', '--copy-propagate-arrays', - '--eliminate-common-uniform', '--eliminate-dead-branches', + '--eliminate-dead-branches', '--eliminate-dead-code-aggressive', '--eliminate-dead-const', '--eliminate-dead-functions', '--eliminate-dead-inserts', '--eliminate-dead-variables', '--eliminate-insert-extract', @@ -82,7 +82,6 @@ class TestValidPassFlags(expect.ValidObjectFile1_4, 'compact-ids', 'convert-local-access-chains', 'copy-propagate-arrays', - 'eliminate-common-uniform', 'eliminate-dead-branches', 'eliminate-dead-code-aggressive', 'eliminate-dead-const', @@ -332,3 +331,45 @@ class TestLoopPeelingThresholdArgsInvalidNumber(expect.ErrorMessageSubstr): spirv_args = ['--loop-peeling-threshold=a10f'] expected_error_substr = 'must have a positive integer argument' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestWebGPUToVulkanThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests Vulkan->WebGPU flag cannot be used after WebGPU->Vulkan flag.""" + + spirv_args = ['--webgpu-to-vulkan', '--vulkan-to-webgpu'] + expected_error_substr = 'Cannot use both' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestVulkanToWebGPUThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests WebGPU->Vulkan flag cannot be used after Vulkan->WebGPU flag.""" + + spirv_args = ['--vulkan-to-webgpu', '--webgpu-to-vulkan'] + expected_error_substr = 'Cannot use both' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestTargetEnvThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests Vulkan->WebGPU flag cannot be used after target env flag.""" + + spirv_args = ['--target-env=opengl4.0', '--vulkan-to-webgpu'] + expected_error_substr = 'defines the target environment' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestVulkanToWebGPUThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests target env flag cannot be used after Vulkan->WebGPU flag.""" + + spirv_args = ['--vulkan-to-webgpu', '--target-env=opengl4.0'] + expected_error_substr = 'defines the target environment' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestTargetEnvThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests WebGPU->Vulkan flag cannot be used after target env flag.""" + + spirv_args = ['--target-env=opengl4.0', '--webgpu-to-vulkan'] + expected_error_substr = 'defines the target environment' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestWebGPUToVulkanThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests target env flag cannot be used after WebGPU->Vulkan flag.""" + + spirv_args = ['--webgpu-to-vulkan', '--target-env=opengl4.0'] + expected_error_substr = 'defines the target environment' diff --git a/3rdparty/spirv-tools/test/val/val_id_test.cpp b/3rdparty/spirv-tools/test/val/val_id_test.cpp index 73e2ce114..883949044 100644 --- a/3rdparty/spirv-tools/test/val/val_id_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_id_test.cpp @@ -937,6 +937,26 @@ TEST_F(ValidateIdWithMessage, OpTypeStructMemberTypeBad) { "a type.")); } +TEST_F(ValidateIdWithMessage, OpTypeStructOpaqueTypeBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + %1 = OpTypeSampler + %2 = OpTypeStruct %1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpTypeStruct must not contain an opaque type")); +} + TEST_F(ValidateIdWithMessage, OpTypePointerGood) { std::string spirv = kGLSL450MemoryModel + R"( %1 = OpTypeInt 32 0 diff --git a/3rdparty/spirv-tools/tools/opt/opt.cpp b/3rdparty/spirv-tools/tools/opt/opt.cpp index d29b8a0a6..cce105385 100644 --- a/3rdparty/spirv-tools/tools/opt/opt.cpp +++ b/3rdparty/spirv-tools/tools/opt/opt.cpp @@ -147,13 +147,6 @@ Options (in lexicographical order):)", around known issues with some Vulkan drivers for initialize variables.)"); printf(R"( - --eliminate-common-uniform - Perform load/load elimination for duplicate uniform values. - Converts any constant index access chain uniform loads into - its equivalent load and extract. Some loads will be moved - to facilitate sharing. Performed only on entry point - call tree functions.)"); - printf(R"( --eliminate-dead-branches Convert conditional branches with constant condition to the indicated unconditional brranch. Delete all resulting dead @@ -728,16 +721,17 @@ OptStatus ParseFlags(int argc, const char** argv, max_id_bound); } else if (0 == strncmp(cur_arg, "--target-env=", sizeof("--target-env=") - 1)) { + target_env_set = true; if (vulkan_to_webgpu_set) { spvtools::Error(opt_diagnostic, nullptr, {}, - "Cannot use both --vulkan-to-webgpu and --target-env " - "at the same time"); + "--vulkan-to-webgpu defines the target environment, " + "so --target-env cannot be set at the same time"); return {OPT_STOP, 1}; } if (webgpu_to_vulkan_set) { spvtools::Error(opt_diagnostic, nullptr, {}, - "Cannot use both --webgpu-to-vulkan and --target-env " - "at the same time"); + "--webgpu-to-vulkan defines the target environment, " + "so --target-env cannot be set at the same time"); return {OPT_STOP, 1}; } const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); @@ -750,32 +744,36 @@ OptStatus ParseFlags(int argc, const char** argv, } optimizer->SetTargetEnv(target_env); } else if (0 == strcmp(cur_arg, "--vulkan-to-webgpu")) { + vulkan_to_webgpu_set = true; if (target_env_set) { spvtools::Error(opt_diagnostic, nullptr, {}, - "Cannot use both --vulkan-to-webgpu and --target-env " - "at the same time"); + "--vulkan-to-webgpu defines the target environment, " + "so --target-env cannot be set at the same time"); return {OPT_STOP, 1}; } if (webgpu_to_vulkan_set) { spvtools::Error(opt_diagnostic, nullptr, {}, - "Cannot use both --vulkan-to-webgpu and " - "--webgpu-to-vulkan at the same time"); + "Cannot use both --webgpu-to-vulkan and " + "--vulkan-to-webgpu at the same time, invoke twice " + "if you are wanting to go to and from"); return {OPT_STOP, 1}; } optimizer->SetTargetEnv(SPV_ENV_WEBGPU_0); optimizer->RegisterVulkanToWebGPUPasses(); } else if (0 == strcmp(cur_arg, "--webgpu-to-vulkan")) { + webgpu_to_vulkan_set = true; if (target_env_set) { spvtools::Error(opt_diagnostic, nullptr, {}, - "Cannot use both --webgpu-to-vulkan and --target-env " - "at the same time"); + "--webgpu-to-vulkan defines the target environment, " + "so --target-env cannot be set at the same time"); return {OPT_STOP, 1}; } if (vulkan_to_webgpu_set) { spvtools::Error(opt_diagnostic, nullptr, {}, "Cannot use both --webgpu-to-vulkan and " - "--vulkan-to-webgpu at the same time"); + "--vulkan-to-webgpu at the same time, invoke twice " + "if you are wanting to go to and from"); return {OPT_STOP, 1}; }