Updated spirv-tools.
This commit is contained in:
parent
c3405c13ff
commit
a91c5a877e
1
3rdparty/spirv-tools/Android.mk
vendored
1
3rdparty/spirv-tools/Android.mk
vendored
@ -98,6 +98,7 @@ SPVTOOLS_OPT_SRC_FILES := \
|
||||
source/opt/dominator_tree.cpp \
|
||||
source/opt/eliminate_dead_constant_pass.cpp \
|
||||
source/opt/eliminate_dead_functions_pass.cpp \
|
||||
source/opt/eliminate_dead_functions_util.cpp \
|
||||
source/opt/feature_manager.cpp \
|
||||
source/opt/flatten_decoration_pass.cpp \
|
||||
source/opt/fold.cpp \
|
||||
|
2
3rdparty/spirv-tools/BUILD.gn
vendored
2
3rdparty/spirv-tools/BUILD.gn
vendored
@ -496,6 +496,8 @@ static_library("spvtools_opt") {
|
||||
"source/opt/eliminate_dead_constant_pass.h",
|
||||
"source/opt/eliminate_dead_functions_pass.cpp",
|
||||
"source/opt/eliminate_dead_functions_pass.h",
|
||||
"source/opt/eliminate_dead_functions_util.cpp",
|
||||
"source/opt/eliminate_dead_functions_util.h",
|
||||
"source/opt/feature_manager.cpp",
|
||||
"source/opt/feature_manager.h",
|
||||
"source/opt/flatten_decoration_pass.cpp",
|
||||
|
12
3rdparty/spirv-tools/README.md
vendored
12
3rdparty/spirv-tools/README.md
vendored
@ -432,6 +432,18 @@ The validator operates on the binary form.
|
||||
* `spirv-val` - the standalone validator
|
||||
* `<spirv-dir>/tools/val`
|
||||
|
||||
### Reducer tool
|
||||
|
||||
The reducer shrinks a SPIR-V binary module, guided by a user-supplied
|
||||
*interestingness test*.
|
||||
|
||||
This is a work in progress, with initially only shrinks a module in a few ways.
|
||||
|
||||
* `spirv-reduce` - the standalone reducer
|
||||
* `<spirv-dir>/tools/reduce`
|
||||
|
||||
Run `spirv-reduce --help` to see how to specify interestingness.
|
||||
|
||||
### Control flow dumper tool
|
||||
|
||||
The control flow dumper prints the control flow graph for a SPIR-V module as a
|
||||
|
@ -1 +1 @@
|
||||
"v2019.2-dev", "SPIRV-Tools v2019.2-dev 6bc0c3fb0a18b013fc222ac6173abaff22f65a39"
|
||||
"v2019.2-dev", "SPIRV-Tools v2019.2-dev c3405c13ff287fcc881a3244dafd761d40edaa50"
|
||||
|
@ -30,17 +30,17 @@ namespace spvtools {
|
||||
|
||||
// Stream Output Buffer Offsets
|
||||
//
|
||||
// The following values provide 32-bit word offsets into the output buffer
|
||||
// The following values provide offsets into the output buffer struct
|
||||
// generated by InstrumentPass::GenDebugStreamWrite. This method is utilized
|
||||
// by InstBindlessCheckPass.
|
||||
//
|
||||
// The first word of the debug output buffer contains the next available word
|
||||
// The first member of the debug output buffer contains the next available word
|
||||
// in the data stream to be written. Shaders will atomically read and update
|
||||
// this value so as not to overwrite each others records. This value must be
|
||||
// initialized to zero
|
||||
static const int kDebugOutputSizeOffset = 0;
|
||||
|
||||
// The second word of the output buffer is the start of the stream of records
|
||||
// The second member of the output buffer is the start of the stream of records
|
||||
// written by the instrumented shaders. Each record represents a validation
|
||||
// error. The format of the records is documented below.
|
||||
static const int kDebugOutputDataOffset = 1;
|
||||
@ -122,14 +122,45 @@ static const int kInstMaxOutCnt = kInstStageOutCnt + 3;
|
||||
// These are the possible validation error codes.
|
||||
static const int kInstErrorBindlessBounds = 0;
|
||||
|
||||
// Direct Input Buffer Offsets
|
||||
//
|
||||
// The following values provide member offsets into the input buffers
|
||||
// consumed by InstrumentPass::GenDebugDirectRead(). This method is utilized
|
||||
// by InstBindlessCheckPass.
|
||||
//
|
||||
// The only object in an input buffer is a runtime array of unsigned
|
||||
// integers. Each validation will have its own formatting of this array.
|
||||
static const int kDebugInputDataOffset = 0;
|
||||
|
||||
// Debug Buffer Bindings
|
||||
//
|
||||
// These are the bindings for the different buffers which are
|
||||
// read or written by the instrumentation passes.
|
||||
//
|
||||
// This is the output buffer written by InstBindlessCheckPass.
|
||||
// This is the output buffer written by InstBindlessCheckPass
|
||||
// and possibly other future validations.
|
||||
static const int kDebugOutputBindingStream = 0;
|
||||
|
||||
// The binding for the input buffer for InstBindlessCheckPass. The input
|
||||
// buffer needs only be created if the shaders being validated contain a
|
||||
// descriptor array of runtime size, and validation of runtime size descriptor
|
||||
// arrays have been enabled at the time of the bindless validation pass
|
||||
// creation.
|
||||
static const int kDebugInputBindingBindless = 1;
|
||||
|
||||
// Bindless Validation Input Buffer Format
|
||||
//
|
||||
// An input buffer for bindless validation consists of a single array of
|
||||
// unsigned integers we will call Data[]. This array is formatted as follows.
|
||||
//
|
||||
// At the beginning of the array is a single uint reserved for future use.
|
||||
static const int kDebugInputBindlessOffsetReserved = 0;
|
||||
|
||||
// Following the reserved uint is some number of uints such that the following
|
||||
// is true: the number of descriptors at (set=s, binding=b) is:
|
||||
// Data[ Data[ s + kDebugInputBindlessOffsetLengths ] + b ]
|
||||
static const int kDebugInputBindlessOffsetLengths = 1;
|
||||
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_
|
||||
|
@ -445,6 +445,10 @@ typedef enum {
|
||||
// Returns a string describing the given SPIR-V target environment.
|
||||
SPIRV_TOOLS_EXPORT const char* spvTargetEnvDescription(spv_target_env env);
|
||||
|
||||
// Parses s into *env and returns true if successful. If unparsable, returns
|
||||
// false and sets *env to SPV_ENV_UNIVERSAL_1_0.
|
||||
SPIRV_TOOLS_EXPORT bool spvParseTargetEnv(const char* s, spv_target_env* env);
|
||||
|
||||
// Creates a context object. Returns null if env is invalid.
|
||||
SPIRV_TOOLS_EXPORT spv_context spvContextCreate(spv_target_env env);
|
||||
|
||||
|
@ -711,10 +711,12 @@ Optimizer::PassToken CreateCombineAccessChainsPass();
|
||||
// The instrumentation will read and write buffers in debug
|
||||
// descriptor set |desc_set|. It will write |shader_id| in each output record
|
||||
// to identify the shader module which generated the record.
|
||||
// |runtime_array_enable| controls instrumentation of runtime arrays which
|
||||
// require input buffer support.
|
||||
//
|
||||
// TODO(greg-lunarg): Add support for vk_ext_descriptor_indexing.
|
||||
Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set,
|
||||
uint32_t shader_id);
|
||||
Optimizer::PassToken CreateInstBindlessCheckPass(
|
||||
uint32_t desc_set, uint32_t shader_id, bool runtime_array_enable = false);
|
||||
|
||||
// Create a pass to upgrade to the VulkanKHR memory model.
|
||||
// This pass upgrades the Logical GLSL450 memory model to Logical VulkanKHR.
|
||||
|
@ -37,7 +37,7 @@ cd $SHADERC_DIR/third_party
|
||||
|
||||
# Get shaderc dependencies. Link the appropriate SPIRV-Tools.
|
||||
git clone https://github.com/google/googletest.git
|
||||
git clone https://github.com/google/glslang.git
|
||||
git clone https://github.com/KhronosGroup/glslang.git
|
||||
ln -s $GITHUB_DIR/SPIRV-Tools spirv-tools
|
||||
git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-headers
|
||||
git clone https://github.com/google/re2
|
||||
|
@ -37,6 +37,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
||||
dominator_tree.h
|
||||
eliminate_dead_constant_pass.h
|
||||
eliminate_dead_functions_pass.h
|
||||
eliminate_dead_functions_util.h
|
||||
feature_manager.h
|
||||
flatten_decoration_pass.h
|
||||
fold.h
|
||||
@ -131,6 +132,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
||||
dominator_tree.cpp
|
||||
eliminate_dead_constant_pass.cpp
|
||||
eliminate_dead_functions_pass.cpp
|
||||
eliminate_dead_functions_util.cpp
|
||||
feature_manager.cpp
|
||||
flatten_decoration_pass.cpp
|
||||
fold.cpp
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/opt/eliminate_dead_functions_pass.h"
|
||||
#include "source/opt/eliminate_dead_functions_util.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
@ -36,8 +37,8 @@ Pass::Status EliminateDeadFunctionsPass::Process() {
|
||||
funcIter != get_module()->end();) {
|
||||
if (live_function_set.count(&*funcIter) == 0) {
|
||||
modified = true;
|
||||
EliminateFunction(&*funcIter);
|
||||
funcIter = funcIter.Erase();
|
||||
funcIter =
|
||||
eliminatedeadfunctionsutil::EliminateFunction(context(), &funcIter);
|
||||
} else {
|
||||
++funcIter;
|
||||
}
|
||||
@ -47,10 +48,5 @@ Pass::Status EliminateDeadFunctionsPass::Process() {
|
||||
: Pass::Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
void EliminateDeadFunctionsPass::EliminateFunction(Function* func) {
|
||||
// Remove all of the instruction in the function body
|
||||
func->ForEachInst([this](Instruction* inst) { context()->KillInst(inst); },
|
||||
true);
|
||||
}
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
32
3rdparty/spirv-tools/source/opt/eliminate_dead_functions_util.cpp
vendored
Normal file
32
3rdparty/spirv-tools/source/opt/eliminate_dead_functions_util.cpp
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// 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 "eliminate_dead_functions_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
namespace eliminatedeadfunctionsutil {
|
||||
|
||||
Module::iterator EliminateFunction(IRContext* context,
|
||||
Module::iterator* func_iter) {
|
||||
(*func_iter)
|
||||
->ForEachInst([context](Instruction* inst) { context->KillInst(inst); },
|
||||
true);
|
||||
return func_iter->Erase();
|
||||
}
|
||||
|
||||
} // namespace eliminatedeadfunctionsutil
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
36
3rdparty/spirv-tools/source/opt/eliminate_dead_functions_util.h
vendored
Normal file
36
3rdparty/spirv-tools/source/opt/eliminate_dead_functions_util.h
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// 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_FUNCTIONS_UTIL_H_
|
||||
#define SOURCE_OPT_ELIMINATE_DEAD_FUNCTIONS_UTIL_H_
|
||||
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
// Provides functionality for eliminating functions that are not needed, for use
|
||||
// by various analyses and passes.
|
||||
namespace eliminatedeadfunctionsutil {
|
||||
|
||||
// Removes all of the function's instructions, removes the function from the
|
||||
// module, and returns the next iterator.
|
||||
Module::iterator EliminateFunction(IRContext* context,
|
||||
Module::iterator* func_iter);
|
||||
|
||||
} // namespace eliminatedeadfunctionsutil
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_OPT_ELIMINATE_DEAD_FUNCTIONS_UTIL_H_
|
@ -35,6 +35,18 @@ static const int kSpvConstantValueInIdx = 0;
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
uint32_t InstBindlessCheckPass::GenDebugReadLength(
|
||||
uint32_t image_id, InstructionBuilder* builder) {
|
||||
uint32_t desc_set_idx =
|
||||
var2desc_set_[image_id] + kDebugInputBindlessOffsetLengths;
|
||||
uint32_t desc_set_idx_id = builder->GetUintConstantId(desc_set_idx);
|
||||
uint32_t desc_set_offset_id = GenDebugDirectRead(desc_set_idx_id, builder);
|
||||
Instruction* binding_idx_inst =
|
||||
builder->AddBinaryOp(GetUintId(), SpvOpIAdd, desc_set_offset_id,
|
||||
builder->GetUintConstantId(var2binding_[image_id]));
|
||||
return GenDebugDirectRead(binding_idx_inst->result_id(), builder);
|
||||
}
|
||||
|
||||
void InstBindlessCheckPass::GenBindlessCheckCode(
|
||||
BasicBlock::iterator ref_inst_itr,
|
||||
UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t instruction_idx,
|
||||
@ -119,20 +131,23 @@ void InstBindlessCheckPass::GenBindlessCheckCode(
|
||||
uint32_t ptr_type_id =
|
||||
var_type_inst->GetSingleWordInOperand(kSpvTypePointerTypeIdInIdx);
|
||||
Instruction* ptr_type_inst = get_def_use_mgr()->GetDef(ptr_type_id);
|
||||
// TODO(greg-lunarg): Handle RuntimeArray. Will need to pull length
|
||||
// out of debug input buffer.
|
||||
if (ptr_type_inst->opcode() != SpvOpTypeArray) return;
|
||||
// If index and bound both compile-time constants and index < bound,
|
||||
// return without changing
|
||||
uint32_t length_id =
|
||||
ptr_type_inst->GetSingleWordInOperand(kSpvTypeArrayLengthIdInIdx);
|
||||
Instruction* index_inst = get_def_use_mgr()->GetDef(index_id);
|
||||
Instruction* length_inst = get_def_use_mgr()->GetDef(length_id);
|
||||
if (index_inst->opcode() == SpvOpConstant &&
|
||||
length_inst->opcode() == SpvOpConstant &&
|
||||
index_inst->GetSingleWordInOperand(kSpvConstantValueInIdx) <
|
||||
length_inst->GetSingleWordInOperand(kSpvConstantValueInIdx))
|
||||
uint32_t length_id = 0;
|
||||
if (ptr_type_inst->opcode() == SpvOpTypeArray) {
|
||||
length_id =
|
||||
ptr_type_inst->GetSingleWordInOperand(kSpvTypeArrayLengthIdInIdx);
|
||||
Instruction* index_inst = get_def_use_mgr()->GetDef(index_id);
|
||||
Instruction* length_inst = get_def_use_mgr()->GetDef(length_id);
|
||||
if (index_inst->opcode() == SpvOpConstant &&
|
||||
length_inst->opcode() == SpvOpConstant &&
|
||||
index_inst->GetSingleWordInOperand(kSpvConstantValueInIdx) <
|
||||
length_inst->GetSingleWordInOperand(kSpvConstantValueInIdx))
|
||||
return;
|
||||
} else if (!runtime_array_enabled_ ||
|
||||
ptr_type_inst->opcode() != SpvOpTypeRuntimeArray) {
|
||||
return;
|
||||
}
|
||||
// Generate full runtime bounds test code with true branch
|
||||
// being full reference and false branch being debug output and zero
|
||||
// for the referenced value.
|
||||
@ -141,6 +156,13 @@ void InstBindlessCheckPass::GenBindlessCheckCode(
|
||||
context(), &*new_blk_ptr,
|
||||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
||||
uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBounds);
|
||||
// If length id not yet set, descriptor array is runtime size so
|
||||
// generate load of length from stage's debug input buffer.
|
||||
if (length_id == 0) {
|
||||
assert(ptr_type_inst->opcode() == SpvOpTypeRuntimeArray &&
|
||||
"unexpected bindless type");
|
||||
length_id = GenDebugReadLength(image_id, &builder);
|
||||
}
|
||||
Instruction* ult_inst =
|
||||
builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, index_id, length_id);
|
||||
uint32_t merge_blk_id = TakeNextId();
|
||||
@ -236,6 +258,18 @@ void InstBindlessCheckPass::InitializeInstBindlessCheck() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If descriptor indexing extension and runtime array support enabled,
|
||||
// create variable to descriptor set mapping.
|
||||
if (ext_descriptor_indexing_defined_ && runtime_array_enabled_)
|
||||
for (auto& anno : get_module()->annotations())
|
||||
if (anno.opcode() == SpvOpDecorate) {
|
||||
if (anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet)
|
||||
var2desc_set_[anno.GetSingleWordInOperand(0u)] =
|
||||
anno.GetSingleWordInOperand(2u);
|
||||
else if (anno.GetSingleWordInOperand(1u) == SpvDecorationBinding)
|
||||
var2binding_[anno.GetSingleWordInOperand(0u)] =
|
||||
anno.GetSingleWordInOperand(2u);
|
||||
}
|
||||
}
|
||||
|
||||
Pass::Status InstBindlessCheckPass::ProcessImpl() {
|
||||
|
@ -29,10 +29,14 @@ namespace opt {
|
||||
class InstBindlessCheckPass : public InstrumentPass {
|
||||
public:
|
||||
// For test harness only
|
||||
InstBindlessCheckPass() : InstrumentPass(7, 23, kInstValidationIdBindless) {}
|
||||
InstBindlessCheckPass()
|
||||
: InstrumentPass(7, 23, kInstValidationIdBindless),
|
||||
runtime_array_enabled_(true) {}
|
||||
// For all other interfaces
|
||||
InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id)
|
||||
: InstrumentPass(desc_set, shader_id, kInstValidationIdBindless) {}
|
||||
InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
|
||||
bool runtime_array_enable)
|
||||
: InstrumentPass(desc_set, shader_id, kInstValidationIdBindless),
|
||||
runtime_array_enabled_(runtime_array_enable) {}
|
||||
|
||||
~InstBindlessCheckPass() override = default;
|
||||
|
||||
@ -42,6 +46,10 @@ class InstBindlessCheckPass : public InstrumentPass {
|
||||
const char* name() const override { return "inst-bindless-check-pass"; }
|
||||
|
||||
private:
|
||||
// Generate instructions into |builder| to read length of runtime descriptor
|
||||
// array |image_id| from debug input buffer and return id of value.
|
||||
uint32_t GenDebugReadLength(uint32_t image_id, InstructionBuilder* builder);
|
||||
|
||||
// Initialize state for instrumenting bindless checking
|
||||
void InitializeInstBindlessCheck();
|
||||
|
||||
@ -85,6 +93,15 @@ class InstBindlessCheckPass : public InstrumentPass {
|
||||
|
||||
// True if VK_EXT_descriptor_indexing is defined
|
||||
bool ext_descriptor_indexing_defined_;
|
||||
|
||||
// Enable instrumentation of runtime arrays
|
||||
bool runtime_array_enabled_;
|
||||
|
||||
// Mapping from variable to descriptor set
|
||||
std::unordered_map<uint32_t, uint32_t> var2desc_set_;
|
||||
|
||||
// Mapping from variable to binding
|
||||
std::unordered_map<uint32_t, uint32_t> var2binding_;
|
||||
};
|
||||
|
||||
} // namespace opt
|
||||
|
148
3rdparty/spirv-tools/source/opt/instrument_pass.cpp
vendored
148
3rdparty/spirv-tools/source/opt/instrument_pass.cpp
vendored
@ -107,7 +107,7 @@ void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
|
||||
builder->AddBinaryOp(GetUintId(), SpvOpIAdd, base_offset_id,
|
||||
builder->GetUintConstantId(field_offset));
|
||||
uint32_t buf_id = GetOutputBufferId();
|
||||
uint32_t buf_uint_ptr_id = GetOutputBufferUintPtrId();
|
||||
uint32_t buf_uint_ptr_id = GetBufferUintPtrId();
|
||||
Instruction* achain_inst =
|
||||
builder->AddTernaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
|
||||
builder->GetUintConstantId(kDebugOutputDataOffset),
|
||||
@ -222,6 +222,18 @@ void InstrumentPass::GenDebugStreamWrite(
|
||||
(void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall, args);
|
||||
}
|
||||
|
||||
uint32_t InstrumentPass::GenDebugDirectRead(uint32_t idx_id,
|
||||
InstructionBuilder* builder) {
|
||||
uint32_t input_buf_id = GetInputBufferId();
|
||||
uint32_t buf_uint_ptr_id = GetBufferUintPtrId();
|
||||
Instruction* ibuf_ac_inst = builder->AddTernaryOp(
|
||||
buf_uint_ptr_id, SpvOpAccessChain, input_buf_id,
|
||||
builder->GetUintConstantId(kDebugInputDataOffset), idx_id);
|
||||
Instruction* load_inst =
|
||||
builder->AddUnaryOp(GetUintId(), SpvOpLoad, ibuf_ac_inst->result_id());
|
||||
return load_inst->result_id();
|
||||
}
|
||||
|
||||
bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const {
|
||||
return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage;
|
||||
}
|
||||
@ -280,12 +292,12 @@ void InstrumentPass::UpdateSucceedingPhis(
|
||||
}
|
||||
|
||||
// Return id for output buffer uint ptr type
|
||||
uint32_t InstrumentPass::GetOutputBufferUintPtrId() {
|
||||
if (output_buffer_uint_ptr_id_ == 0) {
|
||||
output_buffer_uint_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
|
||||
uint32_t InstrumentPass::GetBufferUintPtrId() {
|
||||
if (buffer_uint_ptr_id_ == 0) {
|
||||
buffer_uint_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
|
||||
GetUintId(), SpvStorageClassStorageBuffer);
|
||||
}
|
||||
return output_buffer_uint_ptr_id_;
|
||||
return buffer_uint_ptr_id_;
|
||||
}
|
||||
|
||||
uint32_t InstrumentPass::GetOutputBufferBinding() {
|
||||
@ -298,22 +310,74 @@ uint32_t InstrumentPass::GetOutputBufferBinding() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t InstrumentPass::GetInputBufferBinding() {
|
||||
switch (validation_id_) {
|
||||
case kInstValidationIdBindless:
|
||||
return kDebugInputBindingBindless;
|
||||
default:
|
||||
assert(false && "unexpected validation id");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
analysis::Type* InstrumentPass::GetUintRuntimeArrayType(
|
||||
analysis::DecorationManager* deco_mgr, analysis::TypeManager* type_mgr) {
|
||||
if (uint_rarr_ty_ == nullptr) {
|
||||
analysis::Integer uint_ty(32, false);
|
||||
analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
|
||||
analysis::RuntimeArray uint_rarr_ty_tmp(reg_uint_ty);
|
||||
uint_rarr_ty_ = type_mgr->GetRegisteredType(&uint_rarr_ty_tmp);
|
||||
uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(uint_rarr_ty_);
|
||||
// By the Vulkan spec, a pre-existing RuntimeArray of uint must be part of
|
||||
// a block, and will therefore be decorated with an ArrayStride. Therefore
|
||||
// the undecorated type returned here will not be pre-existing and can
|
||||
// safely be decorated. Since this type is now decorated, it is out of
|
||||
// sync with the TypeManager and therefore the TypeManager must be
|
||||
// invalidated after this pass.
|
||||
assert(context()->get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 &&
|
||||
"used RuntimeArray type returned");
|
||||
deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride, 4u);
|
||||
}
|
||||
return uint_rarr_ty_;
|
||||
}
|
||||
|
||||
void InstrumentPass::AddStorageBufferExt() {
|
||||
if (storage_buffer_ext_defined_) return;
|
||||
if (!get_feature_mgr()->HasExtension(kSPV_KHR_storage_buffer_storage_class)) {
|
||||
const std::string ext_name("SPV_KHR_storage_buffer_storage_class");
|
||||
const auto num_chars = ext_name.size();
|
||||
// Compute num words, accommodate the terminating null character.
|
||||
const auto num_words = (num_chars + 1 + 3) / 4;
|
||||
std::vector<uint32_t> ext_words(num_words, 0u);
|
||||
std::memcpy(ext_words.data(), ext_name.data(), num_chars);
|
||||
context()->AddExtension(std::unique_ptr<Instruction>(
|
||||
new Instruction(context(), SpvOpExtension, 0u, 0u,
|
||||
{{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
|
||||
}
|
||||
storage_buffer_ext_defined_ = true;
|
||||
}
|
||||
|
||||
// Return id for output buffer
|
||||
uint32_t InstrumentPass::GetOutputBufferId() {
|
||||
if (output_buffer_id_ == 0) {
|
||||
// If not created yet, create one
|
||||
analysis::DecorationManager* deco_mgr = get_decoration_mgr();
|
||||
analysis::TypeManager* type_mgr = context()->get_type_mgr();
|
||||
analysis::Type* reg_uint_rarr_ty =
|
||||
GetUintRuntimeArrayType(deco_mgr, type_mgr);
|
||||
analysis::Integer uint_ty(32, false);
|
||||
analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
|
||||
analysis::RuntimeArray uint_rarr_ty(reg_uint_ty);
|
||||
analysis::Type* reg_uint_rarr_ty =
|
||||
type_mgr->GetRegisteredType(&uint_rarr_ty);
|
||||
uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(reg_uint_rarr_ty);
|
||||
deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride, 4u);
|
||||
analysis::Struct obuf_ty({reg_uint_ty, reg_uint_rarr_ty});
|
||||
analysis::Type* reg_obuf_ty = type_mgr->GetRegisteredType(&obuf_ty);
|
||||
uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_obuf_ty);
|
||||
analysis::Struct buf_ty({reg_uint_ty, reg_uint_rarr_ty});
|
||||
analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
|
||||
uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
|
||||
// By the Vulkan spec, a pre-existing struct containing a RuntimeArray
|
||||
// must be a block, and will therefore be decorated with Block. Therefore
|
||||
// the undecorated type returned here will not be pre-existing and can
|
||||
// safely be decorated. Since this type is now decorated, it is out of
|
||||
// sync with the TypeManager and therefore the TypeManager must be
|
||||
// invalidated after this pass.
|
||||
assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
|
||||
"used struct type returned");
|
||||
deco_mgr->AddDecoration(obufTyId, SpvDecorationBlock);
|
||||
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
|
||||
SpvDecorationOffset, 0);
|
||||
@ -331,23 +395,48 @@ uint32_t InstrumentPass::GetOutputBufferId() {
|
||||
desc_set_);
|
||||
deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationBinding,
|
||||
GetOutputBufferBinding());
|
||||
// Look for storage buffer extension. If none, create one.
|
||||
if (!get_feature_mgr()->HasExtension(
|
||||
kSPV_KHR_storage_buffer_storage_class)) {
|
||||
const std::string ext_name("SPV_KHR_storage_buffer_storage_class");
|
||||
const auto num_chars = ext_name.size();
|
||||
// Compute num words, accommodate the terminating null character.
|
||||
const auto num_words = (num_chars + 1 + 3) / 4;
|
||||
std::vector<uint32_t> ext_words(num_words, 0u);
|
||||
std::memcpy(ext_words.data(), ext_name.data(), num_chars);
|
||||
context()->AddExtension(std::unique_ptr<Instruction>(
|
||||
new Instruction(context(), SpvOpExtension, 0u, 0u,
|
||||
{{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
|
||||
}
|
||||
AddStorageBufferExt();
|
||||
}
|
||||
return output_buffer_id_;
|
||||
}
|
||||
|
||||
uint32_t InstrumentPass::GetInputBufferId() {
|
||||
if (input_buffer_id_ == 0) {
|
||||
// If not created yet, create one
|
||||
analysis::DecorationManager* deco_mgr = get_decoration_mgr();
|
||||
analysis::TypeManager* type_mgr = context()->get_type_mgr();
|
||||
analysis::Type* reg_uint_rarr_ty =
|
||||
GetUintRuntimeArrayType(deco_mgr, type_mgr);
|
||||
analysis::Struct buf_ty({reg_uint_rarr_ty});
|
||||
analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
|
||||
uint32_t ibufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
|
||||
// By the Vulkan spec, a pre-existing struct containing a RuntimeArray
|
||||
// must be a block, and will therefore be decorated with Block. Therefore
|
||||
// the undecorated type returned here will not be pre-existing and can
|
||||
// safely be decorated. Since this type is now decorated, it is out of
|
||||
// sync with the TypeManager and therefore the TypeManager must be
|
||||
// invalidated after this pass.
|
||||
assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 &&
|
||||
"used struct type returned");
|
||||
deco_mgr->AddDecoration(ibufTyId, SpvDecorationBlock);
|
||||
deco_mgr->AddMemberDecoration(ibufTyId, 0, SpvDecorationOffset, 0);
|
||||
uint32_t ibufTyPtrId_ =
|
||||
type_mgr->FindPointerToType(ibufTyId, SpvStorageClassStorageBuffer);
|
||||
input_buffer_id_ = TakeNextId();
|
||||
std::unique_ptr<Instruction> newVarOp(new Instruction(
|
||||
context(), SpvOpVariable, ibufTyPtrId_, input_buffer_id_,
|
||||
{{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
|
||||
{SpvStorageClassStorageBuffer}}}));
|
||||
context()->AddGlobalValue(std::move(newVarOp));
|
||||
deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationDescriptorSet,
|
||||
desc_set_);
|
||||
deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationBinding,
|
||||
GetInputBufferBinding());
|
||||
AddStorageBufferExt();
|
||||
}
|
||||
return input_buffer_id_;
|
||||
}
|
||||
|
||||
uint32_t InstrumentPass::GetVec4FloatId() {
|
||||
if (v4float_id_ == 0) {
|
||||
analysis::TypeManager* type_mgr = context()->get_type_mgr();
|
||||
@ -447,7 +536,7 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
|
||||
// Gen test if debug output buffer size will not be exceeded.
|
||||
uint32_t obuf_record_sz = kInstStageOutCnt + val_spec_param_cnt;
|
||||
uint32_t buf_id = GetOutputBufferId();
|
||||
uint32_t buf_uint_ptr_id = GetOutputBufferUintPtrId();
|
||||
uint32_t buf_uint_ptr_id = GetBufferUintPtrId();
|
||||
Instruction* obuf_curr_sz_ac_inst =
|
||||
builder.AddBinaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
|
||||
builder.GetUintConstantId(kDebugOutputSizeOffset));
|
||||
@ -620,14 +709,17 @@ bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
|
||||
|
||||
void InstrumentPass::InitializeInstrument() {
|
||||
output_buffer_id_ = 0;
|
||||
output_buffer_uint_ptr_id_ = 0;
|
||||
buffer_uint_ptr_id_ = 0;
|
||||
output_func_id_ = 0;
|
||||
output_func_param_cnt_ = 0;
|
||||
input_buffer_id_ = 0;
|
||||
v4float_id_ = 0;
|
||||
uint_id_ = 0;
|
||||
v4uint_id_ = 0;
|
||||
bool_id_ = 0;
|
||||
void_id_ = 0;
|
||||
storage_buffer_ext_defined_ = false;
|
||||
uint_rarr_ty_ = nullptr;
|
||||
|
||||
// clear collections
|
||||
id2function_.clear();
|
||||
|
@ -76,7 +76,7 @@ class InstrumentPass : public Pass {
|
||||
IRContext::kAnalysisInstrToBlockMapping |
|
||||
IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
|
||||
IRContext::kAnalysisNameMap | IRContext::kAnalysisBuiltinVarId |
|
||||
IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
|
||||
IRContext::kAnalysisConstants;
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -195,6 +195,13 @@ class InstrumentPass : public Pass {
|
||||
const std::vector<uint32_t>& validation_ids,
|
||||
InstructionBuilder* builder);
|
||||
|
||||
// Generate in |builder| instructions to read the unsigned integer from the
|
||||
// input buffer at offset |idx_id|. Return the result id.
|
||||
//
|
||||
// The binding and the format of the input buffer is determined by each
|
||||
// specific validation, which is specified at the creation of the pass.
|
||||
uint32_t GenDebugDirectRead(uint32_t idx_id, InstructionBuilder* builder);
|
||||
|
||||
// Generate code to cast |value_id| to unsigned, if needed. Return
|
||||
// an id to the unsigned equivalent.
|
||||
uint32_t GenUintCastCode(uint32_t value_id, InstructionBuilder* builder);
|
||||
@ -211,15 +218,28 @@ class InstrumentPass : public Pass {
|
||||
// Return id for void type
|
||||
uint32_t GetVoidId();
|
||||
|
||||
// Return id for output buffer uint type
|
||||
uint32_t GetOutputBufferUintPtrId();
|
||||
// Return pointer to type for runtime array of uint
|
||||
analysis::Type* GetUintRuntimeArrayType(analysis::DecorationManager* deco_mgr,
|
||||
analysis::TypeManager* type_mgr);
|
||||
|
||||
// Return id for buffer uint type
|
||||
uint32_t GetBufferUintPtrId();
|
||||
|
||||
// Return binding for output buffer for current validation.
|
||||
uint32_t GetOutputBufferBinding();
|
||||
|
||||
// Return binding for input buffer for current validation.
|
||||
uint32_t GetInputBufferBinding();
|
||||
|
||||
// Add storage buffer extension if needed
|
||||
void AddStorageBufferExt();
|
||||
|
||||
// Return id for debug output buffer
|
||||
uint32_t GetOutputBufferId();
|
||||
|
||||
// Return id for debug input buffer
|
||||
uint32_t GetInputBufferId();
|
||||
|
||||
// Return id for v4float type
|
||||
uint32_t GetVec4FloatId();
|
||||
|
||||
@ -321,7 +341,7 @@ class InstrumentPass : public Pass {
|
||||
uint32_t output_buffer_id_;
|
||||
|
||||
// type id for output buffer element
|
||||
uint32_t output_buffer_uint_ptr_id_;
|
||||
uint32_t buffer_uint_ptr_id_;
|
||||
|
||||
// id for debug output function
|
||||
uint32_t output_func_id_;
|
||||
@ -329,6 +349,9 @@ class InstrumentPass : public Pass {
|
||||
// param count for output function
|
||||
uint32_t output_func_param_cnt_;
|
||||
|
||||
// id for input buffer variable
|
||||
uint32_t input_buffer_id_;
|
||||
|
||||
// id for v4float type
|
||||
uint32_t v4float_id_;
|
||||
|
||||
@ -344,6 +367,12 @@ class InstrumentPass : public Pass {
|
||||
// id for void type
|
||||
uint32_t void_id_;
|
||||
|
||||
// boolean to remember storage buffer extension
|
||||
bool storage_buffer_ext_defined_;
|
||||
|
||||
// runtime array of uint type
|
||||
analysis::Type* uint_rarr_ty_;
|
||||
|
||||
// Pre-instrumentation same-block insts
|
||||
std::unordered_map<uint32_t, Instruction*> same_block_pre_;
|
||||
|
||||
|
16
3rdparty/spirv-tools/source/opt/optimizer.cpp
vendored
16
3rdparty/spirv-tools/source/opt/optimizer.cpp
vendored
@ -57,8 +57,8 @@ Optimizer::PassToken::~PassToken() {}
|
||||
struct Optimizer::Impl {
|
||||
explicit Impl(spv_target_env env) : target_env(env), pass_manager() {}
|
||||
|
||||
spv_target_env target_env; // Target environment.
|
||||
opt::PassManager pass_manager; // Internal implementation pass manager.
|
||||
spv_target_env target_env; // Target environment.
|
||||
opt::PassManager pass_manager; // Internal implementation pass manager.
|
||||
};
|
||||
|
||||
Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {}
|
||||
@ -218,7 +218,9 @@ Optimizer& Optimizer::RegisterSizePasses() {
|
||||
}
|
||||
|
||||
Optimizer& Optimizer::RegisterWebGPUPasses() {
|
||||
return RegisterPass(CreateAggressiveDCEPass())
|
||||
return RegisterPass(CreateStripDebugInfoPass())
|
||||
.RegisterPass(CreateFlattenDecorationPass())
|
||||
.RegisterPass(CreateAggressiveDCEPass())
|
||||
.RegisterPass(CreateDeadBranchElimPass());
|
||||
}
|
||||
|
||||
@ -379,7 +381,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
|
||||
} else if (pass_name == "replace-invalid-opcode") {
|
||||
RegisterPass(CreateReplaceInvalidOpcodePass());
|
||||
} else if (pass_name == "inst-bindless-check") {
|
||||
RegisterPass(CreateInstBindlessCheckPass(7, 23));
|
||||
RegisterPass(CreateInstBindlessCheckPass(7, 23, true));
|
||||
RegisterPass(CreateSimplificationPass());
|
||||
RegisterPass(CreateDeadBranchElimPass());
|
||||
RegisterPass(CreateBlockMergePass());
|
||||
@ -788,9 +790,11 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass() {
|
||||
}
|
||||
|
||||
Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set,
|
||||
uint32_t shader_id) {
|
||||
uint32_t shader_id,
|
||||
bool runtime_array_enable) {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::InstBindlessCheckPass>(desc_set, shader_id));
|
||||
MakeUnique<opt::InstBindlessCheckPass>(desc_set, shader_id,
|
||||
runtime_array_enable));
|
||||
}
|
||||
|
||||
Optimizer::PassToken CreateCodeSinkingPass() {
|
||||
|
@ -25,6 +25,8 @@ set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||
reduction_pass.h
|
||||
reduction_util.h
|
||||
remove_instruction_reduction_opportunity.h
|
||||
remove_function_reduction_opportunity.h
|
||||
remove_function_reduction_opportunity_finder.h
|
||||
remove_opname_instruction_reduction_opportunity_finder.h
|
||||
remove_unreferenced_instruction_reduction_opportunity_finder.h
|
||||
structured_loop_to_selection_reduction_opportunity.h
|
||||
@ -41,6 +43,8 @@ set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||
reduction_opportunity.cpp
|
||||
reduction_pass.cpp
|
||||
reduction_util.cpp
|
||||
remove_function_reduction_opportunity.cpp
|
||||
remove_function_reduction_opportunity_finder.cpp
|
||||
remove_instruction_reduction_opportunity.cpp
|
||||
remove_unreferenced_instruction_reduction_opportunity_finder.cpp
|
||||
remove_opname_instruction_reduction_opportunity_finder.cpp
|
||||
|
40
3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity.cpp
vendored
Normal file
40
3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity.cpp
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// 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 "remove_function_reduction_opportunity.h"
|
||||
#include "source/opt/eliminate_dead_functions_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
bool RemoveFunctionReductionOpportunity::PreconditionHolds() {
|
||||
// Removing one function cannot influence whether another function can be
|
||||
// removed.
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoveFunctionReductionOpportunity::Apply() {
|
||||
for (opt::Module::iterator function_it = context_->module()->begin();
|
||||
function_it != context_->module()->end(); ++function_it) {
|
||||
if (&*function_it == function_) {
|
||||
opt::eliminatedeadfunctionsutil::EliminateFunction(context_,
|
||||
&function_it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(0 && "Function to be removed was not found.");
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
49
3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity.h
vendored
Normal file
49
3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// 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_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_H_
|
||||
#define SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_H_
|
||||
|
||||
#include "reduction_opportunity.h"
|
||||
#include "source/opt/function.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// An opportunity to remove an unreferenced function.
|
||||
class RemoveFunctionReductionOpportunity : public ReductionOpportunity {
|
||||
public:
|
||||
// Creates an opportunity to remove |function| from the module represented by
|
||||
// |context|.
|
||||
RemoveFunctionReductionOpportunity(opt::IRContext* context,
|
||||
opt::Function* function)
|
||||
: context_(context), function_(function) {}
|
||||
|
||||
bool PreconditionHolds() override;
|
||||
|
||||
protected:
|
||||
void Apply() override;
|
||||
|
||||
private:
|
||||
// The IR context for the module under analysis.
|
||||
opt::IRContext* context_;
|
||||
|
||||
// The function that can be removed.
|
||||
opt::Function* function_;
|
||||
};
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_H_
|
42
3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.cpp
vendored
Normal file
42
3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.cpp
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// 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 "remove_function_reduction_opportunity_finder.h"
|
||||
#include "remove_function_reduction_opportunity.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
RemoveFunctionReductionOpportunityFinder::GetAvailableOpportunities(
|
||||
opt::IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
// Consider each function.
|
||||
for (auto& function : *context->module()) {
|
||||
if (context->get_def_use_mgr()->NumUses(function.result_id()) > 0) {
|
||||
// If the function is referenced, ignore it.
|
||||
continue;
|
||||
}
|
||||
result.push_back(
|
||||
MakeUnique<RemoveFunctionReductionOpportunity>(context, &function));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string RemoveFunctionReductionOpportunityFinder::GetName() const {
|
||||
return "RemoveFunctionReductionOpportunityFinder";
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
42
3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.h
vendored
Normal file
42
3rdparty/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.h
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// 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_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
#define SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
|
||||
#include "source/reduce/reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A finder of opportunities to remove unreferenced functions.
|
||||
class RemoveFunctionReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
RemoveFunctionReductionOpportunityFinder() = default;
|
||||
|
||||
~RemoveFunctionReductionOpportunityFinder() override = default;
|
||||
|
||||
std::string GetName() const final;
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
@ -19,10 +19,6 @@
|
||||
|
||||
#include "spirv-tools/libspirv.h"
|
||||
|
||||
// Parses s into *env and returns true if successful. If unparsable, returns
|
||||
// false and sets *env to SPV_ENV_UNIVERSAL_1_0.
|
||||
bool spvParseTargetEnv(const char* s, spv_target_env* env);
|
||||
|
||||
// Returns true if |env| is a VULKAN environment, false otherwise.
|
||||
bool spvIsVulkanEnv(spv_target_env env);
|
||||
|
||||
|
@ -247,6 +247,49 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _,
|
||||
<< "'s type does not match Function <id> '"
|
||||
<< _.getIdName(parameter_type_id) << "'s parameter type.";
|
||||
}
|
||||
|
||||
if (_.addressing_model() == SpvAddressingModelLogical) {
|
||||
if (parameter_type->opcode() == SpvOpTypePointer) {
|
||||
SpvStorageClass sc = parameter_type->GetOperandAs<SpvStorageClass>(1u);
|
||||
// Validate which storage classes can be pointer operands.
|
||||
switch (sc) {
|
||||
case SpvStorageClassUniformConstant:
|
||||
case SpvStorageClassFunction:
|
||||
case SpvStorageClassPrivate:
|
||||
case SpvStorageClassWorkgroup:
|
||||
case SpvStorageClassAtomicCounter:
|
||||
// These are always allowed.
|
||||
break;
|
||||
case SpvStorageClassStorageBuffer:
|
||||
if (!_.features().variable_pointers_storage_buffer) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "StorageBuffer pointer operand "
|
||||
<< _.getIdName(argument_id)
|
||||
<< " requires a variable pointers capability";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Invalid storage class for pointer operand "
|
||||
<< _.getIdName(argument_id);
|
||||
}
|
||||
|
||||
// Validate memory object declaration requirements.
|
||||
if (argument->opcode() != SpvOpVariable &&
|
||||
argument->opcode() != SpvOpFunctionParameter) {
|
||||
const bool ssbo_vptr =
|
||||
_.features().variable_pointers_storage_buffer &&
|
||||
sc == SpvStorageClassStorageBuffer;
|
||||
const bool wg_vptr =
|
||||
_.features().variable_pointers && sc == SpvStorageClassWorkgroup;
|
||||
if (!ssbo_vptr && !wg_vptr) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Pointer operand " << _.getIdName(argument_id)
|
||||
<< " must be a memory object declaration";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
@ -262,17 +262,23 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) {
|
||||
|
||||
spv_result_t ValidateTypePointer(ValidationState_t& _,
|
||||
const Instruction* inst) {
|
||||
const auto type_id = inst->GetOperandAs<uint32_t>(2);
|
||||
const auto type = _.FindDef(type_id);
|
||||
auto type_id = inst->GetOperandAs<uint32_t>(2);
|
||||
auto type = _.FindDef(type_id);
|
||||
if (!type || !spvOpcodeGeneratesType(type->opcode())) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpTypePointer Type <id> '" << _.getIdName(type_id)
|
||||
<< "' is not a type.";
|
||||
}
|
||||
// See if this points to a storage image.
|
||||
if (type->opcode() == SpvOpTypeImage) {
|
||||
const auto storage_class = inst->GetOperandAs<uint32_t>(1);
|
||||
if (storage_class == SpvStorageClassUniformConstant) {
|
||||
const auto storage_class = inst->GetOperandAs<SpvStorageClass>(1);
|
||||
if (storage_class == SpvStorageClassUniformConstant) {
|
||||
// Unpack an optional level of arraying.
|
||||
if (type->opcode() == SpvOpTypeArray ||
|
||||
type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
type_id = type->GetOperandAs<uint32_t>(1);
|
||||
type = _.FindDef(type_id);
|
||||
}
|
||||
if (type->opcode() == SpvOpTypeImage) {
|
||||
const auto sampled = type->GetOperandAs<uint32_t>(6);
|
||||
// 2 indicates this image is known to be be used without a sampler, i.e.
|
||||
// a storage image.
|
||||
|
@ -630,274 +630,6 @@ OpFunctionEnd
|
||||
true);
|
||||
}
|
||||
|
||||
TEST_F(InstBindlessTest, ReuseConstsTypesBuiltins) {
|
||||
// This test verifies that the pass resuses existing constants, types
|
||||
// and builtin variables. This test was created by editing the SPIR-V
|
||||
// from the Simple test.
|
||||
|
||||
const std::string defs_before =
|
||||
R"(OpCapability Shader
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
|
||||
OpExecutionMode %MainPs OriginUpperLeft
|
||||
OpSource HLSL 500
|
||||
OpName %MainPs "MainPs"
|
||||
OpName %g_tColor "g_tColor"
|
||||
OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
|
||||
OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
|
||||
OpName %_ ""
|
||||
OpName %g_sAniso "g_sAniso"
|
||||
OpName %i_vTextureCoords "i.vTextureCoords"
|
||||
OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
|
||||
OpDecorate %g_tColor DescriptorSet 3
|
||||
OpDecorate %g_tColor Binding 0
|
||||
OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
|
||||
OpDecorate %PerViewConstantBuffer_t Block
|
||||
OpDecorate %g_sAniso DescriptorSet 0
|
||||
OpDecorate %i_vTextureCoords Location 0
|
||||
OpDecorate %_entryPointOutput_vColor Location 0
|
||||
OpDecorate %85 DescriptorSet 7
|
||||
OpDecorate %85 Binding 0
|
||||
OpDecorate %gl_FragCoord BuiltIn FragCoord
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v2float = OpTypeVector %float 2
|
||||
%v4float = OpTypeVector %float 4
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%20 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_128 = OpConstant %uint 128
|
||||
%_arr_20_uint_128 = OpTypeArray %20 %uint_128
|
||||
%_ptr_UniformConstant__arr_20_uint_128 = OpTypePointer UniformConstant %_arr_20_uint_128
|
||||
%g_tColor = OpVariable %_ptr_UniformConstant__arr_20_uint_128 UniformConstant
|
||||
%PerViewConstantBuffer_t = OpTypeStruct %uint
|
||||
%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
|
||||
%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
|
||||
%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
|
||||
%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
|
||||
%35 = OpTypeSampler
|
||||
%_ptr_UniformConstant_35 = OpTypePointer UniformConstant %35
|
||||
%g_sAniso = OpVariable %_ptr_UniformConstant_35 UniformConstant
|
||||
%39 = OpTypeSampledImage %20
|
||||
%_ptr_Input_v2float = OpTypePointer Input %v2float
|
||||
%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%bool = OpTypeBool
|
||||
%_runtimearr_uint = OpTypeRuntimeArray %uint
|
||||
%_struct_83 = OpTypeStruct %uint %_runtimearr_uint
|
||||
%_ptr_StorageBuffer__struct_83 = OpTypePointer StorageBuffer %_struct_83
|
||||
%85 = OpVariable %_ptr_StorageBuffer__struct_83 StorageBuffer
|
||||
%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
|
||||
%uint_10 = OpConstant %uint 10
|
||||
%uint_4 = OpConstant %uint 4
|
||||
%uint_1 = OpConstant %uint 1
|
||||
%uint_23 = OpConstant %uint 23
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%uint_9 = OpConstant %uint 9
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
|
||||
%v4uint = OpTypeVector %uint 4
|
||||
%uint_5 = OpConstant %uint 5
|
||||
%uint_6 = OpConstant %uint 6
|
||||
%uint_7 = OpConstant %uint 7
|
||||
%uint_8 = OpConstant %uint 8
|
||||
%131 = OpConstantNull %v4float
|
||||
)";
|
||||
|
||||
const std::string defs_after =
|
||||
R"(OpCapability Shader
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
|
||||
OpExecutionMode %MainPs OriginUpperLeft
|
||||
OpSource HLSL 500
|
||||
OpName %MainPs "MainPs"
|
||||
OpName %g_tColor "g_tColor"
|
||||
OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
|
||||
OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
|
||||
OpName %_ ""
|
||||
OpName %g_sAniso "g_sAniso"
|
||||
OpName %i_vTextureCoords "i.vTextureCoords"
|
||||
OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
|
||||
OpDecorate %g_tColor DescriptorSet 3
|
||||
OpDecorate %g_tColor Binding 0
|
||||
OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
|
||||
OpDecorate %PerViewConstantBuffer_t Block
|
||||
OpDecorate %g_sAniso DescriptorSet 0
|
||||
OpDecorate %i_vTextureCoords Location 0
|
||||
OpDecorate %_entryPointOutput_vColor Location 0
|
||||
OpDecorate %10 DescriptorSet 7
|
||||
OpDecorate %10 Binding 0
|
||||
OpDecorate %gl_FragCoord BuiltIn FragCoord
|
||||
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_34 Block
|
||||
OpMemberDecorate %_struct_34 0 Offset 0
|
||||
OpMemberDecorate %_struct_34 1 Offset 4
|
||||
OpDecorate %74 DescriptorSet 7
|
||||
OpDecorate %74 Binding 0
|
||||
%void = OpTypeVoid
|
||||
%12 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v2float = OpTypeVector %float 2
|
||||
%v4float = OpTypeVector %float 4
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%18 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_128 = OpConstant %uint 128
|
||||
%_arr_18_uint_128 = OpTypeArray %18 %uint_128
|
||||
%_ptr_UniformConstant__arr_18_uint_128 = OpTypePointer UniformConstant %_arr_18_uint_128
|
||||
%g_tColor = OpVariable %_ptr_UniformConstant__arr_18_uint_128 UniformConstant
|
||||
%PerViewConstantBuffer_t = OpTypeStruct %uint
|
||||
%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
|
||||
%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
|
||||
%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
|
||||
%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
|
||||
%26 = OpTypeSampler
|
||||
%_ptr_UniformConstant_26 = OpTypePointer UniformConstant %26
|
||||
%g_sAniso = OpVariable %_ptr_UniformConstant_26 UniformConstant
|
||||
%28 = OpTypeSampledImage %18
|
||||
%_ptr_Input_v2float = OpTypePointer Input %v2float
|
||||
%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%bool = OpTypeBool
|
||||
%_runtimearr_uint = OpTypeRuntimeArray %uint
|
||||
%_struct_34 = OpTypeStruct %uint %_runtimearr_uint
|
||||
%_ptr_StorageBuffer__struct_34 = OpTypePointer StorageBuffer %_struct_34
|
||||
%10 = OpVariable %_ptr_StorageBuffer__struct_34 StorageBuffer
|
||||
%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
|
||||
%uint_10 = OpConstant %uint 10
|
||||
%uint_4 = OpConstant %uint 4
|
||||
%uint_1 = OpConstant %uint 1
|
||||
%uint_23 = OpConstant %uint 23
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%uint_9 = OpConstant %uint 9
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
|
||||
%v4uint = OpTypeVector %uint 4
|
||||
%uint_5 = OpConstant %uint 5
|
||||
%uint_6 = OpConstant %uint 6
|
||||
%uint_7 = OpConstant %uint 7
|
||||
%uint_8 = OpConstant %uint 8
|
||||
%50 = OpConstantNull %v4float
|
||||
%68 = OpTypeFunction %void %uint %uint %uint %uint
|
||||
%74 = OpVariable %_ptr_StorageBuffer__struct_34 StorageBuffer
|
||||
%uint_82 = OpConstant %uint 82
|
||||
)";
|
||||
|
||||
const std::string func_before =
|
||||
R"(%MainPs = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%53 = OpLoad %v2float %i_vTextureCoords
|
||||
%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
|
||||
%64 = OpLoad %uint %63
|
||||
%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64
|
||||
%67 = OpLoad %35 %g_sAniso
|
||||
%78 = OpLoad %20 %65
|
||||
%79 = OpSampledImage %39 %78 %67
|
||||
%71 = OpImageSampleImplicitLod %v4float %79 %53
|
||||
OpStore %_entryPointOutput_vColor %71
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string func_after =
|
||||
R"(%MainPs = OpFunction %void None %12
|
||||
%51 = OpLabel
|
||||
%52 = OpLoad %v2float %i_vTextureCoords
|
||||
%53 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
|
||||
%54 = OpLoad %uint %53
|
||||
%55 = OpAccessChain %_ptr_UniformConstant_18 %g_tColor %54
|
||||
%56 = OpLoad %26 %g_sAniso
|
||||
%57 = OpLoad %18 %55
|
||||
%58 = OpSampledImage %28 %57 %56
|
||||
%60 = OpULessThan %bool %54 %uint_128
|
||||
OpSelectionMerge %61 None
|
||||
OpBranchConditional %60 %62 %63
|
||||
%62 = OpLabel
|
||||
%64 = OpLoad %18 %55
|
||||
%65 = OpSampledImage %28 %64 %56
|
||||
%66 = OpImageSampleImplicitLod %v4float %65 %52
|
||||
OpBranch %61
|
||||
%63 = OpLabel
|
||||
%105 = OpFunctionCall %void %67 %uint_82 %uint_0 %54 %uint_128
|
||||
OpBranch %61
|
||||
%61 = OpLabel
|
||||
%106 = OpPhi %v4float %66 %62 %50 %63
|
||||
OpStore %_entryPointOutput_vColor %106
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string output_func =
|
||||
R"(%67 = OpFunction %void None %68
|
||||
%69 = OpFunctionParameter %uint
|
||||
%70 = OpFunctionParameter %uint
|
||||
%71 = OpFunctionParameter %uint
|
||||
%72 = OpFunctionParameter %uint
|
||||
%73 = OpLabel
|
||||
%75 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_0
|
||||
%76 = OpAtomicIAdd %uint %75 %uint_4 %uint_0 %uint_9
|
||||
%77 = OpIAdd %uint %76 %uint_9
|
||||
%78 = OpArrayLength %uint %74 1
|
||||
%79 = OpULessThanEqual %bool %77 %78
|
||||
OpSelectionMerge %80 None
|
||||
OpBranchConditional %79 %81 %80
|
||||
%81 = OpLabel
|
||||
%82 = OpIAdd %uint %76 %uint_0
|
||||
%83 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_1 %82
|
||||
OpStore %83 %uint_9
|
||||
%84 = OpIAdd %uint %76 %uint_1
|
||||
%85 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_1 %84
|
||||
OpStore %85 %uint_23
|
||||
%86 = OpIAdd %uint %76 %uint_2
|
||||
%87 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_1 %86
|
||||
OpStore %87 %69
|
||||
%88 = OpIAdd %uint %76 %uint_3
|
||||
%89 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_1 %88
|
||||
OpStore %89 %uint_4
|
||||
%90 = OpLoad %v4float %gl_FragCoord
|
||||
%91 = OpBitcast %v4uint %90
|
||||
%92 = OpCompositeExtract %uint %91 0
|
||||
%93 = OpIAdd %uint %76 %uint_4
|
||||
%94 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_1 %93
|
||||
OpStore %94 %92
|
||||
%95 = OpCompositeExtract %uint %91 1
|
||||
%96 = OpIAdd %uint %76 %uint_5
|
||||
%97 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_1 %96
|
||||
OpStore %97 %95
|
||||
%98 = OpIAdd %uint %76 %uint_6
|
||||
%99 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_1 %98
|
||||
OpStore %99 %70
|
||||
%100 = OpIAdd %uint %76 %uint_7
|
||||
%101 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_1 %100
|
||||
OpStore %101 %71
|
||||
%102 = OpIAdd %uint %76 %uint_8
|
||||
%103 = OpAccessChain %_ptr_StorageBuffer_uint %74 %uint_1 %102
|
||||
OpStore %103 %72
|
||||
OpBranch %80
|
||||
%80 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
SinglePassRunAndCheck<InstBindlessCheckPass>(
|
||||
defs_before + func_before, defs_after + func_after + output_func, true,
|
||||
true);
|
||||
}
|
||||
|
||||
TEST_F(InstBindlessTest, InstrumentOpImage) {
|
||||
// This test verifies that the pass will correctly instrument shader
|
||||
// using OpImage. This test was created by editing the SPIR-V
|
||||
@ -1848,6 +1580,261 @@ OpFunctionEnd
|
||||
true);
|
||||
}
|
||||
|
||||
TEST_F(InstBindlessTest, RuntimeArray) {
|
||||
// This test verifies that the pass will correctly instrument shader
|
||||
// with runtime descriptor array. This test was created by editing the
|
||||
// SPIR-V from the Simple test.
|
||||
|
||||
const std::string defs_before =
|
||||
R"(OpCapability Shader
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
|
||||
OpExecutionMode %MainPs OriginUpperLeft
|
||||
OpSource HLSL 500
|
||||
OpName %MainPs "MainPs"
|
||||
OpName %g_tColor "g_tColor"
|
||||
OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
|
||||
OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
|
||||
OpName %_ ""
|
||||
OpName %g_sAniso "g_sAniso"
|
||||
OpName %i_vTextureCoords "i.vTextureCoords"
|
||||
OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
|
||||
OpDecorate %g_tColor DescriptorSet 0
|
||||
OpDecorate %g_tColor Binding 0
|
||||
OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
|
||||
OpDecorate %PerViewConstantBuffer_t Block
|
||||
OpDecorate %g_sAniso DescriptorSet 0
|
||||
OpDecorate %g_sAniso Binding 1
|
||||
OpDecorate %i_vTextureCoords Location 0
|
||||
OpDecorate %_entryPointOutput_vColor Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v2float = OpTypeVector %float 2
|
||||
%v4float = OpTypeVector %float 4
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%20 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_1 = OpConstant %uint 1
|
||||
%_rarr_20 = OpTypeRuntimeArray %20
|
||||
%_ptr_UniformConstant__arr_20 = OpTypePointer UniformConstant %_rarr_20
|
||||
%g_tColor = OpVariable %_ptr_UniformConstant__arr_20 UniformConstant
|
||||
%PerViewConstantBuffer_t = OpTypeStruct %uint
|
||||
%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
|
||||
%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
|
||||
%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
|
||||
%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
|
||||
%35 = OpTypeSampler
|
||||
%_ptr_UniformConstant_35 = OpTypePointer UniformConstant %35
|
||||
%g_sAniso = OpVariable %_ptr_UniformConstant_35 UniformConstant
|
||||
%39 = OpTypeSampledImage %20
|
||||
%_ptr_Input_v2float = OpTypePointer Input %v2float
|
||||
%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
|
||||
)";
|
||||
|
||||
const std::string defs_after =
|
||||
R"(OpCapability Shader
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
|
||||
OpExecutionMode %MainPs OriginUpperLeft
|
||||
OpSource HLSL 500
|
||||
OpName %MainPs "MainPs"
|
||||
OpName %g_tColor "g_tColor"
|
||||
OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
|
||||
OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
|
||||
OpName %_ ""
|
||||
OpName %g_sAniso "g_sAniso"
|
||||
OpName %i_vTextureCoords "i.vTextureCoords"
|
||||
OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
|
||||
OpDecorate %g_tColor DescriptorSet 0
|
||||
OpDecorate %g_tColor Binding 0
|
||||
OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
|
||||
OpDecorate %PerViewConstantBuffer_t Block
|
||||
OpDecorate %g_sAniso DescriptorSet 0
|
||||
OpDecorate %g_sAniso Binding 1
|
||||
OpDecorate %i_vTextureCoords Location 0
|
||||
OpDecorate %_entryPointOutput_vColor Location 0
|
||||
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_40 Block
|
||||
OpMemberDecorate %_struct_40 0 Offset 0
|
||||
OpDecorate %42 DescriptorSet 7
|
||||
OpDecorate %42 Binding 1
|
||||
OpDecorate %_struct_64 Block
|
||||
OpMemberDecorate %_struct_64 0 Offset 0
|
||||
OpMemberDecorate %_struct_64 1 Offset 4
|
||||
OpDecorate %66 DescriptorSet 7
|
||||
OpDecorate %66 Binding 0
|
||||
OpDecorate %gl_FragCoord BuiltIn FragCoord
|
||||
%void = OpTypeVoid
|
||||
%10 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v2float = OpTypeVector %float 2
|
||||
%v4float = OpTypeVector %float 4
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%16 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_1 = OpConstant %uint 1
|
||||
%_runtimearr_16 = OpTypeRuntimeArray %16
|
||||
%_ptr_UniformConstant__runtimearr_16 = OpTypePointer UniformConstant %_runtimearr_16
|
||||
%g_tColor = OpVariable %_ptr_UniformConstant__runtimearr_16 UniformConstant
|
||||
%PerViewConstantBuffer_t = OpTypeStruct %uint
|
||||
%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
|
||||
%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
|
||||
%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
|
||||
%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16
|
||||
%24 = OpTypeSampler
|
||||
%_ptr_UniformConstant_24 = OpTypePointer UniformConstant %24
|
||||
%g_sAniso = OpVariable %_ptr_UniformConstant_24 UniformConstant
|
||||
%26 = OpTypeSampledImage %16
|
||||
%_ptr_Input_v2float = OpTypePointer Input %v2float
|
||||
%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_runtimearr_uint = OpTypeRuntimeArray %uint
|
||||
%_struct_40 = OpTypeStruct %_runtimearr_uint
|
||||
%_ptr_StorageBuffer__struct_40 = OpTypePointer StorageBuffer %_struct_40
|
||||
%42 = OpVariable %_ptr_StorageBuffer__struct_40 StorageBuffer
|
||||
%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
|
||||
%bool = OpTypeBool
|
||||
%58 = OpTypeFunction %void %uint %uint %uint %uint
|
||||
%_struct_64 = OpTypeStruct %uint %_runtimearr_uint
|
||||
%_ptr_StorageBuffer__struct_64 = OpTypePointer StorageBuffer %_struct_64
|
||||
%66 = OpVariable %_ptr_StorageBuffer__struct_64 StorageBuffer
|
||||
%uint_9 = OpConstant %uint 9
|
||||
%uint_4 = OpConstant %uint 4
|
||||
%uint_23 = OpConstant %uint 23
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
|
||||
%v4uint = OpTypeVector %uint 4
|
||||
%uint_5 = OpConstant %uint 5
|
||||
%uint_6 = OpConstant %uint 6
|
||||
%uint_7 = OpConstant %uint 7
|
||||
%uint_8 = OpConstant %uint 8
|
||||
%uint_59 = OpConstant %uint 59
|
||||
%110 = OpConstantNull %v4float
|
||||
)";
|
||||
|
||||
const std::string func_before =
|
||||
R"(%MainPs = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%53 = OpLoad %v2float %i_vTextureCoords
|
||||
%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
|
||||
%64 = OpLoad %uint %63
|
||||
%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64
|
||||
%66 = OpLoad %20 %65
|
||||
%67 = OpLoad %35 %g_sAniso
|
||||
%68 = OpSampledImage %39 %66 %67
|
||||
%71 = OpImageSampleImplicitLod %v4float %68 %53
|
||||
OpStore %_entryPointOutput_vColor %71
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string func_after =
|
||||
R"(%MainPs = OpFunction %void None %10
|
||||
%29 = OpLabel
|
||||
%30 = OpLoad %v2float %i_vTextureCoords
|
||||
%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
|
||||
%32 = OpLoad %uint %31
|
||||
%33 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %32
|
||||
%34 = OpLoad %16 %33
|
||||
%35 = OpLoad %24 %g_sAniso
|
||||
%36 = OpSampledImage %26 %34 %35
|
||||
%44 = OpAccessChain %_ptr_StorageBuffer_uint %42 %uint_0 %uint_1
|
||||
%45 = OpLoad %uint %44
|
||||
%46 = OpIAdd %uint %45 %uint_0
|
||||
%47 = OpAccessChain %_ptr_StorageBuffer_uint %42 %uint_0 %46
|
||||
%48 = OpLoad %uint %47
|
||||
%50 = OpULessThan %bool %32 %48
|
||||
OpSelectionMerge %51 None
|
||||
OpBranchConditional %50 %52 %53
|
||||
%52 = OpLabel
|
||||
%54 = OpLoad %16 %33
|
||||
%55 = OpSampledImage %26 %54 %35
|
||||
%56 = OpImageSampleImplicitLod %v4float %55 %30
|
||||
OpBranch %51
|
||||
%53 = OpLabel
|
||||
%109 = OpFunctionCall %void %57 %uint_59 %uint_0 %32 %48
|
||||
OpBranch %51
|
||||
%51 = OpLabel
|
||||
%111 = OpPhi %v4float %56 %52 %110 %53
|
||||
OpStore %_entryPointOutput_vColor %111
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string output_func =
|
||||
R"(%57 = OpFunction %void None %58
|
||||
%59 = OpFunctionParameter %uint
|
||||
%60 = OpFunctionParameter %uint
|
||||
%61 = OpFunctionParameter %uint
|
||||
%62 = OpFunctionParameter %uint
|
||||
%63 = OpLabel
|
||||
%67 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_0
|
||||
%70 = OpAtomicIAdd %uint %67 %uint_4 %uint_0 %uint_9
|
||||
%71 = OpIAdd %uint %70 %uint_9
|
||||
%72 = OpArrayLength %uint %66 1
|
||||
%73 = OpULessThanEqual %bool %71 %72
|
||||
OpSelectionMerge %74 None
|
||||
OpBranchConditional %73 %75 %74
|
||||
%75 = OpLabel
|
||||
%76 = OpIAdd %uint %70 %uint_0
|
||||
%77 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_1 %76
|
||||
OpStore %77 %uint_9
|
||||
%79 = OpIAdd %uint %70 %uint_1
|
||||
%80 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_1 %79
|
||||
OpStore %80 %uint_23
|
||||
%82 = OpIAdd %uint %70 %uint_2
|
||||
%83 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_1 %82
|
||||
OpStore %83 %59
|
||||
%85 = OpIAdd %uint %70 %uint_3
|
||||
%86 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_1 %85
|
||||
OpStore %86 %uint_4
|
||||
%89 = OpLoad %v4float %gl_FragCoord
|
||||
%91 = OpBitcast %v4uint %89
|
||||
%92 = OpCompositeExtract %uint %91 0
|
||||
%93 = OpIAdd %uint %70 %uint_4
|
||||
%94 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_1 %93
|
||||
OpStore %94 %92
|
||||
%95 = OpCompositeExtract %uint %91 1
|
||||
%97 = OpIAdd %uint %70 %uint_5
|
||||
%98 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_1 %97
|
||||
OpStore %98 %95
|
||||
%100 = OpIAdd %uint %70 %uint_6
|
||||
%101 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_1 %100
|
||||
OpStore %101 %60
|
||||
%103 = OpIAdd %uint %70 %uint_7
|
||||
%104 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_1 %103
|
||||
OpStore %104 %61
|
||||
%106 = OpIAdd %uint %70 %uint_8
|
||||
%107 = OpAccessChain %_ptr_StorageBuffer_uint %66 %uint_1 %106
|
||||
OpStore %107 %62
|
||||
OpBranch %74
|
||||
%74 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
SinglePassRunAndCheck<InstBindlessCheckPass>(
|
||||
defs_before + func_before, defs_after + func_after + output_func, true,
|
||||
true);
|
||||
}
|
||||
|
||||
// TODO(greg-lunarg): Add tests to verify handling of these cases:
|
||||
//
|
||||
// TODO(greg-lunarg): Come up with cases to put here :)
|
||||
|
127
3rdparty/spirv-tools/test/opt/optimizer_test.cpp
vendored
127
3rdparty/spirv-tools/test/opt/optimizer_test.cpp
vendored
@ -222,6 +222,133 @@ TEST(Optimizer, CanRegisterPassesFromFlags) {
|
||||
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
|
||||
}
|
||||
|
||||
TEST(Optimizer, WebGPUModeSetsCorrectPasses) {
|
||||
Optimizer opt(SPV_ENV_WEBGPU_0);
|
||||
opt.RegisterWebGPUPasses();
|
||||
std::vector<const char*> pass_names = opt.GetPassNames();
|
||||
|
||||
std::vector<std::string> registered_passes;
|
||||
for (auto name = pass_names.begin(); name != pass_names.end(); ++name)
|
||||
registered_passes.push_back(*name);
|
||||
|
||||
std::vector<std::string> expected_passes = {
|
||||
"eliminate-dead-branches", "eliminate-dead-code-aggressive",
|
||||
"flatten-decorations", "strip-debug"};
|
||||
std::sort(registered_passes.begin(), registered_passes.end());
|
||||
std::sort(expected_passes.begin(), expected_passes.end());
|
||||
|
||||
ASSERT_EQ(registered_passes.size(), expected_passes.size());
|
||||
for (size_t i = 0; i < registered_passes.size(); i++)
|
||||
EXPECT_EQ(registered_passes[i], expected_passes[i]);
|
||||
}
|
||||
|
||||
TEST(Optimizer, WebGPUModeFlattenDecorationsRuns) {
|
||||
const std::string input = R"(OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Fragment %main "main" %hue %saturation %value
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %group Flat
|
||||
OpDecorate %group NoPerspective
|
||||
%group = OpDecorationGroup
|
||||
%void = OpTypeVoid
|
||||
%void_fn = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%hue = OpVariable %_ptr_Input_float Input
|
||||
%saturation = OpVariable %_ptr_Input_float Input
|
||||
%value = OpVariable %_ptr_Input_float Input
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string expected = R"(OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Fragment %1 "main" %2 %3 %4
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%7 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%2 = OpVariable %_ptr_Input_float Input
|
||||
%3 = OpVariable %_ptr_Input_float Input
|
||||
%4 = OpVariable %_ptr_Input_float Input
|
||||
%1 = OpFunction %void None %7
|
||||
%10 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SpirvTools tools(SPV_ENV_WEBGPU_0);
|
||||
std::vector<uint32_t> binary;
|
||||
tools.Assemble(input, &binary);
|
||||
|
||||
Optimizer opt(SPV_ENV_WEBGPU_0);
|
||||
opt.RegisterWebGPUPasses();
|
||||
|
||||
std::vector<uint32_t> optimized;
|
||||
ValidatorOptions validator_options;
|
||||
ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized,
|
||||
validator_options, true));
|
||||
|
||||
std::string disassembly;
|
||||
tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
|
||||
|
||||
EXPECT_EQ(expected, disassembly);
|
||||
}
|
||||
|
||||
TEST(Optimizer, WebGPUModeStripDebugRuns) {
|
||||
const std::string input = R"(OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Vertex %func "shader"
|
||||
OpName %main "main"
|
||||
OpName %void_fn "void_fn"
|
||||
%void = OpTypeVoid
|
||||
%void_f = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_f
|
||||
%label = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string expected = R"(OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Vertex %1 "shader"
|
||||
%void = OpTypeVoid
|
||||
%5 = OpTypeFunction %void
|
||||
%1 = OpFunction %void None %5
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SpirvTools tools(SPV_ENV_WEBGPU_0);
|
||||
std::vector<uint32_t> binary;
|
||||
tools.Assemble(input, &binary);
|
||||
|
||||
Optimizer opt(SPV_ENV_WEBGPU_0);
|
||||
opt.RegisterWebGPUPasses();
|
||||
|
||||
std::vector<uint32_t> optimized;
|
||||
ValidatorOptions validator_options;
|
||||
ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized,
|
||||
validator_options, true));
|
||||
|
||||
std::string disassembly;
|
||||
tools.Disassemble(optimized.data(), optimized.size(), &disassembly);
|
||||
|
||||
EXPECT_EQ(expected, disassembly);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
@ -20,6 +20,7 @@ add_spvtools_unittest(TARGET reduce
|
||||
reduce_test_util.cpp
|
||||
reduce_test_util.h
|
||||
reducer_test.cpp
|
||||
remove_function_test.cpp
|
||||
remove_opname_instruction_test.cpp
|
||||
remove_unreferenced_instruction_test.cpp
|
||||
structured_loop_to_selection_test.cpp
|
||||
|
294
3rdparty/spirv-tools/test/reduce/remove_function_test.cpp
vendored
Normal file
294
3rdparty/spirv-tools/test/reduce/remove_function_test.cpp
vendored
Normal file
@ -0,0 +1,294 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// 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 "reduce_test_util.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/reduce/reduction_opportunity.h"
|
||||
#include "source/reduce/remove_function_reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
namespace {
|
||||
|
||||
// Helper to count the number of functions in the module.
|
||||
// Remove if there turns out to be a more direct way to do this.
|
||||
uint32_t count_functions(opt::IRContext* context) {
|
||||
uint32_t result = 0;
|
||||
for (auto& function : *context->module()) {
|
||||
(void)(function);
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, BasicCheck) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %2 None %3
|
||||
%9 = OpLabel
|
||||
%10 = OpFunctionCall %2 %6
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
|
||||
ASSERT_EQ(3, count_functions(context.get()));
|
||||
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
|
||||
ASSERT_EQ(2, count_functions(context.get()));
|
||||
|
||||
std::string after_first = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after_first, context.get());
|
||||
|
||||
ops = RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
|
||||
ASSERT_EQ(1, count_functions(context.get()));
|
||||
|
||||
std::string after_second = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after_second, context.get());
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, NothingToRemove) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%11 = OpFunctionCall %2 %8
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %2 None %3
|
||||
%9 = OpLabel
|
||||
%10 = OpFunctionCall %2 %6
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, TwoRemovableFunctions) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %2 None %3
|
||||
%9 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
|
||||
ASSERT_EQ(3, count_functions(context.get()));
|
||||
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(2, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
ASSERT_EQ(2, count_functions(context.get()));
|
||||
ASSERT_TRUE(ops[1]->PreconditionHolds());
|
||||
ops[1]->TryToApply();
|
||||
ASSERT_EQ(1, count_functions(context.get()));
|
||||
|
||||
std::string after = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after, context.get());
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, NoRemovalsDueToOpName) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %6 "foo("
|
||||
OpName %8 "bar("
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %2 None %3
|
||||
%9 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, NoRemovalDueToLinkageDecoration) {
|
||||
// The non-entry point function is not removable because it is referenced by a
|
||||
// linkage decoration. Thus no function can be removed.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "main"
|
||||
OpName %1 "main"
|
||||
OpDecorate %2 LinkageAttributes "ExportedFunc" Export
|
||||
%4 = OpTypeVoid
|
||||
%5 = OpTypeFunction %4
|
||||
%1 = OpFunction %4 None %5
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%2 = OpFunction %4 None %5
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
3
3rdparty/spirv-tools/test/val/CMakeLists.txt
vendored
3
3rdparty/spirv-tools/test/val/CMakeLists.txt
vendored
@ -51,8 +51,9 @@ add_spvtools_unittest(TARGET val_limits
|
||||
PCH_FILE pch_test_val
|
||||
)
|
||||
|
||||
add_spvtools_unittest(TARGET val_ijklmnop
|
||||
add_spvtools_unittest(TARGET val_fghijklmnop
|
||||
SRCS
|
||||
val_function_test.cpp
|
||||
val_id_test.cpp
|
||||
val_image_test.cpp
|
||||
val_interfaces_test.cpp
|
||||
|
@ -1995,7 +1995,7 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
"needs to be a 4-component 32-bit float vector",
|
||||
"is not a float vector"))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
PositionArrayedF32Vec4Vertex, ValidateWebGPUCombineBuiltInArrayedVariable,
|
||||
Combine(Values("Position"), Values("Vertex"), Values("Output"),
|
||||
Values("%f32vec4"),
|
||||
|
@ -5517,6 +5517,8 @@ std::string ShaderWithNonWritableTarget(const std::string& target,
|
||||
|
||||
return std::string(R"(
|
||||
OpCapability Shader
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
@ -5546,6 +5548,8 @@ std::string ShaderWithNonWritableTarget(const std::string& target,
|
||||
%void_fn = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%int = OpTypeInt 32 0
|
||||
%int_2 = OpConstant %int 2
|
||||
%struct_b = OpTypeStruct %float
|
||||
%struct_bb = OpTypeStruct %float
|
||||
%rtarr = OpTypeRuntimeArray %float
|
||||
@ -5555,6 +5559,8 @@ std::string ShaderWithNonWritableTarget(const std::string& target,
|
||||
%imstor = OpTypeImage %float 2D 0 0 0 2 R32f
|
||||
; sampled image
|
||||
%imsam = OpTypeImage %float 2D 0 0 0 1 R32f
|
||||
%array_imstor = OpTypeArray %imstor %int_2
|
||||
%rta_imstor = OpTypeRuntimeArray %imstor
|
||||
|
||||
%_ptr_Uniform_stb = OpTypePointer Uniform %struct_b
|
||||
%_ptr_Uniform_stbb = OpTypePointer Uniform %struct_bb
|
||||
@ -5565,6 +5571,8 @@ std::string ShaderWithNonWritableTarget(const std::string& target,
|
||||
%_ptr_Function = OpTypePointer Function %float
|
||||
%_ptr_imstor = OpTypePointer UniformConstant %imstor
|
||||
%_ptr_imsam = OpTypePointer UniformConstant %imsam
|
||||
%_ptr_array_imstor = OpTypePointer UniformConstant %array_imstor
|
||||
%_ptr_rta_imstor = OpTypePointer UniformConstant %rta_imstor
|
||||
|
||||
%extra_fn = OpTypeFunction %void %float %_ptr_Private %_ptr_imstor
|
||||
|
||||
@ -5576,6 +5584,8 @@ std::string ShaderWithNonWritableTarget(const std::string& target,
|
||||
%var_priv = OpVariable %_ptr_Private Private
|
||||
%var_imstor = OpVariable %_ptr_imstor UniformConstant
|
||||
%var_imsam = OpVariable %_ptr_imsam UniformConstant
|
||||
%var_array_imstor = OpVariable %_ptr_array_imstor UniformConstant
|
||||
%var_rta_imstor = OpVariable %_ptr_rta_imstor UniformConstant
|
||||
|
||||
%helper = OpFunction %void None %extra_fn
|
||||
%param_f = OpFunctionParameter %float
|
||||
@ -5754,6 +5764,20 @@ TEST_F(ValidateDecorations, NonWritableVarFunctionBad) {
|
||||
"buffer\n %var_func"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NonWritableArrayGood) {
|
||||
std::string spirv = ShaderWithNonWritableTarget("%var_array_imstor");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NonWritableRuntimeArrayGood) {
|
||||
std::string spirv = ShaderWithNonWritableTarget("%var_rta_imstor");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_P(ValidateWebGPUCombineDecorationResult, Decorate) {
|
||||
const char* const decoration = std::get<0>(GetParam());
|
||||
const TestResult& test_result = std::get<1>(GetParam());
|
||||
|
7
3rdparty/spirv-tools/test/val/val_fixtures.h
vendored
7
3rdparty/spirv-tools/test/val/val_fixtures.h
vendored
@ -125,6 +125,13 @@ void ValidateBase<T>::OverwriteAssembledBinary(uint32_t index, uint32_t word) {
|
||||
template <typename T>
|
||||
spv_result_t ValidateBase<T>::ValidateInstructions(spv_target_env env) {
|
||||
DestroyDiagnostic();
|
||||
if (binary_ == nullptr) {
|
||||
fprintf(stderr,
|
||||
"ERROR: Attempting to validate a null binary, did you forget to "
|
||||
"call CompileSuccessfully?");
|
||||
fflush(stderr);
|
||||
}
|
||||
assert(binary_ != nullptr);
|
||||
return spvValidateWithOptions(ScopedContext(env).context, options_,
|
||||
get_const_binary(), &diagnostic_);
|
||||
}
|
||||
|
424
3rdparty/spirv-tools/test/val/val_function_test.cpp
vendored
Normal file
424
3rdparty/spirv-tools/test/val/val_function_test.cpp
vendored
Normal file
@ -0,0 +1,424 @@
|
||||
// Copyright (c) 2019 Google LLC.
|
||||
//
|
||||
// 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 <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/test_fixture.h"
|
||||
#include "test/unit_spirv.h"
|
||||
#include "test/val/val_fixtures.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace val {
|
||||
namespace {
|
||||
|
||||
using ::testing::Combine;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Values;
|
||||
|
||||
using ValidateFunctionCall = spvtest::ValidateBase<std::string>;
|
||||
|
||||
std::string GenerateShader(const std::string& storage_class,
|
||||
const std::string& capabilities,
|
||||
const std::string& extensions) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability AtomicStorage
|
||||
)" + capabilities + R"(
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
)" +
|
||||
extensions + R"(
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpName %var "var"
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%ptr = OpTypePointer )" + storage_class + R"( %int
|
||||
%caller_ty = OpTypeFunction %void
|
||||
%callee_ty = OpTypeFunction %void %ptr
|
||||
)";
|
||||
|
||||
if (storage_class != "Function") {
|
||||
spirv += "%var = OpVariable %ptr " + storage_class;
|
||||
}
|
||||
|
||||
spirv += R"(
|
||||
%caller = OpFunction %void None %caller_ty
|
||||
%1 = OpLabel
|
||||
)";
|
||||
|
||||
if (storage_class == "Function") {
|
||||
spirv += "%var = OpVariable %ptr Function";
|
||||
}
|
||||
|
||||
spirv += R"(
|
||||
%call = OpFunctionCall %void %callee %var
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%callee = OpFunction %void None %callee_ty
|
||||
%param = OpFunctionParameter %ptr
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
return spirv;
|
||||
}
|
||||
|
||||
std::string GenerateShaderParameter(const std::string& storage_class,
|
||||
const std::string& capabilities,
|
||||
const std::string& extensions) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability AtomicStorage
|
||||
)" + capabilities + R"(
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
)" +
|
||||
extensions + R"(
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpName %p "p"
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%ptr = OpTypePointer )" + storage_class + R"( %int
|
||||
%func_ty = OpTypeFunction %void %ptr
|
||||
%caller = OpFunction %void None %func_ty
|
||||
%p = OpFunctionParameter %ptr
|
||||
%1 = OpLabel
|
||||
%call = OpFunctionCall %void %callee %p
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%callee = OpFunction %void None %func_ty
|
||||
%param = OpFunctionParameter %ptr
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
return spirv;
|
||||
}
|
||||
|
||||
std::string GenerateShaderAccessChain(const std::string& storage_class,
|
||||
const std::string& capabilities,
|
||||
const std::string& extensions) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability AtomicStorage
|
||||
)" + capabilities + R"(
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
)" +
|
||||
extensions + R"(
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpName %var "var"
|
||||
OpName %gep "gep"
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int2 = OpTypeVector %int 2
|
||||
%int_0 = OpConstant %int 0
|
||||
%ptr = OpTypePointer )" + storage_class + R"( %int2
|
||||
%ptr2 = OpTypePointer )" +
|
||||
storage_class + R"( %int
|
||||
%caller_ty = OpTypeFunction %void
|
||||
%callee_ty = OpTypeFunction %void %ptr2
|
||||
)";
|
||||
|
||||
if (storage_class != "Function") {
|
||||
spirv += "%var = OpVariable %ptr " + storage_class;
|
||||
}
|
||||
|
||||
spirv += R"(
|
||||
%caller = OpFunction %void None %caller_ty
|
||||
%1 = OpLabel
|
||||
)";
|
||||
|
||||
if (storage_class == "Function") {
|
||||
spirv += "%var = OpVariable %ptr Function";
|
||||
}
|
||||
|
||||
spirv += R"(
|
||||
%gep = OpAccessChain %ptr2 %var %int_0
|
||||
%call = OpFunctionCall %void %callee %gep
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%callee = OpFunction %void None %callee_ty
|
||||
%param = OpFunctionParameter %ptr2
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
return spirv;
|
||||
}
|
||||
|
||||
TEST_P(ValidateFunctionCall, VariableNoVariablePointers) {
|
||||
const std::string storage_class = GetParam();
|
||||
|
||||
std::string spirv = GenerateShader(storage_class, "", "");
|
||||
|
||||
const std::vector<std::string> valid_storage_classes = {
|
||||
"UniformConstant", "Function", "Private", "Workgroup", "AtomicCounter"};
|
||||
bool valid =
|
||||
std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
|
||||
storage_class) != valid_storage_classes.end();
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
if (valid) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
} else {
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
if (storage_class == "StorageBuffer") {
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("StorageBuffer pointer operand 1[%var] requires a "
|
||||
"variable pointers capability"));
|
||||
} else {
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Invalid storage class for pointer operand 1[%var]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateFunctionCall, VariableVariablePointersStorageClass) {
|
||||
const std::string storage_class = GetParam();
|
||||
|
||||
std::string spirv = GenerateShader(
|
||||
storage_class, "OpCapability VariablePointersStorageBuffer",
|
||||
"OpExtension \"SPV_KHR_variable_pointers\"");
|
||||
|
||||
const std::vector<std::string> valid_storage_classes = {
|
||||
"UniformConstant", "Function", "Private",
|
||||
"Workgroup", "StorageBuffer", "AtomicCounter"};
|
||||
bool valid =
|
||||
std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
|
||||
storage_class) != valid_storage_classes.end();
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
if (valid) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
} else {
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Invalid storage class for pointer operand 1[%var]"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateFunctionCall, VariableVariablePointers) {
|
||||
const std::string storage_class = GetParam();
|
||||
|
||||
std::string spirv =
|
||||
GenerateShader(storage_class, "OpCapability VariablePointers",
|
||||
"OpExtension \"SPV_KHR_variable_pointers\"");
|
||||
|
||||
const std::vector<std::string> valid_storage_classes = {
|
||||
"UniformConstant", "Function", "Private",
|
||||
"Workgroup", "StorageBuffer", "AtomicCounter"};
|
||||
bool valid =
|
||||
std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
|
||||
storage_class) != valid_storage_classes.end();
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
if (valid) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
} else {
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Invalid storage class for pointer operand 1[%var]"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateFunctionCall, ParameterNoVariablePointers) {
|
||||
const std::string storage_class = GetParam();
|
||||
|
||||
std::string spirv = GenerateShaderParameter(storage_class, "", "");
|
||||
|
||||
const std::vector<std::string> valid_storage_classes = {
|
||||
"UniformConstant", "Function", "Private", "Workgroup", "AtomicCounter"};
|
||||
bool valid =
|
||||
std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
|
||||
storage_class) != valid_storage_classes.end();
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
if (valid) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
} else {
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
if (storage_class == "StorageBuffer") {
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("StorageBuffer pointer operand 1[%p] requires a "
|
||||
"variable pointers capability"));
|
||||
} else {
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Invalid storage class for pointer operand 1[%p]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateFunctionCall, ParameterVariablePointersStorageBuffer) {
|
||||
const std::string storage_class = GetParam();
|
||||
|
||||
std::string spirv = GenerateShaderParameter(
|
||||
storage_class, "OpCapability VariablePointersStorageBuffer",
|
||||
"OpExtension \"SPV_KHR_variable_pointers\"");
|
||||
|
||||
const std::vector<std::string> valid_storage_classes = {
|
||||
"UniformConstant", "Function", "Private",
|
||||
"Workgroup", "StorageBuffer", "AtomicCounter"};
|
||||
bool valid =
|
||||
std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
|
||||
storage_class) != valid_storage_classes.end();
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
if (valid) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
} else {
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Invalid storage class for pointer operand 1[%p]"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateFunctionCall, ParameterVariablePointers) {
|
||||
const std::string storage_class = GetParam();
|
||||
|
||||
std::string spirv =
|
||||
GenerateShaderParameter(storage_class, "OpCapability VariablePointers",
|
||||
"OpExtension \"SPV_KHR_variable_pointers\"");
|
||||
|
||||
const std::vector<std::string> valid_storage_classes = {
|
||||
"UniformConstant", "Function", "Private",
|
||||
"Workgroup", "StorageBuffer", "AtomicCounter"};
|
||||
bool valid =
|
||||
std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
|
||||
storage_class) != valid_storage_classes.end();
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
if (valid) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
} else {
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Invalid storage class for pointer operand 1[%p]"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationNoVariablePointers) {
|
||||
const std::string storage_class = GetParam();
|
||||
|
||||
std::string spirv = GenerateShaderAccessChain(storage_class, "", "");
|
||||
|
||||
const std::vector<std::string> valid_storage_classes = {
|
||||
"UniformConstant", "Function", "Private", "Workgroup", "AtomicCounter"};
|
||||
bool valid_sc =
|
||||
std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
|
||||
storage_class) != valid_storage_classes.end();
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
if (valid_sc) {
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Pointer operand 2[%gep] must be a memory object declaration"));
|
||||
} else {
|
||||
if (storage_class == "StorageBuffer") {
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("StorageBuffer pointer operand 2[%gep] requires a "
|
||||
"variable pointers capability"));
|
||||
} else {
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Invalid storage class for pointer operand 2[%gep]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateFunctionCall,
|
||||
NonMemoryObjectDeclarationVariablePointersStorageBuffer) {
|
||||
const std::string storage_class = GetParam();
|
||||
|
||||
std::string spirv = GenerateShaderAccessChain(
|
||||
storage_class, "OpCapability VariablePointersStorageBuffer",
|
||||
"OpExtension \"SPV_KHR_variable_pointers\"");
|
||||
|
||||
const std::vector<std::string> valid_storage_classes = {
|
||||
"UniformConstant", "Function", "Private",
|
||||
"Workgroup", "StorageBuffer", "AtomicCounter"};
|
||||
bool valid_sc =
|
||||
std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
|
||||
storage_class) != valid_storage_classes.end();
|
||||
bool validate = storage_class == "StorageBuffer";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
if (validate) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
} else {
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
if (valid_sc) {
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Pointer operand 2[%gep] must be a memory object declaration"));
|
||||
} else {
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Invalid storage class for pointer operand 2[%gep]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationVariablePointers) {
|
||||
const std::string storage_class = GetParam();
|
||||
|
||||
std::string spirv =
|
||||
GenerateShaderAccessChain(storage_class, "OpCapability VariablePointers",
|
||||
"OpExtension \"SPV_KHR_variable_pointers\"");
|
||||
|
||||
const std::vector<std::string> valid_storage_classes = {
|
||||
"UniformConstant", "Function", "Private",
|
||||
"Workgroup", "StorageBuffer", "AtomicCounter"};
|
||||
bool valid_sc =
|
||||
std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
|
||||
storage_class) != valid_storage_classes.end();
|
||||
bool validate =
|
||||
storage_class == "StorageBuffer" || storage_class == "Workgroup";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
if (validate) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
} else {
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
if (valid_sc) {
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Pointer operand 2[%gep] must be a memory object declaration"));
|
||||
} else {
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Invalid storage class for pointer operand 2[%gep]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(StorageClass, ValidateFunctionCall,
|
||||
Values("UniformConstant", "Input", "Uniform", "Output",
|
||||
"Workgroup", "Private", "Function",
|
||||
"PushConstant", "Image", "StorageBuffer",
|
||||
"AtomicCounter"));
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
@ -2274,6 +2274,7 @@ void createVariablePointerSpirvProgram(std::ostringstream* spirv,
|
||||
*spirv << "OpCapability VariablePointers ";
|
||||
*spirv << "OpExtension \"SPV_KHR_variable_pointers\" ";
|
||||
}
|
||||
*spirv << "OpExtension \"SPV_KHR_storage_buffer_storage_class\" ";
|
||||
*spirv << R"(
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
@ -2282,12 +2283,12 @@ void createVariablePointerSpirvProgram(std::ostringstream* spirv,
|
||||
%bool = OpTypeBool
|
||||
%i32 = OpTypeInt 32 1
|
||||
%f32 = OpTypeFloat 32
|
||||
%f32ptr = OpTypePointer Uniform %f32
|
||||
%f32ptr = OpTypePointer StorageBuffer %f32
|
||||
%i = OpConstant %i32 1
|
||||
%zero = OpConstant %i32 0
|
||||
%float_1 = OpConstant %f32 1.0
|
||||
%ptr1 = OpVariable %f32ptr Uniform
|
||||
%ptr2 = OpVariable %f32ptr Uniform
|
||||
%ptr1 = OpVariable %f32ptr StorageBuffer
|
||||
%ptr2 = OpVariable %f32ptr StorageBuffer
|
||||
)";
|
||||
if (add_helper_function) {
|
||||
*spirv << R"(
|
||||
|
9
3rdparty/spirv-tools/tools/CMakeLists.txt
vendored
9
3rdparty/spirv-tools/tools/CMakeLists.txt
vendored
@ -42,7 +42,9 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES})
|
||||
add_spvtools_tool(TARGET spirv-dis SRCS dis/dis.cpp LIBS ${SPIRV_TOOLS})
|
||||
add_spvtools_tool(TARGET spirv-val SRCS val/val.cpp util/cli_consumer.cpp LIBS ${SPIRV_TOOLS})
|
||||
add_spvtools_tool(TARGET spirv-opt SRCS opt/opt.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS})
|
||||
add_spvtools_tool(TARGET spirv-reduce SRCS reduce/reduce.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-reduce ${SPIRV_TOOLS})
|
||||
if (NOT DEFINED IOS_PLATFORM) # iOS does not allow std::system calls which spirv-reduce requires
|
||||
add_spvtools_tool(TARGET spirv-reduce SRCS reduce/reduce.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-reduce ${SPIRV_TOOLS})
|
||||
endif()
|
||||
add_spvtools_tool(TARGET spirv-link SRCS link/linker.cpp LIBS SPIRV-Tools-link ${SPIRV_TOOLS})
|
||||
add_spvtools_tool(TARGET spirv-stats
|
||||
SRCS stats/stats.cpp
|
||||
@ -62,7 +64,10 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES})
|
||||
${SPIRV_HEADER_INCLUDE_DIR})
|
||||
|
||||
set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt spirv-stats
|
||||
spirv-cfg spirv-link spirv-reduce)
|
||||
spirv-cfg spirv-link)
|
||||
if(NOT DEFINED IOS_PLATFORM)
|
||||
set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-reduce)
|
||||
endif()
|
||||
|
||||
if(SPIRV_BUILD_COMPRESSION)
|
||||
add_spvtools_tool(TARGET spirv-markv
|
||||
|
3
3rdparty/spirv-tools/tools/reduce/reduce.cpp
vendored
3
3rdparty/spirv-tools/tools/reduce/reduce.cpp
vendored
@ -25,6 +25,7 @@
|
||||
#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/reducer.h"
|
||||
#include "source/reduce/remove_function_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h"
|
||||
@ -243,6 +244,8 @@ int main(int argc, const char** argv) {
|
||||
StructuredLoopToSelectionReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<MergeBlocksReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<RemoveFunctionReductionOpportunityFinder>());
|
||||
|
||||
reducer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user