Squashed 'third_party/SPIRV-Tools/' changes from 0741f4273..9668d2e4e
9668d2e4e spirv-val: Label and add test for PSB Aligned (#4756)
c6d5474f4 BUILD.gn: Enable independent builds within the Chromium tree (#4762)
9d1b57288 spirv-opt: (WIP) Eliminate Dead Input Component Pass (#4720)
f8cd51431 spirv-val: Add better error code for invalid operand (#4753)
3820c4f6e Qualify std::move. (#4741)
0ab57c2c4 spirv-val: Small Cleanup of validate image (#4752)
7963fa13c spirv-val: Add Vulkan Dref not allowed 3D dim VUID (#4751)
5c9d55a59 spirv-val: Add Vulkan Image VUID 06214 (#4750)
970070857 spirv-val: Label Vulkan RuntimeArray VUID (#4749)
ca59914c7 spirv-val: Disallow array of push constants (#4742)
git-subtree-dir: third_party/SPIRV-Tools
git-subtree-split: 9668d2e4e4b7e089fd8f25c50c373df07e05d4a9
diff --git a/Android.mk b/Android.mk
index 3e836c5..e7616f9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -106,6 +106,7 @@
source/opt/eliminate_dead_constant_pass.cpp \
source/opt/eliminate_dead_functions_pass.cpp \
source/opt/eliminate_dead_functions_util.cpp \
+ source/opt/eliminate_dead_input_components_pass.cpp \
source/opt/eliminate_dead_members_pass.cpp \
source/opt/feature_manager.cpp \
source/opt/fix_storage_class.cpp \
diff --git a/BUILD.gn b/BUILD.gn
index 0f58884..5910e5e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -19,6 +19,12 @@
import("//third_party/protobuf/proto_library.gni")
}
+# SPIRV-Tools may be part of multiple projects in the Chromium tree.
+# Only enable building executables if this is the main copy, or standalone.
+abspath = get_path_info(".", "abspath")
+spvtools_chromium_third_party = (abspath == "//third_party/SPIRV-Tools/")
+spvtools_build_executables = !build_with_chromium || spvtools_chromium_third_party
+
spirv_headers = spirv_tools_spirv_headers_dir
spirv_is_winuwp = is_win && target_os == "winuwp"
@@ -611,6 +617,8 @@
"source/opt/eliminate_dead_functions_pass.h",
"source/opt/eliminate_dead_functions_util.cpp",
"source/opt/eliminate_dead_functions_util.h",
+ "source/opt/eliminate_dead_input_components_pass.cpp",
+ "source/opt/eliminate_dead_input_components_pass.h",
"source/opt/eliminate_dead_members_pass.cpp",
"source/opt/eliminate_dead_members_pass.h",
"source/opt/empty_pass.h",
@@ -875,7 +883,7 @@
configs += [ ":spvtools_internal_config" ]
}
-if (build_with_chromium) {
+if (build_with_chromium && spvtools_build_executables) {
# The spirv-fuzz library is only built when in a Chromium checkout
# due to its dependency on protobuf.
@@ -1304,7 +1312,7 @@
# The tests are scoped to Chromium to avoid needing to write gtest integration.
# See Chromium's third_party/googletest/BUILD.gn for a complete integration.
-if (build_with_chromium) {
+if (build_with_chromium && spvtools_build_executables) {
test("spvtools_test") {
sources = [
"test/assembly_context_test.cpp",
@@ -1413,73 +1421,75 @@
configs += [ ":spvtools_internal_config" ]
}
-executable("spirv-as") {
- sources = [ "tools/as/as.cpp" ]
- deps = [
- ":spvtools",
- ":spvtools_software_version",
- ]
- configs += [ ":spvtools_internal_config" ]
+if (spvtools_build_executables) {
+ executable("spirv-as") {
+ sources = [ "tools/as/as.cpp" ]
+ deps = [
+ ":spvtools",
+ ":spvtools_software_version",
+ ]
+ configs += [ ":spvtools_internal_config" ]
+ }
+
+ executable("spirv-dis") {
+ sources = [ "tools/dis/dis.cpp" ]
+ deps = [
+ ":spvtools",
+ ":spvtools_software_version",
+ ]
+ configs += [ ":spvtools_internal_config" ]
+ }
+
+ executable("spirv-val") {
+ sources = [ "tools/val/val.cpp" ]
+ deps = [
+ ":spvtools",
+ ":spvtools_software_version",
+ ":spvtools_util_cli_consumer",
+ ":spvtools_val",
+ ]
+ configs += [ ":spvtools_internal_config" ]
+ }
+
+ executable("spirv-cfg") {
+ sources = [
+ "tools/cfg/bin_to_dot.cpp",
+ "tools/cfg/bin_to_dot.h",
+ "tools/cfg/cfg.cpp",
+ ]
+ deps = [
+ ":spvtools",
+ ":spvtools_software_version",
+ ]
+ configs += [ ":spvtools_internal_config" ]
+ }
+
+ executable("spirv-opt") {
+ sources = [ "tools/opt/opt.cpp" ]
+ deps = [
+ ":spvtools",
+ ":spvtools_opt",
+ ":spvtools_software_version",
+ ":spvtools_util_cli_consumer",
+ ":spvtools_val",
+ ]
+ configs += [ ":spvtools_internal_config" ]
+ }
+
+ executable("spirv-link") {
+ sources = [ "tools/link/linker.cpp" ]
+ deps = [
+ ":spvtools",
+ ":spvtools_link",
+ ":spvtools_opt",
+ ":spvtools_software_version",
+ ":spvtools_val",
+ ]
+ configs += [ ":spvtools_internal_config" ]
+ }
}
-executable("spirv-dis") {
- sources = [ "tools/dis/dis.cpp" ]
- deps = [
- ":spvtools",
- ":spvtools_software_version",
- ]
- configs += [ ":spvtools_internal_config" ]
-}
-
-executable("spirv-val") {
- sources = [ "tools/val/val.cpp" ]
- deps = [
- ":spvtools",
- ":spvtools_software_version",
- ":spvtools_util_cli_consumer",
- ":spvtools_val",
- ]
- configs += [ ":spvtools_internal_config" ]
-}
-
-executable("spirv-cfg") {
- sources = [
- "tools/cfg/bin_to_dot.cpp",
- "tools/cfg/bin_to_dot.h",
- "tools/cfg/cfg.cpp",
- ]
- deps = [
- ":spvtools",
- ":spvtools_software_version",
- ]
- configs += [ ":spvtools_internal_config" ]
-}
-
-executable("spirv-opt") {
- sources = [ "tools/opt/opt.cpp" ]
- deps = [
- ":spvtools",
- ":spvtools_opt",
- ":spvtools_software_version",
- ":spvtools_util_cli_consumer",
- ":spvtools_val",
- ]
- configs += [ ":spvtools_internal_config" ]
-}
-
-executable("spirv-link") {
- sources = [ "tools/link/linker.cpp" ]
- deps = [
- ":spvtools",
- ":spvtools_link",
- ":spvtools_opt",
- ":spvtools_software_version",
- ":spvtools_val",
- ]
- configs += [ ":spvtools_internal_config" ]
-}
-
-if (!is_ios && !spirv_is_winuwp && build_with_chromium) {
+if (!is_ios && !spirv_is_winuwp && build_with_chromium && spvtools_build_executables) {
# iOS and UWP do not allow std::system calls which spirv-fuzz
# requires. Additionally, spirv-fuzz is only built when in a
# Chromium checkout due to its dependency on protobuf.
@@ -1500,7 +1510,7 @@
}
}
-if (!is_ios && !spirv_is_winuwp) {
+if (!is_ios && !spirv_is_winuwp && spvtools_build_executables) {
# iOS and UWP do not allow std::system calls which spirv-reduce
# requires.
@@ -1518,19 +1528,21 @@
}
}
-group("all_spirv_tools") {
- deps = [
- ":spirv-as",
- ":spirv-cfg",
- ":spirv-dis",
- ":spirv-link",
- ":spirv-opt",
- ":spirv-val",
- ]
- if (!is_ios && !spirv_is_winuwp && build_with_chromium) {
- deps += [ ":spirv-fuzz" ]
- }
- if (!is_ios && !spirv_is_winuwp) {
- deps += [ ":spirv-reduce" ]
+if (spvtools_build_executables){
+ group("all_spirv_tools") {
+ deps = [
+ ":spirv-as",
+ ":spirv-cfg",
+ ":spirv-dis",
+ ":spirv-link",
+ ":spirv-opt",
+ ":spirv-val",
+ ]
+ if (!is_ios && !spirv_is_winuwp && build_with_chromium) {
+ deps += [ ":spirv-fuzz" ]
+ }
+ if (!is_ios && !spirv_is_winuwp) {
+ deps += [ ":spirv-reduce" ]
+ }
}
}
diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
index 2273e85..fbbd9bc 100644
--- a/include/spirv-tools/optimizer.hpp
+++ b/include/spirv-tools/optimizer.hpp
@@ -886,6 +886,13 @@
// propagated into their final positions.
Optimizer::PassToken CreateInterpolateFixupPass();
+// Removes unused components from composite input variables. Current
+// implementation just removes trailing unused components from input arrays.
+// The pass performs best after maximizing dead code removal. A subsequent dead
+// code elimination pass would be beneficial in removing newly unused component
+// types.
+Optimizer::PassToken CreateEliminateDeadInputComponentsPass();
+
// Creates a convert-to-sampled-image pass to convert images and/or
// samplers with given pairs of descriptor set and binding to sampled image.
// If a pair of an image and a sampler have the same pair of descriptor set and
diff --git a/source/assembly_grammar.cpp b/source/assembly_grammar.cpp
index 79f18ee..4f5942a 100644
--- a/source/assembly_grammar.cpp
+++ b/source/assembly_grammar.cpp
@@ -62,9 +62,9 @@
end = std::find(begin, text_end, separator);
spv_operand_desc entry = nullptr;
- if (spvOperandTableNameLookup(env, operandTable, type, begin, end - begin,
- &entry)) {
- return SPV_ERROR_INVALID_TEXT;
+ if (auto error = spvOperandTableNameLookup(env, operandTable, type, begin,
+ end - begin, &entry)) {
+ return error;
}
value |= entry->value;
diff --git a/source/operand.cpp b/source/operand.cpp
index 6d83e81..0c255a3 100644
--- a/source/operand.cpp
+++ b/source/operand.cpp
@@ -72,12 +72,16 @@
// Note that the second rule assumes the extension enabling this operand
// is indeed requested in the SPIR-V code; checking that should be
// validator's work.
- if (((version >= entry.minVersion && version <= entry.lastVersion) ||
- entry.numExtensions > 0u || entry.numCapabilities > 0u) &&
- nameLength == strlen(entry.name) &&
+ if (nameLength == strlen(entry.name) &&
!strncmp(entry.name, name, nameLength)) {
- *pEntry = &entry;
- return SPV_SUCCESS;
+ if ((version >= entry.minVersion && version <= entry.lastVersion) ||
+ entry.numExtensions > 0u || entry.numCapabilities > 0u) {
+ *pEntry = &entry;
+ return SPV_SUCCESS;
+ } else {
+ // if there is no extension/capability then the version is wrong
+ return SPV_ERROR_WRONG_VERSION;
+ }
}
}
}
diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt
index 05c02fc..61e7a98 100644
--- a/source/opt/CMakeLists.txt
+++ b/source/opt/CMakeLists.txt
@@ -45,6 +45,7 @@
eliminate_dead_constant_pass.h
eliminate_dead_functions_pass.h
eliminate_dead_functions_util.h
+ eliminate_dead_input_components_pass.h
eliminate_dead_members_pass.h
empty_pass.h
feature_manager.h
@@ -158,6 +159,7 @@
eliminate_dead_constant_pass.cpp
eliminate_dead_functions_pass.cpp
eliminate_dead_functions_util.cpp
+ eliminate_dead_input_components_pass.cpp
eliminate_dead_members_pass.cpp
feature_manager.cpp
fix_storage_class.cpp
diff --git a/source/opt/dead_branch_elim_pass.cpp b/source/opt/dead_branch_elim_pass.cpp
index 356dbcb..cc616ca 100644
--- a/source/opt/dead_branch_elim_pass.cpp
+++ b/source/opt/dead_branch_elim_pass.cpp
@@ -207,7 +207,7 @@
Instruction::OperandList new_operands;
new_operands.push_back(terminator->GetInOperand(0));
new_operands.push_back({SPV_OPERAND_TYPE_ID, {live_lab_id}});
- terminator->SetInOperands(move(new_operands));
+ terminator->SetInOperands(std::move(new_operands));
context()->UpdateDefUse(terminator);
} else {
// Check if the merge instruction is still needed because of a
diff --git a/source/opt/eliminate_dead_input_components_pass.cpp b/source/opt/eliminate_dead_input_components_pass.cpp
new file mode 100644
index 0000000..f383136
--- /dev/null
+++ b/source/opt/eliminate_dead_input_components_pass.cpp
@@ -0,0 +1,146 @@
+// Copyright (c) 2022 The Khronos Group Inc.
+// Copyright (c) 2022 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/eliminate_dead_input_components_pass.h"
+
+#include <set>
+#include <vector>
+
+#include "source/opt/instruction.h"
+#include "source/opt/ir_builder.h"
+#include "source/opt/ir_context.h"
+#include "source/util/bit_vector.h"
+
+namespace {
+
+const uint32_t kAccessChainBaseInIdx = 0;
+const uint32_t kAccessChainIndex0InIdx = 1;
+const uint32_t kConstantValueInIdx = 0;
+const uint32_t kVariableStorageClassInIdx = 0;
+
+} // namespace
+
+namespace spvtools {
+namespace opt {
+
+Pass::Status EliminateDeadInputComponentsPass::Process() {
+ // Current functionality assumes shader capability
+ if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
+ return Status::SuccessWithoutChange;
+ analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
+ analysis::TypeManager* type_mgr = context()->get_type_mgr();
+ bool modified = false;
+ std::vector<std::pair<Instruction*, unsigned>> arrays_to_change;
+ for (auto& var : context()->types_values()) {
+ if (var.opcode() != SpvOpVariable) {
+ continue;
+ }
+ analysis::Type* var_type = type_mgr->GetType(var.type_id());
+ analysis::Pointer* ptr_type = var_type->AsPointer();
+ if (ptr_type == nullptr) {
+ continue;
+ }
+ if (ptr_type->storage_class() != SpvStorageClassInput) {
+ continue;
+ }
+ const analysis::Array* arr_type = ptr_type->pointee_type()->AsArray();
+ if (arr_type == nullptr) {
+ continue;
+ }
+ unsigned arr_len_id = arr_type->LengthId();
+ Instruction* arr_len_inst = def_use_mgr->GetDef(arr_len_id);
+ if (arr_len_inst->opcode() != SpvOpConstant) {
+ continue;
+ }
+ // SPIR-V requires array size is >= 1, so this works for signed or
+ // unsigned size
+ unsigned original_max =
+ arr_len_inst->GetSingleWordInOperand(kConstantValueInIdx) - 1;
+ unsigned max_idx = FindMaxIndex(var, original_max);
+ if (max_idx != original_max) {
+ ChangeArrayLength(var, max_idx + 1);
+ modified = true;
+ }
+ }
+
+ return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+}
+
+unsigned EliminateDeadInputComponentsPass::FindMaxIndex(Instruction& var,
+ unsigned original_max) {
+ unsigned max = 0;
+ bool seen_non_const_ac = false;
+ assert(var.opcode() == SpvOpVariable && "must be variable");
+ context()->get_def_use_mgr()->WhileEachUser(
+ var.result_id(), [&max, &seen_non_const_ac, var, this](Instruction* use) {
+ auto use_opcode = use->opcode();
+ if (use_opcode == SpvOpLoad || use_opcode == SpvOpCopyMemory ||
+ use_opcode == SpvOpCopyMemorySized ||
+ use_opcode == SpvOpCopyObject) {
+ seen_non_const_ac = true;
+ return false;
+ }
+ if (use->opcode() != SpvOpAccessChain &&
+ use->opcode() != SpvOpInBoundsAccessChain) {
+ return true;
+ }
+ // OpAccessChain with no indices currently not optimized
+ if (use->NumInOperands() == 1) {
+ seen_non_const_ac = true;
+ return false;
+ }
+ unsigned base_id = use->GetSingleWordInOperand(kAccessChainBaseInIdx);
+ USE_ASSERT(base_id == var.result_id() && "unexpected base");
+ unsigned idx_id = use->GetSingleWordInOperand(kAccessChainIndex0InIdx);
+ Instruction* idx_inst = context()->get_def_use_mgr()->GetDef(idx_id);
+ if (idx_inst->opcode() != SpvOpConstant) {
+ seen_non_const_ac = true;
+ return false;
+ }
+ unsigned value = idx_inst->GetSingleWordInOperand(kConstantValueInIdx);
+ if (value > max) max = value;
+ return true;
+ });
+ return seen_non_const_ac ? original_max : max;
+}
+
+void EliminateDeadInputComponentsPass::ChangeArrayLength(Instruction& arr,
+ unsigned length) {
+ analysis::TypeManager* type_mgr = context()->get_type_mgr();
+ analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
+ analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
+ analysis::Pointer* ptr_type = type_mgr->GetType(arr.type_id())->AsPointer();
+ const analysis::Array* arr_ty = ptr_type->pointee_type()->AsArray();
+ assert(arr_ty && "expecting array type");
+ uint32_t length_id = const_mgr->GetUIntConst(length);
+ analysis::Array new_arr_ty(arr_ty->element_type(),
+ arr_ty->GetConstantLengthInfo(length_id, length));
+ analysis::Type* reg_new_arr_ty = type_mgr->GetRegisteredType(&new_arr_ty);
+ analysis::Pointer new_ptr_ty(reg_new_arr_ty, SpvStorageClassInput);
+ analysis::Type* reg_new_ptr_ty = type_mgr->GetRegisteredType(&new_ptr_ty);
+ uint32_t new_ptr_ty_id = type_mgr->GetTypeInstruction(reg_new_ptr_ty);
+ arr.SetResultType(new_ptr_ty_id);
+ def_use_mgr->AnalyzeInstUse(&arr);
+ // Move array OpVariable instruction after its new type to preserve order
+ USE_ASSERT(arr.GetSingleWordInOperand(kVariableStorageClassInIdx) !=
+ SpvStorageClassFunction &&
+ "cannot move Function variable");
+ Instruction* new_ptr_ty_inst = def_use_mgr->GetDef(new_ptr_ty_id);
+ arr.RemoveFromList();
+ arr.InsertAfter(new_ptr_ty_inst);
+}
+
+} // namespace opt
+} // namespace spvtools
diff --git a/source/opt/eliminate_dead_input_components_pass.h b/source/opt/eliminate_dead_input_components_pass.h
new file mode 100644
index 0000000..b77857f
--- /dev/null
+++ b/source/opt/eliminate_dead_input_components_pass.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2022 The Khronos Group Inc.
+// Copyright (c) 2022 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_ELIMINATE_DEAD_INPUT_COMPONENTS_H_
+#define SOURCE_OPT_ELIMINATE_DEAD_INPUT_COMPONENTS_H_
+
+#include <unordered_map>
+
+#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 EliminateDeadInputComponentsPass : public Pass {
+ public:
+ explicit EliminateDeadInputComponentsPass() {}
+
+ const char* name() const override { return "reduce-load-size"; }
+ Status Process() override;
+
+ // Return the mask of preserved Analyses.
+ IRContext::Analysis GetPreservedAnalyses() override {
+ return IRContext::kAnalysisDefUse |
+ IRContext::kAnalysisInstrToBlockMapping |
+ IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG |
+ IRContext::kAnalysisDominatorAnalysis |
+ IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
+ IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
+ }
+
+ private:
+ // Find the max constant used to index the variable declared by |var|
+ // through OpAccessChain or OpInBoundsAccessChain. If any non-constant
+ // indices or non-Op*AccessChain use of |var|, return |original_max|.
+ unsigned FindMaxIndex(Instruction& var, unsigned original_max);
+
+ // Change the length of the array |inst| to |length|
+ void ChangeArrayLength(Instruction& inst, unsigned length);
+};
+
+} // namespace opt
+} // namespace spvtools
+
+#endif // SOURCE_OPT_ELIMINATE_DEAD_INPUT_COMPONENTS_H_
diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp
index 5607239..c2c5d6c 100644
--- a/source/opt/inst_bindless_check_pass.cpp
+++ b/source/opt/inst_bindless_check_pass.cpp
@@ -39,13 +39,6 @@
static const int kSpvTypeImageSampled = 5;
} // anonymous namespace
-// Avoid unused variable warning/error on Linux
-#ifndef NDEBUG
-#define USE_ASSERT(x) assert(x)
-#else
-#define USE_ASSERT(x) ((void)(x))
-#endif
-
namespace spvtools {
namespace opt {
diff --git a/source/opt/interp_fixup_pass.cpp b/source/opt/interp_fixup_pass.cpp
index ad29e6a..e8cdd99 100644
--- a/source/opt/interp_fixup_pass.cpp
+++ b/source/opt/interp_fixup_pass.cpp
@@ -31,13 +31,6 @@
// Input Operand Indices
static const int kSpvVariableStorageClassInIdx = 0;
-// Avoid unused variable warning/error on Linux
-#ifndef NDEBUG
-#define USE_ASSERT(x) assert(x)
-#else
-#define USE_ASSERT(x) ((void)(x))
-#endif
-
// Folding rule function which attempts to replace |op(OpLoad(a),...)|
// by |op(a,...)|, where |op| is one of the GLSLstd450 InterpolateAt*
// instructions. Returns true if replaced, false otherwise.
diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp
index ec2c8ea..f28b1ba 100644
--- a/source/opt/optimizer.cpp
+++ b/source/opt/optimizer.cpp
@@ -523,6 +523,8 @@
RegisterPass(CreateInterpolateFixupPass());
} else if (pass_name == "remove-dont-inline") {
RegisterPass(CreateRemoveDontInlinePass());
+ } else if (pass_name == "eliminate-dead-input-components") {
+ RegisterPass(CreateEliminateDeadInputComponentsPass());
} else if (pass_name == "convert-to-sampled-image") {
if (pass_args.size() > 0) {
auto descriptor_set_binding_pairs =
@@ -1004,6 +1006,11 @@
MakeUnique<opt::InterpFixupPass>());
}
+Optimizer::PassToken CreateEliminateDeadInputComponentsPass() {
+ return MakeUnique<Optimizer::PassToken::Impl>(
+ MakeUnique<opt::EliminateDeadInputComponentsPass>());
+}
+
Optimizer::PassToken CreateConvertToSampledImagePass(
const std::vector<opt::DescriptorSetAndBinding>&
descriptor_set_binding_pairs) {
diff --git a/source/opt/pass.h b/source/opt/pass.h
index 4a8ea67..b2303e2 100644
--- a/source/opt/pass.h
+++ b/source/opt/pass.h
@@ -28,6 +28,13 @@
#include "spirv-tools/libspirv.hpp"
#include "types.h"
+// Avoid unused variable warning/error on Linux
+#ifndef NDEBUG
+#define USE_ASSERT(x) assert(x)
+#else
+#define USE_ASSERT(x) ((void)(x))
+#endif
+
namespace spvtools {
namespace opt {
diff --git a/source/opt/passes.h b/source/opt/passes.h
index 26739cd..a12c76b 100644
--- a/source/opt/passes.h
+++ b/source/opt/passes.h
@@ -34,6 +34,7 @@
#include "source/opt/desc_sroa.h"
#include "source/opt/eliminate_dead_constant_pass.h"
#include "source/opt/eliminate_dead_functions_pass.h"
+#include "source/opt/eliminate_dead_input_components_pass.h"
#include "source/opt/eliminate_dead_members_pass.h"
#include "source/opt/empty_pass.h"
#include "source/opt/fix_storage_class.h"
diff --git a/source/opt/private_to_local_pass.cpp b/source/opt/private_to_local_pass.cpp
index 12a226d..80fb4c5 100644
--- a/source/opt/private_to_local_pass.cpp
+++ b/source/opt/private_to_local_pass.cpp
@@ -135,7 +135,7 @@
// Place the variable at the start of the first basic block.
context()->AnalyzeUses(variable);
context()->set_instr_block(variable, &*function->begin());
- function->begin()->begin()->InsertBefore(move(var));
+ function->begin()->begin()->InsertBefore(std::move(var));
// Update uses where the type may have changed.
return UpdateUses(variable);
diff --git a/source/opt/types.cpp b/source/opt/types.cpp
index 47abd41..ebbdc36 100644
--- a/source/opt/types.cpp
+++ b/source/opt/types.cpp
@@ -419,6 +419,12 @@
void Array::ReplaceElementType(const Type* type) { element_type_ = type; }
+Array::LengthInfo Array::GetConstantLengthInfo(uint32_t const_id,
+ uint32_t length) const {
+ std::vector<uint32_t> extra_words{LengthInfo::Case::kConstant, length};
+ return {const_id, extra_words};
+}
+
RuntimeArray::RuntimeArray(const Type* type)
: Type(kRuntimeArray), element_type_(type) {
assert(!type->AsVoid());
diff --git a/source/opt/types.h b/source/opt/types.h
index 01e8f3c..f5a4a6b 100644
--- a/source/opt/types.h
+++ b/source/opt/types.h
@@ -390,6 +390,7 @@
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
void ReplaceElementType(const Type* element_type);
+ LengthInfo GetConstantLengthInfo(uint32_t const_id, uint32_t length) const;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
diff --git a/source/text.cpp b/source/text.cpp
index 415c059..97d00cb 100644
--- a/source/text.cpp
+++ b/source/text.cpp
@@ -403,9 +403,10 @@
case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: {
uint32_t value;
- if (grammar.parseMaskOperand(type, textValue, &value)) {
- return context->diagnostic() << "Invalid " << spvOperandTypeStr(type)
- << " operand '" << textValue << "'.";
+ if (auto error = grammar.parseMaskOperand(type, textValue, &value)) {
+ return context->diagnostic(error)
+ << "Invalid " << spvOperandTypeStr(type) << " operand '"
+ << textValue << "'.";
}
if (auto error = context->binaryEncodeU32(value, pInst)) return error;
// Prepare to parse the operands for this logical operand.
@@ -769,8 +770,8 @@
instructions.push_back({});
spv_instruction_t& inst = instructions.back();
- if (spvTextEncodeOpcode(grammar, &context, &inst)) {
- return SPV_ERROR_INVALID_TEXT;
+ if (auto error = spvTextEncodeOpcode(grammar, &context, &inst)) {
+ return error;
}
if (context.advance()) break;
diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp
index cfa15d9..3b0a7fa 100644
--- a/source/val/validate_atomics.cpp
+++ b/source/val/validate_atomics.cpp
@@ -39,7 +39,7 @@
case SpvStorageClassAtomicCounter:
case SpvStorageClassImage:
case SpvStorageClassFunction:
- case SpvStorageClassPhysicalStorageBufferEXT:
+ case SpvStorageClassPhysicalStorageBuffer:
return true;
break;
default:
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index eb6caf0..e712936 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -1017,7 +1017,7 @@
}
const bool phys_storage_buffer =
- storageClass == SpvStorageClassPhysicalStorageBufferEXT;
+ storageClass == SpvStorageClassPhysicalStorageBuffer;
const bool workgroup =
storageClass == SpvStorageClassWorkgroup &&
vstate.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayoutKHR);
@@ -1407,11 +1407,11 @@
storage != SpvStorageClassUniform &&
storage != SpvStorageClassPushConstant &&
storage != SpvStorageClassInput && storage != SpvStorageClassOutput &&
- storage != SpvStorageClassPhysicalStorageBufferEXT) {
+ storage != SpvStorageClassPhysicalStorageBuffer) {
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
<< "FPRoundingMode decoration can be applied only to the "
"Object operand of an OpStore in the StorageBuffer, "
- "PhysicalStorageBufferEXT, Uniform, PushConstant, Input, or "
+ "PhysicalStorageBuffer, Uniform, PushConstant, Input, or "
"Output Storage Classes.";
}
}
diff --git a/source/val/validate_function.cpp b/source/val/validate_function.cpp
index 596186b..656893f 100644
--- a/source/val/validate_function.cpp
+++ b/source/val/validate_function.cpp
@@ -147,8 +147,8 @@
"type of the same index.";
}
- // Validate that PhysicalStorageBufferEXT have one of Restrict, Aliased,
- // RestrictPointerEXT, or AliasedPointerEXT.
+ // Validate that PhysicalStorageBuffer have one of Restrict, Aliased,
+ // RestrictPointer, or AliasedPointer.
auto param_nonarray_type_id = param_type->id();
while (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypeArray) {
param_nonarray_type_id =
@@ -157,7 +157,7 @@
if (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypePointer) {
auto param_nonarray_type = _.FindDef(param_nonarray_type_id);
if (param_nonarray_type->GetOperandAs<uint32_t>(1u) ==
- SpvStorageClassPhysicalStorageBufferEXT) {
+ SpvStorageClassPhysicalStorageBuffer) {
// check for Aliased or Restrict
const auto& decorations = _.id_decorations(inst->id());
@@ -174,14 +174,14 @@
if (!foundAliased && !foundRestrict) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpFunctionParameter " << inst->id()
- << ": expected Aliased or Restrict for PhysicalStorageBufferEXT "
+ << ": expected Aliased or Restrict for PhysicalStorageBuffer "
"pointer.";
}
if (foundAliased && foundRestrict) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpFunctionParameter " << inst->id()
<< ": can't specify both Aliased and Restrict for "
- "PhysicalStorageBufferEXT pointer.";
+ "PhysicalStorageBuffer pointer.";
}
} else {
const auto pointee_type_id =
@@ -189,31 +189,31 @@
const auto pointee_type = _.FindDef(pointee_type_id);
if (SpvOpTypePointer == pointee_type->opcode() &&
pointee_type->GetOperandAs<uint32_t>(1u) ==
- SpvStorageClassPhysicalStorageBufferEXT) {
- // check for AliasedPointerEXT/RestrictPointerEXT
+ SpvStorageClassPhysicalStorageBuffer) {
+ // check for AliasedPointer/RestrictPointer
const auto& decorations = _.id_decorations(inst->id());
bool foundAliased = std::any_of(
decorations.begin(), decorations.end(), [](const Decoration& d) {
- return SpvDecorationAliasedPointerEXT == d.dec_type();
+ return SpvDecorationAliasedPointer == d.dec_type();
});
bool foundRestrict = std::any_of(
decorations.begin(), decorations.end(), [](const Decoration& d) {
- return SpvDecorationRestrictPointerEXT == d.dec_type();
+ return SpvDecorationRestrictPointer == d.dec_type();
});
if (!foundAliased && !foundRestrict) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpFunctionParameter " << inst->id()
- << ": expected AliasedPointerEXT or RestrictPointerEXT for "
- "PhysicalStorageBufferEXT pointer.";
+ << ": expected AliasedPointer or RestrictPointer for "
+ "PhysicalStorageBuffer pointer.";
}
if (foundAliased && foundRestrict) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpFunctionParameter " << inst->id()
- << ": can't specify both AliasedPointerEXT and "
- "RestrictPointerEXT for PhysicalStorageBufferEXT pointer.";
+ << ": can't specify both AliasedPointer and "
+ "RestrictPointer for PhysicalStorageBuffer pointer.";
}
}
}
diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp
index b12d1e8..e9164af 100644
--- a/source/val/validate_image.cpp
+++ b/source/val/validate_image.cpp
@@ -640,65 +640,64 @@
return SPV_SUCCESS;
}
-// Checks some of the validation rules which are common to multiple opcodes.
-spv_result_t ValidateImageCommon(ValidationState_t& _, const Instruction* inst,
- const ImageTypeInfo& info) {
- const SpvOp opcode = inst->opcode();
- if (IsProj(opcode)) {
- if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D &&
- info.dim != SpvDimRect) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected Image 'Dim' parameter to be 1D, 2D, 3D or Rect";
- }
-
- if (info.multisampled != 0) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected Image 'MS' parameter to be 0";
- }
-
- if (info.arrayed != 0) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected Image 'arrayed' parameter to be 0";
- }
+// Validate OpImage*Proj* instructions
+spv_result_t ValidateImageProj(ValidationState_t& _, const Instruction* inst,
+ const ImageTypeInfo& info) {
+ if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D &&
+ info.dim != SpvDimRect) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected Image 'Dim' parameter to be 1D, 2D, 3D or Rect";
}
- if (opcode == SpvOpImageRead || opcode == SpvOpImageSparseRead ||
- opcode == SpvOpImageWrite) {
- if (info.sampled == 0) {
- } else if (info.sampled == 2) {
- if (info.dim == SpvDim1D && !_.HasCapability(SpvCapabilityImage1D)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Capability Image1D is required to access storage image";
- } else if (info.dim == SpvDimRect &&
- !_.HasCapability(SpvCapabilityImageRect)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Capability ImageRect is required to access storage image";
- } else if (info.dim == SpvDimBuffer &&
- !_.HasCapability(SpvCapabilityImageBuffer)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Capability ImageBuffer is required to access storage image";
- } else if (info.dim == SpvDimCube && info.arrayed == 1 &&
- !_.HasCapability(SpvCapabilityImageCubeArray)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Capability ImageCubeArray is required to access "
- << "storage image";
- }
+ if (info.multisampled != 0) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected Image 'MS' parameter to be 0";
+ }
- if (info.multisampled == 1 &&
- !_.HasCapability(SpvCapabilityImageMSArray)) {
-#if 0
- // TODO(atgoo@github.com) The description of this rule in the spec
- // is unclear and Glslang doesn't declare ImageMSArray. Need to clarify
- // and reenable.
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Capability ImageMSArray is required to access storage "
- << "image";
-#endif
- }
- } else {
+ if (info.arrayed != 0) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected Image 'arrayed' parameter to be 0";
+ }
+
+ return SPV_SUCCESS;
+}
+
+// Validate OpImage*Read and OpImage*Write instructions
+spv_result_t ValidateImageReadWrite(ValidationState_t& _,
+ const Instruction* inst,
+ const ImageTypeInfo& info) {
+ if (info.sampled == 2) {
+ if (info.dim == SpvDim1D && !_.HasCapability(SpvCapabilityImage1D)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected Image 'Sampled' parameter to be 0 or 2";
+ << "Capability Image1D is required to access storage image";
+ } else if (info.dim == SpvDimRect &&
+ !_.HasCapability(SpvCapabilityImageRect)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Capability ImageRect is required to access storage image";
+ } else if (info.dim == SpvDimBuffer &&
+ !_.HasCapability(SpvCapabilityImageBuffer)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Capability ImageBuffer is required to access storage image";
+ } else if (info.dim == SpvDimCube && info.arrayed == 1 &&
+ !_.HasCapability(SpvCapabilityImageCubeArray)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Capability ImageCubeArray is required to access "
+ << "storage image";
}
+
+ if (info.multisampled == 1 && !_.HasCapability(SpvCapabilityImageMSArray)) {
+#if 0
+ // TODO(atgoo@github.com) The description of this rule in the spec
+ // is unclear and Glslang doesn't declare ImageMSArray. Need to clarify
+ // and reenable.
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Capability ImageMSArray is required to access storage "
+ << "image";
+#endif
+ }
+ } else if (info.sampled != 0) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected Image 'Sampled' parameter to be 0 or 2";
}
return SPV_SUCCESS;
@@ -813,7 +812,8 @@
}
}
- // Dim is checked elsewhere.
+ // Universal checks on image type operands
+ // Dim and Format and Access Qualifier are checked elsewhere.
if (info.depth > 2) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -825,6 +825,35 @@
<< "Invalid Arrayed " << info.arrayed << " (must be 0 or 1)";
}
+ if (info.multisampled > 1) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Invalid MS " << info.multisampled << " (must be 0 or 1)";
+ }
+
+ if (info.sampled > 2) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)";
+ }
+
+ if (info.dim == SpvDimSubpassData) {
+ if (info.sampled != 2) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(6214) << "Dim SubpassData requires Sampled to be 2";
+ }
+
+ if (info.format != SpvImageFormatUnknown) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Dim SubpassData requires format Unknown";
+ }
+ } else {
+ if (info.multisampled && (info.sampled == 2) &&
+ !_.HasCapability(SpvCapabilityStorageImageMultisample)) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Capability StorageImageMultisample is required when using "
+ "multisampled storage image";
+ }
+ }
+
if (spvIsOpenCLEnv(target_env)) {
if ((info.arrayed == 1) && (info.dim != SpvDim1D) &&
(info.dim != SpvDim2D)) {
@@ -832,23 +861,22 @@
<< "In the OpenCL environment, Arrayed may only be set to 1 "
<< "when Dim is either 1D or 2D.";
}
- }
- if (info.multisampled > 1) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Invalid MS " << info.multisampled << " (must be 0 or 1)";
- }
-
- if (spvIsOpenCLEnv(target_env)) {
if (info.multisampled != 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "MS must be 0 in the OpenCL environment.";
}
- }
- if (info.sampled > 2) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)";
+ if (info.sampled != 0) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Sampled must be 0 in the OpenCL environment.";
+ }
+
+ if (info.access_qualifier == SpvAccessQualifierMax) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "In the OpenCL environment, the optional Access Qualifier"
+ << " must be present.";
+ }
}
if (spvIsVulkanEnv(target_env)) {
@@ -857,43 +885,10 @@
<< _.VkErrorID(4657)
<< "Sampled must be 1 or 2 in the Vulkan environment.";
}
- }
- if (spvIsOpenCLEnv(_.context()->target_env)) {
- if (info.sampled != 0) {
+ if (info.dim == SpvDimSubpassData && info.arrayed != 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Sampled must be 0 in the OpenCL environment.";
- }
- }
-
- if (info.dim == SpvDimSubpassData) {
- if (info.sampled != 2) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Dim SubpassData requires Sampled to be 2";
- }
-
- if (info.format != SpvImageFormatUnknown) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Dim SubpassData requires format Unknown";
- }
- }
-
- // Format and Access Qualifier are also checked elsewhere.
-
- if (spvIsOpenCLEnv(_.context()->target_env)) {
- if (info.access_qualifier == SpvAccessQualifierMax) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "In the OpenCL environment, the optional Access Qualifier"
- << " must be present.";
- }
- }
-
- if (info.multisampled && (info.sampled == 2) &&
- (info.dim != SpvDimSubpassData)) {
- if (!_.HasCapability(SpvCapabilityStorageImageMultisample)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Capability StorageImageMultisample is required when using "
- "multisampled storage image";
+ << _.VkErrorID(6214) << "Dim SubpassData requires Arrayed to be 0";
}
}
@@ -1205,7 +1200,9 @@
<< "Corrupt image type definition";
}
- if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
+ if (IsProj(opcode)) {
+ if (spv_result_t result = ValidateImageProj(_, inst, info)) return result;
+ }
if (info.multisampled) {
// When using image operands, the Sample image operand is required if and
@@ -1268,6 +1265,27 @@
return SPV_SUCCESS;
}
+// Validates anything OpImage*Dref* instruction
+spv_result_t ValidateImageDref(ValidationState_t& _, const Instruction* inst,
+ const ImageTypeInfo& info) {
+ const uint32_t dref_type = _.GetOperandTypeId(inst, 4);
+ if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Expected Dref to be of 32-bit float type";
+ }
+
+ if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (info.dim == SpvDim3D) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << _.VkErrorID(4777)
+ << "In Vulkan, OpImage*Dref* instructions must not use images "
+ "with a 3D Dim";
+ }
+ }
+
+ return SPV_SUCCESS;
+}
+
spv_result_t ValidateImageDrefLod(ValidationState_t& _,
const Instruction* inst) {
const SpvOp opcode = inst->opcode();
@@ -1295,7 +1313,9 @@
<< "Corrupt image type definition";
}
- if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
+ if (IsProj(opcode)) {
+ if (spv_result_t result = ValidateImageProj(_, inst, info)) return result;
+ }
if (info.multisampled) {
// When using image operands, the Sample image operand is required if and
@@ -1325,11 +1345,7 @@
<< " components, but given only " << actual_coord_size;
}
- const uint32_t dref_type = _.GetOperandTypeId(inst, 4);
- if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected Dref to be of 32-bit float type";
- }
+ if (spv_result_t result = ValidateImageDref(_, inst, info)) return result;
if (spv_result_t result =
ValidateImageOperands(_, inst, info, /* word_index = */ 7))
@@ -1464,7 +1480,8 @@
if (info.dim != SpvDim2D && info.dim != SpvDimCube &&
info.dim != SpvDimRect) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected Image 'Dim' cannot be Cube";
+ << _.VkErrorID(4777)
+ << "Expected Image 'Dim' to be 2D, Cube, or Rect";
}
const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
@@ -1500,11 +1517,7 @@
} else {
assert(opcode == SpvOpImageDrefGather ||
opcode == SpvOpImageSparseDrefGather);
- const uint32_t dref_type = _.GetOperandTypeId(inst, 4);
- if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "Expected Dref to be of 32-bit float type";
- }
+ if (spv_result_t result = ValidateImageDref(_, inst, info)) return result;
}
if (spv_result_t result =
@@ -1572,6 +1585,13 @@
<< " to have 4 components";
}
}
+
+ const uint32_t mask = inst->words().size() <= 5 ? 0 : inst->word(5);
+ if (mask & SpvImageOperandsConstOffsetMask) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "ConstOffset image operand not allowed "
+ << "in the OpenCL environment.";
+ }
}
if (info.dim == SpvDimSubpassData) {
@@ -1597,7 +1617,8 @@
}
}
- if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
+ if (spv_result_t result = ValidateImageReadWrite(_, inst, info))
+ return result;
const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
if (!_.IsIntScalarOrVectorType(coord_type)) {
@@ -1622,16 +1643,6 @@
}
}
- const uint32_t mask = inst->words().size() <= 5 ? 0 : inst->word(5);
-
- if (mask & SpvImageOperandsConstOffsetMask) {
- if (spvIsOpenCLEnv(_.context()->target_env)) {
- return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << "ConstOffset image operand not allowed "
- << "in the OpenCL environment.";
- }
- }
-
if (spv_result_t result =
ValidateImageOperands(_, inst, info, /* word_index = */ 6))
return result;
@@ -1657,7 +1668,8 @@
<< "Image 'Dim' cannot be SubpassData";
}
- if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
+ if (spv_result_t result = ValidateImageReadWrite(_, inst, info))
+ return result;
const uint32_t coord_type = _.GetOperandTypeId(inst, 1);
if (!_.IsIntScalarOrVectorType(coord_type)) {
diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp
index 4f3d9cd..0b23126 100644
--- a/source/val/validate_memory.cpp
+++ b/source/val/validate_memory.cpp
@@ -315,11 +315,12 @@
SpvStorageClass dst_sc, src_sc;
std::tie(dst_sc, src_sc) = GetStorageClass(_, inst);
if (inst->operands().size() <= index) {
- if (src_sc == SpvStorageClassPhysicalStorageBufferEXT ||
- dst_sc == SpvStorageClassPhysicalStorageBufferEXT) {
+ // Cases where lack of some operand is invalid
+ if (src_sc == SpvStorageClassPhysicalStorageBuffer ||
+ dst_sc == SpvStorageClassPhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "Memory accesses with PhysicalStorageBufferEXT must use "
- "Aligned.";
+ << _.VkErrorID(4708)
+ << "Memory accesses with PhysicalStorageBuffer must use Aligned.";
}
return SPV_SUCCESS;
}
@@ -368,7 +369,7 @@
dst_sc != SpvStorageClassCrossWorkgroup &&
dst_sc != SpvStorageClassGeneric && dst_sc != SpvStorageClassImage &&
dst_sc != SpvStorageClassStorageBuffer &&
- dst_sc != SpvStorageClassPhysicalStorageBufferEXT) {
+ dst_sc != SpvStorageClassPhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "NonPrivatePointerKHR requires a pointer in Uniform, "
<< "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
@@ -379,7 +380,7 @@
src_sc != SpvStorageClassCrossWorkgroup &&
src_sc != SpvStorageClassGeneric && src_sc != SpvStorageClassImage &&
src_sc != SpvStorageClassStorageBuffer &&
- src_sc != SpvStorageClassPhysicalStorageBufferEXT) {
+ src_sc != SpvStorageClassPhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "NonPrivatePointerKHR requires a pointer in Uniform, "
<< "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
@@ -388,11 +389,11 @@
}
if (!(mask & SpvMemoryAccessAlignedMask)) {
- if (src_sc == SpvStorageClassPhysicalStorageBufferEXT ||
- dst_sc == SpvStorageClassPhysicalStorageBufferEXT) {
+ if (src_sc == SpvStorageClassPhysicalStorageBuffer ||
+ dst_sc == SpvStorageClassPhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "Memory accesses with PhysicalStorageBufferEXT must use "
- "Aligned.";
+ << _.VkErrorID(4708)
+ << "Memory accesses with PhysicalStorageBuffer must use Aligned.";
}
}
@@ -519,20 +520,21 @@
}
}
- // Vulkan 14.5.1: Check type of PushConstant variables.
- // Vulkan 14.5.2: Check type of UniformConstant and Uniform variables.
if (spvIsVulkanEnv(_.context()->target_env)) {
+ // Vulkan Push Constant Interface section: Check type of PushConstant
+ // variables.
if (storage_class == SpvStorageClassPushConstant) {
- if (!IsAllowedTypeOrArrayOfSame(_, pointee, {SpvOpTypeStruct})) {
+ if (pointee->opcode() != SpvOpTypeStruct) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "PushConstant OpVariable <id> '" << _.getIdName(inst->id())
<< "' has illegal type.\n"
- << "From Vulkan spec, section 14.5.1:\n"
- << "Such variables must be typed as OpTypeStruct, "
- << "or an array of this type";
+ << "From Vulkan spec, Push Constant Interface section:\n"
+ << "Such variables must be typed as OpTypeStruct";
}
}
+ // Vulkan Descriptor Set Interface: Check type of UniformConstant and
+ // Uniform variables.
if (storage_class == SpvStorageClassUniformConstant) {
if (!IsAllowedTypeOrArrayOfSame(
_, pointee,
@@ -627,9 +629,9 @@
}
}
- if (storage_class == SpvStorageClassPhysicalStorageBufferEXT) {
+ if (storage_class == SpvStorageClassPhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "PhysicalStorageBufferEXT must not be used with OpVariable.";
+ << "PhysicalStorageBuffer must not be used with OpVariable.";
}
auto pointee_base = pointee;
@@ -638,23 +640,23 @@
}
if (pointee_base->opcode() == SpvOpTypePointer) {
if (pointee_base->GetOperandAs<uint32_t>(1u) ==
- SpvStorageClassPhysicalStorageBufferEXT) {
- // check for AliasedPointerEXT/RestrictPointerEXT
+ SpvStorageClassPhysicalStorageBuffer) {
+ // check for AliasedPointer/RestrictPointer
bool foundAliased =
- _.HasDecoration(inst->id(), SpvDecorationAliasedPointerEXT);
+ _.HasDecoration(inst->id(), SpvDecorationAliasedPointer);
bool foundRestrict =
- _.HasDecoration(inst->id(), SpvDecorationRestrictPointerEXT);
+ _.HasDecoration(inst->id(), SpvDecorationRestrictPointer);
if (!foundAliased && !foundRestrict) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpVariable " << inst->id()
- << ": expected AliasedPointerEXT or RestrictPointerEXT for "
- << "PhysicalStorageBufferEXT pointer.";
+ << ": expected AliasedPointer or RestrictPointer for "
+ << "PhysicalStorageBuffer pointer.";
}
if (foundAliased && foundRestrict) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpVariable " << inst->id()
- << ": can't specify both AliasedPointerEXT and "
- << "RestrictPointerEXT for PhysicalStorageBufferEXT pointer.";
+ << ": can't specify both AliasedPointer and "
+ << "RestrictPointer for PhysicalStorageBuffer pointer.";
}
}
}
@@ -667,7 +669,8 @@
if (value_type && value_type->opcode() == SpvOpTypeRuntimeArray) {
if (!_.HasCapability(SpvCapabilityRuntimeDescriptorArrayEXT)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpVariable, <id> '" << _.getIdName(inst->id())
+ << _.VkErrorID(4680) << "OpVariable, <id> '"
+ << _.getIdName(inst->id())
<< "', is attempting to create memory for an illegal type, "
<< "OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray can only "
<< "appear as the final member of an OpTypeStruct, thus cannot "
@@ -679,6 +682,7 @@
storage_class != SpvStorageClassUniform &&
storage_class != SpvStorageClassUniformConstant) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(4680)
<< "For Vulkan with RuntimeDescriptorArrayEXT, a variable "
<< "containing OpTypeRuntimeArray must have storage class of "
<< "StorageBuffer, Uniform, or UniformConstant.";
@@ -692,25 +696,30 @@
// as BufferBlock.
if (value_type && value_type->opcode() == SpvOpTypeStruct) {
if (DoesStructContainRTA(_, value_type)) {
- if (storage_class == SpvStorageClassStorageBuffer) {
+ if (storage_class == SpvStorageClassStorageBuffer ||
+ storage_class == SpvStorageClassPhysicalStorageBuffer) {
if (!_.HasDecoration(value_id, SpvDecorationBlock)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(4680)
<< "For Vulkan, an OpTypeStruct variable containing an "
<< "OpTypeRuntimeArray must be decorated with Block if it "
- << "has storage class StorageBuffer.";
+ << "has storage class StorageBuffer or "
+ "PhysicalStorageBuffer.";
}
} else if (storage_class == SpvStorageClassUniform) {
if (!_.HasDecoration(value_id, SpvDecorationBufferBlock)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(4680)
<< "For Vulkan, an OpTypeStruct variable containing an "
<< "OpTypeRuntimeArray must be decorated with BufferBlock "
<< "if it has storage class Uniform.";
}
} else {
return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(4680)
<< "For Vulkan, OpTypeStruct variables containing "
<< "OpTypeRuntimeArray must have storage class of "
- << "StorageBuffer or Uniform.";
+ << "StorageBuffer, PhysicalStorageBuffer, or Uniform.";
}
}
}
@@ -745,7 +754,7 @@
SPV_OPERAND_TYPE_STORAGE_CLASS, storage_class);
switch (storage_class) {
case SpvStorageClassStorageBuffer:
- case SpvStorageClassPhysicalStorageBufferEXT:
+ case SpvStorageClassPhysicalStorageBuffer:
if (!_.HasCapability(SpvCapabilityStorageBuffer16BitAccess)) {
storage_class_ok = false;
}
@@ -807,7 +816,7 @@
SPV_OPERAND_TYPE_STORAGE_CLASS, storage_class);
switch (storage_class) {
case SpvStorageClassStorageBuffer:
- case SpvStorageClassPhysicalStorageBufferEXT:
+ case SpvStorageClassPhysicalStorageBuffer:
if (!_.HasCapability(SpvCapabilityStorageBuffer8BitAccess)) {
storage_class_ok = false;
}
@@ -1138,8 +1147,6 @@
<< "'s type does not match Source <id> '"
<< _.getIdName(source_type->id()) << "'s type.";
}
-
- if (auto error = CheckMemoryAccess(_, inst, 2)) return error;
} else {
const auto size_id = inst->GetOperandAs<uint32_t>(2);
const auto size = _.FindDef(size_id);
@@ -1182,8 +1189,6 @@
// Cannot infer any other opcodes.
break;
}
-
- if (auto error = CheckMemoryAccess(_, inst, 3)) return error;
}
if (auto error = ValidateCopyMemoryMemoryAccess(_, inst)) return error;
@@ -1508,7 +1513,7 @@
if (storage_class != SpvStorageClassWorkgroup &&
storage_class != SpvStorageClassStorageBuffer &&
- storage_class != SpvStorageClassPhysicalStorageBufferEXT) {
+ storage_class != SpvStorageClassPhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " storage class for pointer type <id> '"
<< _.getIdName(pointer_type_id)
diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp
index 4376b52..2aded61 100644
--- a/source/val/validate_type.cpp
+++ b/source/val/validate_type.cpp
@@ -228,8 +228,8 @@
if (spvIsVulkanEnv(_.context()->target_env) &&
element_type->opcode() == SpvOpTypeRuntimeArray) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpTypeArray Element Type <id> '" << _.getIdName(element_type_id)
- << "' is not valid in "
+ << _.VkErrorID(4680) << "OpTypeArray Element Type <id> '"
+ << _.getIdName(element_type_id) << "' is not valid in "
<< spvLogStringForEnv(_.context()->target_env) << " environments.";
}
@@ -298,7 +298,7 @@
if (spvIsVulkanEnv(_.context()->target_env) &&
element_type->opcode() == SpvOpTypeRuntimeArray) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "OpTypeRuntimeArray Element Type <id> '"
+ << _.VkErrorID(4680) << "OpTypeRuntimeArray Element Type <id> '"
<< _.getIdName(element_id) << "' is not valid in "
<< spvLogStringForEnv(_.context()->target_env) << " environments.";
}
@@ -373,7 +373,8 @@
member_type_index == inst->operands().size() - 1;
if (!is_last_member) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
- << "In " << spvLogStringForEnv(_.context()->target_env)
+ << _.VkErrorID(4680) << "In "
+ << spvLogStringForEnv(_.context()->target_env)
<< ", OpTypeRuntimeArray must only be used for the last member "
"of an OpTypeStruct";
}
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 977a160..65c1dd6 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -460,7 +460,7 @@
default:
// fall through
case SpvAddressingModelPhysical64:
- case SpvAddressingModelPhysicalStorageBuffer64EXT:
+ case SpvAddressingModelPhysicalStorageBuffer64:
pointer_size_and_alignment_ = 8;
break;
}
@@ -1862,6 +1862,8 @@
return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
case 4677:
return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677);
+ case 4680:
+ return VUID_WRAP( VUID-StandaloneSpirv-OpTypeRuntimeArray-04680);
case 4682:
return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682);
case 6426:
@@ -1870,6 +1872,8 @@
return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
case 4686:
return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
+ case 4708:
+ return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708);
case 4710:
return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710);
case 4711:
@@ -1884,6 +1888,8 @@
return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733);
case 4734:
return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04734);
+ case 4777:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpImage-04777);
case 4780:
return VUID_WRAP(VUID-StandaloneSpirv-Result-04780);
case 4915:
@@ -1896,6 +1902,8 @@
return VUID_WRAP(VUID-StandaloneSpirv-Location-04918);
case 4919:
return VUID_WRAP(VUID-StandaloneSpirv-Location-04919);
+ case 6214:
+ return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-06214);
case 6491:
return VUID_WRAP(VUID-StandaloneSpirv-DescriptorSet-06491);
default:
diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt
index f50fdda..6dfb1b7 100644
--- a/test/opt/CMakeLists.txt
+++ b/test/opt/CMakeLists.txt
@@ -42,6 +42,7 @@
desc_sroa_test.cpp
eliminate_dead_const_test.cpp
eliminate_dead_functions_test.cpp
+ eliminate_dead_input_components_test.cpp
eliminate_dead_member_test.cpp
feature_manager_test.cpp
fix_storage_class_test.cpp
diff --git a/test/opt/eliminate_dead_input_components_test.cpp b/test/opt/eliminate_dead_input_components_test.cpp
new file mode 100644
index 0000000..b0098f7
--- /dev/null
+++ b/test/opt/eliminate_dead_input_components_test.cpp
@@ -0,0 +1,404 @@
+// Copyright (c) 2022 The Khronos Group Inc.
+// Copyright (c) 2022 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 <vector>
+
+#include "gmock/gmock.h"
+#include "test/opt/pass_fixture.h"
+#include "test/opt/pass_utils.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+using ElimDeadInputComponentsTest = PassTest<::testing::Test>;
+
+TEST_F(ElimDeadInputComponentsTest, ElimOneConstantIndex) {
+ // Should reduce to uv[2]
+ //
+ // #version 450
+ //
+ // layout(location = 0) in vec4 uv[8];
+ //
+ // out gl_PerVertex {
+ // vec4 gl_Position;
+ // };
+ //
+ // void main()
+ // {
+ // gl_Position = uv[1];
+ // }
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %_ %uv
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %gl_PerVertex "gl_PerVertex"
+ OpMemberName %gl_PerVertex 0 "gl_Position"
+ OpName %_ ""
+ OpName %uv "uv"
+ OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+ OpDecorate %gl_PerVertex Block
+ OpDecorate %uv Location 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%gl_PerVertex = OpTypeStruct %v4float
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+ %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %uint = OpTypeInt 32 0
+ %uint_8 = OpConstant %uint 8
+%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
+%_ptr_Input__arr_v4float_uint_8 = OpTypePointer Input %_arr_v4float_uint_8
+ %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+ %int_1 = OpConstant %int 1
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+;CHECK-NOT: %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+;CHECK: %uv = OpVariable %_ptr_Input__arr_v4float_uint_2 Input
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %20 = OpAccessChain %_ptr_Input_v4float %uv %int_1
+ %21 = OpLoad %v4float %20
+ %23 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+ OpStore %23 %21
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_3);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true);
+}
+
+TEST_F(ElimDeadInputComponentsTest, ElimOneConstantIndexInBounds) {
+ // Same as ElimOneConstantIndex but with OpInBoundsAccessChain
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %_ %uv
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %gl_PerVertex "gl_PerVertex"
+ OpMemberName %gl_PerVertex 0 "gl_Position"
+ OpName %_ ""
+ OpName %uv "uv"
+ OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+ OpDecorate %gl_PerVertex Block
+ OpDecorate %uv Location 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%gl_PerVertex = OpTypeStruct %v4float
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+ %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %uint = OpTypeInt 32 0
+ %uint_8 = OpConstant %uint 8
+%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
+%_ptr_Input__arr_v4float_uint_8 = OpTypePointer Input %_arr_v4float_uint_8
+ %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+ %int_1 = OpConstant %int 1
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+;CHECK-NOT: %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+;CHECK: %uv = OpVariable %_ptr_Input__arr_v4float_uint_2 Input
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %20 = OpInBoundsAccessChain %_ptr_Input_v4float %uv %int_1
+ %21 = OpLoad %v4float %20
+ %23 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+ OpStore %23 %21
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_3);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true);
+}
+
+TEST_F(ElimDeadInputComponentsTest, ElimTwoConstantIndices) {
+ // Should reduce to uv[4]
+ //
+ // #version 450
+ //
+ // layout(location = 0) in vec4 uv[8];
+ //
+ // out gl_PerVertex {
+ // vec4 gl_Position;
+ // };
+ //
+ // void main()
+ // {
+ // gl_Position = uv[1] + uv[3];
+ // }
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %_ %uv
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %gl_PerVertex "gl_PerVertex"
+ OpMemberName %gl_PerVertex 0 "gl_Position"
+ OpName %_ ""
+ OpName %uv "uv"
+ OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+ OpDecorate %gl_PerVertex Block
+ OpDecorate %uv Location 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%gl_PerVertex = OpTypeStruct %v4float
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+ %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %uint = OpTypeInt 32 0
+ %uint_8 = OpConstant %uint 8
+%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
+%_ptr_Input__arr_v4float_uint_8 = OpTypePointer Input %_arr_v4float_uint_8
+ %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+ %int_1 = OpConstant %int 1
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %int_3 = OpConstant %int 3
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+;CHECK-NOT: %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+;CHECK: %uv = OpVariable %_ptr_Input__arr_v4float_uint_4 Input
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %20 = OpAccessChain %_ptr_Input_v4float %uv %int_1
+ %21 = OpLoad %v4float %20
+ %23 = OpAccessChain %_ptr_Input_v4float %uv %int_3
+ %24 = OpLoad %v4float %23
+ %25 = OpFAdd %v4float %21 %24
+ %27 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+ OpStore %27 %25
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_3);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true);
+}
+
+TEST_F(ElimDeadInputComponentsTest, NoElimMaxConstantIndex) {
+ // Should not reduce uv[8] because of max index of 7
+ //
+ // #version 450
+ //
+ // layout(location = 0) in vec4 uv[8];
+ //
+ // out gl_PerVertex {
+ // vec4 gl_Position;
+ // };
+ //
+ // void main()
+ // {
+ // gl_Position = uv[1] + uv[7];
+ // }
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %_ %uv
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %gl_PerVertex "gl_PerVertex"
+ OpMemberName %gl_PerVertex 0 "gl_Position"
+ OpName %_ ""
+ OpName %uv "uv"
+ OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+ OpDecorate %gl_PerVertex Block
+ OpDecorate %uv Location 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%gl_PerVertex = OpTypeStruct %v4float
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+ %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %uint = OpTypeInt 32 0
+ %uint_8 = OpConstant %uint 8
+%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
+%_ptr_Input__arr_v4float_uint_8 = OpTypePointer Input %_arr_v4float_uint_8
+ %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+ %int_1 = OpConstant %int 1
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %int_7 = OpConstant %int 7
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+;CHECK: %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %20 = OpAccessChain %_ptr_Input_v4float %uv %int_1
+ %21 = OpLoad %v4float %20
+ %23 = OpAccessChain %_ptr_Input_v4float %uv %int_7
+ %24 = OpLoad %v4float %23
+ %25 = OpFAdd %v4float %21 %24
+ %27 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+ OpStore %27 %25
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_3);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true);
+}
+
+TEST_F(ElimDeadInputComponentsTest, NoElimNonConstantIndex) {
+ // Should not reduce uv[8] because of non-constant index of ui
+ //
+ // #version 450
+ //
+ // layout(location = 0) in vec4 uv[8];
+ //
+ // out gl_PerVertex {
+ // vec4 gl_Position;
+ // };
+ //
+ // uniform ubname {
+ // int ui;
+ // } ubinst;
+ //
+ // void main()
+ // {
+ // gl_Position = uv[1] + uv[ubinst.ui];
+ // }
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %_ %uv %ubinst
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %gl_PerVertex "gl_PerVertex"
+ OpMemberName %gl_PerVertex 0 "gl_Position"
+ OpName %_ ""
+ OpName %uv "uv"
+ OpName %ubname "ubname"
+ OpMemberName %ubname 0 "ui"
+ OpName %ubinst "ubinst"
+ OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+ OpDecorate %gl_PerVertex Block
+ OpDecorate %uv Location 0
+ OpMemberDecorate %ubname 0 Offset 0
+ OpDecorate %ubname Block
+ OpDecorate %ubinst DescriptorSet 0
+ OpDecorate %ubinst Binding 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%gl_PerVertex = OpTypeStruct %v4float
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+ %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %uint = OpTypeInt 32 0
+ %uint_8 = OpConstant %uint 8
+%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
+%_ptr_Input__arr_v4float_uint_8 = OpTypePointer Input %_arr_v4float_uint_8
+ %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+ %int_1 = OpConstant %int 1
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %ubname = OpTypeStruct %int
+%_ptr_Uniform_ubname = OpTypePointer Uniform %ubname
+ %ubinst = OpVariable %_ptr_Uniform_ubname Uniform
+%_ptr_Uniform_int = OpTypePointer Uniform %int
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+;CHECK: %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %20 = OpAccessChain %_ptr_Input_v4float %uv %int_1
+ %21 = OpLoad %v4float %20
+ %26 = OpAccessChain %_ptr_Uniform_int %ubinst %int_0
+ %27 = OpLoad %int %26
+ %28 = OpAccessChain %_ptr_Input_v4float %uv %27
+ %29 = OpLoad %v4float %28
+ %30 = OpFAdd %v4float %21 %29
+ %32 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+ OpStore %32 %30
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_3);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true);
+}
+
+TEST_F(ElimDeadInputComponentsTest, NoElimNonIndexedAccessChain) {
+ // Should not change due to non-indexed access chain
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %_ %uv
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %gl_PerVertex "gl_PerVertex"
+ OpMemberName %gl_PerVertex 0 "gl_Position"
+ OpName %_ ""
+ OpName %uv "uv"
+ OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+ OpDecorate %gl_PerVertex Block
+ OpDecorate %uv Location 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%gl_PerVertex = OpTypeStruct %v4float
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+ %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %uint = OpTypeInt 32 0
+ %uint_8 = OpConstant %uint 8
+%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
+%_ptr_Input__arr_v4float_uint_8 = OpTypePointer Input %_arr_v4float_uint_8
+ %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+ %int_1 = OpConstant %int 1
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+;CHECK: %uv = OpVariable %_ptr_Input__arr_v4float_uint_8 Input
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %20 = OpAccessChain %_ptr_Input__arr_v4float_uint_8 %uv
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SetTargetEnv(SPV_ENV_VULKAN_1_3);
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true);
+}
+
+} // namespace
+} // namespace opt
+} // namespace spvtools
diff --git a/test/val/val_capability_test.cpp b/test/val/val_capability_test.cpp
index c432c3c..0d84caa 100644
--- a/test/val/val_capability_test.cpp
+++ b/test/val/val_capability_test.cpp
@@ -2918,8 +2918,8 @@
"StorageTexelBufferArrayNonUniformIndexing",
"SPV_EXT_descriptor_indexing"),
// SPV_EXT_physical_storage_buffer
- IN15("PhysicalStorageBufferAddressesEXT",
- "PhysicalStorageBufferAddresses", "SPV_EXT_physical_storage_buffer"),
+ IN15("PhysicalStorageBufferAddresses", "PhysicalStorageBufferAddresses",
+ "SPV_EXT_physical_storage_buffer"),
// SPV_KHR_vulkan_memory_model
IN15("VulkanMemoryModelKHR", "VulkanMemoryModel",
"SPV_KHR_vulkan_memory_model"),
diff --git a/test/val/val_conversion_test.cpp b/test/val/val_conversion_test.cpp
index b9802ec..94bd27d 100644
--- a/test/val/val_conversion_test.cpp
+++ b/test/val/val_conversion_test.cpp
@@ -1557,7 +1557,7 @@
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 RestrictPointerEXT
+OpDecorate %val1 RestrictPointer
%uint64 = OpTypeInt 64 0
%u64_1 = OpConstant %uint64 1
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
@@ -1615,7 +1615,7 @@
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 RestrictPointerEXT
+OpDecorate %val1 RestrictPointer
%uint32 = OpTypeInt 32 0
%uint64 = OpTypeInt 64 0
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
diff --git a/test/val/val_data_test.cpp b/test/val/val_data_test.cpp
index 1d4c0e0..eef08a1 100644
--- a/test/val/val_data_test.cpp
+++ b/test/val/val_data_test.cpp
@@ -767,6 +767,8 @@
CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("In Vulkan, OpTypeRuntimeArray must only be used for "
"the last member of an OpTypeStruct\n %_struct_3 = "
"OpTypeStruct %_runtimearr_uint %uint\n"));
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index 6f5a246..9eaf825 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -5943,16 +5943,16 @@
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerSuccess) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 RestrictPointerEXT
+OpDecorate %val1 RestrictPointer
%uint64 = OpTypeInt 64 0
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%pptr_f = OpTypePointer Function %ptr
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
@@ -5969,15 +5969,15 @@
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerMissing) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%uint64 = OpTypeInt 64 0
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%pptr_f = OpTypePointer Function %ptr
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
@@ -5991,23 +5991,23 @@
CompileSuccessfully(body.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
- HasSubstr("expected AliasedPointerEXT or RestrictPointerEXT for "
- "PhysicalStorageBufferEXT pointer"));
+ HasSubstr("expected AliasedPointer or RestrictPointer for "
+ "PhysicalStorageBuffer pointer"));
}
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerBoth) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 RestrictPointerEXT
-OpDecorate %val1 AliasedPointerEXT
+OpDecorate %val1 RestrictPointer
+OpDecorate %val1 AliasedPointer
%uint64 = OpTypeInt 64 0
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%pptr_f = OpTypePointer Function %ptr
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
@@ -6020,24 +6020,23 @@
CompileSuccessfully(body.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("can't specify both AliasedPointerEXT and RestrictPointerEXT "
- "for PhysicalStorageBufferEXT pointer"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("can't specify both AliasedPointer and RestrictPointer "
+ "for PhysicalStorageBuffer pointer"));
}
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamSuccess) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpDecorate %fparam Restrict
%uint64 = OpTypeInt 64 0
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%fnptr = OpTypeFunction %void %ptr
@@ -6058,15 +6057,15 @@
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamMissing) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%uint64 = OpTypeInt 64 0
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%fnptr = OpTypeFunction %void %ptr
@@ -6085,22 +6084,22 @@
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("expected Aliased or Restrict for "
- "PhysicalStorageBufferEXT pointer"));
+ "PhysicalStorageBuffer pointer"));
}
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamBoth) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpDecorate %fparam Restrict
OpDecorate %fparam Aliased
%uint64 = OpTypeInt 64 0
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%fnptr = OpTypeFunction %void %ptr
@@ -6119,12 +6118,12 @@
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("can't specify both Aliased and Restrict for "
- "PhysicalStorageBufferEXT pointer"));
+ "PhysicalStorageBuffer pointer"));
}
TEST_F(ValidateDecorations, PSBFPRoundingModeSuccess) {
std::string spirv = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Shader
OpCapability Linkage
OpCapability StorageBuffer16BitAccess
@@ -6132,14 +6131,14 @@
OpExtension "SPV_KHR_storage_buffer_storage_class"
OpExtension "SPV_KHR_variable_pointers"
OpExtension "SPV_KHR_16bit_storage"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %main "main"
OpDecorate %_ FPRoundingMode RTE
-OpDecorate %half_ptr_var AliasedPointerEXT
+OpDecorate %half_ptr_var AliasedPointer
%half = OpTypeFloat 16
%float = OpTypeFloat 32
%float_1_25 = OpConstant %float 1.25
-%half_ptr = OpTypePointer PhysicalStorageBufferEXT %half
+%half_ptr = OpTypePointer PhysicalStorageBuffer %half
%half_pptr_f = OpTypePointer Function %half_ptr
%void = OpTypeVoid
%func = OpTypeFunction %void
diff --git a/test/val/val_fixtures.h b/test/val/val_fixtures.h
index acbe0e5..98d8d32 100644
--- a/test/val/val_fixtures.h
+++ b/test/val/val_fixtures.h
@@ -40,8 +40,10 @@
// Assembles the given SPIR-V text, checks that it fails to assemble,
// and returns resulting diagnostic. No internal state is updated.
+ // Setting the desired_result to SPV_SUCCESS is used to allow all results
std::string CompileFailure(std::string code,
- spv_target_env env = SPV_ENV_UNIVERSAL_1_0);
+ spv_target_env env = SPV_ENV_UNIVERSAL_1_0,
+ spv_result_t desired_result = SPV_SUCCESS);
// Checks that 'code' is valid SPIR-V text representation and stores the
// binary version for further method calls.
@@ -108,11 +110,17 @@
template <typename T>
std::string ValidateBase<T>::CompileFailure(std::string code,
- spv_target_env env) {
+ spv_target_env env,
+ spv_result_t desired_result) {
spv_diagnostic diagnostic = nullptr;
- EXPECT_NE(SPV_SUCCESS,
- spvTextToBinary(ScopedContext(env).context, code.c_str(),
- code.size(), &binary_, &diagnostic));
+ spv_result_t actual_result =
+ spvTextToBinary(ScopedContext(env).context, code.c_str(), code.size(),
+ &binary_, &diagnostic);
+ EXPECT_NE(SPV_SUCCESS, actual_result);
+ // optional check for exact result
+ if (desired_result != SPV_SUCCESS) {
+ EXPECT_EQ(actual_result, desired_result);
+ }
std::string result(diagnostic->error);
spvDiagnosticDestroy(diagnostic);
return result;
diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp
index a11d07c..d8f6b44 100644
--- a/test/val/val_image_test.cpp
+++ b/test/val/val_image_test.cpp
@@ -246,6 +246,11 @@
%uniform_image_u32_2d_0001 = OpVariable %ptr_image_u32_2d_0001 UniformConstant
%type_sampled_image_u32_2d_0001 = OpTypeSampledImage %type_image_u32_2d_0001
+%type_image_u32_3d_0001 = OpTypeImage %u32 3D 0 0 0 1 Unknown
+%ptr_image_u32_3d_0001 = OpTypePointer UniformConstant %type_image_u32_3d_0001
+%uniform_image_u32_3d_0001 = OpVariable %ptr_image_u32_3d_0001 UniformConstant
+%type_sampled_image_u32_3d_0001 = OpTypeSampledImage %type_image_u32_3d_0001
+
%type_image_u32_2d_0002 = OpTypeImage %u32 2D 0 0 0 2 Unknown
%ptr_image_u32_2d_0002 = OpTypePointer UniformConstant %type_image_u32_2d_0002
%uniform_image_u32_2d_0002 = OpVariable %ptr_image_u32_2d_0002 UniformConstant
@@ -272,6 +277,11 @@
%uniform_image_f32_3d_0111 = OpVariable %ptr_image_f32_3d_0111 UniformConstant
%type_sampled_image_f32_3d_0111 = OpTypeSampledImage %type_image_f32_3d_0111
+%type_image_f32_3d_0001 = OpTypeImage %f32 3D 0 0 0 1 Unknown
+%ptr_image_f32_3d_0001 = OpTypePointer UniformConstant %type_image_f32_3d_0001
+%uniform_image_f32_3d_0001 = OpVariable %ptr_image_f32_3d_0001 UniformConstant
+%type_sampled_image_f32_3d_0001 = OpTypeSampledImage %type_image_f32_3d_0001
+
%type_image_f32_cube_0101 = OpTypeImage %f32 Cube 0 1 0 1 Unknown
%ptr_image_f32_cube_0101 = OpTypePointer UniformConstant %type_image_f32_cube_0101
%uniform_image_f32_cube_0101 = OpVariable %ptr_image_f32_cube_0101 UniformConstant
@@ -738,6 +748,34 @@
HasSubstr("Dim SubpassData requires Sampled to be 2"));
}
+TEST_F(ValidateImage, TypeImageWrongSampledForSubpassDataVulkan) {
+ const std::string code = GetShaderHeader("OpCapability InputAttachment\n") +
+ R"(
+%img_type = OpTypeImage %f32 SubpassData 0 0 0 1 Unknown
+)" + TrivialMain();
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeImage-06214"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Dim SubpassData requires Sampled to be 2"));
+}
+
+TEST_F(ValidateImage, TypeImageWrongArrayForSubpassDataVulkan) {
+ const std::string code = GetShaderHeader("OpCapability InputAttachment\n") +
+ R"(
+%img_type = OpTypeImage %f32 SubpassData 0 1 0 2 Unknown
+)" + TrivialMain();
+
+ CompileSuccessfully(code.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeImage-06214"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Dim SubpassData requires Arrayed to be 0"));
+}
+
TEST_F(ValidateImage, TypeImage_OpenCL_Sampled0_OK) {
const std::string code = GetKernelHeader() + R"(
%img_type = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
@@ -1062,7 +1100,7 @@
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 137[%137] cannot be a "
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 145[%145] cannot be a "
"type"));
}
@@ -2293,6 +2331,24 @@
HasSubstr("Expected Dref to be of 32-bit float type"));
}
+TEST_F(ValidateImage, SampleDrefImplicitLodWrongDimVulkan) {
+ const std::string body = R"(
+%img = OpLoad %type_image_u32_3d_0001 %uniform_image_u32_3d_0001
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_u32_3d_0001 %img %sampler
+%res1 = OpImageSampleDrefImplicitLod %u32 %simg %f32vec3_hhh %f32_1
+)";
+
+ CompileSuccessfully(
+ GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_VULKAN_1_0).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpImage-04777"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("In Vulkan, OpImage*Dref* instructions must not use "
+ "images with a 3D Dim"));
+}
+
TEST_F(ValidateImage, SampleDrefExplicitLodSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_s32_3d_0001 %uniform_image_s32_3d_0001
@@ -3249,6 +3305,23 @@
HasSubstr("Expected Dref to be of 32-bit float type"));
}
+TEST_F(ValidateImage, DrefGatherWrongDimVulkan) {
+ const std::string body = R"(
+%img = OpLoad %type_image_f32_3d_0001 %uniform_image_f32_3d_0001
+%sampler = OpLoad %type_sampler %uniform_sampler
+%simg = OpSampledImage %type_sampled_image_f32_3d_0001 %img %sampler
+%res1 = OpImageDrefGather %f32vec4 %simg %f32vec4_0000 %f32_0_5
+)";
+
+ CompileSuccessfully(
+ GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_VULKAN_1_0).c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpImage-04777"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Expected Image 'Dim' to be 2D, Cube, or Rect"));
+}
+
TEST_F(ValidateImage, ReadSuccess1) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002
@@ -5467,7 +5540,8 @@
)";
EXPECT_THAT(CompileFailure(GenerateShaderCode(body, "", "Fragment", "",
- SPV_ENV_UNIVERSAL_1_3)),
+ SPV_ENV_UNIVERSAL_1_3),
+ SPV_ENV_UNIVERSAL_1_3, SPV_ERROR_WRONG_VERSION),
HasSubstr("Invalid image operand 'SignExtend'"));
}
@@ -5478,7 +5552,8 @@
)";
EXPECT_THAT(CompileFailure(GenerateShaderCode(body, "", "Fragment", "",
- SPV_ENV_UNIVERSAL_1_3)),
+ SPV_ENV_UNIVERSAL_1_3),
+ SPV_ENV_UNIVERSAL_1_3, SPV_ERROR_WRONG_VERSION),
HasSubstr("Invalid image operand 'ZeroExtend'"));
}
diff --git a/test/val/val_logicals_test.cpp b/test/val/val_logicals_test.cpp
index b57c743..1b76c85 100644
--- a/test/val/val_logicals_test.cpp
+++ b/test/val/val_logicals_test.cpp
@@ -1053,18 +1053,18 @@
TEST_F(ValidateLogicals, PSBSelectSuccess) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 AliasedPointerEXT
+OpDecorate %val1 AliasedPointer
%uint64 = OpTypeInt 64 0
%bool = OpTypeBool
%true = OpConstantTrue %bool
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%pptr_f = OpTypePointer Function %ptr
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp
index 7215974..f4369c6 100644
--- a/test/val/val_memory_test.cpp
+++ b/test/val/val_memory_test.cpp
@@ -833,11 +833,45 @@
)";
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("PushConstant OpVariable <id> '6[%6]' has illegal "
- "type.\nFrom Vulkan spec, section 14.5.1:\n"
- "Such variables must be typed as OpTypeStruct, "
- "or an array of this type"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("PushConstant OpVariable <id> '6[%6]' has illegal "
+ "type.\nFrom Vulkan spec, Push Constant Interface section:\n"
+ "Such variables must be typed as OpTypeStruct"));
+}
+
+TEST_F(ValidateMemory, VulkanPushConstantArrayOfStructBad) {
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %1 "main"
+ OpExecutionMode %1 OriginUpperLeft
+
+ OpDecorate %struct Block
+ OpMemberDecorate %struct 0 Offset 0
+
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %int = OpTypeInt 32 0
+ %int_1 = OpConstant %int 1
+ %struct = OpTypeStruct %float
+ %array = OpTypeArray %struct %int_1
+ %ptr = OpTypePointer PushConstant %array
+ %pc = OpVariable %ptr PushConstant
+
+ %1 = OpFunction %void None %voidfn
+ %label = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("PushConstant OpVariable <id> '10[%10]' has illegal "
+ "type.\nFrom Vulkan spec, Push Constant Interface section:\n"
+ "Such variables must be typed as OpTypeStruct"));
}
TEST_F(ValidateMemory, VulkanPushConstant) {
@@ -1563,16 +1597,16 @@
TEST_F(ValidateMemory, PSBLoadAlignedSuccess) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 AliasedPointerEXT
+OpDecorate %val1 AliasedPointer
%uint64 = OpTypeInt 64 0
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%pptr_f = OpTypePointer Function %ptr
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
@@ -1585,22 +1619,22 @@
OpFunctionEnd
)";
- CompileSuccessfully(body.c_str());
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
}
TEST_F(ValidateMemory, PSBLoadAlignedMissing) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 AliasedPointerEXT
+OpDecorate %val1 AliasedPointer
%uint64 = OpTypeInt 64 0
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%pptr_f = OpTypePointer Function %ptr
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
@@ -1613,27 +1647,61 @@
OpFunctionEnd
)";
- CompileSuccessfully(body.c_str());
- ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708"));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr(
- "Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
+ HasSubstr("Memory accesses with PhysicalStorageBuffer must use Aligned"));
+}
+
+TEST_F(ValidateMemory, PSBLoadAlignedMissingWithOtherOperand) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointer
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpLoad %uint64 %val2 Volatile
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Memory accesses with PhysicalStorageBuffer must use Aligned"));
}
TEST_F(ValidateMemory, PSBStoreAlignedSuccess) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 AliasedPointerEXT
+OpDecorate %val1 AliasedPointer
%uint64 = OpTypeInt 64 0
%u64_1 = OpConstant %uint64 1
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%pptr_f = OpTypePointer Function %ptr
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
@@ -1646,23 +1714,23 @@
OpFunctionEnd
)";
- CompileSuccessfully(body.c_str());
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
}
TEST_F(ValidateMemory, PSBStoreAlignedMissing) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 AliasedPointerEXT
+OpDecorate %val1 AliasedPointer
%uint64 = OpTypeInt 64 0
%u64_1 = OpConstant %uint64 1
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
%pptr_f = OpTypePointer Function %ptr
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
@@ -1675,27 +1743,168 @@
OpFunctionEnd
)";
- CompileSuccessfully(body.c_str());
- ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708"));
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr(
- "Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
+ HasSubstr("Memory accesses with PhysicalStorageBuffer must use Aligned"));
+}
+
+TEST_F(ValidateMemory, PSBCopyMemoryAlignedSuccess) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointer
+%int = OpTypeInt 32 0
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpLoad %ptr %val1
+OpCopyMemory %val2 %val3 Aligned 4
+OpCopyMemory %val3 %val2 Aligned 4 Aligned 4
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+}
+
+TEST_F(ValidateMemory, PSBCopyMemoryAlignedMissingTarget) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointer
+%int = OpTypeInt 32 0
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpLoad %ptr %val1
+OpCopyMemory %val2 %val3 Volatile Aligned 4
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Memory accesses with PhysicalStorageBuffer must use Aligned"));
+}
+
+TEST_F(ValidateMemory, PSBCopyMemoryAlignedMissingSource) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointer
+%int = OpTypeInt 32 0
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpLoad %ptr %val1
+OpCopyMemory %val2 %val3 Aligned 4 Volatile
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Memory accesses with PhysicalStorageBuffer must use Aligned"));
+}
+
+TEST_F(ValidateMemory, PSBCopyMemoryAlignedMissingBoth) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddresses
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointer
+%int = OpTypeInt 32 0
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpLoad %ptr %val1
+OpCopyMemory %val2 %val3 Volatile
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Memory accesses with PhysicalStorageBuffer must use Aligned"));
}
TEST_F(ValidateMemory, PSBVariable) {
const std::string body = R"(
-OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability PhysicalStorageBufferAddresses
OpCapability Int64
OpCapability Shader
OpExtension "SPV_EXT_physical_storage_buffer"
-OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
-OpDecorate %val1 AliasedPointerEXT
+OpDecorate %val1 AliasedPointer
%uint64 = OpTypeInt 64 0
-%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
-%val1 = OpVariable %ptr PhysicalStorageBufferEXT
+%ptr = OpTypePointer PhysicalStorageBuffer %uint64
+%val1 = OpVariable %ptr PhysicalStorageBuffer
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%main = OpFunction %void None %voidfn
@@ -1708,7 +1917,7 @@
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
- HasSubstr("PhysicalStorageBufferEXT must not be used with OpVariable"));
+ HasSubstr("PhysicalStorageBuffer must not be used with OpVariable"));
}
std::string GenCoopMatLoadStoreShader(const std::string& storeMemoryAccess,
@@ -2097,6 +2306,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
@@ -2162,6 +2373,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("For Vulkan with RuntimeDescriptorArrayEXT, a variable "
@@ -2217,11 +2430,14 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"For Vulkan, OpTypeStruct variables containing OpTypeRuntimeArray "
- "must have storage class of StorageBuffer or Uniform.\n %6 = "
+ "must have storage class of StorageBuffer, PhysicalStorageBuffer, or "
+ "Uniform.\n %6 = "
"OpVariable %_ptr_Workgroup__struct_4 Workgroup\n"));
}
@@ -2247,9 +2463,12 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("For Vulkan, an OpTypeStruct variable containing an "
"OpTypeRuntimeArray must be decorated with Block if it "
- "has storage class StorageBuffer.\n %6 = OpVariable "
+ "has storage class StorageBuffer or "
+ "PhysicalStorageBuffer.\n %6 = OpVariable "
"%_ptr_StorageBuffer__struct_4 StorageBuffer\n"));
}
@@ -2301,6 +2520,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("For Vulkan, an OpTypeStruct variable containing an "
"OpTypeRuntimeArray must be decorated with BufferBlock "
"if it has storage class Uniform.\n %6 = OpVariable "
@@ -2328,6 +2549,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
@@ -2361,6 +2584,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
@@ -2423,6 +2648,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
@@ -2459,6 +2686,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
@@ -2490,6 +2719,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("OpTypeArray Element Type <id> '5[%_runtimearr_4]' is not "
@@ -2524,6 +2755,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
@@ -2558,6 +2791,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
@@ -2595,6 +2830,8 @@
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index 63511a6..0129478 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -208,6 +208,10 @@
unused stores to vector components, that are not removed by
aggressive dead code elimination.)");
printf(R"(
+ --eliminate-dead-input-components
+ Deletes unused components from input variables. Currently
+ deletes trailing unused elements from input arrays.)");
+ printf(R"(
--eliminate-dead-variables
Deletes module scope variables that are not referenced.)");
printf(R"(