blob: 1986f83380bc61aa44a217119407426b56cef716 [file] [log] [blame]
// Copyright 2022 The Tint Authors.
//
// 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 "src/tint/writer/spirv/generator_impl.h"
#include <utility>
#include <vector>
#include "src/tint/transform/add_block_attribute.h"
#include "src/tint/transform/add_empty_entry_point.h"
#include "src/tint/transform/builtin_polyfill.h"
#include "src/tint/transform/canonicalize_entry_point_io.h"
#include "src/tint/transform/clamp_frag_depth.h"
#include "src/tint/transform/demote_to_helper.h"
#include "src/tint/transform/direct_variable_access.h"
#include "src/tint/transform/disable_uniformity_analysis.h"
#include "src/tint/transform/expand_compound_assignment.h"
#include "src/tint/transform/for_loop_to_loop.h"
#include "src/tint/transform/manager.h"
#include "src/tint/transform/merge_return.h"
#include "src/tint/transform/multiplanar_external_texture.h"
#include "src/tint/transform/preserve_padding.h"
#include "src/tint/transform/promote_side_effects_to_decl.h"
#include "src/tint/transform/remove_phonies.h"
#include "src/tint/transform/remove_unreachable_statements.h"
#include "src/tint/transform/robustness.h"
#include "src/tint/transform/simplify_pointers.h"
#include "src/tint/transform/std140.h"
#include "src/tint/transform/unshadow.h"
#include "src/tint/transform/var_for_dynamic_index.h"
#include "src/tint/transform/vectorize_matrix_conversions.h"
#include "src/tint/transform/vectorize_scalar_matrix_initializers.h"
#include "src/tint/transform/while_to_loop.h"
#include "src/tint/transform/zero_init_workgroup_memory.h"
namespace tint::writer::spirv {
SanitizedResult Sanitize(const Program* in, const Options& options) {
transform::Manager manager;
transform::DataMap data;
if (options.clamp_frag_depth) {
manager.Add<tint::transform::ClampFragDepth>();
}
manager.Add<transform::DisableUniformityAnalysis>();
// ExpandCompoundAssignment must come before BuiltinPolyfill
manager.Add<transform::ExpandCompoundAssignment>();
manager.Add<transform::PreservePadding>(); // Must come before DirectVariableAccess
manager.Add<transform::Unshadow>(); // Must come before DirectVariableAccess
manager.Add<transform::RemoveUnreachableStatements>();
manager.Add<transform::PromoteSideEffectsToDecl>();
manager.Add<transform::SimplifyPointers>(); // Required for arrayLength()
manager.Add<transform::RemovePhonies>();
manager.Add<transform::VectorizeScalarMatrixInitializers>();
manager.Add<transform::VectorizeMatrixConversions>();
manager.Add<transform::WhileToLoop>(); // ZeroInitWorkgroupMemory
manager.Add<transform::MergeReturn>();
if (!options.disable_robustness) {
// Robustness must come after PromoteSideEffectsToDecl
// Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
manager.Add<transform::Robustness>();
}
if (!options.external_texture_options.bindings_map.empty()) {
// Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(
options.external_texture_options.bindings_map);
manager.Add<transform::MultiplanarExternalTexture>();
}
{ // Builtin polyfills
// BuiltinPolyfill must come before DirectVariableAccess, due to the use of pointer
// parameter for workgroupUniformLoad()
transform::BuiltinPolyfill::Builtins polyfills;
polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
polyfills.bgra8unorm = true;
polyfills.bitshift_modulo = true;
polyfills.clamp_int = true;
polyfills.conv_f32_to_iu32 = true;
polyfills.count_leading_zeros = true;
polyfills.count_trailing_zeros = true;
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
polyfills.first_leading_bit = true;
polyfills.first_trailing_bit = true;
polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
polyfills.int_div_mod = true;
polyfills.saturate = true;
polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
polyfills.quantize_to_vec_f16 = true; // crbug.com/tint/1741
polyfills.workgroup_uniform_load = true;
data.Add<transform::BuiltinPolyfill::Config>(polyfills);
manager.Add<transform::BuiltinPolyfill>();
}
bool disable_workgroup_init_in_sanitizer =
options.disable_workgroup_init || options.use_zero_initialize_workgroup_memory_extension;
if (!disable_workgroup_init_in_sanitizer) {
// ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
// ZeroInitWorkgroupMemory may inject new builtin parameters.
manager.Add<transform::ZeroInitWorkgroupMemory>();
}
{
transform::DirectVariableAccess::Options opts;
opts.transform_private = true;
opts.transform_function = true;
data.Add<transform::DirectVariableAccess::Config>(opts);
manager.Add<transform::DirectVariableAccess>();
}
// CanonicalizeEntryPointIO must come after Robustness
manager.Add<transform::CanonicalizeEntryPointIO>();
manager.Add<transform::AddEmptyEntryPoint>();
// AddBlockAttribute must come after MultiplanarExternalTexture
manager.Add<transform::AddBlockAttribute>();
// DemoteToHelper must come after CanonicalizeEntryPointIO, PromoteSideEffectsToDecl, and
// ExpandCompoundAssignment.
// TODO(crbug.com/tint/1752): Use SPV_EXT_demote_to_helper_invocation if available.
manager.Add<transform::DemoteToHelper>();
// Std140 must come after PromoteSideEffectsToDecl.
// Std140 must come before VarForDynamicIndex and ForLoopToLoop.
manager.Add<transform::Std140>();
// VarForDynamicIndex must come after Std140
manager.Add<transform::VarForDynamicIndex>();
// ForLoopToLoop must come after Std140, ZeroInitWorkgroupMemory
manager.Add<transform::ForLoopToLoop>();
data.Add<transform::CanonicalizeEntryPointIO::Config>(
transform::CanonicalizeEntryPointIO::Config(
transform::CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF,
options.emit_vertex_point_size));
SanitizedResult result;
result.program = std::move(manager.Run(in, data).program);
return result;
}
GeneratorImpl::GeneratorImpl(const Program* program, bool zero_initialize_workgroup_memory)
: builder_(program, zero_initialize_workgroup_memory) {}
bool GeneratorImpl::Generate() {
if (builder_.Build()) {
writer_.WriteHeader(builder_.id_bound());
writer_.WriteBuilder(&builder_);
return true;
}
return false;
}
const std::vector<uint32_t>& GeneratorImpl::result() const {
return writer_.result();
}
std::vector<uint32_t>& GeneratorImpl::result() {
return writer_.result();
}
std::string GeneratorImpl::error() const {
return builder_.error();
}
} // namespace tint::writer::spirv