[tint][ast][fuzz] Replace Options DI with Context
Instead of dependency-injecting `fuzz::wgsl::Options` to the TINT_WGSL_PROGRAM_FUZZER() function, wrap this in a new `Context` structure, which holds the `Options` along with a new set of `ProgramProperties`.
This holds useful information about the `Program` that transforms can use (like skip).
Bug: 339704100
Change-Id: I66542b1a719281eb16a17aeb2f569a7fb66c0d45
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/189120
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/cmd/fuzz/ir/fuzz.cc b/src/tint/cmd/fuzz/ir/fuzz.cc
index 771a37a..b726fb7 100644
--- a/src/tint/cmd/fuzz/ir/fuzz.cc
+++ b/src/tint/cmd/fuzz/ir/fuzz.cc
@@ -64,7 +64,7 @@
void Register(const IRFuzzer& fuzzer) {
wgsl::Register({
fuzzer.name,
- [fn = fuzzer.fn](const Program& program, const fuzz::wgsl::Options& options,
+ [fn = fuzzer.fn](const Program& program, const fuzz::wgsl::Context& context,
Slice<const std::byte> data) {
if (program.AST().Enables().Any(IsUnsupported)) {
return;
diff --git a/src/tint/cmd/fuzz/wgsl/fuzz.cc b/src/tint/cmd/fuzz/wgsl/fuzz.cc
index 17c2e1c..20de4f5 100644
--- a/src/tint/cmd/fuzz/wgsl/fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/fuzz.cc
@@ -28,14 +28,24 @@
#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
#include <iostream>
+#include <string>
+#include <string_view>
#include <thread>
+#include "src/tint/lang/core/builtin_type.h"
+#include "src/tint/lang/wgsl/ast/alias.h"
+#include "src/tint/lang/wgsl/ast/function.h"
+#include "src/tint/lang/wgsl/ast/identifier.h"
+#include "src/tint/lang/wgsl/ast/struct.h"
+#include "src/tint/lang/wgsl/ast/variable.h"
+#include "src/tint/lang/wgsl/builtin_fn.h"
#include "src/tint/lang/wgsl/common/allowed_features.h"
#include "src/tint/lang/wgsl/reader/options.h"
#include "src/tint/lang/wgsl/reader/reader.h"
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/macros/defer.h"
#include "src/tint/utils/macros/static_init.h"
+#include "src/tint/utils/rtti/switch.h"
#if TINT_BUILD_WGSL_WRITER
#include "src/tint/lang/wgsl/program/program.h"
@@ -61,6 +71,42 @@
__builtin_trap();
}
+bool IsBuiltinFn(std::string_view name) {
+ return tint::wgsl::ParseBuiltinFn(name) != tint::wgsl::BuiltinFn::kNone;
+}
+
+bool IsBuiltinType(std::string_view name) {
+ return tint::core::ParseBuiltinType(name) != tint::core::BuiltinType::kUndefined;
+}
+
+/// Scans @p program for patterns, returning a set of ProgramProperties.
+EnumSet<ProgramProperties> ScanProgramProperties(const Program& program) {
+ EnumSet<ProgramProperties> out;
+ auto check = [&](std::string_view name) {
+ if (IsBuiltinFn(name)) {
+ out.Add(ProgramProperties::kBuiltinFnsShadowed);
+ }
+ if (IsBuiltinType(name)) {
+ out.Add(ProgramProperties::kBuiltinTypesShadowed);
+ }
+ };
+
+ for (auto* node : program.ASTNodes().Objects()) {
+ tint::Switch(
+ node, //
+ [&](const ast::Variable* variable) { check(variable->name->symbol.NameView()); },
+ [&](const ast::Function* fn) { check(fn->name->symbol.NameView()); },
+ [&](const ast::Struct* str) { check(str->name->symbol.NameView()); },
+ [&](const ast::Alias* alias) { check(alias->name->symbol.NameView()); });
+
+ if (out.Contains(ProgramProperties::kBuiltinFnsShadowed) &&
+ out.Contains(ProgramProperties::kBuiltinTypesShadowed)) {
+ break; // Early exit - nothing more to find.
+ }
+ }
+ return out;
+}
+
} // namespace
void Register(const ProgramFuzzer& fuzzer) {
@@ -100,6 +146,10 @@
return;
}
+ Context context;
+ context.options = options;
+ context.program_properties = ScanProgramProperties(program);
+
// Run each of the program fuzzer functions
if (options.run_concurrently) {
size_t n = Fuzzers().Length();
@@ -110,13 +160,13 @@
Fuzzers()[i].name.find(options.filter) == std::string::npos) {
continue;
}
- threads.Push(std::thread([i, &program, &data, &options] {
+ threads.Push(std::thread([i, &program, &data, &context] {
auto& fuzzer = Fuzzers()[i];
currently_running = fuzzer.name;
- if (options.verbose) {
+ if (context.options.verbose) {
std::cout << " • [" << i << "] Running: " << currently_running << std::endl;
}
- fuzzer.fn(program, options, data);
+ fuzzer.fn(program, context, data);
}));
}
for (auto& thread : threads) {
@@ -133,7 +183,7 @@
if (options.verbose) {
std::cout << " • Running: " << currently_running << std::endl;
}
- fuzzer.fn(program, options, data);
+ fuzzer.fn(program, context, data);
}
}
}
diff --git a/src/tint/cmd/fuzz/wgsl/fuzz.h b/src/tint/cmd/fuzz/wgsl/fuzz.h
index d128695..a24514b 100644
--- a/src/tint/cmd/fuzz/wgsl/fuzz.h
+++ b/src/tint/cmd/fuzz/wgsl/fuzz.h
@@ -35,6 +35,7 @@
#include "src/tint/lang/wgsl/program/program.h"
#include "src/tint/utils/bytes/buffer_reader.h"
#include "src/tint/utils/bytes/decoder.h"
+#include "src/tint/utils/containers/enum_set.h"
#include "src/tint/utils/containers/slice.h"
#include "src/tint/utils/macros/static_init.h"
@@ -53,17 +54,34 @@
std::string dxc;
};
+/// ProgramProperties is an enumerator of flags used to describe characteristics of the input
+/// program.
+enum class ProgramProperties {
+ /// The program has builtin functions which have been shadowed
+ kBuiltinFnsShadowed,
+ /// The program has builtin types which have been shadowed
+ kBuiltinTypesShadowed,
+};
+
+/// Context holds information about the fuzzer options and the input program.
+struct Context {
+ /// The options used for Run()
+ Options options;
+ /// The properties of the input program
+ EnumSet<ProgramProperties> program_properties;
+};
+
/// ProgramFuzzer describes a fuzzer function that takes a WGSL program as input
struct ProgramFuzzer {
/// @param name the name of the fuzzer
- /// @param fn the fuzzer function with the signature `void(const Program&, const Options&, ...)`
- /// @returns a ProgramFuzzer that invokes the function @p fn with the Program, Options, along
+ /// @param fn the fuzzer function with the signature `void(const Program&, const Context&, ...)`
+ /// @returns a ProgramFuzzer that invokes the function @p fn with the Program, Context, along
/// with any additional arguments which are deserialized from the fuzzer input.
template <typename... ARGS>
static ProgramFuzzer Create(std::string_view name,
- void (*fn)(const Program&, const Options&, ARGS...)) {
+ void (*fn)(const Program&, const Context&, ARGS...)) {
if constexpr (sizeof...(ARGS) > 0) {
- auto fn_with_decode = [fn](const Program& program, const Options& options,
+ auto fn_with_decode = [fn](const Program& program, const Context& context,
Slice<const std::byte> data) {
if (!data.data) {
return;
@@ -72,7 +90,7 @@
auto data_args = bytes::Decode<std::tuple<std::decay_t<ARGS>...>>(reader);
if (data_args == Success) {
auto all_args =
- std::tuple_cat(std::tuple<const Program&, const Options&>{program, options},
+ std::tuple_cat(std::tuple<const Program&, const Context&>{program, context},
data_args.Get());
std::apply(*fn, all_args);
}
@@ -81,7 +99,7 @@
} else {
return ProgramFuzzer{
name,
- [fn](const Program& program, const Options& options, Slice<const std::byte>) {
+ [fn](const Program& program, const Context& options, Slice<const std::byte>) {
fn(program, options);
},
};
@@ -95,7 +113,7 @@
template <typename... ARGS>
static ProgramFuzzer Create(std::string_view name, void (*fn)(const Program&, ARGS...)) {
if constexpr (sizeof...(ARGS) > 0) {
- auto fn_with_decode = [fn](const Program& program, const Options&,
+ auto fn_with_decode = [fn](const Program& program, const Context&,
Slice<const std::byte> data) {
if (!data.data) {
return;
@@ -112,7 +130,7 @@
} else {
return ProgramFuzzer{
name,
- [fn](const Program& program, const Options&, Slice<const std::byte>) {
+ [fn](const Program& program, const Context&, Slice<const std::byte>) {
fn(program);
},
};
@@ -122,7 +140,7 @@
/// Name of the fuzzer function
std::string_view name;
/// The fuzzer function
- std::function<void(const Program&, const Options&, Slice<const std::byte> data)> fn;
+ std::function<void(const Program&, const Context&, Slice<const std::byte> data)> fn;
};
/// Runs all the registered WGSL fuzzers with the supplied WGSL
@@ -142,9 +160,9 @@
/// Where `...` is any number of deserializable parameters which are decoded from the base64
/// content of the WGSL comments.
/// @see bytes::Decode()
-#define TINT_WGSL_PROGRAM_FUZZER(FUNCTION) \
+#define TINT_WGSL_PROGRAM_FUZZER(FUNCTION, ...) \
TINT_STATIC_INIT(::tint::fuzz::wgsl::Register( \
- ::tint::fuzz::wgsl::ProgramFuzzer::Create(#FUNCTION, FUNCTION)))
+ ::tint::fuzz::wgsl::ProgramFuzzer::Create(#FUNCTION, FUNCTION, ##__VA_ARGS__)))
} // namespace tint::fuzz::wgsl
diff --git a/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc b/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc
index 12497e6..568a636 100644
--- a/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc
+++ b/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc
@@ -39,9 +39,7 @@
namespace tint::hlsl::writer {
namespace {
-void ASTFuzzer(const tint::Program& program,
- const fuzz::wgsl::Options& fuzz_options,
- Options options) {
+void ASTFuzzer(const tint::Program& program, const fuzz::wgsl::Context& context, Options options) {
if (program.AST().HasOverrides()) {
return;
}
@@ -50,9 +48,9 @@
if (res == Success) {
const char* dxc_path = validate::kDxcDLLName;
bool must_validate = false;
- if (!fuzz_options.dxc.empty()) {
+ if (!context.options.dxc.empty()) {
must_validate = true;
- dxc_path = fuzz_options.dxc.c_str();
+ dxc_path = context.options.dxc.c_str();
}
auto dxc = tint::Command::LookPath(dxc_path);