mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-17 20:52:36 +01:00
Updated spirv-tools.
This commit is contained in:
166
3rdparty/spirv-tools/DEPS
vendored
166
3rdparty/spirv-tools/DEPS
vendored
@@ -1,174 +1,26 @@
|
||||
use_relative_paths = True
|
||||
|
||||
vars = {
|
||||
'chromium_git': 'https://chromium.googlesource.com',
|
||||
'github': 'https://github.com',
|
||||
|
||||
'build_revision': '037f38ae0fe5e11b4f7c33b750fd7a1e9634a606',
|
||||
'buildtools_revision': 'ab7b6a7b350dd15804c87c20ce78982811fdd76f',
|
||||
'clang_revision': 'abe5e4f9dc0f1df848c7a0efa05256253e77a7b7',
|
||||
'effcee_revision': '04b624799f5a9dbaf3fa1dbed2ba9dce2fc8dcf2',
|
||||
'googletest_revision': '98a0d007d7092b72eea0e501bb9ad17908a1a036',
|
||||
'testing_revision': '340252637e2e7c72c0901dcbeeacfff419e19b59',
|
||||
're2_revision': '6cf8ccd82dbaab2668e9b13596c68183c9ecd13f',
|
||||
'spirv_headers_revision': '8b911bd2ba37677037b38c9bd286c7c05701bcda',
|
||||
'effcee_revision': 'b83b58d177b797edd1f94c5f10837f2cc2863f0a',
|
||||
'googletest_revision': '2f42d769ad1b08742f7ccb5ad4dd357fc5ff248c',
|
||||
're2_revision': '848dfb7e1d7ba641d598cb66f81590f3999a555a',
|
||||
'spirv_headers_revision': 'de99d4d834aeb51dd9f099baa285bd44fd04bb3d',
|
||||
}
|
||||
|
||||
deps = {
|
||||
"build":
|
||||
Var('chromium_git') + "/chromium/src/build.git@" + Var('build_revision'),
|
||||
|
||||
'buildtools':
|
||||
Var('chromium_git') + '/chromium/buildtools.git@' +
|
||||
Var('buildtools_revision'),
|
||||
|
||||
'external/spirv-headers':
|
||||
Var('github') + '/KhronosGroup/SPIRV-Headers.git@' +
|
||||
Var('spirv_headers_revision'),
|
||||
'external/effcee':
|
||||
Var('github') + '/google/effcee.git@' + Var('effcee_revision'),
|
||||
|
||||
'external/googletest':
|
||||
Var('github') + '/google/googletest.git@' + Var('googletest_revision'),
|
||||
|
||||
'external/effcee':
|
||||
Var('github') + '/google/effcee.git@' + Var('effcee_revision'),
|
||||
|
||||
'external/re2':
|
||||
Var('github') + '/google/re2.git@' + Var('re2_revision'),
|
||||
|
||||
'testing':
|
||||
Var('chromium_git') + '/chromium/src/testing@' +
|
||||
Var('testing_revision'),
|
||||
|
||||
'tools/clang':
|
||||
Var('chromium_git') + '/chromium/src/tools/clang@' + Var('clang_revision')
|
||||
'external/spirv-headers':
|
||||
Var('github') + '/KhronosGroup/SPIRV-Headers.git@' +
|
||||
Var('spirv_headers_revision'),
|
||||
}
|
||||
|
||||
recursedeps = [
|
||||
# buildtools provides clang_format, libc++, and libc++api
|
||||
'buildtools',
|
||||
]
|
||||
|
||||
hooks = [
|
||||
{
|
||||
'name': 'gn_win',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--platform=win32',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-gn',
|
||||
'-s', 'SPIRV-Tools/buildtools/win/gn.exe.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'gn_mac',
|
||||
'pattern': '.',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--platform=darwin',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-gn',
|
||||
'-s', 'SPIRV-Tools/buildtools/mac/gn.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'gn_linux64',
|
||||
'pattern': '.',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--platform=linux*',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-gn',
|
||||
'-s', 'SPIRV-Tools/buildtools/linux64/gn.sha1',
|
||||
],
|
||||
},
|
||||
# Pull clang-format binaries using checked-in hashes.
|
||||
{
|
||||
'name': 'clang_format_win',
|
||||
'pattern': '.',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--platform=win32',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-clang-format',
|
||||
'-s', 'SPIRV-Tools/buildtools/win/clang-format.exe.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'clang_format_mac',
|
||||
'pattern': '.',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--platform=darwin',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-clang-format',
|
||||
'-s', 'SPIRV-Tools/buildtools/mac/clang-format.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'clang_format_linux',
|
||||
'pattern': '.',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--platform=linux*',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-clang-format',
|
||||
'-s', 'SPIRV-Tools/buildtools/linux64/clang-format.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
# Pull clang
|
||||
'name': 'clang',
|
||||
'pattern': '.',
|
||||
'action': ['python',
|
||||
'SPIRV-Tools/tools/clang/scripts/update.py'
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'sysroot_arm',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_linux and checkout_arm',
|
||||
'action': ['python', 'SPIRV-Tools/build/linux/sysroot_scripts/install-sysroot.py',
|
||||
'--arch=arm'],
|
||||
},
|
||||
{
|
||||
'name': 'sysroot_arm64',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_linux and checkout_arm64',
|
||||
'action': ['python', 'SPIRV-Tools/build/linux/sysroot_scripts/install-sysroot.py',
|
||||
'--arch=arm64'],
|
||||
},
|
||||
{
|
||||
'name': 'sysroot_x86',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_linux and (checkout_x86 or checkout_x64)',
|
||||
'action': ['python', 'SPIRV-Tools/build/linux/sysroot_scripts/install-sysroot.py',
|
||||
'--arch=x86'],
|
||||
},
|
||||
{
|
||||
'name': 'sysroot_mips',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_linux and checkout_mips',
|
||||
'action': ['python', 'SPIRV-Tools/build/linux/sysroot_scripts/install-sysroot.py',
|
||||
'--arch=mips'],
|
||||
},
|
||||
{
|
||||
'name': 'sysroot_x64',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_linux and checkout_x64',
|
||||
'action': ['python', 'SPIRV-Tools/build/linux/sysroot_scripts/install-sysroot.py',
|
||||
'--arch=x64'],
|
||||
},
|
||||
{
|
||||
# Update the Windows toolchain if necessary.
|
||||
'name': 'win_toolchain',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_win',
|
||||
'action': ['python', 'SPIRV-Tools/build/vs_toolchain.py', 'update', '--force'],
|
||||
},
|
||||
{
|
||||
# Update the Mac toolchain if necessary.
|
||||
'name': 'mac_toolchain',
|
||||
'pattern': '.',
|
||||
'action': ['python', 'SPIRV-Tools/build/mac_toolchain.py'],
|
||||
},
|
||||
]
|
||||
|
||||
11
3rdparty/spirv-tools/README.md
vendored
11
3rdparty/spirv-tools/README.md
vendored
@@ -270,6 +270,10 @@ mkdir build && cd build
|
||||
cmake [-G <platform-generator>] <spirv-dir>
|
||||
```
|
||||
|
||||
*Note*:
|
||||
The script `utils/git-sync-deps` can be used to checkout and/or update the
|
||||
contents of the repos under `external/` instead of manually maintaining them.
|
||||
|
||||
Once the build files have been generated, build using your preferred
|
||||
development environment.
|
||||
|
||||
@@ -344,6 +348,13 @@ $ANDROID_NDK/ndk-build -C ../android_test \
|
||||
NDK_APP_OUT=`pwd`/app
|
||||
```
|
||||
|
||||
### Updating DEPS
|
||||
Occasionally the entries in DEPS will need to be updated. This is done on demand
|
||||
when there is a request to do this, often due to downstream breakages. There is
|
||||
a script `utils/roll_deps.sh` provided, which will generate a patch with the
|
||||
updated DEPS values. This will still need to be tested in your checkout to
|
||||
confirm that there are no integration issues that need to be resolved.
|
||||
|
||||
## Library
|
||||
|
||||
### Usage
|
||||
|
||||
@@ -1 +1 @@
|
||||
"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-47-g59983a60"
|
||||
"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-60-gdf86bb44"
|
||||
|
||||
@@ -32,6 +32,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass.h
|
||||
fuzzer_pass_add_dead_breaks.h
|
||||
fuzzer_pass_add_useful_constructs.h
|
||||
fuzzer_pass_obfuscate_constants.h
|
||||
fuzzer_pass_permute_blocks.h
|
||||
fuzzer_pass_split_blocks.h
|
||||
fuzzer_util.h
|
||||
@@ -46,8 +47,10 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_type_boolean.h
|
||||
transformation_add_type_float.h
|
||||
transformation_add_type_int.h
|
||||
transformation_add_type_pointer.h
|
||||
transformation_move_block_down.h
|
||||
transformation_replace_boolean_constant_with_constant_binary.h
|
||||
transformation_replace_constant_with_uniform.h
|
||||
transformation_split_block.h
|
||||
uniform_buffer_element_descriptor.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h
|
||||
@@ -58,6 +61,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass.cpp
|
||||
fuzzer_pass_add_dead_breaks.cpp
|
||||
fuzzer_pass_add_useful_constructs.cpp
|
||||
fuzzer_pass_obfuscate_constants.cpp
|
||||
fuzzer_pass_permute_blocks.cpp
|
||||
fuzzer_pass_split_blocks.cpp
|
||||
fuzzer_util.cpp
|
||||
@@ -71,8 +75,10 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_type_boolean.cpp
|
||||
transformation_add_type_float.cpp
|
||||
transformation_add_type_int.cpp
|
||||
transformation_add_type_pointer.cpp
|
||||
transformation_move_block_down.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary.cpp
|
||||
transformation_replace_constant_with_uniform.cpp
|
||||
transformation_split_block.cpp
|
||||
uniform_buffer_element_descriptor.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc
|
||||
|
||||
@@ -64,6 +64,11 @@ struct FactManager::ConstantUniformFacts {
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact,
|
||||
uint32_t type_id) const;
|
||||
|
||||
// Checks that the width of a floating-point constant is supported, and that
|
||||
// the constant is finite.
|
||||
bool FloatingPointValueIsSuitable(const protobufs::FactConstantUniform& fact,
|
||||
uint32_t width) const;
|
||||
|
||||
std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>
|
||||
facts_and_type_ids;
|
||||
};
|
||||
@@ -169,22 +174,48 @@ FactManager::ConstantUniformFacts::GetTypesForWhichUniformValuesAreKnown()
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FactManager::ConstantUniformFacts::FloatingPointValueIsSuitable(
|
||||
const protobufs::FactConstantUniform& fact, uint32_t width) const {
|
||||
const uint32_t kFloatWidth = 32;
|
||||
const uint32_t kDoubleWidth = 64;
|
||||
if (width != kFloatWidth && width != kDoubleWidth) {
|
||||
// Only 32- and 64-bit floating-point types are handled.
|
||||
return false;
|
||||
}
|
||||
std::vector<uint32_t> words = GetConstantWords(fact);
|
||||
if (width == 32) {
|
||||
float value;
|
||||
memcpy(&value, words.data(), sizeof(float));
|
||||
if (!std::isfinite(value)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
double value;
|
||||
memcpy(&value, words.data(), sizeof(double));
|
||||
if (!std::isfinite(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FactManager::ConstantUniformFacts::AddFact(
|
||||
const protobufs::FactConstantUniform& fact, opt::IRContext* context) {
|
||||
auto should_be_uniform_variable = context->get_def_use_mgr()->GetDef(
|
||||
fact.uniform_buffer_element_descriptor().uniform_variable_id());
|
||||
if (!should_be_uniform_variable) {
|
||||
return false;
|
||||
}
|
||||
if (SpvOpVariable != should_be_uniform_variable->opcode()) {
|
||||
return false;
|
||||
}
|
||||
if (SpvStorageClassUniform !=
|
||||
should_be_uniform_variable->GetSingleWordInOperand(0)) {
|
||||
// Try to find a unique instruction that declares a variable such that the
|
||||
// variable is decorated with the descriptor set and binding associated with
|
||||
// the constant uniform fact.
|
||||
opt::Instruction* uniform_variable = FindUniformVariable(
|
||||
fact.uniform_buffer_element_descriptor(), context, true);
|
||||
|
||||
if (!uniform_variable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(SpvOpVariable == uniform_variable->opcode());
|
||||
assert(SpvStorageClassUniform == uniform_variable->GetSingleWordInOperand(0));
|
||||
|
||||
auto should_be_uniform_pointer_type =
|
||||
context->get_type_mgr()->GetType(should_be_uniform_variable->type_id());
|
||||
context->get_type_mgr()->GetType(uniform_variable->type_id());
|
||||
if (!should_be_uniform_pointer_type->AsPointer()) {
|
||||
return false;
|
||||
}
|
||||
@@ -193,7 +224,7 @@ bool FactManager::ConstantUniformFacts::AddFact(
|
||||
return false;
|
||||
}
|
||||
auto should_be_uniform_pointer_instruction =
|
||||
context->get_def_use_mgr()->GetDef(should_be_uniform_variable->type_id());
|
||||
context->get_def_use_mgr()->GetDef(uniform_variable->type_id());
|
||||
auto element_type =
|
||||
should_be_uniform_pointer_instruction->GetSingleWordInOperand(1);
|
||||
|
||||
@@ -236,6 +267,12 @@ bool FactManager::ConstantUniformFacts::AddFact(
|
||||
auto width = final_element_type->AsFloat()
|
||||
? final_element_type->AsFloat()->width()
|
||||
: final_element_type->AsInteger()->width();
|
||||
|
||||
if (final_element_type->AsFloat() &&
|
||||
!FloatingPointValueIsSuitable(fact, width)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto required_words = (width + 32 - 1) / 32;
|
||||
if (static_cast<uint32_t>(fact.constant_word().size()) != required_words) {
|
||||
return false;
|
||||
|
||||
6
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
vendored
6
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
vendored
@@ -21,6 +21,7 @@
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_dead_breaks.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
|
||||
#include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
|
||||
#include "source/fuzz/fuzzer_pass_permute_blocks.h"
|
||||
#include "source/fuzz/fuzzer_pass_split_blocks.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
@@ -113,8 +114,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
FuzzerPassAddDeadBreaks(ir_context.get(), &fact_manager, &fuzzer_context,
|
||||
transformation_sequence_out)
|
||||
.Apply();
|
||||
|
||||
// TODO(afd) Various other passes will be added.
|
||||
FuzzerPassObfuscateConstants(ir_context.get(), &fact_manager, &fuzzer_context,
|
||||
transformation_sequence_out)
|
||||
.Apply();
|
||||
|
||||
// Finally, give the blocks in the module a good shake-up.
|
||||
FuzzerPassPermuteBlocks(ir_context.get(), &fact_manager, &fuzzer_context,
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
@@ -24,8 +26,19 @@ namespace {
|
||||
|
||||
const uint32_t kDefaultChanceOfAddingDeadBreak = 20;
|
||||
const uint32_t kDefaultChanceOfMovingBlockDown = 25;
|
||||
const uint32_t kDefaultChanceOfObfuscatingConstant = 20;
|
||||
const uint32_t kDefaultChanceOfSplittingBlock = 20;
|
||||
|
||||
// Default functions for controlling how deep to go during recursive
|
||||
// generation/transformation. Keep them in alphabetical order.
|
||||
|
||||
const std::function<bool(uint32_t, RandomGenerator*)>
|
||||
kDefaultGoDeeperInConstantObfuscation =
|
||||
[](uint32_t current_depth, RandomGenerator* random_generator) -> bool {
|
||||
double chance = 1.0 / std::pow(3.0, static_cast<float>(current_depth + 1));
|
||||
return random_generator->RandomDouble() < chance;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
@@ -34,7 +47,10 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
next_fresh_id_(min_fresh_id),
|
||||
chance_of_adding_dead_break_(kDefaultChanceOfAddingDeadBreak),
|
||||
chance_of_moving_block_down_(kDefaultChanceOfMovingBlockDown),
|
||||
chance_of_splitting_block_(kDefaultChanceOfSplittingBlock) {}
|
||||
chance_of_obfuscating_constant_(kDefaultChanceOfObfuscatingConstant),
|
||||
chance_of_splitting_block_(kDefaultChanceOfSplittingBlock),
|
||||
go_deeper_in_constant_obfuscation_(
|
||||
kDefaultGoDeeperInConstantObfuscation) {}
|
||||
|
||||
FuzzerContext::~FuzzerContext() = default;
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#ifndef SOURCE_FUZZ_FUZZER_CONTEXT_H_
|
||||
#define SOURCE_FUZZ_FUZZER_CONTEXT_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "source/fuzz/random_generator.h"
|
||||
#include "source/opt/function.h"
|
||||
|
||||
@@ -43,8 +45,18 @@ class FuzzerContext {
|
||||
// Keep them in alphabetical order.
|
||||
uint32_t GetChanceOfAddingDeadBreak() { return chance_of_adding_dead_break_; }
|
||||
uint32_t GetChanceOfMovingBlockDown() { return chance_of_moving_block_down_; }
|
||||
uint32_t GetChanceOfObfuscatingConstant() {
|
||||
return chance_of_obfuscating_constant_;
|
||||
}
|
||||
uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; }
|
||||
|
||||
// Probability distributions to control how deeply to recurse.
|
||||
// Keep them in alphabetical order.
|
||||
const std::function<bool(uint32_t, RandomGenerator*)>&
|
||||
GoDeeperInConstantObfuscation() {
|
||||
return go_deeper_in_constant_obfuscation_;
|
||||
}
|
||||
|
||||
private:
|
||||
// The source of randomness.
|
||||
RandomGenerator* random_generator_;
|
||||
@@ -55,7 +67,13 @@ class FuzzerContext {
|
||||
// Keep them in alphabetical order.
|
||||
uint32_t chance_of_adding_dead_break_;
|
||||
uint32_t chance_of_moving_block_down_;
|
||||
uint32_t chance_of_obfuscating_constant_;
|
||||
uint32_t chance_of_splitting_block_;
|
||||
|
||||
// Functions to determine with what probability to go deeper when generating
|
||||
// or mutating constructs recursively.
|
||||
const std::function<bool(uint32_t, RandomGenerator*)>&
|
||||
go_deeper_in_constant_obfuscation_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "source/fuzz/transformation_add_type_boolean.h"
|
||||
#include "source/fuzz/transformation_add_type_float.h"
|
||||
#include "source/fuzz/transformation_add_type_int.h"
|
||||
#include "source/fuzz/transformation_add_type_pointer.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
@@ -176,6 +177,55 @@ void FuzzerPassAddUsefulConstructs::Apply() {
|
||||
for (unsigned int& datum : uint_data) {
|
||||
MaybeAddFloatConstant(32, {datum});
|
||||
}
|
||||
|
||||
// For every known-to-be-constant uniform, make sure we have instructions
|
||||
// declaring:
|
||||
// - a pointer type with uniform storage class, whose pointee type is the type
|
||||
// of the element
|
||||
// - a signed integer constant for each index required to access the element
|
||||
// - a constant for the constant value itself
|
||||
for (auto& fact_and_type_id :
|
||||
GetFactManager()->GetConstantUniformFactsAndTypes()) {
|
||||
uint32_t element_type_id = fact_and_type_id.second;
|
||||
assert(element_type_id);
|
||||
auto element_type =
|
||||
GetIRContext()->get_type_mgr()->GetType(element_type_id);
|
||||
assert(element_type &&
|
||||
"If the constant uniform fact is well-formed, the module must "
|
||||
"already have a declaration of the type for the uniform element.");
|
||||
opt::analysis::Pointer uniform_pointer(element_type,
|
||||
SpvStorageClassUniform);
|
||||
if (!GetIRContext()->get_type_mgr()->GetId(&uniform_pointer)) {
|
||||
auto add_pointer = transformation::MakeTransformationAddTypePointer(
|
||||
GetFuzzerContext()->GetFreshId(), SpvStorageClassUniform,
|
||||
element_type_id);
|
||||
assert(transformation::IsApplicable(add_pointer, GetIRContext(),
|
||||
*GetFactManager()) &&
|
||||
"Should be applicable by construction.");
|
||||
transformation::Apply(add_pointer, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation()->mutable_add_type_pointer() =
|
||||
add_pointer;
|
||||
}
|
||||
std::vector<uint32_t> words;
|
||||
for (auto word : fact_and_type_id.first.constant_word()) {
|
||||
words.push_back(word);
|
||||
}
|
||||
// We get the element type again as the type manager may have been
|
||||
// invalidated since we last retrieved it.
|
||||
element_type = GetIRContext()->get_type_mgr()->GetType(element_type_id);
|
||||
if (element_type->AsInteger()) {
|
||||
MaybeAddIntConstant(element_type->AsInteger()->width(),
|
||||
element_type->AsInteger()->IsSigned(), words);
|
||||
} else {
|
||||
assert(element_type->AsFloat() &&
|
||||
"Known uniform values must be integer or floating-point.");
|
||||
MaybeAddFloatConstant(element_type->AsFloat()->width(), words);
|
||||
}
|
||||
for (auto index :
|
||||
fact_and_type_id.first.uniform_buffer_element_descriptor().index()) {
|
||||
MaybeAddIntConstant(32, true, {index});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
|
||||
471
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
vendored
Normal file
471
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
vendored
Normal file
@@ -0,0 +1,471 @@
|
||||
// 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 "source/fuzz/fuzzer_pass_obfuscate_constants.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassObfuscateConstants::FuzzerPassObfuscateConstants(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
|
||||
|
||||
FuzzerPassObfuscateConstants::~FuzzerPassObfuscateConstants() = default;
|
||||
|
||||
void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
const std::vector<SpvOp>& greater_than_opcodes,
|
||||
const std::vector<SpvOp>& less_than_opcodes, uint32_t constant_id_1,
|
||||
uint32_t constant_id_2, bool first_constant_is_larger) {
|
||||
auto bool_constant_opcode = GetIRContext()
|
||||
->get_def_use_mgr()
|
||||
->GetDef(bool_constant_use.id_of_interest())
|
||||
->opcode();
|
||||
assert((bool_constant_opcode == SpvOpConstantFalse ||
|
||||
bool_constant_opcode == SpvOpConstantTrue) &&
|
||||
"Precondition: this must be a usage of a boolean constant.");
|
||||
|
||||
// Pick an opcode at random. First randomly decide whether to generate
|
||||
// a 'greater than' or 'less than' kind of opcode, and then select a
|
||||
// random opcode from the resulting subset.
|
||||
SpvOp comparison_opcode;
|
||||
if (GetFuzzerContext()->GetRandomGenerator()->RandomBool()) {
|
||||
comparison_opcode = greater_than_opcodes
|
||||
[GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
|
||||
static_cast<uint32_t>(greater_than_opcodes.size()))];
|
||||
} else {
|
||||
comparison_opcode = less_than_opcodes
|
||||
[GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
|
||||
static_cast<uint32_t>(less_than_opcodes.size()))];
|
||||
}
|
||||
|
||||
// We now need to decide how to order constant_id_1 and constant_id_2 such
|
||||
// that 'constant_id_1 comparison_opcode constant_id_2' evaluates to the
|
||||
// boolean constant.
|
||||
const bool is_greater_than_opcode =
|
||||
std::find(greater_than_opcodes.begin(), greater_than_opcodes.end(),
|
||||
comparison_opcode) != greater_than_opcodes.end();
|
||||
uint32_t lhs_id;
|
||||
uint32_t rhs_id;
|
||||
if ((bool_constant_opcode == SpvOpConstantTrue &&
|
||||
first_constant_is_larger == is_greater_than_opcode) ||
|
||||
(bool_constant_opcode == SpvOpConstantFalse &&
|
||||
first_constant_is_larger != is_greater_than_opcode)) {
|
||||
lhs_id = constant_id_1;
|
||||
rhs_id = constant_id_2;
|
||||
} else {
|
||||
lhs_id = constant_id_2;
|
||||
rhs_id = constant_id_1;
|
||||
}
|
||||
|
||||
// We can now make a transformation that will replace |bool_constant_use|
|
||||
// with an expression of the form (written using infix notation):
|
||||
// |lhs_id| |comparison_opcode| |rhs_id|
|
||||
auto transformation = transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
bool_constant_use, lhs_id, rhs_id, comparison_opcode,
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
// The transformation should be applicable by construction.
|
||||
assert(transformation::IsApplicable(transformation, GetIRContext(),
|
||||
*GetFactManager()));
|
||||
|
||||
// Applying this transformation yields a pointer to the new instruction that
|
||||
// computes the result of the binary expression.
|
||||
auto binary_operator_instruction =
|
||||
transformation::Apply(transformation, GetIRContext(), GetFactManager());
|
||||
|
||||
// Add this transformation to the sequence of transformations that have been
|
||||
// applied.
|
||||
*GetTransformations()
|
||||
->add_transformation()
|
||||
->mutable_replace_boolean_constant_with_constant_binary() =
|
||||
transformation;
|
||||
|
||||
// Having made a binary expression, there may now be opportunities to further
|
||||
// obfuscate the constants used as the LHS and RHS of the expression (e.g. by
|
||||
// replacing them with loads from known uniforms).
|
||||
//
|
||||
// We thus consider operands 0 and 1 (LHS and RHS in turn).
|
||||
for (uint32_t index : {0u, 1u}) {
|
||||
// We randomly decide, based on the current depth of obfuscation, whether
|
||||
// to further obfuscate this operand.
|
||||
if (GetFuzzerContext()->GoDeeperInConstantObfuscation()(
|
||||
depth, GetFuzzerContext()->GetRandomGenerator())) {
|
||||
auto in_operand_use = transformation::MakeIdUseDescriptor(
|
||||
binary_operator_instruction->GetSingleWordInOperand(index),
|
||||
binary_operator_instruction->opcode(), index,
|
||||
binary_operator_instruction->result_id(), 0);
|
||||
ObfuscateConstant(depth + 1, in_operand_use);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaFloatConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
uint32_t float_constant_id_1, uint32_t float_constant_id_2) {
|
||||
auto float_constant_1 = GetIRContext()
|
||||
->get_constant_mgr()
|
||||
->FindDeclaredConstant(float_constant_id_1)
|
||||
->AsFloatConstant();
|
||||
auto float_constant_2 = GetIRContext()
|
||||
->get_constant_mgr()
|
||||
->FindDeclaredConstant(float_constant_id_2)
|
||||
->AsFloatConstant();
|
||||
assert(float_constant_1->words() != float_constant_2->words() &&
|
||||
"The constants should not be identical.");
|
||||
assert(std::isfinite(float_constant_1->GetValueAsDouble()) &&
|
||||
"The constants must be finite numbers.");
|
||||
assert(std::isfinite(float_constant_2->GetValueAsDouble()) &&
|
||||
"The constants must be finite numbers.");
|
||||
bool first_constant_is_larger;
|
||||
assert(float_constant_1->type()->AsFloat()->width() ==
|
||||
float_constant_2->type()->AsFloat()->width() &&
|
||||
"First and second floating-point constants must have the same width.");
|
||||
if (float_constant_1->type()->AsFloat()->width() == 32) {
|
||||
first_constant_is_larger =
|
||||
float_constant_1->GetFloat() > float_constant_2->GetFloat();
|
||||
} else {
|
||||
assert(float_constant_1->type()->AsFloat()->width() == 64 &&
|
||||
"Supported floating-point widths are 32 and 64.");
|
||||
first_constant_is_larger =
|
||||
float_constant_1->GetDouble() > float_constant_2->GetDouble();
|
||||
}
|
||||
std::vector<SpvOp> greater_than_opcodes{
|
||||
SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
|
||||
SpvOpFUnordGreaterThanEqual};
|
||||
std::vector<SpvOp> less_than_opcodes{
|
||||
SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
|
||||
SpvOpFUnordGreaterThanEqual};
|
||||
|
||||
ObfuscateBoolConstantViaConstantPair(
|
||||
depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
|
||||
float_constant_id_1, float_constant_id_2, first_constant_is_larger);
|
||||
}
|
||||
|
||||
void FuzzerPassObfuscateConstants::
|
||||
ObfuscateBoolConstantViaSignedIntConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
uint32_t signed_int_constant_id_1, uint32_t signed_int_constant_id_2) {
|
||||
auto signed_int_constant_1 =
|
||||
GetIRContext()
|
||||
->get_constant_mgr()
|
||||
->FindDeclaredConstant(signed_int_constant_id_1)
|
||||
->AsIntConstant();
|
||||
auto signed_int_constant_2 =
|
||||
GetIRContext()
|
||||
->get_constant_mgr()
|
||||
->FindDeclaredConstant(signed_int_constant_id_2)
|
||||
->AsIntConstant();
|
||||
assert(signed_int_constant_1->words() != signed_int_constant_2->words() &&
|
||||
"The constants should not be identical.");
|
||||
bool first_constant_is_larger;
|
||||
assert(signed_int_constant_1->type()->AsInteger()->width() ==
|
||||
signed_int_constant_2->type()->AsInteger()->width() &&
|
||||
"First and second floating-point constants must have the same width.");
|
||||
assert(signed_int_constant_1->type()->AsInteger()->IsSigned());
|
||||
assert(signed_int_constant_2->type()->AsInteger()->IsSigned());
|
||||
if (signed_int_constant_1->type()->AsFloat()->width() == 32) {
|
||||
first_constant_is_larger =
|
||||
signed_int_constant_1->GetS32() > signed_int_constant_2->GetS32();
|
||||
} else {
|
||||
assert(signed_int_constant_1->type()->AsFloat()->width() == 64 &&
|
||||
"Supported integer widths are 32 and 64.");
|
||||
first_constant_is_larger =
|
||||
signed_int_constant_1->GetS64() > signed_int_constant_2->GetS64();
|
||||
}
|
||||
std::vector<SpvOp> greater_than_opcodes{SpvOpSGreaterThan,
|
||||
SpvOpSGreaterThanEqual};
|
||||
std::vector<SpvOp> less_than_opcodes{SpvOpSLessThan, SpvOpSLessThanEqual};
|
||||
|
||||
ObfuscateBoolConstantViaConstantPair(
|
||||
depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
|
||||
signed_int_constant_id_1, signed_int_constant_id_2,
|
||||
first_constant_is_larger);
|
||||
}
|
||||
|
||||
void FuzzerPassObfuscateConstants::
|
||||
ObfuscateBoolConstantViaUnsignedIntConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
uint32_t unsigned_int_constant_id_1,
|
||||
uint32_t unsigned_int_constant_id_2) {
|
||||
auto unsigned_int_constant_1 =
|
||||
GetIRContext()
|
||||
->get_constant_mgr()
|
||||
->FindDeclaredConstant(unsigned_int_constant_id_1)
|
||||
->AsIntConstant();
|
||||
auto unsigned_int_constant_2 =
|
||||
GetIRContext()
|
||||
->get_constant_mgr()
|
||||
->FindDeclaredConstant(unsigned_int_constant_id_2)
|
||||
->AsIntConstant();
|
||||
assert(unsigned_int_constant_1->words() != unsigned_int_constant_2->words() &&
|
||||
"The constants should not be identical.");
|
||||
bool first_constant_is_larger;
|
||||
assert(unsigned_int_constant_1->type()->AsInteger()->width() ==
|
||||
unsigned_int_constant_2->type()->AsInteger()->width() &&
|
||||
"First and second floating-point constants must have the same width.");
|
||||
assert(!unsigned_int_constant_1->type()->AsInteger()->IsSigned());
|
||||
assert(!unsigned_int_constant_2->type()->AsInteger()->IsSigned());
|
||||
if (unsigned_int_constant_1->type()->AsFloat()->width() == 32) {
|
||||
first_constant_is_larger =
|
||||
unsigned_int_constant_1->GetU32() > unsigned_int_constant_2->GetU32();
|
||||
} else {
|
||||
assert(unsigned_int_constant_1->type()->AsFloat()->width() == 64 &&
|
||||
"Supported integer widths are 32 and 64.");
|
||||
first_constant_is_larger =
|
||||
unsigned_int_constant_1->GetU64() > unsigned_int_constant_2->GetU64();
|
||||
}
|
||||
std::vector<SpvOp> greater_than_opcodes{SpvOpUGreaterThan,
|
||||
SpvOpUGreaterThanEqual};
|
||||
std::vector<SpvOp> less_than_opcodes{SpvOpULessThan, SpvOpULessThanEqual};
|
||||
|
||||
ObfuscateBoolConstantViaConstantPair(
|
||||
depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
|
||||
unsigned_int_constant_id_1, unsigned_int_constant_id_2,
|
||||
first_constant_is_larger);
|
||||
}
|
||||
|
||||
void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& constant_use) {
|
||||
// We want to replace the boolean constant use with a binary expression over
|
||||
// scalar constants, but only if we can then potentially replace the constants
|
||||
// with uniforms of the same value.
|
||||
|
||||
auto available_types_with_uniforms =
|
||||
GetFactManager()->GetTypesForWhichUniformValuesAreKnown();
|
||||
if (available_types_with_uniforms.empty()) {
|
||||
// Do not try to obfuscate if we do not have access to any uniform
|
||||
// elements with known values.
|
||||
return;
|
||||
}
|
||||
auto chosen_type_id = available_types_with_uniforms
|
||||
[GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
|
||||
static_cast<uint32_t>(available_types_with_uniforms.size()))];
|
||||
auto available_constants =
|
||||
GetFactManager()->GetConstantsAvailableFromUniformsForType(
|
||||
GetIRContext(), chosen_type_id);
|
||||
if (available_constants.size() == 1) {
|
||||
// TODO(afd): for now we only obfuscate a boolean if there are at least
|
||||
// two constants available from uniforms, so that we can do a
|
||||
// comparison between them. It would be good to be able to do the
|
||||
// obfuscation even if there is only one such constant, if there is
|
||||
// also another regular constant available.
|
||||
return;
|
||||
}
|
||||
|
||||
// We know we have at least two known-to-be-constant uniforms of the chosen
|
||||
// type. Pick one of them at random.
|
||||
auto constant_index_1 =
|
||||
GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
|
||||
static_cast<uint32_t>(available_constants.size()));
|
||||
uint32_t constant_index_2;
|
||||
|
||||
// Now choose another one distinct from the first one.
|
||||
do {
|
||||
constant_index_2 = GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
|
||||
static_cast<uint32_t>(available_constants.size()));
|
||||
} while (constant_index_1 == constant_index_2);
|
||||
|
||||
auto constant_id_1 = available_constants[constant_index_1];
|
||||
auto constant_id_2 = available_constants[constant_index_2];
|
||||
|
||||
assert(constant_id_1 != 0 && constant_id_2 != 0 &&
|
||||
"We should not find an available constant with an id of 0.");
|
||||
|
||||
// Now perform the obfuscation, according to whether the type of the constants
|
||||
// is float, signed int, or unsigned int.
|
||||
auto chosen_type = GetIRContext()->get_type_mgr()->GetType(chosen_type_id);
|
||||
if (chosen_type->AsFloat()) {
|
||||
ObfuscateBoolConstantViaFloatConstantPair(depth, constant_use,
|
||||
constant_id_1, constant_id_2);
|
||||
} else {
|
||||
assert(chosen_type->AsInteger() &&
|
||||
"We should only have uniform facts about ints and floats.");
|
||||
if (chosen_type->AsInteger()->IsSigned()) {
|
||||
ObfuscateBoolConstantViaSignedIntConstantPair(
|
||||
depth, constant_use, constant_id_1, constant_id_2);
|
||||
} else {
|
||||
ObfuscateBoolConstantViaUnsignedIntConstantPair(
|
||||
depth, constant_use, constant_id_1, constant_id_2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
|
||||
uint32_t /*depth*/, const protobufs::IdUseDescriptor& constant_use) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2670): consider
|
||||
// additional ways to obfuscate scalar constants.
|
||||
|
||||
// Check whether we know that any uniforms are guaranteed to be equal to the
|
||||
// scalar constant associated with |constant_use|.
|
||||
auto uniform_descriptors = GetFactManager()->GetUniformDescriptorsForConstant(
|
||||
GetIRContext(), constant_use.id_of_interest());
|
||||
if (uniform_descriptors.empty()) {
|
||||
// No relevant uniforms, so do not obfuscate.
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose a random available uniform known to be equal to the constant.
|
||||
protobufs::UniformBufferElementDescriptor uniform_descriptor =
|
||||
uniform_descriptors
|
||||
[GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
|
||||
static_cast<uint32_t>(uniform_descriptors.size()))];
|
||||
// Create, apply and record a transformation to replace the constant use with
|
||||
// the result of a load from the chosen uniform.
|
||||
auto transformation =
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
// Transformation should be applicable by construction.
|
||||
assert(transformation::IsApplicable(transformation, GetIRContext(),
|
||||
*GetFactManager()));
|
||||
transformation::Apply(transformation, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()
|
||||
->add_transformation()
|
||||
->mutable_replace_constant_with_uniform() = transformation;
|
||||
}
|
||||
|
||||
void FuzzerPassObfuscateConstants::ObfuscateConstant(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& constant_use) {
|
||||
switch (GetIRContext()
|
||||
->get_def_use_mgr()
|
||||
->GetDef(constant_use.id_of_interest())
|
||||
->opcode()) {
|
||||
case SpvOpConstantTrue:
|
||||
case SpvOpConstantFalse:
|
||||
ObfuscateBoolConstant(depth, constant_use);
|
||||
break;
|
||||
case SpvOpConstant:
|
||||
ObfuscateScalarConstant(depth, constant_use);
|
||||
break;
|
||||
default:
|
||||
assert(false && "The opcode should be one of the above.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzerPassObfuscateConstants::MaybeAddConstantIdUse(
|
||||
const opt::Instruction& inst, uint32_t in_operand_index,
|
||||
uint32_t base_instruction_result_id,
|
||||
const std::map<SpvOp, uint32_t>& skipped_opcode_count,
|
||||
std::vector<protobufs::IdUseDescriptor>* constant_uses) {
|
||||
if (inst.GetInOperand(in_operand_index).type != SPV_OPERAND_TYPE_ID) {
|
||||
// The operand is not an id, so it cannot be a constant id.
|
||||
return;
|
||||
}
|
||||
auto operand_id = inst.GetSingleWordInOperand(in_operand_index);
|
||||
auto operand_definition =
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(operand_id);
|
||||
switch (operand_definition->opcode()) {
|
||||
case SpvOpConstantFalse:
|
||||
case SpvOpConstantTrue:
|
||||
case SpvOpConstant: {
|
||||
// The operand is a constant id, so make an id use descriptor and record
|
||||
// it.
|
||||
protobufs::IdUseDescriptor id_use_descriptor;
|
||||
id_use_descriptor.set_id_of_interest(operand_id);
|
||||
id_use_descriptor.set_target_instruction_opcode(inst.opcode());
|
||||
id_use_descriptor.set_in_operand_index(in_operand_index);
|
||||
id_use_descriptor.set_base_instruction_result_id(
|
||||
base_instruction_result_id);
|
||||
id_use_descriptor.set_num_opcodes_to_ignore(
|
||||
skipped_opcode_count.find(inst.opcode()) == skipped_opcode_count.end()
|
||||
? 0
|
||||
: skipped_opcode_count.at(inst.opcode()));
|
||||
constant_uses->push_back(id_use_descriptor);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzerPassObfuscateConstants::Apply() {
|
||||
// First, gather up all the constant uses available in the module, by going
|
||||
// through each block in each function.
|
||||
std::vector<protobufs::IdUseDescriptor> constant_uses;
|
||||
for (auto& function : *GetIRContext()->module()) {
|
||||
for (auto& block : function) {
|
||||
// For each constant use we encounter we are going to make an id use
|
||||
// descriptor. An id use is described with respect to a base instruction;
|
||||
// if there are instructions at the start of the block without result ids,
|
||||
// the base instruction will have to be the block's label.
|
||||
uint32_t base_instruction_result_id = block.id();
|
||||
|
||||
// An id use descriptor also records how many instructions of a particular
|
||||
// opcode need to be skipped in order to find the instruction of interest
|
||||
// from the base instruction. We maintain a mapping that records a skip
|
||||
// count for each relevant opcode.
|
||||
std::map<SpvOp, uint32_t> skipped_opcode_count;
|
||||
|
||||
// Go through each instruction in the block.
|
||||
for (auto& inst : block) {
|
||||
if (inst.HasResultId()) {
|
||||
// The instruction has a result id, so can be used as the base
|
||||
// instruction from now on, until another instruction with a result id
|
||||
// is encountered.
|
||||
base_instruction_result_id = inst.result_id();
|
||||
// Opcode skip counts were with respect to the previous base
|
||||
// instruction and are now irrelevant.
|
||||
skipped_opcode_count.clear();
|
||||
}
|
||||
|
||||
// Consider each operand of the instruction, and add a constant id use
|
||||
// for the operand if relevant.
|
||||
for (uint32_t in_operand_index = 0;
|
||||
in_operand_index < inst.NumInOperands(); in_operand_index++) {
|
||||
MaybeAddConstantIdUse(inst, in_operand_index,
|
||||
base_instruction_result_id,
|
||||
skipped_opcode_count, &constant_uses);
|
||||
}
|
||||
|
||||
if (!inst.HasResultId()) {
|
||||
// The instruction has no result id, so in order to identify future id
|
||||
// uses for instructions with this opcode from the existing base
|
||||
// instruction, we need to increase the skip count for this opcode.
|
||||
skipped_opcode_count[inst.opcode()] =
|
||||
skipped_opcode_count.find(inst.opcode()) ==
|
||||
skipped_opcode_count.end()
|
||||
? 1
|
||||
: skipped_opcode_count[inst.opcode()] + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go through the constant uses in a random order by repeatedly pulling out a
|
||||
// constant use at a random index.
|
||||
while (!constant_uses.empty()) {
|
||||
auto index = GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
|
||||
static_cast<uint32_t>(constant_uses.size()));
|
||||
auto constant_use = std::move(constant_uses[index]);
|
||||
constant_uses.erase(constant_uses.begin() + index);
|
||||
// Decide probabilistically whether to skip or obfuscate this constant use.
|
||||
if (GetFuzzerContext()->GetRandomGenerator()->RandomPercentage() >
|
||||
GetFuzzerContext()->GetChanceOfObfuscatingConstant()) {
|
||||
continue;
|
||||
}
|
||||
ObfuscateConstant(0, constant_use);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
107
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h
vendored
Normal file
107
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// 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_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// A fuzzer pass for turning uses of constants into more complex forms.
|
||||
// Examples include replacing 'true' with '42 < 52', and replacing '42' with
|
||||
// 'a.b.c' if 'a.b.c' is known to hold the value '42'.
|
||||
class FuzzerPassObfuscateConstants : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassObfuscateConstants(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassObfuscateConstants() override;
|
||||
|
||||
void Apply() override;
|
||||
|
||||
private:
|
||||
// Applies 0 or more transformations to potentially obfuscate the constant
|
||||
// use represented by |constant_use|. The |depth| parameter controls how
|
||||
// deeply obfuscation can recurse.
|
||||
void ObfuscateConstant(uint32_t depth,
|
||||
const protobufs::IdUseDescriptor& constant_use);
|
||||
|
||||
// This method will try to turn |constant_use|, required to be a use of a
|
||||
// boolean constant, into a binary expression on scalar constants, which may
|
||||
// themselves be recursively obfuscated.
|
||||
void ObfuscateBoolConstant(uint32_t depth,
|
||||
const protobufs::IdUseDescriptor& constant_use);
|
||||
|
||||
// This method will try to turn |constant_use|, required to be a use of a
|
||||
// scalar constant, into the value loaded from a uniform known to have the
|
||||
// same value as the constant (if one exists).
|
||||
void ObfuscateScalarConstant(uint32_t depth,
|
||||
const protobufs::IdUseDescriptor& constant_use);
|
||||
|
||||
// Applies a transformation to replace the boolean constant usage represented
|
||||
// by |bool_constant_use| with a binary expression involving
|
||||
// |float_constant_id_1| and |float_constant_id_2|, which must not be equal
|
||||
// to one another. Possibly further obfuscates the uses of these float
|
||||
// constants. The |depth| parameter controls how deeply obfuscation can
|
||||
// recurse.
|
||||
void ObfuscateBoolConstantViaFloatConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
uint32_t float_constant_id_1, uint32_t float_constant_id_2);
|
||||
|
||||
// Similar to the above, but for signed int constants.
|
||||
void ObfuscateBoolConstantViaSignedIntConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
uint32_t signed_int_constant_id_1, uint32_t signed_int_constant_id_2);
|
||||
|
||||
// Similar to the above, but for unsigned int constants.
|
||||
void ObfuscateBoolConstantViaUnsignedIntConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
uint32_t unsigned_int_constant_id_1, uint32_t unsigned_int_constant_id_2);
|
||||
|
||||
// A helper method to capture the common parts of the above methods.
|
||||
// The method is used to obfuscate the boolean constant usage represented by
|
||||
// |bool_constant_use| by replacing it with '|constant_id_1| OP
|
||||
// |constant_id_2|', where 'OP' is chosen from either |greater_than_opcodes|
|
||||
// or |less_than_opcodes|.
|
||||
//
|
||||
// The two constant ids must not represent the same value, and thus
|
||||
// |greater_than_opcodes| may include 'greater than or equal' opcodes
|
||||
// (similar for |less_than_opcodes|).
|
||||
void ObfuscateBoolConstantViaConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
const std::vector<SpvOp>& greater_than_opcodes,
|
||||
const std::vector<SpvOp>& less_than_opcodes, uint32_t constant_id_1,
|
||||
uint32_t constant_id_2, bool first_constant_is_larger);
|
||||
|
||||
// A helper method to determine whether input operand |in_operand_index| of
|
||||
// |inst| is the id of a constant, and add an id use descriptor to
|
||||
// |candidate_constant_uses| if so. The other parameters are used for id use
|
||||
// descriptor construction.
|
||||
void MaybeAddConstantIdUse(
|
||||
const opt::Instruction& inst, uint32_t in_operand_index,
|
||||
uint32_t base_instruction_result_id,
|
||||
const std::map<SpvOp, uint32_t>& skipped_opcode_count,
|
||||
std::vector<protobufs::IdUseDescriptor>* constant_uses);
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // #define SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_
|
||||
@@ -64,8 +64,9 @@ message UniformBufferElementDescriptor {
|
||||
// is contained, and (b) a series of indices that need to be followed to get
|
||||
// to the element (via fields and array/vector indices).
|
||||
//
|
||||
// Example: suppose %42 is the id of a uniform variable, and that the uniform
|
||||
// variable has the following type (using GLSL-like syntax):
|
||||
// Example: suppose there is a uniform variable with descriptor set 7 and
|
||||
// binding 9, and that the uniform variable has the following type (using
|
||||
// GLSL-like syntax):
|
||||
//
|
||||
// struct S {
|
||||
// float f;
|
||||
@@ -74,16 +75,17 @@ message UniformBufferElementDescriptor {
|
||||
// };
|
||||
//
|
||||
// Then:
|
||||
// - 42[0] describes the 'f' field.
|
||||
// - 42[1,1] describes the y component of the 'g' field.
|
||||
// - 42[2,7,3] describes the w component of element 7 of the 'h' field
|
||||
// - (7, 9, [0]) describes the 'f' field.
|
||||
// - (7, 9, [1,1]) describes the y component of the 'g' field.
|
||||
// - (7, 9, [2,7,3]) describes the w component of element 7 of the 'h' field
|
||||
|
||||
// The result id of a uniform variable.
|
||||
uint32 uniform_variable_id = 1;
|
||||
// The descriptor set and binding associated with a uniform variable.
|
||||
uint32 descriptor_set = 1;
|
||||
uint32 binding = 2;
|
||||
|
||||
// An ordered sequence of indices through composite structures in the
|
||||
// uniform buffer.
|
||||
repeated uint32 index = 2;
|
||||
repeated uint32 index = 3;
|
||||
|
||||
}
|
||||
|
||||
@@ -133,6 +135,8 @@ message Transformation {
|
||||
TransformationAddTypeInt add_type_int = 7;
|
||||
TransformationAddDeadBreak add_dead_break = 8;
|
||||
TransformationReplaceBooleanConstantWithConstantBinary replace_boolean_constant_with_constant_binary = 9;
|
||||
TransformationAddTypePointer add_type_pointer = 10;
|
||||
TransformationReplaceConstantWithUniform replace_constant_with_uniform = 11;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
@@ -222,6 +226,22 @@ message TransformationAddTypeInt {
|
||||
|
||||
}
|
||||
|
||||
message TransformationAddTypePointer {
|
||||
|
||||
// Adds OpTypePointer to the module, with the given storage class and base
|
||||
// type
|
||||
|
||||
// Id to be used for the type
|
||||
uint32 fresh_id = 1;
|
||||
|
||||
// Pointer storage class
|
||||
uint32 storage_class = 2;
|
||||
|
||||
// Id of the base type for the pointer
|
||||
uint32 base_type_id = 3;
|
||||
|
||||
}
|
||||
|
||||
message TransformationMoveBlockDown {
|
||||
|
||||
// A transformation that moves a basic block to be one position lower in
|
||||
@@ -229,6 +249,24 @@ message TransformationMoveBlockDown {
|
||||
|
||||
// The id of the block to move down.
|
||||
uint32 block_id = 1;
|
||||
}
|
||||
|
||||
message TransformationReplaceConstantWithUniform {
|
||||
|
||||
// Replaces a use of a constant id with the the result of a load from an
|
||||
// element of uniform buffer known to hold the same value as the constant
|
||||
|
||||
// A descriptor for the id we would like to replace
|
||||
IdUseDescriptor id_use_descriptor = 1;
|
||||
|
||||
// Uniform descriptor to identify which uniform value to choose
|
||||
UniformBufferElementDescriptor uniform_descriptor = 2;
|
||||
|
||||
// Id that will store the result of an access chain
|
||||
uint32 fresh_id_for_access_chain = 3;
|
||||
|
||||
// Id that will store the result of a load
|
||||
uint32 fresh_id_for_load = 4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
19
3rdparty/spirv-tools/source/fuzz/replayer.cpp
vendored
19
3rdparty/spirv-tools/source/fuzz/replayer.cpp
vendored
@@ -24,8 +24,10 @@
|
||||
#include "source/fuzz/transformation_add_type_boolean.h"
|
||||
#include "source/fuzz/transformation_add_type_float.h"
|
||||
#include "source/fuzz/transformation_add_type_int.h"
|
||||
#include "source/fuzz/transformation_add_type_pointer.h"
|
||||
#include "source/fuzz/transformation_move_block_down.h"
|
||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
|
||||
#include "source/fuzz/transformation_split_block.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/util/make_unique.h"
|
||||
@@ -58,6 +60,9 @@ bool IsApplicable(const protobufs::Transformation& transformation,
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeInt:
|
||||
return transformation::IsApplicable(transformation.add_type_int(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kAddTypePointer:
|
||||
return transformation::IsApplicable(transformation.add_type_pointer(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
|
||||
return transformation::IsApplicable(transformation.move_block_down(),
|
||||
context, fact_manager);
|
||||
@@ -66,6 +71,11 @@ bool IsApplicable(const protobufs::Transformation& transformation,
|
||||
return transformation::IsApplicable(
|
||||
transformation.replace_boolean_constant_with_constant_binary(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceConstantWithUniform:
|
||||
return transformation::IsApplicable(
|
||||
transformation.replace_constant_with_uniform(), context,
|
||||
fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kSplitBlock:
|
||||
return transformation::IsApplicable(transformation.split_block(), context,
|
||||
fact_manager);
|
||||
@@ -107,6 +117,10 @@ void Apply(const protobufs::Transformation& transformation,
|
||||
transformation::Apply(transformation.add_type_int(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kAddTypePointer:
|
||||
transformation::Apply(transformation.add_type_pointer(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
|
||||
transformation::Apply(transformation.move_block_down(), context,
|
||||
fact_manager);
|
||||
@@ -117,6 +131,11 @@ void Apply(const protobufs::Transformation& transformation,
|
||||
transformation.replace_boolean_constant_with_constant_binary(),
|
||||
context, fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceConstantWithUniform:
|
||||
transformation::Apply(transformation.replace_constant_with_uniform(),
|
||||
context, fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kSplitBlock:
|
||||
transformation::Apply(transformation.split_block(), context,
|
||||
fact_manager);
|
||||
|
||||
61
3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp
vendored
Normal file
61
3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// 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 "source/fuzz/transformation_add_type_pointer.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::IRContext;
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationAddTypePointer& message,
|
||||
IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) {
|
||||
// The id must be fresh.
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
// The base type must be known.
|
||||
return context->get_type_mgr()->GetType(message.base_type_id()) != nullptr;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationAddTypePointer& message,
|
||||
IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
|
||||
// Add the pointer type.
|
||||
opt::Instruction::OperandList in_operands = {
|
||||
{SPV_OPERAND_TYPE_STORAGE_CLASS, {message.storage_class()}},
|
||||
{SPV_OPERAND_TYPE_ID, {message.base_type_id()}}};
|
||||
context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
context, SpvOpTypePointer, 0, message.fresh_id(), in_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationAddTypePointer MakeTransformationAddTypePointer(
|
||||
uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id) {
|
||||
protobufs::TransformationAddTypePointer result;
|
||||
result.set_fresh_id(fresh_id);
|
||||
result.set_storage_class(storage_class);
|
||||
result.set_base_type_id(base_type_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
44
3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.h
vendored
Normal file
44
3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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_FUZZ_TRANSFORMATION_ADD_TYPE_POINTER_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_POINTER_H_
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |message.fresh_id| must not be used by the module
|
||||
// - |message.base_type_id| must be the result id of an OpType[...] instruction
|
||||
bool IsApplicable(const protobufs::TransformationAddTypePointer& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
|
||||
// Adds an OpTypePointer instruction with the given storage class and base type
|
||||
// to the module.
|
||||
void Apply(const protobufs::TransformationAddTypePointer& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationAddTypePointer MakeTransformationAddTypePointer(
|
||||
uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id);
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_POINTER_H_
|
||||
230
3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp
vendored
Normal file
230
3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
// 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 "source/fuzz/transformation_replace_constant_with_uniform.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
namespace {
|
||||
|
||||
std::unique_ptr<opt::Instruction> MakeAccessChainInstruction(
|
||||
const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
spvtools::opt::IRContext* context, uint32_t constant_type_id) {
|
||||
// The input operands for the access chain.
|
||||
opt::Instruction::OperandList operands_for_access_chain;
|
||||
|
||||
opt::Instruction* uniform_variable =
|
||||
FindUniformVariable(message.uniform_descriptor(), context, false);
|
||||
|
||||
// The first input operand is the id of the uniform variable.
|
||||
operands_for_access_chain.push_back(
|
||||
{SPV_OPERAND_TYPE_ID, {uniform_variable->result_id()}});
|
||||
|
||||
// The other input operands are the ids of the constants used to index into
|
||||
// the uniform. The uniform buffer descriptor specifies a series of literals;
|
||||
// for each we find the id of the instruction that defines it, and add these
|
||||
// instruction ids as operands.
|
||||
opt::analysis::Integer int_type(32, true);
|
||||
auto registered_int_type =
|
||||
context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger();
|
||||
auto int_type_id = context->get_type_mgr()->GetId(&int_type);
|
||||
for (auto index : message.uniform_descriptor().index()) {
|
||||
opt::analysis::IntConstant int_constant(registered_int_type, {index});
|
||||
auto constant_id = context->get_constant_mgr()->FindDeclaredConstant(
|
||||
&int_constant, int_type_id);
|
||||
operands_for_access_chain.push_back({SPV_OPERAND_TYPE_ID, {constant_id}});
|
||||
}
|
||||
|
||||
// The type id for the access chain is a uniform pointer with base type
|
||||
// matching the given constant id type.
|
||||
auto type_and_pointer_type = context->get_type_mgr()->GetTypeAndPointerType(
|
||||
constant_type_id, SpvStorageClassUniform);
|
||||
assert(type_and_pointer_type.first != nullptr);
|
||||
assert(type_and_pointer_type.second != nullptr);
|
||||
auto pointer_to_uniform_constant_type_id =
|
||||
context->get_type_mgr()->GetId(type_and_pointer_type.second.get());
|
||||
|
||||
return MakeUnique<opt::Instruction>(
|
||||
context, SpvOpAccessChain, pointer_to_uniform_constant_type_id,
|
||||
message.fresh_id_for_access_chain(), operands_for_access_chain);
|
||||
}
|
||||
|
||||
std::unique_ptr<opt::Instruction> MakeLoadInstruction(
|
||||
const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
spvtools::opt::IRContext* context, uint32_t constant_type_id) {
|
||||
opt::Instruction::OperandList operands_for_load = {
|
||||
{SPV_OPERAND_TYPE_ID, {message.fresh_id_for_access_chain()}}};
|
||||
return MakeUnique<opt::Instruction>(context, SpvOpLoad, constant_type_id,
|
||||
message.fresh_id_for_load(),
|
||||
operands_for_load);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsApplicable(
|
||||
const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
spvtools::opt::IRContext* context,
|
||||
const spvtools::fuzz::FactManager& fact_manager) {
|
||||
// The following is really an invariant of the transformation rather than
|
||||
// merely a requirement of the precondition. We check it here since we cannot
|
||||
// check it in the message constructor.
|
||||
assert(message.fresh_id_for_access_chain() != message.fresh_id_for_load() &&
|
||||
"Fresh ids for access chain and load result cannot be the same.");
|
||||
|
||||
// The ids for the access chain and load instructions must both be fresh.
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id_for_access_chain())) {
|
||||
return false;
|
||||
}
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id_for_load())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The id specified in the id use descriptor must be that of a declared scalar
|
||||
// constant.
|
||||
auto declared_constant = context->get_constant_mgr()->FindDeclaredConstant(
|
||||
message.id_use_descriptor().id_of_interest());
|
||||
if (!declared_constant) {
|
||||
return false;
|
||||
}
|
||||
if (!declared_constant->AsScalarConstant()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The fact manager needs to believe that the uniform data element described
|
||||
// by the uniform buffer element descriptor will hold a scalar value.
|
||||
auto constant_id_associated_with_uniform =
|
||||
fact_manager.GetConstantFromUniformDescriptor(
|
||||
context, message.uniform_descriptor());
|
||||
if (!constant_id_associated_with_uniform) {
|
||||
return false;
|
||||
}
|
||||
auto constant_associated_with_uniform =
|
||||
context->get_constant_mgr()->FindDeclaredConstant(
|
||||
constant_id_associated_with_uniform);
|
||||
assert(constant_associated_with_uniform &&
|
||||
"The constant should be present in the module.");
|
||||
if (!constant_associated_with_uniform->AsScalarConstant()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The types and values of the scalar value held in the id specified by the id
|
||||
// use descriptor and in the uniform data element specified by the uniform
|
||||
// buffer element descriptor need to match on both type and value.
|
||||
if (!declared_constant->type()->IsSame(
|
||||
constant_associated_with_uniform->type())) {
|
||||
return false;
|
||||
}
|
||||
if (declared_constant->AsScalarConstant()->words() !=
|
||||
constant_associated_with_uniform->AsScalarConstant()->words()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The id use descriptor must identify some instruction with respect to the
|
||||
// module.
|
||||
auto instruction_using_constant =
|
||||
transformation::FindInstruction(message.id_use_descriptor(), context);
|
||||
if (!instruction_using_constant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The module needs to have a uniform pointer type suitable for indexing into
|
||||
// the uniform variable, i.e. matching the type of the constant we wish to
|
||||
// replace with a uniform.
|
||||
opt::analysis::Pointer pointer_to_type_of_constant(declared_constant->type(),
|
||||
SpvStorageClassUniform);
|
||||
if (!context->get_type_mgr()->GetId(&pointer_to_type_of_constant)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// In order to index into the uniform, the module has got to contain the int32
|
||||
// type, plus an OpConstant for each of the indices of interest.
|
||||
opt::analysis::Integer int_type(32, true);
|
||||
if (!context->get_type_mgr()->GetId(&int_type)) {
|
||||
return false;
|
||||
}
|
||||
auto registered_int_type =
|
||||
context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger();
|
||||
auto int_type_id = context->get_type_mgr()->GetId(&int_type);
|
||||
for (auto index : message.uniform_descriptor().index()) {
|
||||
opt::analysis::IntConstant int_constant(registered_int_type, {index});
|
||||
if (!context->get_constant_mgr()->FindDeclaredConstant(&int_constant,
|
||||
int_type_id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
spvtools::opt::IRContext* context,
|
||||
spvtools::fuzz::FactManager* /*unused*/) {
|
||||
// Get the instruction that contains the id use we wish to replace.
|
||||
auto instruction_containing_constant_use =
|
||||
transformation::FindInstruction(message.id_use_descriptor(), context);
|
||||
assert(instruction_containing_constant_use &&
|
||||
"Precondition requires that the id use can be found.");
|
||||
assert(instruction_containing_constant_use->GetSingleWordInOperand(
|
||||
message.id_use_descriptor().in_operand_index()) ==
|
||||
message.id_use_descriptor().id_of_interest() &&
|
||||
"Does not appear to be a usage of the desired id.");
|
||||
|
||||
// The id of the type for the constant whose use we wish to replace.
|
||||
auto constant_type_id =
|
||||
context->get_def_use_mgr()
|
||||
->GetDef(message.id_use_descriptor().id_of_interest())
|
||||
->type_id();
|
||||
|
||||
// Add an access chain instruction to target the uniform element.
|
||||
instruction_containing_constant_use->InsertBefore(
|
||||
MakeAccessChainInstruction(message, context, constant_type_id));
|
||||
|
||||
// Add a load from this access chain.
|
||||
instruction_containing_constant_use->InsertBefore(
|
||||
MakeLoadInstruction(message, context, constant_type_id));
|
||||
|
||||
// Adjust the instruction containing the usage of the constant so that this
|
||||
// usage refers instead to the result of the load.
|
||||
instruction_containing_constant_use->SetInOperand(
|
||||
message.id_use_descriptor().in_operand_index(),
|
||||
{message.fresh_id_for_load()});
|
||||
|
||||
// Update the module id bound to reflect the new instructions.
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id_for_load());
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id_for_access_chain());
|
||||
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationReplaceConstantWithUniform
|
||||
MakeTransformationReplaceConstantWithUniform(
|
||||
protobufs::IdUseDescriptor id_use,
|
||||
protobufs::UniformBufferElementDescriptor uniform_descriptor,
|
||||
uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load) {
|
||||
protobufs::TransformationReplaceConstantWithUniform result;
|
||||
*result.mutable_id_use_descriptor() = std::move(id_use);
|
||||
*result.mutable_uniform_descriptor() = std::move(uniform_descriptor);
|
||||
result.set_fresh_id_for_access_chain(fresh_id_for_access_chain);
|
||||
result.set_fresh_id_for_load(fresh_id_for_load);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
73
3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h
vendored
Normal file
73
3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
#include <utility>
|
||||
|
||||
// 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_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/id_use_descriptor.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |fresh_id_for_access_chain| and |fresh_id_for_load| must be distinct fresh
|
||||
// ids.
|
||||
// - |uniform_descriptor| specifies a result id and a list of integer literal
|
||||
// indices.
|
||||
// As an example, suppose |uniform_descriptor| is (18, [0, 1, 0])
|
||||
// It is required that:
|
||||
// - the result id (18 in our example) is the id of some uniform variable
|
||||
// - the module contains an integer constant instruction corresponding to
|
||||
// each of the literal indices; in our example there must thus be
|
||||
// OpConstant instructions %A and %B say for each of 0 and 1
|
||||
// - it is legitimate to index into the uniform variable using the
|
||||
// sequence of indices; in our example this means indexing into %18 using
|
||||
// the sequence %A %B %A
|
||||
// - the module contains a uniform pointer type corresponding to the type
|
||||
// of the uniform data element obtained by following these indices
|
||||
// - |id_use_descriptor| identifies the use of some id %C. It is required that:
|
||||
// - this use does indeed exist in the module
|
||||
// - %C is an OpConstant
|
||||
// - According to the fact manager, the uniform data element specified by
|
||||
// |uniform_descriptor| holds a value with the same type and value as %C
|
||||
bool IsApplicable(
|
||||
const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
|
||||
// - Introduces two new instructions:
|
||||
// - An access chain targeting the uniform data element specified by
|
||||
// |uniform_descriptor|, with result id |fresh_id_for_access_chain|
|
||||
// - A load from this access chain, with id |fresh_id_for_load|
|
||||
// - Replaces the id use specified by |id_use_descriptor| with
|
||||
// |fresh_id_for_load|
|
||||
void Apply(const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationReplaceConstantWithUniform
|
||||
MakeTransformationReplaceConstantWithUniform(
|
||||
protobufs::IdUseDescriptor id_use,
|
||||
protobufs::UniformBufferElementDescriptor uniform_descriptor,
|
||||
uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load);
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_
|
||||
@@ -14,13 +14,17 @@
|
||||
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
|
||||
#include <source/opt/instruction.h>
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor(
|
||||
uint32_t uniform_variable_id, std::vector<uint32_t>&& indices) {
|
||||
uint32_t descriptor_set, uint32_t binding,
|
||||
std::vector<uint32_t>&& indices) {
|
||||
protobufs::UniformBufferElementDescriptor result;
|
||||
result.set_uniform_variable_id(uniform_variable_id);
|
||||
result.set_descriptor_set(descriptor_set);
|
||||
result.set_binding(binding);
|
||||
for (auto index : indices) {
|
||||
result.add_index(index);
|
||||
}
|
||||
@@ -30,10 +34,85 @@ protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor(
|
||||
bool UniformBufferElementDescriptorEquals::operator()(
|
||||
const protobufs::UniformBufferElementDescriptor* first,
|
||||
const protobufs::UniformBufferElementDescriptor* second) const {
|
||||
return first->uniform_variable_id() == second->uniform_variable_id() &&
|
||||
return first->descriptor_set() == second->descriptor_set() &&
|
||||
first->binding() == second->binding() &&
|
||||
first->index().size() == second->index().size() &&
|
||||
std::equal(first->index().begin(), first->index().end(),
|
||||
second->index().begin());
|
||||
}
|
||||
|
||||
opt::Instruction* FindUniformVariable(
|
||||
const protobufs::UniformBufferElementDescriptor&
|
||||
uniform_buffer_element_descriptor,
|
||||
opt::IRContext* context, bool check_unique) {
|
||||
opt::Instruction* result = nullptr;
|
||||
|
||||
for (auto& inst : context->types_values()) {
|
||||
// Consider all global variables with uniform storage class.
|
||||
if (inst.opcode() != SpvOpVariable) {
|
||||
continue;
|
||||
}
|
||||
if (inst.GetSingleWordInOperand(0) != SpvStorageClassUniform) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine whether the variable is decorated with a descriptor set
|
||||
// matching that in |uniform_buffer_element|.
|
||||
bool descriptor_set_matches = false;
|
||||
context->get_decoration_mgr()->ForEachDecoration(
|
||||
inst.result_id(), SpvDecorationDescriptorSet,
|
||||
[&descriptor_set_matches, &uniform_buffer_element_descriptor](
|
||||
const opt::Instruction& decoration_inst) {
|
||||
const uint32_t kDescriptorSetOperandIndex = 2;
|
||||
if (decoration_inst.GetSingleWordInOperand(
|
||||
kDescriptorSetOperandIndex) ==
|
||||
uniform_buffer_element_descriptor.descriptor_set()) {
|
||||
descriptor_set_matches = true;
|
||||
}
|
||||
});
|
||||
if (!descriptor_set_matches) {
|
||||
// Descriptor set does not match.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine whether the variable is decorated with a binding matching that
|
||||
// in |uniform_buffer_element|.
|
||||
bool binding_matches = false;
|
||||
context->get_decoration_mgr()->ForEachDecoration(
|
||||
inst.result_id(), SpvDecorationBinding,
|
||||
[&binding_matches, &uniform_buffer_element_descriptor](
|
||||
const opt::Instruction& decoration_inst) {
|
||||
const uint32_t kBindingOperandIndex = 2;
|
||||
if (decoration_inst.GetSingleWordInOperand(kBindingOperandIndex) ==
|
||||
uniform_buffer_element_descriptor.binding()) {
|
||||
binding_matches = true;
|
||||
}
|
||||
});
|
||||
if (!binding_matches) {
|
||||
// Binding does not match.
|
||||
continue;
|
||||
}
|
||||
|
||||
// This instruction is a uniform variable with the right descriptor set and
|
||||
// binding.
|
||||
if (!check_unique) {
|
||||
// If we aren't checking uniqueness, return it.
|
||||
return &inst;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
// More than one uniform variable is decorated with the given descriptor
|
||||
// set and binding. This means the fact is ambiguous.
|
||||
return nullptr;
|
||||
}
|
||||
result = &inst;
|
||||
}
|
||||
|
||||
// We get here either if no match was found, or if |check_unique| holds and
|
||||
// exactly one match was found.
|
||||
assert(result == nullptr || check_unique);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
@@ -26,7 +28,7 @@ namespace fuzz {
|
||||
// Factory method to create a uniform buffer element descriptor message from an
|
||||
// id and list of indices.
|
||||
protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor(
|
||||
uint32_t uniform_variable_id, std::vector<uint32_t>&& indices);
|
||||
uint32_t descriptor_set, uint32_t binding, std::vector<uint32_t>&& indices);
|
||||
|
||||
// Equality function for uniform buffer element descriptors.
|
||||
struct UniformBufferElementDescriptorEquals {
|
||||
@@ -35,6 +37,16 @@ struct UniformBufferElementDescriptorEquals {
|
||||
const protobufs::UniformBufferElementDescriptor* second) const;
|
||||
};
|
||||
|
||||
// Returns a pointer to an OpVariable in |context| that is decorated with the
|
||||
// descriptor set and binding associated with |uniform_buffer_element|. Returns
|
||||
// nullptr if no such variable exists. If multiple such variables exist, a
|
||||
// pointer to an arbitrary one of the associated instructions is returned if
|
||||
// |check_unique| is false, and nullptr is returned if |check_unique| is true.
|
||||
opt::Instruction* FindUniformVariable(
|
||||
const protobufs::UniformBufferElementDescriptor&
|
||||
uniform_buffer_element_descriptor,
|
||||
opt::IRContext* context, bool check_unique);
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
||||
@@ -868,6 +868,7 @@ void AggressiveDCEPass::InitExtensions() {
|
||||
"SPV_AMD_gpu_shader_half_float_fetch",
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_GOOGLE_user_type",
|
||||
"SPV_NV_shader_subgroup_partitioned",
|
||||
"SPV_EXT_descriptor_indexing",
|
||||
"SPV_NV_fragment_shader_barycentric",
|
||||
|
||||
@@ -579,6 +579,7 @@ void CommonUniformElimPass::InitExtensions() {
|
||||
"SPV_AMD_gpu_shader_half_float_fetch",
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_GOOGLE_user_type",
|
||||
"SPV_NV_shader_subgroup_partitioned",
|
||||
"SPV_EXT_descriptor_indexing",
|
||||
"SPV_NV_fragment_shader_barycentric",
|
||||
|
||||
@@ -343,6 +343,7 @@ void LocalAccessChainConvertPass::InitExtensions() {
|
||||
"SPV_AMD_gpu_shader_half_float_fetch",
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_GOOGLE_user_type",
|
||||
"SPV_NV_shader_subgroup_partitioned",
|
||||
"SPV_EXT_descriptor_indexing",
|
||||
"SPV_NV_fragment_shader_barycentric",
|
||||
|
||||
@@ -246,6 +246,7 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
|
||||
"SPV_AMD_gpu_shader_half_float_fetch",
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_GOOGLE_user_type",
|
||||
"SPV_NV_shader_subgroup_partitioned",
|
||||
"SPV_EXT_descriptor_indexing",
|
||||
"SPV_NV_fragment_shader_barycentric",
|
||||
|
||||
@@ -95,6 +95,7 @@ void LocalMultiStoreElimPass::InitExtensions() {
|
||||
"SPV_AMD_gpu_shader_half_float_fetch",
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_GOOGLE_user_type",
|
||||
"SPV_NV_shader_subgroup_partitioned",
|
||||
"SPV_EXT_descriptor_indexing",
|
||||
"SPV_NV_fragment_shader_barycentric",
|
||||
|
||||
@@ -25,6 +25,12 @@ namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
Pass::Status UpgradeMemoryModel::Process() {
|
||||
// TODO: This pass needs changes to support cooperative matrices.
|
||||
if (context()->get_feature_mgr()->HasCapability(
|
||||
SpvCapabilityCooperativeMatrixNV)) {
|
||||
return Pass::Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
// Only update Logical GLSL450 to Logical VulkanKHR.
|
||||
Instruction* memory_model = get_module()->GetMemoryModel();
|
||||
if (memory_model->GetSingleWordInOperand(0u) != SpvAddressingModelLogical ||
|
||||
@@ -110,6 +116,12 @@ void UpgradeMemoryModel::UpgradeInstructions() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
UpgradeMemoryAndImages();
|
||||
UpgradeAtomics();
|
||||
}
|
||||
|
||||
void UpgradeMemoryModel::UpgradeMemoryAndImages() {
|
||||
for (auto& func : *get_module()) {
|
||||
func.ForEachInst([this](Instruction* inst) {
|
||||
bool is_coherent = false;
|
||||
@@ -239,6 +251,50 @@ void UpgradeMemoryModel::UpgradeInstructions() {
|
||||
}
|
||||
}
|
||||
|
||||
void UpgradeMemoryModel::UpgradeAtomics() {
|
||||
for (auto& func : *get_module()) {
|
||||
func.ForEachInst([this](Instruction* inst) {
|
||||
if (spvOpcodeIsAtomicOp(inst->opcode())) {
|
||||
bool unused_coherent = false;
|
||||
bool is_volatile = false;
|
||||
SpvScope unused_scope = SpvScopeQueueFamilyKHR;
|
||||
std::tie(unused_coherent, is_volatile, unused_scope) =
|
||||
GetInstructionAttributes(inst->GetSingleWordInOperand(0));
|
||||
|
||||
UpgradeSemantics(inst, 2u, is_volatile);
|
||||
if (inst->opcode() == SpvOpAtomicCompareExchange ||
|
||||
inst->opcode() == SpvOpAtomicCompareExchangeWeak) {
|
||||
UpgradeSemantics(inst, 3u, is_volatile);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void UpgradeMemoryModel::UpgradeSemantics(Instruction* inst,
|
||||
uint32_t in_operand,
|
||||
bool is_volatile) {
|
||||
if (!is_volatile) return;
|
||||
|
||||
uint32_t semantics_id = inst->GetSingleWordInOperand(in_operand);
|
||||
const analysis::Constant* constant =
|
||||
context()->get_constant_mgr()->FindDeclaredConstant(semantics_id);
|
||||
const analysis::Integer* type = constant->type()->AsInteger();
|
||||
assert(type && type->width() == 32);
|
||||
uint32_t value = 0;
|
||||
if (type->IsSigned()) {
|
||||
value = static_cast<uint32_t>(constant->GetS32());
|
||||
} else {
|
||||
value = constant->GetU32();
|
||||
}
|
||||
|
||||
value |= SpvMemorySemanticsVolatileMask;
|
||||
auto new_constant = context()->get_constant_mgr()->GetConstant(type, {value});
|
||||
auto new_semantics =
|
||||
context()->get_constant_mgr()->GetDefiningInstruction(new_constant);
|
||||
inst->SetInOperand(in_operand, {new_semantics->result_id()});
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, SpvScope> UpgradeMemoryModel::GetInstructionAttributes(
|
||||
uint32_t id) {
|
||||
// |id| is a pointer used in a memory/image instruction. Need to determine if
|
||||
|
||||
@@ -57,12 +57,19 @@ class UpgradeMemoryModel : public Pass {
|
||||
// capability and extension.
|
||||
void UpgradeMemoryModelInstruction();
|
||||
|
||||
// Upgrades memory, image and barrier instructions.
|
||||
// Upgrades memory, image and atomic instructions.
|
||||
// Memory and image instructions convert coherent and volatile decorations
|
||||
// into flags on the instruction. Barriers in tessellation shaders get the
|
||||
// output storage semantic if appropriate.
|
||||
// into flags on the instruction.
|
||||
// Atomic memory semantics convert volatile decoration into flags on the
|
||||
// instruction.
|
||||
void UpgradeInstructions();
|
||||
|
||||
// Upgrades memory and image operands for instructions that have them.
|
||||
void UpgradeMemoryAndImages();
|
||||
|
||||
// Adds the volatile memory semantic if necessary.
|
||||
void UpgradeAtomics();
|
||||
|
||||
// Returns whether |id| is coherent and/or volatile.
|
||||
std::tuple<bool, bool, SpvScope> GetInstructionAttributes(uint32_t id);
|
||||
|
||||
@@ -95,6 +102,11 @@ class UpgradeMemoryModel : public Pass {
|
||||
bool is_volatile, OperationType operation_type,
|
||||
InstructionType inst_type);
|
||||
|
||||
// Modifies the semantics at |in_operand| of |inst| to include the volatile
|
||||
// bit if |is_volatile| is true.
|
||||
void UpgradeSemantics(Instruction* inst, uint32_t in_operand,
|
||||
bool is_volatile);
|
||||
|
||||
// Returns the result id for a constant for |scope|.
|
||||
uint32_t GetScopeConstant(SpvScope scope);
|
||||
|
||||
|
||||
129
3rdparty/spirv-tools/source/spirv_target_env.cpp
vendored
129
3rdparty/spirv-tools/source/spirv_target_env.cpp
vendored
@@ -103,80 +103,45 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) {
|
||||
return SPV_SPIRV_VERSION_WORD(0, 0);
|
||||
}
|
||||
|
||||
static const std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] = {
|
||||
{"vulkan1.1spv1.4", SPV_ENV_VULKAN_1_1_SPIRV_1_4},
|
||||
{"vulkan1.0", SPV_ENV_VULKAN_1_0},
|
||||
{"vulkan1.1", SPV_ENV_VULKAN_1_1},
|
||||
{"spv1.0", SPV_ENV_UNIVERSAL_1_0},
|
||||
{"spv1.1", SPV_ENV_UNIVERSAL_1_1},
|
||||
{"spv1.2", SPV_ENV_UNIVERSAL_1_2},
|
||||
{"spv1.3", SPV_ENV_UNIVERSAL_1_3},
|
||||
{"spv1.4", SPV_ENV_UNIVERSAL_1_4},
|
||||
{"opencl1.2embedded", SPV_ENV_OPENCL_EMBEDDED_1_2},
|
||||
{"opencl1.2", SPV_ENV_OPENCL_1_2},
|
||||
{"opencl2.0embedded", SPV_ENV_OPENCL_EMBEDDED_2_0},
|
||||
{"opencl2.0", SPV_ENV_OPENCL_2_0},
|
||||
{"opencl2.1embedded", SPV_ENV_OPENCL_EMBEDDED_2_1},
|
||||
{"opencl2.1", SPV_ENV_OPENCL_2_1},
|
||||
{"opencl2.2embedded", SPV_ENV_OPENCL_EMBEDDED_2_2},
|
||||
{"opencl2.2", SPV_ENV_OPENCL_2_2},
|
||||
{"opengl4.0", SPV_ENV_OPENGL_4_0},
|
||||
{"opengl4.1", SPV_ENV_OPENGL_4_1},
|
||||
{"opengl4.2", SPV_ENV_OPENGL_4_2},
|
||||
{"opengl4.3", SPV_ENV_OPENGL_4_3},
|
||||
{"opengl4.5", SPV_ENV_OPENGL_4_5},
|
||||
{"webgpu0", SPV_ENV_WEBGPU_0},
|
||||
};
|
||||
|
||||
bool spvParseTargetEnv(const char* s, spv_target_env* env) {
|
||||
auto match = [s](const char* b) {
|
||||
return s && (0 == strncmp(s, b, strlen(b)));
|
||||
};
|
||||
if (match("vulkan1.1spv1.4")) {
|
||||
if (env) *env = SPV_ENV_VULKAN_1_1_SPIRV_1_4;
|
||||
return true;
|
||||
} else if (match("vulkan1.0")) {
|
||||
if (env) *env = SPV_ENV_VULKAN_1_0;
|
||||
return true;
|
||||
} else if (match("vulkan1.1")) {
|
||||
if (env) *env = SPV_ENV_VULKAN_1_1;
|
||||
return true;
|
||||
} else if (match("spv1.0")) {
|
||||
if (env) *env = SPV_ENV_UNIVERSAL_1_0;
|
||||
return true;
|
||||
} else if (match("spv1.1")) {
|
||||
if (env) *env = SPV_ENV_UNIVERSAL_1_1;
|
||||
return true;
|
||||
} else if (match("spv1.2")) {
|
||||
if (env) *env = SPV_ENV_UNIVERSAL_1_2;
|
||||
return true;
|
||||
} else if (match("spv1.3")) {
|
||||
if (env) *env = SPV_ENV_UNIVERSAL_1_3;
|
||||
return true;
|
||||
} else if (match("spv1.4")) {
|
||||
if (env) *env = SPV_ENV_UNIVERSAL_1_4;
|
||||
return true;
|
||||
} else if (match("opencl1.2embedded")) {
|
||||
if (env) *env = SPV_ENV_OPENCL_EMBEDDED_1_2;
|
||||
return true;
|
||||
} else if (match("opencl1.2")) {
|
||||
if (env) *env = SPV_ENV_OPENCL_1_2;
|
||||
return true;
|
||||
} else if (match("opencl2.0embedded")) {
|
||||
if (env) *env = SPV_ENV_OPENCL_EMBEDDED_2_0;
|
||||
return true;
|
||||
} else if (match("opencl2.0")) {
|
||||
if (env) *env = SPV_ENV_OPENCL_2_0;
|
||||
return true;
|
||||
} else if (match("opencl2.1embedded")) {
|
||||
if (env) *env = SPV_ENV_OPENCL_EMBEDDED_2_1;
|
||||
return true;
|
||||
} else if (match("opencl2.1")) {
|
||||
if (env) *env = SPV_ENV_OPENCL_2_1;
|
||||
return true;
|
||||
} else if (match("opencl2.2embedded")) {
|
||||
if (env) *env = SPV_ENV_OPENCL_EMBEDDED_2_2;
|
||||
return true;
|
||||
} else if (match("opencl2.2")) {
|
||||
if (env) *env = SPV_ENV_OPENCL_2_2;
|
||||
return true;
|
||||
} else if (match("opengl4.0")) {
|
||||
if (env) *env = SPV_ENV_OPENGL_4_0;
|
||||
return true;
|
||||
} else if (match("opengl4.1")) {
|
||||
if (env) *env = SPV_ENV_OPENGL_4_1;
|
||||
return true;
|
||||
} else if (match("opengl4.2")) {
|
||||
if (env) *env = SPV_ENV_OPENGL_4_2;
|
||||
return true;
|
||||
} else if (match("opengl4.3")) {
|
||||
if (env) *env = SPV_ENV_OPENGL_4_3;
|
||||
return true;
|
||||
} else if (match("opengl4.5")) {
|
||||
if (env) *env = SPV_ENV_OPENGL_4_5;
|
||||
return true;
|
||||
} else if (match("webgpu0")) {
|
||||
if (env) *env = SPV_ENV_WEBGPU_0;
|
||||
return true;
|
||||
} else {
|
||||
if (env) *env = SPV_ENV_UNIVERSAL_1_0;
|
||||
return false;
|
||||
for (auto& name_env : spvTargetEnvNameMap) {
|
||||
if (match(name_env.first)) {
|
||||
if (env) {
|
||||
*env = name_env.second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (env) *env = SPV_ENV_UNIVERSAL_1_0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spvIsVulkanEnv(spv_target_env env) {
|
||||
@@ -310,3 +275,29 @@ std::string spvLogStringForEnv(spv_target_env env) {
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
std::string spvTargetEnvList(const int pad, const int wrap) {
|
||||
std::string ret;
|
||||
size_t max_line_len = wrap - pad; // The first line isn't padded
|
||||
std::string line;
|
||||
std::string sep = "";
|
||||
|
||||
for (auto& name_env : spvTargetEnvNameMap) {
|
||||
std::string word = sep + name_env.first;
|
||||
if (line.length() + word.length() > max_line_len) {
|
||||
// Adding one word wouldn't fit, commit the line in progress and
|
||||
// start a new one.
|
||||
ret += line + "\n";
|
||||
line.assign(pad, ' ');
|
||||
// The first line is done. The max length now comprises the
|
||||
// padding.
|
||||
max_line_len = wrap;
|
||||
}
|
||||
line += word;
|
||||
sep = "|";
|
||||
}
|
||||
|
||||
ret += line;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -38,4 +38,12 @@ uint32_t spvVersionForTargetEnv(spv_target_env env);
|
||||
// environment, i.e. "Vulkan", "WebGPU", "OpenCL", etc.
|
||||
std::string spvLogStringForEnv(spv_target_env env);
|
||||
|
||||
// Returns a formatted list of all SPIR-V target environment names that
|
||||
// can be parsed by spvParseTargetEnv.
|
||||
// |pad| is the number of space characters that the begining of each line
|
||||
// except the first one will be padded with.
|
||||
// |wrap| is the max length of lines the user desires. Word-wrapping will
|
||||
// occur to satisfy this limit.
|
||||
std::string spvTargetEnvList(const int pad, const int wrap);
|
||||
|
||||
#endif // SOURCE_SPIRV_TARGET_ENV_H_
|
||||
|
||||
@@ -175,13 +175,37 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (auto error = ValidateMemorySemantics(_, inst, operand_index++))
|
||||
const auto equal_semantics_index = operand_index++;
|
||||
if (auto error = ValidateMemorySemantics(_, inst, equal_semantics_index))
|
||||
return error;
|
||||
|
||||
if (opcode == SpvOpAtomicCompareExchange ||
|
||||
opcode == SpvOpAtomicCompareExchangeWeak) {
|
||||
if (auto error = ValidateMemorySemantics(_, inst, operand_index++))
|
||||
const auto unequal_semantics_index = operand_index++;
|
||||
if (auto error =
|
||||
ValidateMemorySemantics(_, inst, unequal_semantics_index))
|
||||
return error;
|
||||
|
||||
// Volatile bits must match for equal and unequal semantics. Previous
|
||||
// checks guarantee they are 32-bit constants, but we need to recheck
|
||||
// whether they are evaluatable constants.
|
||||
bool is_int32 = false;
|
||||
bool is_equal_const = false;
|
||||
bool is_unequal_const = false;
|
||||
uint32_t equal_value = 0;
|
||||
uint32_t unequal_value = 0;
|
||||
std::tie(is_int32, is_equal_const, equal_value) = _.EvalInt32IfConst(
|
||||
inst->GetOperandAs<uint32_t>(equal_semantics_index));
|
||||
std::tie(is_int32, is_unequal_const, unequal_value) =
|
||||
_.EvalInt32IfConst(
|
||||
inst->GetOperandAs<uint32_t>(unequal_semantics_index));
|
||||
if (is_equal_const && is_unequal_const &&
|
||||
((equal_value & SpvMemorySemanticsVolatileMask) ^
|
||||
(unequal_value & SpvMemorySemanticsVolatileMask))) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Volatile mask setting must match for Equal and Unequal "
|
||||
"memory semantics";
|
||||
}
|
||||
}
|
||||
|
||||
if (opcode == SpvOpAtomicStore) {
|
||||
|
||||
@@ -1393,6 +1393,81 @@ spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate,
|
||||
<< spvOpcodeString(inst.opcode());
|
||||
}
|
||||
|
||||
// Returns SPV_SUCCESS if validation rules are satisfied for the Component
|
||||
// decoration. Otherwise emits a diagnostic and returns something other than
|
||||
// SPV_SUCCESS.
|
||||
spv_result_t CheckComponentDecoration(ValidationState_t& vstate,
|
||||
const Instruction& inst,
|
||||
const Decoration& decoration) {
|
||||
assert(inst.id() && "Parser ensures the target of the decoration has an ID");
|
||||
|
||||
uint32_t type_id;
|
||||
if (decoration.struct_member_index() == Decoration::kInvalidMember) {
|
||||
// The target must be a memory object declaration.
|
||||
const auto opcode = inst.opcode();
|
||||
if (opcode != SpvOpVariable && opcode != SpvOpFunctionParameter) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||
<< "Target of Component decoration must be a memory object "
|
||||
"declaration (a variable or a function parameter)";
|
||||
}
|
||||
|
||||
// Only valid for the Input and Output Storage Classes.
|
||||
const auto storage_class = opcode == SpvOpVariable
|
||||
? inst.GetOperandAs<SpvStorageClass>(2)
|
||||
: SpvStorageClassMax;
|
||||
if (storage_class != SpvStorageClassInput &&
|
||||
storage_class != SpvStorageClassOutput &&
|
||||
storage_class != SpvStorageClassMax) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||
<< "Target of Component decoration is invalid: must point to a "
|
||||
"Storage Class of Input(1) or Output(3). Found Storage "
|
||||
"Class "
|
||||
<< storage_class;
|
||||
}
|
||||
|
||||
type_id = inst.type_id();
|
||||
if (vstate.IsPointerType(type_id)) {
|
||||
const auto pointer = vstate.FindDef(type_id);
|
||||
type_id = pointer->GetOperandAs<uint32_t>(2);
|
||||
}
|
||||
} else {
|
||||
if (inst.opcode() != SpvOpTypeStruct) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< "Attempted to get underlying data type via member index for "
|
||||
"non-struct type.";
|
||||
}
|
||||
type_id = inst.word(decoration.struct_member_index() + 2);
|
||||
}
|
||||
|
||||
if (spvIsVulkanEnv(vstate.context()->target_env)) {
|
||||
if (!vstate.IsIntScalarOrVectorType(type_id) &&
|
||||
!vstate.IsFloatScalarOrVectorType(type_id)) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||
<< "Component decoration specified for type "
|
||||
<< vstate.getIdName(type_id) << " that is not a scalar or vector";
|
||||
}
|
||||
|
||||
// For 16-, and 32-bit types, it is invalid if this sequence of components
|
||||
// gets larger than 3.
|
||||
const auto bit_width = vstate.GetBitWidth(type_id);
|
||||
if (bit_width == 16 || bit_width == 32) {
|
||||
assert(decoration.params().size() == 1 &&
|
||||
"Grammar ensures Component has one parameter");
|
||||
|
||||
const auto component = decoration.params()[0];
|
||||
const auto last_component = component + vstate.GetDimension(type_id) - 1;
|
||||
if (last_component > 3) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||
<< "Sequence of components starting with " << component
|
||||
<< " and ending with " << last_component
|
||||
<< " gets larger than 3";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
#define PASS_OR_BAIL_AT_LINE(X, LINE) \
|
||||
{ \
|
||||
spv_result_t e##LINE = (X); \
|
||||
@@ -1421,6 +1496,9 @@ spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) {
|
||||
|
||||
for (const auto& decoration : decorations) {
|
||||
switch (decoration.dec_type()) {
|
||||
case SpvDecorationComponent:
|
||||
PASS_OR_BAIL(CheckComponentDecoration(vstate, *inst, decoration));
|
||||
break;
|
||||
case SpvDecorationFPRoundingMode:
|
||||
if (is_shader)
|
||||
PASS_OR_BAIL(CheckFPRoundingModeForShaders(vstate, *inst));
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/val/validate.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -21,6 +19,7 @@
|
||||
#include "source/opcode.h"
|
||||
#include "source/spirv_target_env.h"
|
||||
#include "source/val/instruction.h"
|
||||
#include "source/val/validate.h"
|
||||
#include "source/val/validate_scopes.h"
|
||||
#include "source/val/validation_state.h"
|
||||
|
||||
@@ -809,6 +808,25 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction* inst) {
|
||||
<< "OpStore Pointer <id> '" << _.getIdName(pointer_id)
|
||||
<< "' storage class is read-only";
|
||||
}
|
||||
|
||||
if (spvIsVulkanEnv(_.context()->target_env) &&
|
||||
storage_class == SpvStorageClassUniform) {
|
||||
auto base_ptr = _.TracePointer(pointer);
|
||||
if (base_ptr->opcode() == SpvOpVariable) {
|
||||
// If it's not a variable a different check should catch the problem.
|
||||
auto base_type = _.FindDef(base_ptr->GetOperandAs<uint32_t>(0));
|
||||
// Get the pointed-to type.
|
||||
base_type = _.FindDef(base_type->GetOperandAs<uint32_t>(2u));
|
||||
if (base_type->opcode() == SpvOpTypeArray ||
|
||||
base_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
base_type = _.FindDef(base_type->GetOperandAs<uint32_t>(1u));
|
||||
}
|
||||
if (_.HasDecoration(base_type->id(), SpvDecorationBlock)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In the Vulkan environment, cannot store to Uniform Blocks";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto object_index = 1;
|
||||
|
||||
@@ -39,11 +39,20 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
|
||||
}
|
||||
|
||||
if (!is_const_int32) {
|
||||
if (_.HasCapability(SpvCapabilityShader)) {
|
||||
if (_.HasCapability(SpvCapabilityShader) &&
|
||||
!_.HasCapability(SpvCapabilityCooperativeMatrixNV)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Memory Semantics ids must be OpConstant when Shader "
|
||||
"capability is present";
|
||||
}
|
||||
|
||||
if (_.HasCapability(SpvCapabilityShader) &&
|
||||
_.HasCapability(SpvCapabilityCooperativeMatrixNV) &&
|
||||
!spvOpcodeIsConstant(_.GetIdOpcode(id))) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Memory Semantics must be a constant instruction when "
|
||||
"CooperativeMatrixNV capability is present";
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -127,6 +136,21 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
|
||||
<< "VulkanMemoryModelKHR";
|
||||
}
|
||||
|
||||
if (value & SpvMemorySemanticsVolatileMask) {
|
||||
if (!_.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< spvOpcodeString(opcode)
|
||||
<< ": Memory Semantics Volatile requires capability "
|
||||
"VulkanMemoryModelKHR";
|
||||
}
|
||||
|
||||
if (!spvOpcodeIsAtomicOp(inst->opcode())) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Memory Semantics Volatile can only be used with atomic "
|
||||
"instructions";
|
||||
}
|
||||
}
|
||||
|
||||
if (value & SpvMemorySemanticsUniformMemoryMask &&
|
||||
!_.HasCapability(SpvCapabilityShader)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
|
||||
@@ -1213,5 +1213,18 @@ bool ValidationState_t::LogicallyMatch(const Instruction* lhs,
|
||||
return false;
|
||||
}
|
||||
|
||||
const Instruction* ValidationState_t::TracePointer(
|
||||
const Instruction* inst) const {
|
||||
auto base_ptr = inst;
|
||||
while (base_ptr->opcode() == SpvOpAccessChain ||
|
||||
base_ptr->opcode() == SpvOpInBoundsAccessChain ||
|
||||
base_ptr->opcode() == SpvOpPtrAccessChain ||
|
||||
base_ptr->opcode() == SpvOpInBoundsPtrAccessChain ||
|
||||
base_ptr->opcode() == SpvOpCopyObject) {
|
||||
base_ptr = FindDef(base_ptr->GetOperandAs<uint32_t>(2u));
|
||||
}
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -680,6 +680,15 @@ class ValidationState_t {
|
||||
bool LogicallyMatch(const Instruction* lhs, const Instruction* rhs,
|
||||
bool check_decorations);
|
||||
|
||||
// Traces |inst| to find a single base pointer. Returns the base pointer.
|
||||
// Will trace through the following instructions:
|
||||
// * OpAccessChain
|
||||
// * OpInBoundsAccessChain
|
||||
// * OpPtrAccessChain
|
||||
// * OpInBoundsPtrAccessChain
|
||||
// * OpCopyObject
|
||||
const Instruction* TracePointer(const Instruction* inst) const;
|
||||
|
||||
private:
|
||||
ValidationState_t(const ValidationState_t&);
|
||||
|
||||
|
||||
@@ -20,15 +20,19 @@ if (${SPIRV_BUILD_FUZZER})
|
||||
fuzzer_replayer_test.cpp
|
||||
fact_manager_test.cpp
|
||||
fuzz_test_util.cpp
|
||||
fuzzer_pass_add_useful_constructs_test.cpp
|
||||
transformation_add_constant_boolean_test.cpp
|
||||
transformation_add_constant_scalar_test.cpp
|
||||
transformation_add_dead_break_test.cpp
|
||||
transformation_add_type_boolean_test.cpp
|
||||
transformation_add_type_float_test.cpp
|
||||
transformation_add_type_int_test.cpp
|
||||
transformation_add_type_pointer_test.cpp
|
||||
transformation_move_block_down_test.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary_test.cpp
|
||||
transformation_split_block_test.cpp)
|
||||
transformation_replace_constant_with_uniform_test.cpp
|
||||
transformation_split_block_test.cpp
|
||||
uniform_buffer_element_descriptor_test.cpp)
|
||||
|
||||
add_spvtools_unittest(TARGET fuzz
|
||||
SRCS ${SOURCES}
|
||||
|
||||
261
3rdparty/spirv-tools/test/fuzz/fact_manager_test.cpp
vendored
261
3rdparty/spirv-tools/test/fuzz/fact_manager_test.cpp
vendored
@@ -12,6 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
@@ -56,6 +58,44 @@ TEST(FactManagerTest, ConstantsAvailableViaUniforms) {
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpDecorate %100 DescriptorSet 0
|
||||
OpDecorate %100 Binding 0
|
||||
OpDecorate %200 DescriptorSet 0
|
||||
OpDecorate %200 Binding 1
|
||||
OpDecorate %300 DescriptorSet 0
|
||||
OpDecorate %300 Binding 2
|
||||
OpDecorate %400 DescriptorSet 0
|
||||
OpDecorate %400 Binding 3
|
||||
OpDecorate %500 DescriptorSet 0
|
||||
OpDecorate %500 Binding 4
|
||||
OpDecorate %600 DescriptorSet 0
|
||||
OpDecorate %600 Binding 5
|
||||
OpDecorate %700 DescriptorSet 0
|
||||
OpDecorate %700 Binding 6
|
||||
OpDecorate %800 DescriptorSet 1
|
||||
OpDecorate %800 Binding 0
|
||||
OpDecorate %900 DescriptorSet 1
|
||||
OpDecorate %900 Binding 1
|
||||
OpDecorate %1000 DescriptorSet 1
|
||||
OpDecorate %1000 Binding 2
|
||||
OpDecorate %1100 DescriptorSet 1
|
||||
OpDecorate %1100 Binding 3
|
||||
OpDecorate %1200 DescriptorSet 1
|
||||
OpDecorate %1200 Binding 4
|
||||
OpDecorate %1300 DescriptorSet 1
|
||||
OpDecorate %1300 Binding 5
|
||||
OpDecorate %1400 DescriptorSet 1
|
||||
OpDecorate %1400 Binding 6
|
||||
OpDecorate %1500 DescriptorSet 2
|
||||
OpDecorate %1500 Binding 0
|
||||
OpDecorate %1600 DescriptorSet 2
|
||||
OpDecorate %1600 Binding 1
|
||||
OpDecorate %1700 DescriptorSet 2
|
||||
OpDecorate %1700 Binding 2
|
||||
OpDecorate %1800 DescriptorSet 2
|
||||
OpDecorate %1800 Binding 3
|
||||
OpDecorate %1900 DescriptorSet 2
|
||||
OpDecorate %1900 Binding 4
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%10 = OpTypeInt 32 0
|
||||
@@ -229,94 +269,98 @@ TEST(FactManagerTest, ConstantsAvailableViaUniforms) {
|
||||
type_uint32_id)
|
||||
.empty());
|
||||
|
||||
// In the comments that follow we write v[...][...] to refer to uniform
|
||||
// variable v indexed with some given indices, when in practice v is
|
||||
// identified via a (descriptor set, binding) pair.
|
||||
|
||||
// 100[2][3] == int(1)
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
|
||||
MakeUniformBufferElementDescriptor(100, {2, 3})));
|
||||
MakeUniformBufferElementDescriptor(0, 0, {2, 3})));
|
||||
|
||||
// 200[1][2][3] == int(1)
|
||||
ASSERT_TRUE(
|
||||
AddFactHelper(&fact_manager, context.get(), {1},
|
||||
MakeUniformBufferElementDescriptor(200, {1, 2, 3})));
|
||||
MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3})));
|
||||
|
||||
// 300[1][0][2][3] == int(1)
|
||||
ASSERT_TRUE(
|
||||
AddFactHelper(&fact_manager, context.get(), {1},
|
||||
MakeUniformBufferElementDescriptor(300, {1, 0, 2, 3})));
|
||||
MakeUniformBufferElementDescriptor(0, 2, {1, 0, 2, 3})));
|
||||
|
||||
// 400[2][3] = int32_min
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]},
|
||||
MakeUniformBufferElementDescriptor(400, {2, 3})));
|
||||
MakeUniformBufferElementDescriptor(0, 3, {2, 3})));
|
||||
|
||||
// 500[1][2][3] = int32_min
|
||||
ASSERT_TRUE(
|
||||
AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]},
|
||||
MakeUniformBufferElementDescriptor(500, {1, 2, 3})));
|
||||
MakeUniformBufferElementDescriptor(0, 4, {1, 2, 3})));
|
||||
|
||||
// 600[1][2][3] = int64_max
|
||||
ASSERT_TRUE(AddFactHelper(
|
||||
&fact_manager, context.get(), {buffer_int64_max[0], buffer_int64_max[1]},
|
||||
MakeUniformBufferElementDescriptor(600, {1, 2, 3})));
|
||||
MakeUniformBufferElementDescriptor(0, 5, {1, 2, 3})));
|
||||
|
||||
// 700[1][1] = int64_max
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
|
||||
{buffer_int64_max[0], buffer_int64_max[1]},
|
||||
MakeUniformBufferElementDescriptor(700, {1, 1})));
|
||||
MakeUniformBufferElementDescriptor(0, 6, {1, 1})));
|
||||
|
||||
// 800[2][3] = uint(1)
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
|
||||
MakeUniformBufferElementDescriptor(800, {2, 3})));
|
||||
MakeUniformBufferElementDescriptor(1, 0, {2, 3})));
|
||||
|
||||
// 900[1][2][3] = uint(1)
|
||||
ASSERT_TRUE(
|
||||
AddFactHelper(&fact_manager, context.get(), {1},
|
||||
MakeUniformBufferElementDescriptor(900, {1, 2, 3})));
|
||||
MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3})));
|
||||
|
||||
// 1000[1][0][2][3] = uint(1)
|
||||
ASSERT_TRUE(
|
||||
AddFactHelper(&fact_manager, context.get(), {1},
|
||||
MakeUniformBufferElementDescriptor(1000, {1, 0, 2, 3})));
|
||||
MakeUniformBufferElementDescriptor(1, 2, {1, 0, 2, 3})));
|
||||
|
||||
// 1100[0] = uint64(1)
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
|
||||
{buffer_uint64_1[0], buffer_uint64_1[1]},
|
||||
MakeUniformBufferElementDescriptor(1100, {0})));
|
||||
MakeUniformBufferElementDescriptor(1, 3, {0})));
|
||||
|
||||
// 1200[0][0] = uint64_max
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
|
||||
{buffer_uint64_max[0], buffer_uint64_max[1]},
|
||||
MakeUniformBufferElementDescriptor(1200, {0, 0})));
|
||||
MakeUniformBufferElementDescriptor(1, 4, {0, 0})));
|
||||
|
||||
// 1300[1][0] = uint64_max
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
|
||||
{buffer_uint64_max[0], buffer_uint64_max[1]},
|
||||
MakeUniformBufferElementDescriptor(1300, {1, 0})));
|
||||
MakeUniformBufferElementDescriptor(1, 5, {1, 0})));
|
||||
|
||||
// 1400[6] = float(10.0)
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
|
||||
MakeUniformBufferElementDescriptor(1400, {6})));
|
||||
MakeUniformBufferElementDescriptor(1, 6, {6})));
|
||||
|
||||
// 1500[7] = float(10.0)
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
|
||||
MakeUniformBufferElementDescriptor(1500, {7})));
|
||||
MakeUniformBufferElementDescriptor(2, 0, {7})));
|
||||
|
||||
// 1600[9][9] = float(10.0)
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
|
||||
MakeUniformBufferElementDescriptor(1600, {9, 9})));
|
||||
MakeUniformBufferElementDescriptor(2, 1, {9, 9})));
|
||||
|
||||
// 1700[9][9][1] = double(10.0)
|
||||
ASSERT_TRUE(AddFactHelper(
|
||||
&fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]},
|
||||
MakeUniformBufferElementDescriptor(1700, {9, 9, 1})));
|
||||
MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1})));
|
||||
|
||||
// 1800[9][9][2] = double(10.0)
|
||||
ASSERT_TRUE(AddFactHelper(
|
||||
&fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]},
|
||||
MakeUniformBufferElementDescriptor(1800, {9, 9, 2})));
|
||||
MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2})));
|
||||
|
||||
// 1900[0][0][0][0][0] = double(20.0)
|
||||
ASSERT_TRUE(AddFactHelper(
|
||||
&fact_manager, context.get(), {buffer_double_20[0], buffer_double_20[1]},
|
||||
MakeUniformBufferElementDescriptor(1900, {0, 0, 0, 0, 0})));
|
||||
MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0})));
|
||||
|
||||
opt::Instruction::OperandList operands = {
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
|
||||
@@ -427,12 +471,12 @@ TEST(FactManagerTest, ConstantsAvailableViaUniforms) {
|
||||
context.get(), double_constant_ids[0]);
|
||||
ASSERT_EQ(2, descriptors_for_double_10.size());
|
||||
{
|
||||
auto temp = MakeUniformBufferElementDescriptor(1700, {9, 9, 1});
|
||||
auto temp = MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1});
|
||||
ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
|
||||
&temp, &descriptors_for_double_10[0]));
|
||||
}
|
||||
{
|
||||
auto temp = MakeUniformBufferElementDescriptor(1800, {9, 9, 2});
|
||||
auto temp = MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2});
|
||||
ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
|
||||
&temp, &descriptors_for_double_10[1]));
|
||||
}
|
||||
@@ -441,17 +485,17 @@ TEST(FactManagerTest, ConstantsAvailableViaUniforms) {
|
||||
context.get(), double_constant_ids[1]);
|
||||
ASSERT_EQ(1, descriptors_for_double_20.size());
|
||||
{
|
||||
auto temp = MakeUniformBufferElementDescriptor(1900, {0, 0, 0, 0, 0});
|
||||
auto temp = MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0});
|
||||
ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
|
||||
&temp, &descriptors_for_double_20[0]));
|
||||
}
|
||||
|
||||
auto constant_1_id = fact_manager.GetConstantFromUniformDescriptor(
|
||||
context.get(), MakeUniformBufferElementDescriptor(1800, {9, 9, 2}));
|
||||
context.get(), MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}));
|
||||
ASSERT_TRUE(constant_1_id);
|
||||
|
||||
auto constant_2_id = fact_manager.GetConstantFromUniformDescriptor(
|
||||
context.get(), MakeUniformBufferElementDescriptor(1900, {0, 0, 0, 0, 0}));
|
||||
context.get(), MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0}));
|
||||
ASSERT_TRUE(constant_2_id);
|
||||
|
||||
ASSERT_EQ(double_constant_ids[0], constant_1_id);
|
||||
@@ -503,9 +547,9 @@ TEST(FactManagerTest, TwoConstantsWithSameValue) {
|
||||
FactManager fact_manager;
|
||||
|
||||
auto uniform_buffer_element_descriptor =
|
||||
MakeUniformBufferElementDescriptor(12, {0});
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0});
|
||||
|
||||
// 12[0] = int(1)
|
||||
// (0, 0, [0]) = int(1)
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
|
||||
uniform_buffer_element_descriptor));
|
||||
auto constants =
|
||||
@@ -529,6 +573,171 @@ TEST(FactManagerTest, TwoConstantsWithSameValue) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FactManagerTest, NonFiniteFactsAreNotValid) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Float64
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %7 "buf"
|
||||
OpMemberName %7 0 "f"
|
||||
OpMemberName %7 1 "d"
|
||||
OpName %9 ""
|
||||
OpMemberDecorate %7 0 Offset 0
|
||||
OpMemberDecorate %7 1 Offset 8
|
||||
OpDecorate %7 Block
|
||||
OpDecorate %9 DescriptorSet 0
|
||||
OpDecorate %9 Binding 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%10 = OpTypeFloat 64
|
||||
%7 = OpTypeStruct %6 %10
|
||||
%8 = OpTypePointer Uniform %7
|
||||
%9 = OpVariable %8 Uniform
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
auto uniform_buffer_element_descriptor_f =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0});
|
||||
|
||||
auto uniform_buffer_element_descriptor_d =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1});
|
||||
|
||||
if (std::numeric_limits<float>::has_infinity) {
|
||||
// f == +inf
|
||||
float positive_infinity_float = std::numeric_limits<float>::infinity();
|
||||
uint32_t words[1];
|
||||
memcpy(words, &positive_infinity_float, sizeof(float));
|
||||
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]},
|
||||
uniform_buffer_element_descriptor_f));
|
||||
// f == -inf
|
||||
float negative_infinity_float = std::numeric_limits<float>::infinity();
|
||||
memcpy(words, &negative_infinity_float, sizeof(float));
|
||||
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]},
|
||||
uniform_buffer_element_descriptor_f));
|
||||
}
|
||||
|
||||
if (std::numeric_limits<float>::has_quiet_NaN) {
|
||||
// f == NaN
|
||||
float quiet_nan_float = std::numeric_limits<float>::quiet_NaN();
|
||||
uint32_t words[1];
|
||||
memcpy(words, &quiet_nan_float, sizeof(float));
|
||||
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]},
|
||||
uniform_buffer_element_descriptor_f));
|
||||
}
|
||||
|
||||
if (std::numeric_limits<double>::has_infinity) {
|
||||
// d == +inf
|
||||
double positive_infinity_double = std::numeric_limits<double>::infinity();
|
||||
uint32_t words[2];
|
||||
memcpy(words, &positive_infinity_double, sizeof(double));
|
||||
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(),
|
||||
{words[0], words[1]},
|
||||
uniform_buffer_element_descriptor_d));
|
||||
// d == -inf
|
||||
double negative_infinity_double = -std::numeric_limits<double>::infinity();
|
||||
memcpy(words, &negative_infinity_double, sizeof(double));
|
||||
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(),
|
||||
{words[0], words[1]},
|
||||
uniform_buffer_element_descriptor_d));
|
||||
}
|
||||
|
||||
if (std::numeric_limits<double>::has_quiet_NaN) {
|
||||
// d == NaN
|
||||
double quiet_nan_double = std::numeric_limits<double>::quiet_NaN();
|
||||
uint32_t words[2];
|
||||
memcpy(words, &quiet_nan_double, sizeof(double));
|
||||
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(),
|
||||
{words[0], words[1]},
|
||||
uniform_buffer_element_descriptor_d));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FactManagerTest, AmbiguousFact) {
|
||||
// This test came from the following GLSL:
|
||||
//
|
||||
// #version 310 es
|
||||
//
|
||||
// precision highp float;
|
||||
//
|
||||
// layout(set = 0, binding = 0) uniform buf {
|
||||
// float f;
|
||||
// };
|
||||
//
|
||||
// layout(set = 0, binding = 0) uniform buf2 {
|
||||
// float g;
|
||||
// };
|
||||
//
|
||||
// void main() {
|
||||
//
|
||||
// }
|
||||
|
||||
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 %7 "buf"
|
||||
OpMemberName %7 0 "f"
|
||||
OpName %9 ""
|
||||
OpName %10 "buf2"
|
||||
OpMemberName %10 0 "g"
|
||||
OpName %12 ""
|
||||
OpMemberDecorate %7 0 Offset 0
|
||||
OpDecorate %7 Block
|
||||
OpDecorate %9 DescriptorSet 0
|
||||
OpDecorate %9 Binding 0
|
||||
OpMemberDecorate %10 0 Offset 0
|
||||
OpDecorate %10 Block
|
||||
OpDecorate %12 DescriptorSet 0
|
||||
OpDecorate %12 Binding 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypeStruct %6
|
||||
%8 = OpTypePointer Uniform %7
|
||||
%9 = OpVariable %8 Uniform
|
||||
%10 = OpTypeStruct %6
|
||||
%11 = OpTypePointer Uniform %10
|
||||
%12 = OpVariable %11 Uniform
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
auto uniform_buffer_element_descriptor =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0});
|
||||
|
||||
// The fact cannot be added because it is ambiguous: there are two uniforms
|
||||
// with descriptor set 0 and binding 0.
|
||||
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {1},
|
||||
uniform_buffer_element_descriptor));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
393
3rdparty/spirv-tools/test/fuzz/fuzzer_pass_add_useful_constructs_test.cpp
vendored
Normal file
393
3rdparty/spirv-tools/test/fuzz/fuzzer_pass_add_useful_constructs_test.cpp
vendored
Normal file
@@ -0,0 +1,393 @@
|
||||
// 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 "source/fuzz/fuzzer_pass_add_useful_constructs.h"
|
||||
#include "source/fuzz/pseudo_random_generator.h"
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
bool AddFactHelper(
|
||||
FactManager* fact_manager, opt::IRContext* context, uint32_t word,
|
||||
const protobufs::UniformBufferElementDescriptor& descriptor) {
|
||||
protobufs::FactConstantUniform constant_uniform_fact;
|
||||
constant_uniform_fact.add_constant_word(word);
|
||||
*constant_uniform_fact.mutable_uniform_buffer_element_descriptor() =
|
||||
descriptor;
|
||||
protobufs::Fact fact;
|
||||
*fact.mutable_constant_uniform_fact() = constant_uniform_fact;
|
||||
return fact_manager->AddFact(fact, context);
|
||||
}
|
||||
|
||||
TEST(FuzzerPassAddUsefulConstructsTest, CheckBasicStuffIsAdded) {
|
||||
// The SPIR-V came from the following empty GLSL shader:
|
||||
//
|
||||
// #version 450
|
||||
//
|
||||
// void main()
|
||||
// {
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
|
||||
protobufs::TransformationSequence transformation_sequence;
|
||||
|
||||
FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager,
|
||||
&fuzzer_context, &transformation_sequence);
|
||||
pass.Apply();
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%100 = OpTypeBool
|
||||
%101 = OpTypeInt 32 1
|
||||
%102 = OpTypeInt 32 0
|
||||
%103 = OpTypeFloat 32
|
||||
%104 = OpConstantTrue %100
|
||||
%105 = OpConstantFalse %100
|
||||
%106 = OpConstant %101 0
|
||||
%107 = OpConstant %101 1
|
||||
%108 = OpConstant %102 0
|
||||
%109 = OpConstant %102 1
|
||||
%110 = OpConstant %103 0
|
||||
%111 = OpConstant %103 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after, context.get()));
|
||||
}
|
||||
|
||||
TEST(FuzzerPassAddUsefulConstructsTest,
|
||||
CheckTypesIndicesAndConstantsAddedForUniformFacts) {
|
||||
// The SPIR-V came from the following GLSL shader:
|
||||
//
|
||||
// #version 450
|
||||
//
|
||||
// struct S {
|
||||
// int x;
|
||||
// float y;
|
||||
// int z;
|
||||
// int w;
|
||||
// };
|
||||
//
|
||||
// uniform buf {
|
||||
// S s;
|
||||
// uint w[10];
|
||||
// };
|
||||
//
|
||||
// void main() {
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %8 "S"
|
||||
OpMemberName %8 0 "x"
|
||||
OpMemberName %8 1 "y"
|
||||
OpMemberName %8 2 "z"
|
||||
OpMemberName %8 3 "w"
|
||||
OpName %12 "buf"
|
||||
OpMemberName %12 0 "s"
|
||||
OpMemberName %12 1 "w"
|
||||
OpName %14 ""
|
||||
OpMemberDecorate %8 0 Offset 0
|
||||
OpMemberDecorate %8 1 Offset 4
|
||||
OpMemberDecorate %8 2 Offset 8
|
||||
OpMemberDecorate %8 3 Offset 12
|
||||
OpDecorate %11 ArrayStride 16
|
||||
OpMemberDecorate %12 0 Offset 0
|
||||
OpMemberDecorate %12 1 Offset 16
|
||||
OpDecorate %12 Block
|
||||
OpDecorate %14 DescriptorSet 0
|
||||
OpDecorate %14 Binding 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypeFloat 32
|
||||
%8 = OpTypeStruct %6 %7 %6 %6
|
||||
%9 = OpTypeInt 32 0
|
||||
%10 = OpConstant %9 10
|
||||
%11 = OpTypeArray %9 %10
|
||||
%12 = OpTypeStruct %8 %11
|
||||
%13 = OpTypePointer Uniform %12
|
||||
%14 = OpVariable %13 Uniform
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
|
||||
protobufs::TransformationSequence transformation_sequence;
|
||||
|
||||
// Add some uniform facts.
|
||||
|
||||
// buf.s.x == 200
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 0})));
|
||||
|
||||
// buf.s.y == 0.5
|
||||
const float float_value = 0.5;
|
||||
uint32_t float_value_as_uint;
|
||||
memcpy(&float_value_as_uint, &float_value, sizeof(float_value));
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_value_as_uint,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 1})));
|
||||
|
||||
// buf.s.z == 300
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 300,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 2})));
|
||||
|
||||
// buf.s.w == 400
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 400,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 3})));
|
||||
|
||||
// buf.w[6] = 22
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 22,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 6})));
|
||||
|
||||
// buf.w[8] = 23
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 23,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 8})));
|
||||
|
||||
// Assert some things about the module that are not true prior to adding the
|
||||
// pass
|
||||
|
||||
{
|
||||
// No uniform int pointer
|
||||
opt::analysis::Integer temp_type_signed_int(32, true);
|
||||
opt::analysis::Integer* registered_type_signed_int =
|
||||
context->get_type_mgr()
|
||||
->GetRegisteredType(&temp_type_signed_int)
|
||||
->AsInteger();
|
||||
opt::analysis::Pointer type_pointer_uniform_signed_int(
|
||||
registered_type_signed_int, SpvStorageClassUniform);
|
||||
ASSERT_EQ(0,
|
||||
context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
|
||||
|
||||
// No uniform uint pointer
|
||||
opt::analysis::Integer temp_type_unsigned_int(32, false);
|
||||
opt::analysis::Integer* registered_type_unsigned_int =
|
||||
context->get_type_mgr()
|
||||
->GetRegisteredType(&temp_type_unsigned_int)
|
||||
->AsInteger();
|
||||
opt::analysis::Pointer type_pointer_uniform_unsigned_int(
|
||||
registered_type_unsigned_int, SpvStorageClassUniform);
|
||||
ASSERT_EQ(
|
||||
0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
|
||||
|
||||
// No uniform float pointer
|
||||
opt::analysis::Float temp_type_float(32);
|
||||
opt::analysis::Float* registered_type_float =
|
||||
context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
|
||||
opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
|
||||
SpvStorageClassUniform);
|
||||
ASSERT_EQ(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
|
||||
|
||||
// No int constants 200, 300 nor 400
|
||||
opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
|
||||
{200});
|
||||
opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
|
||||
{300});
|
||||
opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
|
||||
{400});
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_200));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_300));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_400));
|
||||
|
||||
// No float constant 0.5
|
||||
opt::analysis::FloatConstant float_constant_zero_point_five(
|
||||
registered_type_float, {float_value_as_uint});
|
||||
ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(
|
||||
&float_constant_zero_point_five));
|
||||
|
||||
// No uint constant 22
|
||||
opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
|
||||
{22});
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&uint_constant_22));
|
||||
|
||||
// No uint constant 23
|
||||
opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
|
||||
{23});
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&uint_constant_23));
|
||||
|
||||
// No int constants 0, 1, 2, 3, 6, 8
|
||||
opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
|
||||
opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
|
||||
opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
|
||||
opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
|
||||
opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
|
||||
opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_0));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_1));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_2));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_3));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_6));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_8));
|
||||
}
|
||||
|
||||
FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager,
|
||||
&fuzzer_context, &transformation_sequence);
|
||||
pass.Apply();
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Now assert some things about the module that should be true following the
|
||||
// pass.
|
||||
|
||||
// We reconstruct all necessary types and constants to guard against the type
|
||||
// and constant managers for the module having been invalidated.
|
||||
|
||||
{
|
||||
// Uniform int pointer now present
|
||||
opt::analysis::Integer temp_type_signed_int(32, true);
|
||||
opt::analysis::Integer* registered_type_signed_int =
|
||||
context->get_type_mgr()
|
||||
->GetRegisteredType(&temp_type_signed_int)
|
||||
->AsInteger();
|
||||
opt::analysis::Pointer type_pointer_uniform_signed_int(
|
||||
registered_type_signed_int, SpvStorageClassUniform);
|
||||
ASSERT_NE(0,
|
||||
context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
|
||||
|
||||
// Uniform uint pointer now present
|
||||
opt::analysis::Integer temp_type_unsigned_int(32, false);
|
||||
opt::analysis::Integer* registered_type_unsigned_int =
|
||||
context->get_type_mgr()
|
||||
->GetRegisteredType(&temp_type_unsigned_int)
|
||||
->AsInteger();
|
||||
opt::analysis::Pointer type_pointer_uniform_unsigned_int(
|
||||
registered_type_unsigned_int, SpvStorageClassUniform);
|
||||
ASSERT_NE(
|
||||
0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
|
||||
|
||||
// Uniform float pointer now present
|
||||
opt::analysis::Float temp_type_float(32);
|
||||
opt::analysis::Float* registered_type_float =
|
||||
context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
|
||||
opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
|
||||
SpvStorageClassUniform);
|
||||
ASSERT_NE(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
|
||||
|
||||
// int constants 200, 300, 400 now present
|
||||
opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
|
||||
{200});
|
||||
opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
|
||||
{300});
|
||||
opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
|
||||
{400});
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_200));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_300));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_400));
|
||||
|
||||
// float constant 0.5 now present
|
||||
opt::analysis::FloatConstant float_constant_zero_point_five(
|
||||
registered_type_float, {float_value_as_uint});
|
||||
ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(
|
||||
&float_constant_zero_point_five));
|
||||
|
||||
// uint constant 22 now present
|
||||
opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
|
||||
{22});
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&uint_constant_22));
|
||||
|
||||
// uint constant 23 now present
|
||||
opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
|
||||
{23});
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&uint_constant_23));
|
||||
|
||||
// int constants 0, 1, 2, 3, 6, 8 now present
|
||||
opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
|
||||
opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
|
||||
opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
|
||||
opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
|
||||
opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
|
||||
opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_0));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_1));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_2));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_3));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_6));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_8));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "source/fuzz/fuzzer.h"
|
||||
#include "source/fuzz/replayer.h"
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
@@ -25,8 +26,9 @@ namespace {
|
||||
// the binary produced after each fuzzer run is valid, and that replaying
|
||||
// the transformations that were applied during fuzzing leads to an
|
||||
// identical binary.
|
||||
void RunFuzzerAndReplayer(const std::string& shader, uint32_t initial_seed,
|
||||
uint32_t num_runs) {
|
||||
void RunFuzzerAndReplayer(const std::string& shader,
|
||||
const protobufs::FactSequence& initial_facts,
|
||||
uint32_t initial_seed, uint32_t num_runs) {
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
|
||||
std::vector<uint32_t> binary_in;
|
||||
@@ -35,23 +37,27 @@ void RunFuzzerAndReplayer(const std::string& shader, uint32_t initial_seed,
|
||||
ASSERT_TRUE(t.Validate(binary_in));
|
||||
|
||||
for (uint32_t seed = initial_seed; seed < initial_seed + num_runs; seed++) {
|
||||
protobufs::FactSequence initial_facts;
|
||||
std::vector<uint32_t> fuzzer_binary_out;
|
||||
protobufs::TransformationSequence fuzzer_transformation_sequence_out;
|
||||
spvtools::FuzzerOptions fuzzer_options;
|
||||
spvFuzzerOptionsSetRandomSeed(fuzzer_options, seed);
|
||||
|
||||
Fuzzer fuzzer(env);
|
||||
fuzzer.Run(binary_in, initial_facts, &fuzzer_binary_out,
|
||||
&fuzzer_transformation_sequence_out, fuzzer_options);
|
||||
auto fuzzer_result_status =
|
||||
fuzzer.Run(binary_in, initial_facts, &fuzzer_binary_out,
|
||||
&fuzzer_transformation_sequence_out, fuzzer_options);
|
||||
ASSERT_EQ(Fuzzer::FuzzerResultStatus::kComplete, fuzzer_result_status);
|
||||
ASSERT_TRUE(t.Validate(fuzzer_binary_out));
|
||||
|
||||
std::vector<uint32_t> replayer_binary_out;
|
||||
protobufs::TransformationSequence replayer_transformation_sequence_out;
|
||||
|
||||
Replayer replayer(env);
|
||||
replayer.Run(binary_in, initial_facts, fuzzer_transformation_sequence_out,
|
||||
&replayer_binary_out, &replayer_transformation_sequence_out);
|
||||
auto replayer_result_status = replayer.Run(
|
||||
binary_in, initial_facts, fuzzer_transformation_sequence_out,
|
||||
&replayer_binary_out, &replayer_transformation_sequence_out);
|
||||
ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete,
|
||||
replayer_result_status);
|
||||
|
||||
// After replaying the transformations applied by the fuzzer, exactly those
|
||||
// transformations should have been applied, and the binary resulting from
|
||||
@@ -233,7 +239,7 @@ TEST(FuzzerReplayerTest, Miscellaneous1) {
|
||||
|
||||
// Do 10 fuzzer runs, starting from an initial seed of 0 (seed value chosen
|
||||
// arbitrarily).
|
||||
RunFuzzerAndReplayer(shader, 0, 10);
|
||||
RunFuzzerAndReplayer(shader, protobufs::FactSequence(), 0, 10);
|
||||
}
|
||||
|
||||
TEST(FuzzerReplayerTest, Miscellaneous2) {
|
||||
@@ -478,7 +484,492 @@ TEST(FuzzerReplayerTest, Miscellaneous2) {
|
||||
|
||||
// Do 10 fuzzer runs, starting from an initial seed of 10 (seed value chosen
|
||||
// arbitrarily).
|
||||
RunFuzzerAndReplayer(shader, 10, 10);
|
||||
RunFuzzerAndReplayer(shader, protobufs::FactSequence(), 10, 10);
|
||||
}
|
||||
|
||||
TEST(FuzzerReplayerTest, Miscellaneous3) {
|
||||
// The SPIR-V came from this GLSL, which was then optimized using spirv-opt
|
||||
// with the -O argument:
|
||||
//
|
||||
// #version 310 es
|
||||
//
|
||||
// precision highp float;
|
||||
//
|
||||
// layout(location = 0) out vec4 _GLF_color;
|
||||
//
|
||||
// layout(set = 0, binding = 0) uniform buf0 {
|
||||
// vec2 resolution;
|
||||
// };
|
||||
// void main(void)
|
||||
// {
|
||||
// float A[50];
|
||||
// for(
|
||||
// int i = 0;
|
||||
// i < 200;
|
||||
// i ++
|
||||
// )
|
||||
// {
|
||||
// if(i >= int(resolution.x))
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// if((4 * (i / 4)) == i)
|
||||
// {
|
||||
// A[i / 4] = float(i);
|
||||
// }
|
||||
// }
|
||||
// for(
|
||||
// int i = 0;
|
||||
// i < 50;
|
||||
// i ++
|
||||
// )
|
||||
// {
|
||||
// if(i < int(gl_FragCoord.x))
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// if(i > 0)
|
||||
// {
|
||||
// A[i] += A[i - 1];
|
||||
// }
|
||||
// }
|
||||
// if(int(gl_FragCoord.x) < 20)
|
||||
// {
|
||||
// _GLF_color = vec4(A[0] / resolution.x, A[4] / resolution.y, 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// if(int(gl_FragCoord.x) < 40)
|
||||
// {
|
||||
// _GLF_color = vec4(A[5] / resolution.x, A[9] / resolution.y, 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// if(int(gl_FragCoord.x) < 60)
|
||||
// {
|
||||
// _GLF_color = vec4(A[10] / resolution.x, A[14] / resolution.y,
|
||||
// 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// if(int(gl_FragCoord.x) < 80)
|
||||
// {
|
||||
// _GLF_color = vec4(A[15] / resolution.x, A[19] / resolution.y,
|
||||
// 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// if(int(gl_FragCoord.x) < 100)
|
||||
// {
|
||||
// _GLF_color = vec4(A[20] / resolution.x, A[24] / resolution.y,
|
||||
// 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// if(int(gl_FragCoord.x) < 120)
|
||||
// {
|
||||
// _GLF_color = vec4(A[25] / resolution.x, A[29] / resolution.y,
|
||||
// 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// if(int(gl_FragCoord.x) < 140)
|
||||
// {
|
||||
// _GLF_color = vec4(A[30] / resolution.x, A[34] / resolution.y,
|
||||
// 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// if(int(gl_FragCoord.x) < 160)
|
||||
// {
|
||||
// _GLF_color = vec4(A[35] / resolution.x, A[39] /
|
||||
// resolution.y, 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// if(int(gl_FragCoord.x) < 180)
|
||||
// {
|
||||
// _GLF_color = vec4(A[40] / resolution.x, A[44] /
|
||||
// resolution.y, 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// if(int(gl_FragCoord.x) < 180)
|
||||
// {
|
||||
// _GLF_color = vec4(A[45] / resolution.x, A[49] /
|
||||
// resolution.y, 1.0, 1.0);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// discard;
|
||||
// }
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %68 %100
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %22 "buf0"
|
||||
OpMemberName %22 0 "resolution"
|
||||
OpName %24 ""
|
||||
OpName %46 "A"
|
||||
OpName %68 "gl_FragCoord"
|
||||
OpName %100 "_GLF_color"
|
||||
OpMemberDecorate %22 0 Offset 0
|
||||
OpDecorate %22 Block
|
||||
OpDecorate %24 DescriptorSet 0
|
||||
OpDecorate %24 Binding 0
|
||||
OpDecorate %37 RelaxedPrecision
|
||||
OpDecorate %38 RelaxedPrecision
|
||||
OpDecorate %55 RelaxedPrecision
|
||||
OpDecorate %68 BuiltIn FragCoord
|
||||
OpDecorate %83 RelaxedPrecision
|
||||
OpDecorate %91 RelaxedPrecision
|
||||
OpDecorate %100 Location 0
|
||||
OpDecorate %302 RelaxedPrecision
|
||||
OpDecorate %304 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 200
|
||||
%17 = OpTypeBool
|
||||
%20 = OpTypeFloat 32
|
||||
%21 = OpTypeVector %20 2
|
||||
%22 = OpTypeStruct %21
|
||||
%23 = OpTypePointer Uniform %22
|
||||
%24 = OpVariable %23 Uniform
|
||||
%25 = OpTypeInt 32 0
|
||||
%26 = OpConstant %25 0
|
||||
%27 = OpTypePointer Uniform %20
|
||||
%35 = OpConstant %6 4
|
||||
%43 = OpConstant %25 50
|
||||
%44 = OpTypeArray %20 %43
|
||||
%45 = OpTypePointer Function %44
|
||||
%51 = OpTypePointer Function %20
|
||||
%54 = OpConstant %6 1
|
||||
%63 = OpConstant %6 50
|
||||
%66 = OpTypeVector %20 4
|
||||
%67 = OpTypePointer Input %66
|
||||
%68 = OpVariable %67 Input
|
||||
%69 = OpTypePointer Input %20
|
||||
%95 = OpConstant %6 20
|
||||
%99 = OpTypePointer Output %66
|
||||
%100 = OpVariable %99 Output
|
||||
%108 = OpConstant %25 1
|
||||
%112 = OpConstant %20 1
|
||||
%118 = OpConstant %6 40
|
||||
%122 = OpConstant %6 5
|
||||
%128 = OpConstant %6 9
|
||||
%139 = OpConstant %6 60
|
||||
%143 = OpConstant %6 10
|
||||
%149 = OpConstant %6 14
|
||||
%160 = OpConstant %6 80
|
||||
%164 = OpConstant %6 15
|
||||
%170 = OpConstant %6 19
|
||||
%181 = OpConstant %6 100
|
||||
%190 = OpConstant %6 24
|
||||
%201 = OpConstant %6 120
|
||||
%205 = OpConstant %6 25
|
||||
%211 = OpConstant %6 29
|
||||
%222 = OpConstant %6 140
|
||||
%226 = OpConstant %6 30
|
||||
%232 = OpConstant %6 34
|
||||
%243 = OpConstant %6 160
|
||||
%247 = OpConstant %6 35
|
||||
%253 = OpConstant %6 39
|
||||
%264 = OpConstant %6 180
|
||||
%273 = OpConstant %6 44
|
||||
%287 = OpConstant %6 45
|
||||
%293 = OpConstant %6 49
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%46 = OpVariable %45 Function
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%302 = OpPhi %6 %9 %5 %55 %42
|
||||
%18 = OpSLessThan %17 %302 %16
|
||||
OpLoopMerge %12 %42 None
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%28 = OpAccessChain %27 %24 %9 %26
|
||||
%29 = OpLoad %20 %28
|
||||
%30 = OpConvertFToS %6 %29
|
||||
%31 = OpSGreaterThanEqual %17 %302 %30
|
||||
OpSelectionMerge %33 None
|
||||
OpBranchConditional %31 %32 %33
|
||||
%32 = OpLabel
|
||||
OpBranch %12
|
||||
%33 = OpLabel
|
||||
%37 = OpSDiv %6 %302 %35
|
||||
%38 = OpIMul %6 %35 %37
|
||||
%40 = OpIEqual %17 %38 %302
|
||||
OpSelectionMerge %42 None
|
||||
OpBranchConditional %40 %41 %42
|
||||
%41 = OpLabel
|
||||
%50 = OpConvertSToF %20 %302
|
||||
%52 = OpAccessChain %51 %46 %37
|
||||
OpStore %52 %50
|
||||
OpBranch %42
|
||||
%42 = OpLabel
|
||||
%55 = OpIAdd %6 %302 %54
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpBranch %57
|
||||
%57 = OpLabel
|
||||
%304 = OpPhi %6 %9 %12 %91 %80
|
||||
%64 = OpSLessThan %17 %304 %63
|
||||
OpLoopMerge %59 %80 None
|
||||
OpBranchConditional %64 %58 %59
|
||||
%58 = OpLabel
|
||||
%70 = OpAccessChain %69 %68 %26
|
||||
%71 = OpLoad %20 %70
|
||||
%72 = OpConvertFToS %6 %71
|
||||
%73 = OpSLessThan %17 %304 %72
|
||||
OpSelectionMerge %75 None
|
||||
OpBranchConditional %73 %74 %75
|
||||
%74 = OpLabel
|
||||
OpBranch %59
|
||||
%75 = OpLabel
|
||||
%78 = OpSGreaterThan %17 %304 %9
|
||||
OpSelectionMerge %80 None
|
||||
OpBranchConditional %78 %79 %80
|
||||
%79 = OpLabel
|
||||
%83 = OpISub %6 %304 %54
|
||||
%84 = OpAccessChain %51 %46 %83
|
||||
%85 = OpLoad %20 %84
|
||||
%86 = OpAccessChain %51 %46 %304
|
||||
%87 = OpLoad %20 %86
|
||||
%88 = OpFAdd %20 %87 %85
|
||||
OpStore %86 %88
|
||||
OpBranch %80
|
||||
%80 = OpLabel
|
||||
%91 = OpIAdd %6 %304 %54
|
||||
OpBranch %57
|
||||
%59 = OpLabel
|
||||
%92 = OpAccessChain %69 %68 %26
|
||||
%93 = OpLoad %20 %92
|
||||
%94 = OpConvertFToS %6 %93
|
||||
%96 = OpSLessThan %17 %94 %95
|
||||
OpSelectionMerge %98 None
|
||||
OpBranchConditional %96 %97 %114
|
||||
%97 = OpLabel
|
||||
%101 = OpAccessChain %51 %46 %9
|
||||
%102 = OpLoad %20 %101
|
||||
%103 = OpAccessChain %27 %24 %9 %26
|
||||
%104 = OpLoad %20 %103
|
||||
%105 = OpFDiv %20 %102 %104
|
||||
%106 = OpAccessChain %51 %46 %35
|
||||
%107 = OpLoad %20 %106
|
||||
%109 = OpAccessChain %27 %24 %9 %108
|
||||
%110 = OpLoad %20 %109
|
||||
%111 = OpFDiv %20 %107 %110
|
||||
%113 = OpCompositeConstruct %66 %105 %111 %112 %112
|
||||
OpStore %100 %113
|
||||
OpBranch %98
|
||||
%114 = OpLabel
|
||||
%119 = OpSLessThan %17 %94 %118
|
||||
OpSelectionMerge %121 None
|
||||
OpBranchConditional %119 %120 %135
|
||||
%120 = OpLabel
|
||||
%123 = OpAccessChain %51 %46 %122
|
||||
%124 = OpLoad %20 %123
|
||||
%125 = OpAccessChain %27 %24 %9 %26
|
||||
%126 = OpLoad %20 %125
|
||||
%127 = OpFDiv %20 %124 %126
|
||||
%129 = OpAccessChain %51 %46 %128
|
||||
%130 = OpLoad %20 %129
|
||||
%131 = OpAccessChain %27 %24 %9 %108
|
||||
%132 = OpLoad %20 %131
|
||||
%133 = OpFDiv %20 %130 %132
|
||||
%134 = OpCompositeConstruct %66 %127 %133 %112 %112
|
||||
OpStore %100 %134
|
||||
OpBranch %121
|
||||
%135 = OpLabel
|
||||
%140 = OpSLessThan %17 %94 %139
|
||||
OpSelectionMerge %142 None
|
||||
OpBranchConditional %140 %141 %156
|
||||
%141 = OpLabel
|
||||
%144 = OpAccessChain %51 %46 %143
|
||||
%145 = OpLoad %20 %144
|
||||
%146 = OpAccessChain %27 %24 %9 %26
|
||||
%147 = OpLoad %20 %146
|
||||
%148 = OpFDiv %20 %145 %147
|
||||
%150 = OpAccessChain %51 %46 %149
|
||||
%151 = OpLoad %20 %150
|
||||
%152 = OpAccessChain %27 %24 %9 %108
|
||||
%153 = OpLoad %20 %152
|
||||
%154 = OpFDiv %20 %151 %153
|
||||
%155 = OpCompositeConstruct %66 %148 %154 %112 %112
|
||||
OpStore %100 %155
|
||||
OpBranch %142
|
||||
%156 = OpLabel
|
||||
%161 = OpSLessThan %17 %94 %160
|
||||
OpSelectionMerge %163 None
|
||||
OpBranchConditional %161 %162 %177
|
||||
%162 = OpLabel
|
||||
%165 = OpAccessChain %51 %46 %164
|
||||
%166 = OpLoad %20 %165
|
||||
%167 = OpAccessChain %27 %24 %9 %26
|
||||
%168 = OpLoad %20 %167
|
||||
%169 = OpFDiv %20 %166 %168
|
||||
%171 = OpAccessChain %51 %46 %170
|
||||
%172 = OpLoad %20 %171
|
||||
%173 = OpAccessChain %27 %24 %9 %108
|
||||
%174 = OpLoad %20 %173
|
||||
%175 = OpFDiv %20 %172 %174
|
||||
%176 = OpCompositeConstruct %66 %169 %175 %112 %112
|
||||
OpStore %100 %176
|
||||
OpBranch %163
|
||||
%177 = OpLabel
|
||||
%182 = OpSLessThan %17 %94 %181
|
||||
OpSelectionMerge %184 None
|
||||
OpBranchConditional %182 %183 %197
|
||||
%183 = OpLabel
|
||||
%185 = OpAccessChain %51 %46 %95
|
||||
%186 = OpLoad %20 %185
|
||||
%187 = OpAccessChain %27 %24 %9 %26
|
||||
%188 = OpLoad %20 %187
|
||||
%189 = OpFDiv %20 %186 %188
|
||||
%191 = OpAccessChain %51 %46 %190
|
||||
%192 = OpLoad %20 %191
|
||||
%193 = OpAccessChain %27 %24 %9 %108
|
||||
%194 = OpLoad %20 %193
|
||||
%195 = OpFDiv %20 %192 %194
|
||||
%196 = OpCompositeConstruct %66 %189 %195 %112 %112
|
||||
OpStore %100 %196
|
||||
OpBranch %184
|
||||
%197 = OpLabel
|
||||
%202 = OpSLessThan %17 %94 %201
|
||||
OpSelectionMerge %204 None
|
||||
OpBranchConditional %202 %203 %218
|
||||
%203 = OpLabel
|
||||
%206 = OpAccessChain %51 %46 %205
|
||||
%207 = OpLoad %20 %206
|
||||
%208 = OpAccessChain %27 %24 %9 %26
|
||||
%209 = OpLoad %20 %208
|
||||
%210 = OpFDiv %20 %207 %209
|
||||
%212 = OpAccessChain %51 %46 %211
|
||||
%213 = OpLoad %20 %212
|
||||
%214 = OpAccessChain %27 %24 %9 %108
|
||||
%215 = OpLoad %20 %214
|
||||
%216 = OpFDiv %20 %213 %215
|
||||
%217 = OpCompositeConstruct %66 %210 %216 %112 %112
|
||||
OpStore %100 %217
|
||||
OpBranch %204
|
||||
%218 = OpLabel
|
||||
%223 = OpSLessThan %17 %94 %222
|
||||
OpSelectionMerge %225 None
|
||||
OpBranchConditional %223 %224 %239
|
||||
%224 = OpLabel
|
||||
%227 = OpAccessChain %51 %46 %226
|
||||
%228 = OpLoad %20 %227
|
||||
%229 = OpAccessChain %27 %24 %9 %26
|
||||
%230 = OpLoad %20 %229
|
||||
%231 = OpFDiv %20 %228 %230
|
||||
%233 = OpAccessChain %51 %46 %232
|
||||
%234 = OpLoad %20 %233
|
||||
%235 = OpAccessChain %27 %24 %9 %108
|
||||
%236 = OpLoad %20 %235
|
||||
%237 = OpFDiv %20 %234 %236
|
||||
%238 = OpCompositeConstruct %66 %231 %237 %112 %112
|
||||
OpStore %100 %238
|
||||
OpBranch %225
|
||||
%239 = OpLabel
|
||||
%244 = OpSLessThan %17 %94 %243
|
||||
OpSelectionMerge %246 None
|
||||
OpBranchConditional %244 %245 %260
|
||||
%245 = OpLabel
|
||||
%248 = OpAccessChain %51 %46 %247
|
||||
%249 = OpLoad %20 %248
|
||||
%250 = OpAccessChain %27 %24 %9 %26
|
||||
%251 = OpLoad %20 %250
|
||||
%252 = OpFDiv %20 %249 %251
|
||||
%254 = OpAccessChain %51 %46 %253
|
||||
%255 = OpLoad %20 %254
|
||||
%256 = OpAccessChain %27 %24 %9 %108
|
||||
%257 = OpLoad %20 %256
|
||||
%258 = OpFDiv %20 %255 %257
|
||||
%259 = OpCompositeConstruct %66 %252 %258 %112 %112
|
||||
OpStore %100 %259
|
||||
OpBranch %246
|
||||
%260 = OpLabel
|
||||
%265 = OpSLessThan %17 %94 %264
|
||||
OpSelectionMerge %267 None
|
||||
OpBranchConditional %265 %266 %280
|
||||
%266 = OpLabel
|
||||
%268 = OpAccessChain %51 %46 %118
|
||||
%269 = OpLoad %20 %268
|
||||
%270 = OpAccessChain %27 %24 %9 %26
|
||||
%271 = OpLoad %20 %270
|
||||
%272 = OpFDiv %20 %269 %271
|
||||
%274 = OpAccessChain %51 %46 %273
|
||||
%275 = OpLoad %20 %274
|
||||
%276 = OpAccessChain %27 %24 %9 %108
|
||||
%277 = OpLoad %20 %276
|
||||
%278 = OpFDiv %20 %275 %277
|
||||
%279 = OpCompositeConstruct %66 %272 %278 %112 %112
|
||||
OpStore %100 %279
|
||||
OpBranch %267
|
||||
%280 = OpLabel
|
||||
OpSelectionMerge %285 None
|
||||
OpBranchConditional %265 %285 %300
|
||||
%285 = OpLabel
|
||||
%288 = OpAccessChain %51 %46 %287
|
||||
%289 = OpLoad %20 %288
|
||||
%290 = OpAccessChain %27 %24 %9 %26
|
||||
%291 = OpLoad %20 %290
|
||||
%292 = OpFDiv %20 %289 %291
|
||||
%294 = OpAccessChain %51 %46 %293
|
||||
%295 = OpLoad %20 %294
|
||||
%296 = OpAccessChain %27 %24 %9 %108
|
||||
%297 = OpLoad %20 %296
|
||||
%298 = OpFDiv %20 %295 %297
|
||||
%299 = OpCompositeConstruct %66 %292 %298 %112 %112
|
||||
OpStore %100 %299
|
||||
OpBranch %267
|
||||
%300 = OpLabel
|
||||
OpKill
|
||||
%267 = OpLabel
|
||||
OpBranch %246
|
||||
%246 = OpLabel
|
||||
OpBranch %225
|
||||
%225 = OpLabel
|
||||
OpBranch %204
|
||||
%204 = OpLabel
|
||||
OpBranch %184
|
||||
%184 = OpLabel
|
||||
OpBranch %163
|
||||
%163 = OpLabel
|
||||
OpBranch %142
|
||||
%142 = OpLabel
|
||||
OpBranch %121
|
||||
%121 = OpLabel
|
||||
OpBranch %98
|
||||
%98 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
// Add the facts "resolution.x == 250" and "resolution.y == 100".
|
||||
protobufs::FactSequence facts;
|
||||
{
|
||||
protobufs::FactConstantUniform resolution_x_eq_250;
|
||||
*resolution_x_eq_250.mutable_uniform_buffer_element_descriptor() =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 0});
|
||||
*resolution_x_eq_250.mutable_constant_word()->Add() = 250;
|
||||
protobufs::Fact temp;
|
||||
*temp.mutable_constant_uniform_fact() = resolution_x_eq_250;
|
||||
*facts.mutable_fact()->Add() = temp;
|
||||
}
|
||||
{
|
||||
protobufs::FactConstantUniform resolution_y_eq_100;
|
||||
*resolution_y_eq_100.mutable_uniform_buffer_element_descriptor() =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 1});
|
||||
*resolution_y_eq_100.mutable_constant_word()->Add() = 100;
|
||||
protobufs::Fact temp;
|
||||
*temp.mutable_constant_uniform_fact() = resolution_y_eq_100;
|
||||
*facts.mutable_fact()->Add() = temp;
|
||||
}
|
||||
|
||||
// Do 10 fuzzer runs, starting from an initial seed of 94 (seed value chosen
|
||||
// arbitrarily).
|
||||
RunFuzzerAndReplayer(shader, facts, 94, 10);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
218
3rdparty/spirv-tools/test/fuzz/transformation_add_type_pointer_test.cpp
vendored
Normal file
218
3rdparty/spirv-tools/test/fuzz/transformation_add_type_pointer_test.cpp
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
// 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 "source/fuzz/transformation_add_type_pointer.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationAddTypePointerTest, BasicTest) {
|
||||
// The SPIR-V was obtained from this GLSL:
|
||||
//
|
||||
// #version 450
|
||||
//
|
||||
// int x;
|
||||
// float y;
|
||||
// vec2 z;
|
||||
//
|
||||
// struct T {
|
||||
// int a, b;
|
||||
// };
|
||||
//
|
||||
// struct S {
|
||||
// T t;
|
||||
// int u;
|
||||
// };
|
||||
//
|
||||
// void main() {
|
||||
// S myS = S(T(1, 2), 3);
|
||||
// myS.u = x;
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %7 "T"
|
||||
OpMemberName %7 0 "a"
|
||||
OpMemberName %7 1 "b"
|
||||
OpName %8 "S"
|
||||
OpMemberName %8 0 "t"
|
||||
OpMemberName %8 1 "u"
|
||||
OpName %10 "myS"
|
||||
OpName %17 "x"
|
||||
OpName %23 "y"
|
||||
OpName %26 "z"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypeStruct %6 %6
|
||||
%8 = OpTypeStruct %7 %6
|
||||
%9 = OpTypePointer Function %8
|
||||
%11 = OpConstant %6 1
|
||||
%12 = OpConstant %6 2
|
||||
%13 = OpConstantComposite %7 %11 %12
|
||||
%14 = OpConstant %6 3
|
||||
%15 = OpConstantComposite %8 %13 %14
|
||||
%16 = OpTypePointer Private %6
|
||||
%17 = OpVariable %16 Private
|
||||
%19 = OpTypePointer Function %6
|
||||
%21 = OpTypeFloat 32
|
||||
%22 = OpTypePointer Private %21
|
||||
%23 = OpVariable %22 Private
|
||||
%24 = OpTypeVector %21 2
|
||||
%25 = OpTypePointer Private %24
|
||||
%26 = OpVariable %25 Private
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%10 = OpVariable %9 Function
|
||||
OpStore %10 %15
|
||||
%18 = OpLoad %6 %17
|
||||
%20 = OpAccessChain %19 %10 %11
|
||||
OpStore %20 %18
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto bad_type_id_does_not_exist =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
100, SpvStorageClassFunction, 101);
|
||||
auto bad_type_id_is_not_type =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
100, SpvStorageClassFunction, 23);
|
||||
auto bad_result_id_is_not_fresh =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
17, SpvStorageClassFunction, 21);
|
||||
|
||||
auto good_new_private_pointer_to_t =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
101, SpvStorageClassPrivate, 7);
|
||||
auto good_new_uniform_pointer_to_t =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
102, SpvStorageClassUniform, 7);
|
||||
auto good_another_function_pointer_to_s =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
103, SpvStorageClassFunction, 8);
|
||||
auto good_new_uniform_pointer_to_s =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
104, SpvStorageClassUniform, 8);
|
||||
auto good_another_private_pointer_to_float =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
105, SpvStorageClassPrivate, 21);
|
||||
auto good_new_private_pointer_to_private_pointer_to_float =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
106, SpvStorageClassPrivate, 105);
|
||||
auto good_new_uniform_pointer_to_vec2 =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
107, SpvStorageClassUniform, 24);
|
||||
auto good_new_private_pointer_to_uniform_pointer_to_vec2 =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
108, SpvStorageClassPrivate, 107);
|
||||
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_type_id_does_not_exist,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_not_type,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_result_id_is_not_fresh,
|
||||
context.get(), fact_manager));
|
||||
|
||||
for (auto& transformation :
|
||||
{good_new_private_pointer_to_t, good_new_uniform_pointer_to_t,
|
||||
good_another_function_pointer_to_s, good_new_uniform_pointer_to_s,
|
||||
good_another_private_pointer_to_float,
|
||||
good_new_private_pointer_to_private_pointer_to_float,
|
||||
good_new_uniform_pointer_to_vec2,
|
||||
good_new_private_pointer_to_uniform_pointer_to_vec2}) {
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(transformation, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
}
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %7 "T"
|
||||
OpMemberName %7 0 "a"
|
||||
OpMemberName %7 1 "b"
|
||||
OpName %8 "S"
|
||||
OpMemberName %8 0 "t"
|
||||
OpMemberName %8 1 "u"
|
||||
OpName %10 "myS"
|
||||
OpName %17 "x"
|
||||
OpName %23 "y"
|
||||
OpName %26 "z"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypeStruct %6 %6
|
||||
%8 = OpTypeStruct %7 %6
|
||||
%9 = OpTypePointer Function %8
|
||||
%11 = OpConstant %6 1
|
||||
%12 = OpConstant %6 2
|
||||
%13 = OpConstantComposite %7 %11 %12
|
||||
%14 = OpConstant %6 3
|
||||
%15 = OpConstantComposite %8 %13 %14
|
||||
%16 = OpTypePointer Private %6
|
||||
%17 = OpVariable %16 Private
|
||||
%19 = OpTypePointer Function %6
|
||||
%21 = OpTypeFloat 32
|
||||
%22 = OpTypePointer Private %21
|
||||
%23 = OpVariable %22 Private
|
||||
%24 = OpTypeVector %21 2
|
||||
%25 = OpTypePointer Private %24
|
||||
%26 = OpVariable %25 Private
|
||||
%101 = OpTypePointer Private %7
|
||||
%102 = OpTypePointer Uniform %7
|
||||
%103 = OpTypePointer Function %8
|
||||
%104 = OpTypePointer Uniform %8
|
||||
%105 = OpTypePointer Private %21
|
||||
%106 = OpTypePointer Private %105
|
||||
%107 = OpTypePointer Uniform %24
|
||||
%108 = OpTypePointer Private %107
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%10 = OpVariable %9 Function
|
||||
OpStore %10 %15
|
||||
%18 = OpLoad %6 %17
|
||||
%20 = OpAccessChain %19 %10 %11
|
||||
OpStore %20 %18
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
1486
3rdparty/spirv-tools/test/fuzz/transformation_replace_constant_with_uniform_test.cpp
vendored
Normal file
1486
3rdparty/spirv-tools/test/fuzz/transformation_replace_constant_with_uniform_test.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
84
3rdparty/spirv-tools/test/fuzz/uniform_buffer_element_descriptor_test.cpp
vendored
Normal file
84
3rdparty/spirv-tools/test/fuzz/uniform_buffer_element_descriptor_test.cpp
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// 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 "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(UniformBufferElementDescriptorTest, TestEquality) {
|
||||
// Test that equality works as expected for various buffer element
|
||||
// descriptors.
|
||||
|
||||
protobufs::UniformBufferElementDescriptor descriptor1 =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor2 =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor3 =
|
||||
MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor4 =
|
||||
MakeUniformBufferElementDescriptor(1, 0, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor5 =
|
||||
MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor6 =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 2, 4});
|
||||
protobufs::UniformBufferElementDescriptor descriptor7 =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 2});
|
||||
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor1));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor2));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor3, &descriptor3));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor4, &descriptor4));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor5, &descriptor5));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor6, &descriptor6));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor7, &descriptor7));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor3));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor3, &descriptor1));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor4));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor4, &descriptor1));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor5));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor5, &descriptor1));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor6));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor6, &descriptor1));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor7));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor7, &descriptor1));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -2037,4 +2037,203 @@ OpFunctionEnd
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, VolatileAtomicLoad) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate {{.*}} Volatile
|
||||
; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32768
|
||||
; CHECK: OpAtomicLoad [[int]] {{.*}} {{.*}} [[volatile]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpDecorate %ssbo_var Volatile
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%device = OpConstant %int 1
|
||||
%relaxed = OpConstant %int 0
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%ld = OpAtomicLoad %int %ssbo_var %device %relaxed
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, VolatileAtomicLoadPreviousFlags) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate {{.*}} Volatile
|
||||
; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32834
|
||||
; CHECK: OpAtomicLoad [[int]] {{.*}} {{.*}} [[volatile]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpDecorate %ssbo_var Volatile
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%device = OpConstant %int 1
|
||||
%acquire_ssbo = OpConstant %int 66
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%ld = OpAtomicLoad %int %ssbo_var %device %acquire_ssbo
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, VolatileAtomicStore) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate {{.*}} Volatile
|
||||
; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant {{.*}} 32768
|
||||
; CHECK: OpAtomicStore {{.*}} {{.*}} [[volatile]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpDecorate %ssbo_var Volatile
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%device = OpConstant %int 1
|
||||
%relaxed = OpConstant %int 0
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpAtomicStore %ssbo_var %device %relaxed %int_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, VolatileAtomicStorePreviousFlags) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate {{.*}} Volatile
|
||||
; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant {{.*}} 32836
|
||||
; CHECK: OpAtomicStore {{.*}} {{.*}} [[volatile]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpDecorate %ssbo_var Volatile
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%device = OpConstant %int 1
|
||||
%release_ssbo = OpConstant %int 68
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpAtomicStore %ssbo_var %device %release_ssbo %int_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, VolatileAtomicCompareExchange) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate {{.*}} Volatile
|
||||
; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32768
|
||||
; CHECK: OpAtomicCompareExchange [[int]] {{.*}} {{.*}} [[volatile]] [[volatile]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpDecorate %ssbo_var Volatile
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%device = OpConstant %int 1
|
||||
%relaxed = OpConstant %int 0
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%ld = OpAtomicCompareExchange %int %ssbo_var %device %relaxed %relaxed %int_0 %int_1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, VolatileAtomicCompareExchangePreviousFlags) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate {{.*}} Volatile
|
||||
; CHECK: [[volatile_acq_rel:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32840
|
||||
; CHECK: [[volatile_acq:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32834
|
||||
; CHECK: OpAtomicCompareExchange [[int]] {{.*}} {{.*}} [[volatile_acq_rel]] [[volatile_acq]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpDecorate %ssbo_var Volatile
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%device = OpConstant %int 1
|
||||
%acq_ssbo = OpConstant %int 66
|
||||
%acq_rel_ssbo = OpConstant %int 72
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%ld = OpAtomicCompareExchange %int %ssbo_var %device %acq_rel_ssbo %acq_ssbo %int_0 %int_1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, VolatileAtomicLoadMemberDecoration) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpMemberDecorate {{.*}} {{.*}} Volatile
|
||||
; CHECK: [[relaxed:%[a-zA-Z0-9_]+]] = OpConstant {{.*}} 0
|
||||
; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32768
|
||||
; CHECK: OpAtomicLoad [[int]] {{.*}} {{.*}} [[relaxed]]
|
||||
; CHECK: OpAtomicLoad [[int]] {{.*}} {{.*}} [[volatile]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpMemberDecorate %struct 1 Volatile
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%device = OpConstant %int 1
|
||||
%relaxed = OpConstant %int 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%struct = OpTypeStruct %int %int
|
||||
%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
|
||||
%ssbo_var = OpVariable %ptr_ssbo_struct StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%gep0 = OpAccessChain %ptr_ssbo_int %ssbo_var %int_0
|
||||
%ld0 = OpAtomicLoad %int %gep0 %device %relaxed
|
||||
%gep1 = OpAccessChain %ptr_ssbo_int %ssbo_var %int_1
|
||||
%ld1 = OpAtomicLoad %int %gep1 %device %relaxed
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
147
3rdparty/spirv-tools/test/val/val_atomics_test.cpp
vendored
147
3rdparty/spirv-tools/test/val/val_atomics_test.cpp
vendored
@@ -1998,6 +1998,153 @@ TEST_F(ValidateAtomics, CompareExchangeWeakV14Bad) {
|
||||
"AtomicCompareExchangeWeak requires SPIR-V version 1.3 or earlier"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateAtomics, CompareExchangeVolatileMatch) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%workgroup = OpConstant %int 2
|
||||
%volatile = OpConstant %int 32768
|
||||
%ptr_wg_int = OpTypePointer Workgroup %int
|
||||
%wg_var = OpVariable %ptr_wg_int Workgroup
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%cmp_ex = OpAtomicCompareExchange %int %wg_var %workgroup %volatile %volatile %int_0 %int_1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateAtomics, CompareExchangeVolatileMismatch) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%workgroup = OpConstant %int 2
|
||||
%volatile = OpConstant %int 32768
|
||||
%non_volatile = OpConstant %int 0
|
||||
%ptr_wg_int = OpTypePointer Workgroup %int
|
||||
%wg_var = OpVariable %ptr_wg_int Workgroup
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%cmp_ex = OpAtomicCompareExchange %int %wg_var %workgroup %non_volatile %volatile %int_0 %int_1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Volatile mask setting must match for Equal and "
|
||||
"Unequal memory semantics"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateAtomics, CompareExchangeVolatileMismatchCooperativeMatrix) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpCapability Linkage
|
||||
OpCapability CooperativeMatrixNV
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpExtension "SPV_NV_cooperative_matrix"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%workgroup = OpConstant %int 2
|
||||
%volatile = OpSpecConstant %int 32768
|
||||
%non_volatile = OpSpecConstant %int 32768
|
||||
%ptr_wg_int = OpTypePointer Workgroup %int
|
||||
%wg_var = OpVariable %ptr_wg_int Workgroup
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%cmp_ex = OpAtomicCompareExchange %int %wg_var %workgroup %volatile %non_volatile %int_0 %int_1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
// This is ok because we cannot evaluate the spec constant defaults.
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateAtomics, VolatileRequiresVulkanMemoryModel) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%workgroup = OpConstant %int 2
|
||||
%volatile = OpConstant %int 32768
|
||||
%ptr_wg_int = OpTypePointer Workgroup %int
|
||||
%wg_var = OpVariable %ptr_wg_int Workgroup
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%ld = OpAtomicLoad %int %wg_var %workgroup %volatile
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Memory Semantics Volatile requires capability "
|
||||
"VulkanMemoryModelKHR"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateAtomics, CooperativeMatrixSemanticsMustBeConstant) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability CooperativeMatrixNV
|
||||
OpExtension "SPV_NV_cooperative_matrix"
|
||||
OpMemoryModel Logical GLSL450
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%workgroup = OpConstant %int 2
|
||||
%undef = OpUndef %int
|
||||
%ptr_wg_int = OpTypePointer Workgroup %int
|
||||
%wg_var = OpVariable %ptr_wg_int Workgroup
|
||||
%void_fn = OpTypeFunction %void
|
||||
%func = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%ld = OpAtomicLoad %int %wg_var %workgroup %undef
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Memory Semantics must be a constant instruction when "
|
||||
"CooperativeMatrixNV capability is present"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
109
3rdparty/spirv-tools/test/val/val_barriers_test.cpp
vendored
109
3rdparty/spirv-tools/test/val/val_barriers_test.cpp
vendored
@@ -1361,6 +1361,115 @@ OpFunctionEnd
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBarriers, VolatileMemoryBarrier) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpCapability VulkanMemoryModelDeviceScopeKHR
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%device = OpConstant %int 1
|
||||
%semantics = OpConstant %int 32768
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpMemoryBarrier %device %semantics
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Memory Semantics Volatile can only be used with "
|
||||
"atomic instructions"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBarriers, VolatileControlBarrier) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpCapability VulkanMemoryModelDeviceScopeKHR
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%device = OpConstant %int 1
|
||||
%semantics = OpConstant %int 32768
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpControlBarrier %device %device %semantics
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Memory Semantics Volatile can only be used with "
|
||||
"atomic instructions"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateBarriers, CooperativeMatrixSpecConstantVolatile) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpCapability VulkanMemoryModelDeviceScopeKHR
|
||||
OpCapability CooperativeMatrixNV
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpExtension "SPV_NV_cooperative_matrix"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%device = OpConstant %int 1
|
||||
%semantics = OpSpecConstant %int 32768
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpControlBarrier %device %device %semantics
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateBarriers, CooperativeMatrixNonConstantSemantics) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpCapability VulkanMemoryModelDeviceScopeKHR
|
||||
OpCapability CooperativeMatrixNV
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpExtension "SPV_NV_cooperative_matrix"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%device = OpConstant %int 1
|
||||
%semantics = OpUndef %int
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpControlBarrier %device %device %semantics
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Memory Semantics must be a constant instruction when "
|
||||
"CooperativeMatrixNV capability is present"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -1168,8 +1168,10 @@ std::make_pair(std::string(kOpenCLMemoryModel) +
|
||||
ShaderDependencies()),
|
||||
std::make_pair(std::string(kOpenCLMemoryModel) +
|
||||
"OpEntryPoint Kernel %func \"compute\" \n"
|
||||
"OpDecorate %intt Component 0\n"
|
||||
"%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
|
||||
"OpDecorate %var Component 0\n"
|
||||
"%intt = OpTypeInt 32 0\n"
|
||||
"%ptr = OpTypePointer Input %intt\n"
|
||||
"%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid),
|
||||
ShaderDependencies()),
|
||||
std::make_pair(std::string(kOpenCLMemoryModel) +
|
||||
"OpEntryPoint Kernel %func \"compute\" \n"
|
||||
|
||||
@@ -6400,6 +6400,314 @@ OpDecorate %1 BufferBlock
|
||||
"requires SPIR-V version 1.3 or earlier"));
|
||||
}
|
||||
|
||||
// Component
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationBadTarget) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpDecorate %t Component 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%t = OpTypeVector %float 2
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Target of Component decoration must be "
|
||||
"a memory object declaration"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationBadStorageClass) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpDecorate %v Component 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%t = OpTypeVector %float 2
|
||||
%ptr_private = OpTypePointer Private %t
|
||||
%v = OpVariable %ptr_private Private
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Target of Component decoration is invalid: must "
|
||||
"point to a Storage Class of Input(1) or Output(3)"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationBadTypeVulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Matrix
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpDecorate %v Component 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%vtype = OpTypeVector %float 4
|
||||
%t = OpTypeMatrix %vtype 4
|
||||
%ptr_input = OpTypePointer Input %t
|
||||
%v = OpVariable %ptr_input Input
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Component decoration specified for type"));
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr("is not a scalar or vector"));
|
||||
}
|
||||
|
||||
std::string ShaderWithComponentDecoration(const std::string& type,
|
||||
const std::string& decoration) {
|
||||
return R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %entryPointOutput
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %entryPointOutput Location 0
|
||||
OpDecorate %entryPointOutput )" +
|
||||
decoration + R"(
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%vtype = )" + type + R"(
|
||||
%float_0 = OpConstant %float 0
|
||||
%_ptr_Output_vtype = OpTypePointer Output %vtype
|
||||
%entryPointOutput = OpVariable %_ptr_Output_vtype Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntGood0Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 0");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntGood1Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 1");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntGood2Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 2");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntGood3Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 3");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntBad4Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 4");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Sequence of components starting with 4 "
|
||||
"and ending with 4 gets larger than 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationVector3GoodVulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeVector %float 3", "Component 1");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationVector4GoodVulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 0");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationVector4Bad1Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 1");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Sequence of components starting with 1 "
|
||||
"and ending with 4 gets larger than 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationVector4Bad3Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 3");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Sequence of components starting with 3 "
|
||||
"and ending with 6 gets larger than 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationBlockGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %9 %12
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpDecorate %9 Location 0
|
||||
OpMemberDecorate %block 0 Location 2
|
||||
OpMemberDecorate %block 0 Component 1
|
||||
OpDecorate %block Block
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%float = OpTypeFloat 32
|
||||
%vec3 = OpTypeVector %float 3
|
||||
%8 = OpTypePointer Output %vec3
|
||||
%9 = OpVariable %8 Output
|
||||
%block = OpTypeStruct %vec3
|
||||
%11 = OpTypePointer Input %block
|
||||
%12 = OpVariable %11 Input
|
||||
%int = OpTypeInt 32 1
|
||||
%14 = OpConstant %int 0
|
||||
%15 = OpTypePointer Input %vec3
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%16 = OpAccessChain %15 %12 %14
|
||||
%17 = OpLoad %vec3 %16
|
||||
OpStore %9 %17
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationBlockBadVulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %9 %12
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpDecorate %9 Location 0
|
||||
OpMemberDecorate %block 0 Location 2
|
||||
OpMemberDecorate %block 0 Component 2
|
||||
OpDecorate %block Block
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%float = OpTypeFloat 32
|
||||
%vec3 = OpTypeVector %float 3
|
||||
%8 = OpTypePointer Output %vec3
|
||||
%9 = OpVariable %8 Output
|
||||
%block = OpTypeStruct %vec3
|
||||
%11 = OpTypePointer Input %block
|
||||
%12 = OpVariable %11 Input
|
||||
%int = OpTypeInt 32 1
|
||||
%14 = OpConstant %int 0
|
||||
%15 = OpTypePointer Input %vec3
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%16 = OpAccessChain %15 %12 %14
|
||||
%17 = OpLoad %vec3 %16
|
||||
OpStore %9 %17
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Sequence of components starting with 2 "
|
||||
"and ending with 4 gets larger than 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationFunctionParameter) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
|
||||
OpDecorate %param_f Component 0
|
||||
|
||||
%void = OpTypeVoid
|
||||
%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
|
||||
|
||||
%extra_fn = OpTypeFunction %void %float
|
||||
|
||||
%helper = OpFunction %void None %extra_fn
|
||||
%param_f = OpFunctionParameter %float
|
||||
%helper_label = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
%main = OpFunction %void None %void_fn
|
||||
%label = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
266
3rdparty/spirv-tools/test/val/val_memory_test.cpp
vendored
266
3rdparty/spirv-tools/test/val/val_memory_test.cpp
vendored
@@ -3566,6 +3566,272 @@ OpMemoryModel Logical GLSL450
|
||||
"the Result Type"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, StoreToUniformBlock) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int4 = OpTypeVector %int 4
|
||||
%struct = OpTypeStruct %int4
|
||||
%ptr_uniform_struct = OpTypePointer Uniform %struct
|
||||
%ptr_uniform_int4 = OpTypePointer Uniform %int4
|
||||
%ptr_uniform_int = OpTypePointer Uniform %int
|
||||
%var = OpVariable %ptr_uniform_struct Uniform
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0
|
||||
%gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0
|
||||
OpStore %gep2 %int_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, StoreToUniformBlockVulkan) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int4 = OpTypeVector %int 4
|
||||
%struct = OpTypeStruct %int4
|
||||
%ptr_uniform_struct = OpTypePointer Uniform %struct
|
||||
%ptr_uniform_int4 = OpTypePointer Uniform %int4
|
||||
%ptr_uniform_int = OpTypePointer Uniform %int
|
||||
%var = OpVariable %ptr_uniform_struct Uniform
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0
|
||||
%gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0
|
||||
OpStore %gep2 %int_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
|
||||
}
|
||||
|
||||
// This test requires that the struct is not id 2.
|
||||
TEST_F(ValidateMemory, StoreToUniformBlockVulkan2) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main" %gid_var
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %3 Block
|
||||
OpMemberDecorate %3 0 Offset 0
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
OpDecorate %gid_var BuiltIn GlobalInvocationId
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int3 = OpTypeVector %int 3
|
||||
%int4 = OpTypeVector %int 4
|
||||
%3 = OpTypeStruct %int4
|
||||
%ptr_uniform_struct = OpTypePointer Uniform %3
|
||||
%ptr_uniform_int4 = OpTypePointer Uniform %int4
|
||||
%ptr_uniform_int = OpTypePointer Uniform %int
|
||||
%var = OpVariable %ptr_uniform_struct Uniform
|
||||
%ptr_input_int3 = OpTypePointer Input %int3
|
||||
%gid_var = OpVariable %ptr_input_int3 Input
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0
|
||||
%gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0
|
||||
OpStore %gep2 %int_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, StoreToUniformBufferBlockVulkan) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct BufferBlock
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int4 = OpTypeVector %int 4
|
||||
%struct = OpTypeStruct %int4
|
||||
%ptr_uniform_struct = OpTypePointer Uniform %struct
|
||||
%ptr_uniform_int4 = OpTypePointer Uniform %int4
|
||||
%ptr_uniform_int = OpTypePointer Uniform %int
|
||||
%var = OpVariable %ptr_uniform_struct Uniform
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0
|
||||
%gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0
|
||||
OpStore %gep2 %int_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, StoreToUniformBlockVulkanArray) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%int4 = OpTypeVector %int 4
|
||||
%struct = OpTypeStruct %int4
|
||||
%array_struct = OpTypeArray %struct %int_1
|
||||
%ptr_uniform_array = OpTypePointer Uniform %array_struct
|
||||
%ptr_uniform_struct = OpTypePointer Uniform %struct
|
||||
%ptr_uniform_int4 = OpTypePointer Uniform %int4
|
||||
%ptr_uniform_int = OpTypePointer Uniform %int
|
||||
%var = OpVariable %ptr_uniform_array Uniform
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%gep1 = OpAccessChain %ptr_uniform_int %var %int_0 %int_0 %int_0
|
||||
%gep2 = OpCopyObject %ptr_uniform_int %gep1
|
||||
OpStore %gep2 %int_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
|
||||
}
|
||||
|
||||
// This test requires that the struct is not id 2.
|
||||
TEST_F(ValidateMemory, StoreToUniformBlockVulkanArray2) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main" %gid_var
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
OpDecorate %gid_var BuiltIn GlobalInvocationId
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_1 = OpConstant %int 1
|
||||
%int3 = OpTypeVector %int 3
|
||||
%int4 = OpTypeVector %int 4
|
||||
%struct = OpTypeStruct %int4
|
||||
%array_struct = OpTypeArray %struct %int_1
|
||||
%ptr_uniform_array = OpTypePointer Uniform %array_struct
|
||||
%ptr_uniform_struct = OpTypePointer Uniform %struct
|
||||
%ptr_uniform_int4 = OpTypePointer Uniform %int4
|
||||
%ptr_uniform_int = OpTypePointer Uniform %int
|
||||
%var = OpVariable %ptr_uniform_array Uniform
|
||||
%ptr_input_int3 = OpTypePointer Input %int3
|
||||
%gid_var = OpVariable %ptr_input_int3 Input
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%gep1 = OpAccessChain %ptr_uniform_int %var %int_0 %int_0 %int_0
|
||||
%gep2 = OpCopyObject %ptr_uniform_int %gep1
|
||||
OpStore %gep2 %int_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, StoreToUniformBlockVulkanRuntimeArray) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%int4 = OpTypeVector %int 4
|
||||
%struct = OpTypeStruct %int4
|
||||
%array_struct = OpTypeRuntimeArray %struct
|
||||
%ptr_uniform_array = OpTypePointer Uniform %array_struct
|
||||
%ptr_uniform_struct = OpTypePointer Uniform %struct
|
||||
%ptr_uniform_int4 = OpTypePointer Uniform %int4
|
||||
%ptr_uniform_int = OpTypePointer Uniform %int
|
||||
%var = OpVariable %ptr_uniform_array Uniform
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0 %int_0
|
||||
%gep2 = OpInBoundsAccessChain %ptr_uniform_int %gep1 %int_0
|
||||
OpStore %gep2 %int_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
8
3rdparty/spirv-tools/tools/as/as.cpp
vendored
8
3rdparty/spirv-tools/tools/as/as.cpp
vendored
@@ -21,6 +21,7 @@
|
||||
#include "tools/io.h"
|
||||
|
||||
void print_usage(char* argv0) {
|
||||
std::string target_env_list = spvTargetEnvList(19, 80);
|
||||
printf(
|
||||
R"(%s - Create a SPIR-V binary module from SPIR-V assembly text
|
||||
|
||||
@@ -41,11 +42,10 @@ Options:
|
||||
Numeric IDs in the binary will have the same values as in the
|
||||
source. Non-numeric IDs are allocated by filling in the gaps,
|
||||
starting with 1 and going up.
|
||||
--target-env {vulkan1.0|vulkan1.1|spv1.0|spv1.1|spv1.2|spv1.3|spv1.4}
|
||||
Use Vulkan 1.0, Vulkan 1.1, SPIR-V 1.0, SPIR-V 1.1,
|
||||
SPIR-V 1.2, SPIR-V 1.3, or SPIR-V 1.4
|
||||
--target-env {%s}
|
||||
Use specified environment.
|
||||
)",
|
||||
argv0, argv0);
|
||||
argv0, argv0, target_env_list.c_str());
|
||||
}
|
||||
|
||||
static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_4;
|
||||
|
||||
2
3rdparty/spirv-tools/tools/fuzz/fuzz.cpp
vendored
2
3rdparty/spirv-tools/tools/fuzz/fuzz.cpp
vendored
@@ -213,7 +213,7 @@ bool Replay(const spv_target_env& target_env,
|
||||
|
||||
bool Fuzz(const spv_target_env& target_env,
|
||||
const spvtools::FuzzerOptions& fuzzer_options,
|
||||
const std::vector<uint>& binary_in,
|
||||
const std::vector<uint32_t>& binary_in,
|
||||
const spvtools::fuzz::protobufs::FactSequence& initial_facts,
|
||||
std::vector<uint32_t>* binary_out,
|
||||
spvtools::fuzz::protobufs::TransformationSequence*
|
||||
|
||||
8
3rdparty/spirv-tools/tools/link/linker.cpp
vendored
8
3rdparty/spirv-tools/tools/link/linker.cpp
vendored
@@ -23,6 +23,7 @@
|
||||
#include "tools/io.h"
|
||||
|
||||
void print_usage(char* argv0) {
|
||||
std::string target_env_list = spvTargetEnvList(27, 95);
|
||||
printf(
|
||||
R"(%s - Link SPIR-V binary files together.
|
||||
|
||||
@@ -39,11 +40,10 @@ Options:
|
||||
--allow-partial-linkage Allow partial linkage by accepting imported symbols to be unresolved.
|
||||
--verify-ids Verify that IDs in the resulting modules are truly unique.
|
||||
--version Display linker version information
|
||||
--target-env {vulkan1.0|vulkan1.1|spv1.0|spv1.1|spv1.2|spv1.3|spv1.4|opencl2.1|opencl2.2}
|
||||
Use Vulkan 1.0, Vulkan 1.1, SPIR-V 1.0, SPIR-V 1.1, SPIR-V 1.2, SPIR-V 1.3,
|
||||
SPIR-V1.4, OpenCL 2.1, OpenCL 2.2 validation rules.
|
||||
--target-env {%s}
|
||||
Use validation rules from the specified environment.
|
||||
)",
|
||||
argv0, argv0);
|
||||
argv0, argv0, target_env_list.c_str());
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
7
3rdparty/spirv-tools/tools/opt/opt.cpp
vendored
7
3rdparty/spirv-tools/tools/opt/opt.cpp
vendored
@@ -92,6 +92,7 @@ std::string GetWebGPUToVulkanPasses() {
|
||||
}
|
||||
|
||||
void PrintUsage(const char* program) {
|
||||
std::string target_env_list = spvTargetEnvList(16, 80);
|
||||
// NOTE: Please maintain flags in lexicographical order.
|
||||
printf(
|
||||
R"(%s - Optimize a SPIR-V binary file.
|
||||
@@ -436,9 +437,9 @@ Options (in lexicographical order):)",
|
||||
printf(R"(
|
||||
--target-env=<env>
|
||||
Set the target environment. Without this flag the target
|
||||
enviroment defaults to spv1.3.
|
||||
<env> must be one of vulkan1.0, vulkan1.1, opencl2.2, spv1.0,
|
||||
spv1.1, spv1.2, spv1.3, or webgpu0.)");
|
||||
enviroment defaults to spv1.3. <env> must be one of
|
||||
{%s})",
|
||||
target_env_list.c_str());
|
||||
printf(R"(
|
||||
--time-report
|
||||
Print the resource utilization of each pass (e.g., CPU time,
|
||||
|
||||
10
3rdparty/spirv-tools/tools/val/val.cpp
vendored
10
3rdparty/spirv-tools/tools/val/val.cpp
vendored
@@ -25,6 +25,7 @@
|
||||
#include "tools/util/cli_consumer.h"
|
||||
|
||||
void print_usage(char* argv0) {
|
||||
std::string target_env_list = spvTargetEnvList(36, 105);
|
||||
printf(
|
||||
R"(%s - Validate a SPIR-V binary file.
|
||||
|
||||
@@ -65,13 +66,10 @@ Options:
|
||||
--before-hlsl-legalization Allows code patterns that are intended to be
|
||||
fixed by spirv-opt's legalization passes.
|
||||
--version Display validator version information.
|
||||
--target-env {vulkan1.0|vulkan1.1|vulkan1.1spv1.4|opencl2.2|spv1.0|spv1.1|
|
||||
spv1.2|spv1.3|spv1.4|webgpu0}
|
||||
Use Vulkan 1.0, Vulkan 1.1, Vulkan 1.1 with SPIR-V 1.4,
|
||||
OpenCL 2.2, SPIR-V 1.0, SPIR-V 1.1, SPIR-V 1.2, SPIR-V 1.3,
|
||||
SPIR-V 1.4, or WIP WebGPU validation rules.
|
||||
--target-env {%s}
|
||||
Use validation rules from the specified environment.
|
||||
)",
|
||||
argv0, argv0);
|
||||
argv0, argv0, target_env_list.c_str());
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
282
3rdparty/spirv-tools/utils/git-sync-deps
vendored
Executable file
282
3rdparty/spirv-tools/utils/git-sync-deps
vendored
Executable file
@@ -0,0 +1,282 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright 2014 Google Inc.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Parse a DEPS file and git checkout all of the dependencies.
|
||||
|
||||
Args:
|
||||
An optional list of deps_os values.
|
||||
|
||||
Environment Variables:
|
||||
GIT_EXECUTABLE: path to "git" binary; if unset, will look for one of
|
||||
['git', 'git.exe', 'git.bat'] in your default path.
|
||||
|
||||
GIT_SYNC_DEPS_PATH: file to get the dependency list from; if unset,
|
||||
will use the file ../DEPS relative to this script's directory.
|
||||
|
||||
GIT_SYNC_DEPS_QUIET: if set to non-empty string, suppress messages.
|
||||
|
||||
Git Config:
|
||||
To disable syncing of a single repository:
|
||||
cd path/to/repository
|
||||
git config sync-deps.disable true
|
||||
|
||||
To re-enable sync:
|
||||
cd path/to/repository
|
||||
git config --unset sync-deps.disable
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
from builtins import bytes
|
||||
|
||||
|
||||
def git_executable():
|
||||
"""Find the git executable.
|
||||
|
||||
Returns:
|
||||
A string suitable for passing to subprocess functions, or None.
|
||||
"""
|
||||
envgit = os.environ.get('GIT_EXECUTABLE')
|
||||
searchlist = ['git', 'git.exe', 'git.bat']
|
||||
if envgit:
|
||||
searchlist.insert(0, envgit)
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
for git in searchlist:
|
||||
try:
|
||||
subprocess.call([git, '--version'], stdout=devnull)
|
||||
except (OSError,):
|
||||
continue
|
||||
return git
|
||||
return None
|
||||
|
||||
|
||||
DEFAULT_DEPS_PATH = os.path.normpath(
|
||||
os.path.join(os.path.dirname(__file__), os.pardir, 'DEPS'))
|
||||
|
||||
|
||||
def usage(deps_file_path = None):
|
||||
sys.stderr.write(
|
||||
'Usage: run to grab dependencies, with optional platform support:\n')
|
||||
sys.stderr.write(' %s %s' % (sys.executable, __file__))
|
||||
if deps_file_path:
|
||||
parsed_deps = parse_file_to_dict(deps_file_path)
|
||||
if 'deps_os' in parsed_deps:
|
||||
for deps_os in parsed_deps['deps_os']:
|
||||
sys.stderr.write(' [%s]' % deps_os)
|
||||
sys.stderr.write('\n\n')
|
||||
sys.stderr.write(__doc__)
|
||||
|
||||
|
||||
def git_repository_sync_is_disabled(git, directory):
|
||||
try:
|
||||
disable = subprocess.check_output(
|
||||
[git, 'config', 'sync-deps.disable'], cwd=directory)
|
||||
return disable.lower().strip() in ['true', '1', 'yes', 'on']
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
|
||||
def is_git_toplevel(git, directory):
|
||||
"""Return true iff the directory is the top level of a Git repository.
|
||||
|
||||
Args:
|
||||
git (string) the git executable
|
||||
|
||||
directory (string) the path into which the repository
|
||||
is expected to be checked out.
|
||||
"""
|
||||
try:
|
||||
toplevel = subprocess.check_output(
|
||||
[git, 'rev-parse', '--show-toplevel'], cwd=directory).strip()
|
||||
return os.path.realpath(bytes(directory, 'utf8')) == os.path.realpath(toplevel)
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
|
||||
def status(directory, checkoutable):
|
||||
def truncate(s, length):
|
||||
return s if len(s) <= length else s[:(length - 3)] + '...'
|
||||
dlen = 36
|
||||
directory = truncate(directory, dlen)
|
||||
checkoutable = truncate(checkoutable, 40)
|
||||
sys.stdout.write('%-*s @ %s\n' % (dlen, directory, checkoutable))
|
||||
|
||||
|
||||
def git_checkout_to_directory(git, repo, checkoutable, directory, verbose):
|
||||
"""Checkout (and clone if needed) a Git repository.
|
||||
|
||||
Args:
|
||||
git (string) the git executable
|
||||
|
||||
repo (string) the location of the repository, suitable
|
||||
for passing to `git clone`.
|
||||
|
||||
checkoutable (string) a tag, branch, or commit, suitable for
|
||||
passing to `git checkout`
|
||||
|
||||
directory (string) the path into which the repository
|
||||
should be checked out.
|
||||
|
||||
verbose (boolean)
|
||||
|
||||
Raises an exception if any calls to git fail.
|
||||
"""
|
||||
if not os.path.isdir(directory):
|
||||
subprocess.check_call(
|
||||
[git, 'clone', '--quiet', repo, directory])
|
||||
|
||||
if not is_git_toplevel(git, directory):
|
||||
# if the directory exists, but isn't a git repo, you will modify
|
||||
# the parent repostory, which isn't what you want.
|
||||
sys.stdout.write('%s\n IS NOT TOP-LEVEL GIT DIRECTORY.\n' % directory)
|
||||
return
|
||||
|
||||
# Check to see if this repo is disabled. Quick return.
|
||||
if git_repository_sync_is_disabled(git, directory):
|
||||
sys.stdout.write('%s\n SYNC IS DISABLED.\n' % directory)
|
||||
return
|
||||
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
# If this fails, we will fetch before trying again. Don't spam user
|
||||
# with error infomation.
|
||||
if 0 == subprocess.call([git, 'checkout', '--quiet', checkoutable],
|
||||
cwd=directory, stderr=devnull):
|
||||
# if this succeeds, skip slow `git fetch`.
|
||||
if verbose:
|
||||
status(directory, checkoutable) # Success.
|
||||
return
|
||||
|
||||
# If the repo has changed, always force use of the correct repo.
|
||||
# If origin already points to repo, this is a quick no-op.
|
||||
subprocess.check_call(
|
||||
[git, 'remote', 'set-url', 'origin', repo], cwd=directory)
|
||||
|
||||
subprocess.check_call([git, 'fetch', '--quiet'], cwd=directory)
|
||||
|
||||
subprocess.check_call([git, 'checkout', '--quiet', checkoutable], cwd=directory)
|
||||
|
||||
if verbose:
|
||||
status(directory, checkoutable) # Success.
|
||||
|
||||
|
||||
def parse_file_to_dict(path):
|
||||
dictionary = {}
|
||||
contents = open(path).read()
|
||||
# Need to convert Var() to vars[], so that the DEPS is actually Python. Var()
|
||||
# comes from Autoroller using gclient which has a slightly different DEPS
|
||||
# format.
|
||||
contents = re.sub(r"Var\((.*?)\)", r"vars[\1]", contents)
|
||||
exec(contents, dictionary)
|
||||
return dictionary
|
||||
|
||||
|
||||
def git_sync_deps(deps_file_path, command_line_os_requests, verbose):
|
||||
"""Grab dependencies, with optional platform support.
|
||||
|
||||
Args:
|
||||
deps_file_path (string) Path to the DEPS file.
|
||||
|
||||
command_line_os_requests (list of strings) Can be empty list.
|
||||
List of strings that should each be a key in the deps_os
|
||||
dictionary in the DEPS file.
|
||||
|
||||
Raises git Exceptions.
|
||||
"""
|
||||
git = git_executable()
|
||||
assert git
|
||||
|
||||
deps_file_directory = os.path.dirname(deps_file_path)
|
||||
deps_file = parse_file_to_dict(deps_file_path)
|
||||
dependencies = deps_file['deps'].copy()
|
||||
os_specific_dependencies = deps_file.get('deps_os', dict())
|
||||
if 'all' in command_line_os_requests:
|
||||
for value in list(os_specific_dependencies.values()):
|
||||
dependencies.update(value)
|
||||
else:
|
||||
for os_name in command_line_os_requests:
|
||||
# Add OS-specific dependencies
|
||||
if os_name in os_specific_dependencies:
|
||||
dependencies.update(os_specific_dependencies[os_name])
|
||||
for directory in dependencies:
|
||||
for other_dir in dependencies:
|
||||
if directory.startswith(other_dir + '/'):
|
||||
raise Exception('%r is parent of %r' % (other_dir, directory))
|
||||
list_of_arg_lists = []
|
||||
for directory in sorted(dependencies):
|
||||
if '@' in dependencies[directory]:
|
||||
repo, checkoutable = dependencies[directory].split('@', 1)
|
||||
else:
|
||||
raise Exception("please specify commit or tag")
|
||||
|
||||
relative_directory = os.path.join(deps_file_directory, directory)
|
||||
|
||||
list_of_arg_lists.append(
|
||||
(git, repo, checkoutable, relative_directory, verbose))
|
||||
|
||||
multithread(git_checkout_to_directory, list_of_arg_lists)
|
||||
|
||||
for directory in deps_file.get('recursedeps', []):
|
||||
recursive_path = os.path.join(deps_file_directory, directory, 'DEPS')
|
||||
git_sync_deps(recursive_path, command_line_os_requests, verbose)
|
||||
|
||||
|
||||
def multithread(function, list_of_arg_lists):
|
||||
# for args in list_of_arg_lists:
|
||||
# function(*args)
|
||||
# return
|
||||
threads = []
|
||||
for args in list_of_arg_lists:
|
||||
thread = threading.Thread(None, function, None, args)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
|
||||
def main(argv):
|
||||
deps_file_path = os.environ.get('GIT_SYNC_DEPS_PATH', DEFAULT_DEPS_PATH)
|
||||
verbose = not bool(os.environ.get('GIT_SYNC_DEPS_QUIET', False))
|
||||
|
||||
if '--help' in argv or '-h' in argv:
|
||||
usage(deps_file_path)
|
||||
return 1
|
||||
|
||||
git_sync_deps(deps_file_path, argv, verbose)
|
||||
# subprocess.check_call(
|
||||
# [sys.executable,
|
||||
# os.path.join(os.path.dirname(deps_file_path), 'bin', 'fetch-gn')])
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main(sys.argv[1:]))
|
||||
31
3rdparty/spirv-tools/utils/roll_deps.sh
vendored
Executable file
31
3rdparty/spirv-tools/utils/roll_deps.sh
vendored
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2019 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Attempts to roll all entries in DEPS to origin/master and creates a
|
||||
# commit.
|
||||
#
|
||||
# Depends on roll-dep from depot_path being in PATH.
|
||||
|
||||
# This script assumes it's parent directory is the repo root.
|
||||
repo_path=$(dirname "$0")/..
|
||||
|
||||
effcee_dir="external/effcee/"
|
||||
googletest_dir="external/googletest/"
|
||||
re2_dir="external/re2/"
|
||||
spirv_headers_dir="external/spirv-headers/"
|
||||
|
||||
cd "$repo_path"
|
||||
|
||||
roll-dep "$@" "${effcee_dir}" "${googletest_dir}" "${re2_dir}" "${spirv_headers_dir}"
|
||||
Reference in New Issue
Block a user