blob: b8e977af072da7f44a8f3299f2d8b9e32b5c40cd [file]
// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
#include "src/tint/lang/wgsl/ast/builder.h"
#include "src/tint/lang/core/enums.h"
using namespace tint::core::number_suffixes; // NOLINT
namespace tint::ast {
Builder::VarOptions::~VarOptions() = default;
Builder::LetOptions::~LetOptions() = default;
Builder::ConstOptions::~ConstOptions() = default;
Builder::OverrideOptions::~OverrideOptions() = default;
Builder::Builder() : ast_(ast_nodes_.Create<ast::Module>(AllocateNodeID(), Source{})) {}
Builder::Builder(Builder&& rhs)
: last_ast_node_id_(std::move(rhs.last_ast_node_id_)),
ast_nodes_(std::move(rhs.ast_nodes_)),
ast_(rhs.ast_),
symbols_(std::move(rhs.symbols_)),
diagnostics_(std::move(rhs.diagnostics_)) {
rhs.MarkAsMoved();
}
Builder::~Builder() = default;
Builder& Builder::operator=(Builder&& rhs) {
rhs.MarkAsMoved();
AssertNotMoved();
last_ast_node_id_ = std::move(rhs.last_ast_node_id_);
ast_nodes_ = std::move(rhs.ast_nodes_);
ast_ = std::move(rhs.ast_);
symbols_ = std::move(rhs.symbols_);
diagnostics_ = std::move(rhs.diagnostics_);
return *this;
}
bool Builder::IsValid() const {
return !diagnostics_.ContainsErrors();
}
void Builder::MarkAsMoved() {
AssertNotMoved();
moved_ = true;
}
void Builder::AssertNotMoved() const {
TINT_ASSERT(!moved_) << "Attempting to use Builder after it has been moved";
}
const ast::Statement* Builder::WrapInStatement(const ast::Expression* expr) {
// Create a temporary variable of inferred type from expr.
return Decl(Let(symbols_.New(), expr));
}
const ast::VariableDeclStatement* Builder::WrapInStatement(const ast::Variable* v) {
return create<ast::VariableDeclStatement>(v);
}
const ast::Statement* Builder::WrapInStatement(const ast::Statement* stmt) {
return stmt;
}
const ast::Function* Builder::WrapInFunction(VectorRef<const ast::Statement*> stmts) {
return Func("test_function", {}, ty.void_(), std::move(stmts),
Vector{
create<ast::StageAttribute>(ast::PipelineStage::kCompute),
WorkgroupSize(1_u, 1_u, 1_u),
});
}
Builder::TypesBuilder::TypesBuilder(Builder* pb) : builder(pb) {}
ast::Type Builder::TypesBuilder::AsType(Symbol sym) const {
return AsType(builder->source_, sym);
}
ast::Type Builder::TypesBuilder::AsType(const Source& source, Symbol sym) const {
return {builder->Expr(builder->Ident(source, sym))};
}
ast::Type Builder::TypesBuilder::AsType(std::string_view name) const {
return AsType(builder->source_, name);
}
ast::Type Builder::TypesBuilder::AsType(const Source& source, std::string_view name) const {
return {builder->Expr(builder->Ident(source, name))};
}
ast::Type Builder::TypesBuilder::AsType(const ast::IdentifierExpression* ident) const {
return {ident};
}
ast::Type Builder::TypesBuilder::void_() const {
return ast::Type{};
}
ast::Type Builder::TypesBuilder::bool_() const {
return AsType("bool");
}
ast::Type Builder::TypesBuilder::bool_(const Source& source) const {
return AsType(source, "bool");
}
ast::Type Builder::TypesBuilder::f16() const {
return AsType("f16");
}
ast::Type Builder::TypesBuilder::f16(const Source& source) const {
return AsType(source, "f16");
}
ast::Type Builder::TypesBuilder::f32() const {
return AsType("f32");
}
ast::Type Builder::TypesBuilder::f32(const Source& source) const {
return AsType(source, "f32");
}
ast::Type Builder::TypesBuilder::i32() const {
return AsType("i32");
}
ast::Type Builder::TypesBuilder::i32(const Source& source) const {
return AsType(source, "i32");
}
ast::Type Builder::TypesBuilder::u32() const {
return AsType("u32");
}
ast::Type Builder::TypesBuilder::u32(const Source& source) const {
return AsType(source, "u32");
}
ast::Type Builder::TypesBuilder::i8() const {
return AsType("i8");
}
ast::Type Builder::TypesBuilder::i8(const Source& source) const {
return AsType(source, "i8");
}
ast::Type Builder::TypesBuilder::u8() const {
return AsType("u8");
}
ast::Type Builder::TypesBuilder::u8(const Source& source) const {
return AsType(source, "u8");
}
ast::Type Builder::TypesBuilder::vec(ast::Type type, uint32_t n) const {
return vec(builder->source_, type, n);
}
ast::Type Builder::TypesBuilder::vec(const Source& source, ast::Type type, uint32_t n) const {
switch (n) {
case 2:
return vec2(source, type);
case 3:
return vec3(source, type);
case 4:
return vec4(source, type);
}
TINT_ICE() << "invalid vector width " << n;
}
ast::Type Builder::TypesBuilder::vec2(ast::Type type) const {
return vec2(builder->source_, type);
}
ast::Type Builder::TypesBuilder::vec2(const Source& source, ast::Type type) const {
return AsType(source, "vec2", type);
}
ast::Type Builder::TypesBuilder::vec3(ast::Type type) const {
return vec3(builder->source_, type);
}
ast::Type Builder::TypesBuilder::vec3(const Source& source, ast::Type type) const {
return AsType(source, "vec3", type);
}
ast::Type Builder::TypesBuilder::vec4(ast::Type type) const {
return vec4(builder->source_, type);
}
ast::Type Builder::TypesBuilder::vec4(const Source& source, ast::Type type) const {
return AsType(source, "vec4", type);
}
ast::Type Builder::TypesBuilder::mat(ast::Type type, uint32_t columns, uint32_t rows) const {
return mat(builder->source_, type, columns, rows);
}
ast::Type Builder::TypesBuilder::mat(const Source& source,
ast::Type type,
uint32_t columns,
uint32_t rows) const {
if (DAWN_LIKELY(columns >= 2 && columns <= 4 && rows >= 2 && rows <= 4)) {
static constexpr std::array<const char*, 9> names = {
"mat2x2", "mat2x3", "mat2x4", //
"mat3x2", "mat3x3", "mat3x4", //
"mat4x2", "mat4x3", "mat4x4", //
};
auto i = (columns - 2) * 3 + (rows - 2);
return AsType(source, names[i], type);
}
TINT_ICE() << "invalid matrix dimensions " << columns << "x" << rows;
}
ast::Type Builder::TypesBuilder::mat2x2(ast::Type type) const {
return mat2x2(builder->source_, type);
}
ast::Type Builder::TypesBuilder::mat2x3(ast::Type type) const {
return mat2x3(builder->source_, type);
}
ast::Type Builder::TypesBuilder::mat2x4(ast::Type type) const {
return mat2x4(builder->source_, type);
}
ast::Type Builder::TypesBuilder::mat3x2(ast::Type type) const {
return mat3x2(builder->source_, type);
}
ast::Type Builder::TypesBuilder::mat3x3(ast::Type type) const {
return mat3x3(builder->source_, type);
}
ast::Type Builder::TypesBuilder::mat3x4(ast::Type type) const {
return mat3x4(builder->source_, type);
}
ast::Type Builder::TypesBuilder::mat4x2(ast::Type type) const {
return mat4x2(builder->source_, type);
}
ast::Type Builder::TypesBuilder::mat4x3(ast::Type type) const {
return mat4x3(builder->source_, type);
}
ast::Type Builder::TypesBuilder::mat4x4(ast::Type type) const {
return mat4x4(builder->source_, type);
}
ast::Type Builder::TypesBuilder::mat2x2(const Source& source) const {
return AsType(source, "mat2x2");
}
ast::Type Builder::TypesBuilder::mat2x2(const Source& source, ast::Type type) const {
return AsType(source, "mat2x2", type);
}
ast::Type Builder::TypesBuilder::mat2x3(const Source& source) const {
return AsType(source, "mat2x3");
}
ast::Type Builder::TypesBuilder::mat2x3(const Source& source, ast::Type type) const {
return AsType(source, "mat2x3", type);
}
ast::Type Builder::TypesBuilder::mat2x4(const Source& source) const {
return AsType(source, "mat2x4");
}
ast::Type Builder::TypesBuilder::mat2x4(const Source& source, ast::Type type) const {
return AsType(source, "mat2x4", type);
}
ast::Type Builder::TypesBuilder::mat3x2(const Source& source) const {
return AsType(source, "mat3x2");
}
ast::Type Builder::TypesBuilder::mat3x2(const Source& source, ast::Type type) const {
return AsType(source, "mat3x2", type);
}
ast::Type Builder::TypesBuilder::mat3x3(const Source& source) const {
return AsType(source, "mat3x3");
}
ast::Type Builder::TypesBuilder::mat3x3(const Source& source, ast::Type type) const {
return AsType(source, "mat3x3", type);
}
ast::Type Builder::TypesBuilder::mat3x4(const Source& source) const {
return AsType(source, "mat3x4");
}
ast::Type Builder::TypesBuilder::mat3x4(const Source& source, ast::Type type) const {
return AsType(source, "mat3x4", type);
}
ast::Type Builder::TypesBuilder::mat4x2(const Source& source) const {
return AsType(source, "mat4x2");
}
ast::Type Builder::TypesBuilder::mat4x2(const Source& source, ast::Type type) const {
return AsType(source, "mat4x2", type);
}
ast::Type Builder::TypesBuilder::mat4x3(const Source& source) const {
return AsType(source, "mat4x3");
}
ast::Type Builder::TypesBuilder::mat4x3(const Source& source, ast::Type type) const {
return AsType(source, "mat4x3", type);
}
ast::Type Builder::TypesBuilder::mat4x4(const Source& source) const {
return AsType(source, "mat4x4");
}
ast::Type Builder::TypesBuilder::mat4x4(const Source& source, ast::Type type) const {
return AsType(source, "mat4x4", type);
}
ast::Type Builder::TypesBuilder::array(const Source& source) const {
return AsType(source, "array");
}
ast::Type Builder::TypesBuilder::array() const {
return array(builder->source_);
}
ast::Type Builder::TypesBuilder::array(ast::Type subtype) const {
return array(builder->source_, subtype);
}
ast::Type Builder::TypesBuilder::array(const Source& source, ast::Type subtype) const {
return ast::Type{
builder->Expr(builder->create<ast::TemplatedIdentifier>(source, builder->Sym("array"),
Vector{
subtype.expr,
}))};
}
ast::Type Builder::TypesBuilder::array(ast::Type subtype, uint32_t n) const {
return array(builder->source_, subtype, core::u32(n));
}
ast::Type Builder::TypesBuilder::array(ast::Type subtype, const ast::Const* expr) const {
return array(builder->source_, subtype, expr);
}
ast::Type Builder::TypesBuilder::array(ast::Type subtype, const ast::Expression* expr) const {
return array(builder->source_, subtype, expr);
}
ast::Type Builder::TypesBuilder::array(ast::Type subtype, const ast::Override* expr) const {
return array(builder->source_, subtype, expr);
}
ast::Type Builder::TypesBuilder::array(const Source& source, ast::Type subtype, uint32_t n) const {
if (n == 0) {
return AsType(source, "array", subtype);
}
return AsType(source, "array", subtype, core::u32(n));
}
ast::Type Builder::TypesBuilder::array(const Source& source,
ast::Type subtype,
const ast::Const* expr) const {
if (expr == nullptr) {
return AsType(source, "array", subtype);
}
return AsType(source, "array", subtype, expr);
}
ast::Type Builder::TypesBuilder::array(const Source& source,
ast::Type subtype,
const ast::Expression* expr) const {
if (expr == nullptr) {
return AsType(source, "array", subtype);
}
return AsType(source, "array", subtype, expr);
}
ast::Type Builder::TypesBuilder::array(const Source& source,
ast::Type subtype,
const ast::Override* expr) const {
if (expr == nullptr) {
return AsType(source, "array", subtype);
}
return AsType(source, "array", subtype, expr);
}
const ast::Alias* Builder::TypesBuilder::alias(std::string_view name, ast::Type type) const {
return alias(builder->source_, builder->Ident(name), type);
}
const ast::Alias* Builder::TypesBuilder::alias(Symbol name, ast::Type type) const {
return alias(builder->source_, builder->Ident(name), type);
}
const ast::Alias* Builder::TypesBuilder::alias(const Source& source,
const ast::Identifier* name,
ast::Type type) const {
return builder->create<ast::Alias>(source, builder->Ident(name), type);
}
ast::Type Builder::TypesBuilder::ptr(core::AddressSpace address_space,
ast::Type type,
core::Access access) const {
return ptr(builder->source_, address_space, type, access);
}
ast::Type Builder::TypesBuilder::ptr(const Source& source,
core::AddressSpace address_space,
ast::Type type,
core::Access access) const {
if (access != core::Access::kUndefined) {
return AsType(source, "ptr", address_space, type, access);
}
return AsType(source, "ptr", address_space, type);
}
ast::Type Builder::TypesBuilder::atomic(const Source& source, ast::Type type) const {
return AsType(source, "atomic", type);
}
ast::Type Builder::TypesBuilder::atomic(ast::Type type) const {
return AsType("atomic", type);
}
ast::Type Builder::TypesBuilder::sampler(core::type::SamplerKind kind) const {
return sampler(builder->source_, kind);
}
ast::Type Builder::TypesBuilder::sampler(core::SamplerFiltering filtering) const {
return sampler(builder->source_, filtering);
}
ast::Type Builder::TypesBuilder::sampler(const Source& source, core::type::SamplerKind kind) const {
switch (kind) {
case core::type::SamplerKind::kSampler:
return AsType(source, "sampler");
case core::type::SamplerKind::kComparisonSampler:
return AsType(source, "sampler_comparison");
}
TINT_ICE() << "invalid sampler kind " << kind;
}
ast::Type Builder::TypesBuilder::sampler(const Source& source,
core::SamplerFiltering filtering) const {
TINT_ASSERT(filtering == core::SamplerFiltering::kFiltering ||
filtering == core::SamplerFiltering::kNonFiltering);
return AsType(source, "sampler", filtering);
}
ast::Type Builder::TypesBuilder::depth_texture(core::type::TextureDimension dims) const {
return depth_texture(builder->source_, dims);
}
ast::Type Builder::TypesBuilder::depth_texture(const Source& source,
core::type::TextureDimension dims) const {
switch (dims) {
case core::type::TextureDimension::k2d:
return AsType(source, "texture_depth_2d");
case core::type::TextureDimension::k2dArray:
return AsType(source, "texture_depth_2d_array");
case core::type::TextureDimension::kCube:
return AsType(source, "texture_depth_cube");
case core::type::TextureDimension::kCubeArray:
return AsType(source, "texture_depth_cube_array");
default:
break;
}
TINT_ICE() << "invalid depth_texture dimensions: " << dims;
}
ast::Type Builder::TypesBuilder::depth_multisampled_texture(
core::type::TextureDimension dims) const {
return depth_multisampled_texture(builder->source_, dims);
}
ast::Type Builder::TypesBuilder::depth_multisampled_texture(
const Source& source,
core::type::TextureDimension dims) const {
if (dims == core::type::TextureDimension::k2d) {
return AsType(source, "texture_depth_multisampled_2d");
}
TINT_ICE() << "invalid depth_multisampled_texture dimensions: " << dims;
}
ast::Type Builder::TypesBuilder::sampled_texture(core::type::TextureDimension dims,
ast::Type subtype) const {
return sampled_texture(builder->source_, dims, subtype);
}
ast::Type Builder::TypesBuilder::sampled_texture(const Source& source,
core::type::TextureDimension dims,
ast::Type subtype) const {
switch (dims) {
case core::type::TextureDimension::k1d:
return AsType(source, "texture_1d", subtype);
case core::type::TextureDimension::k2d:
return AsType(source, "texture_2d", subtype);
case core::type::TextureDimension::k3d:
return AsType(source, "texture_3d", subtype);
case core::type::TextureDimension::k2dArray:
return AsType(source, "texture_2d_array", subtype);
case core::type::TextureDimension::kCube:
return AsType(source, "texture_cube", subtype);
case core::type::TextureDimension::kCubeArray:
return AsType(source, "texture_cube_array", subtype);
default:
break;
}
TINT_ICE() << "invalid sampled_texture dimensions: " << dims;
}
ast::Type Builder::TypesBuilder::sampled_texture(core::type::TextureDimension dims,
ast::Type subtype,
core::TextureFilterable filterable) const {
return sampled_texture(builder->source_, dims, subtype, filterable);
}
ast::Type Builder::TypesBuilder::sampled_texture(const Source& source,
core::type::TextureDimension dims,
ast::Type subtype,
core::TextureFilterable filterable) const {
TINT_ASSERT(filterable == core::TextureFilterable::kFilterable ||
filterable == core::TextureFilterable::kUnfilterable);
std::string_view name;
switch (dims) {
case core::type::TextureDimension::k1d:
name = "texture_1d";
break;
case core::type::TextureDimension::k2d:
name = "texture_2d";
break;
case core::type::TextureDimension::k3d:
name = "texture_3d";
break;
case core::type::TextureDimension::k2dArray:
name = "texture_2d_array";
break;
case core::type::TextureDimension::kCube:
name = "texture_cube";
break;
case core::type::TextureDimension::kCubeArray:
name = "texture_cube_array";
break;
default:
TINT_ICE() << "invalid sampled_texture dimensions: " << dims;
}
return ast::Type{builder->Expr(
builder->create<ast::TemplatedIdentifier>(source, builder->Sym(name),
Vector{
subtype.expr,
builder->Expr(builder->Ident(filterable)),
}))};
}
ast::Type Builder::TypesBuilder::multisampled_texture(core::type::TextureDimension dims,
ast::Type subtype) const {
return multisampled_texture(builder->source_, dims, subtype);
}
ast::Type Builder::TypesBuilder::multisampled_texture(const Source& source,
core::type::TextureDimension dims,
ast::Type subtype) const {
if (dims == core::type::TextureDimension::k2d) {
return AsType(source, "texture_multisampled_2d", subtype);
}
TINT_ICE() << "invalid multisampled_texture dimensions: " << dims;
}
ast::Type Builder::TypesBuilder::storage_texture(core::type::TextureDimension dims,
core::TexelFormat format,
core::Access access) const {
return storage_texture(builder->source_, dims, format, access);
}
ast::Type Builder::TypesBuilder::storage_texture(const Source& source,
core::type::TextureDimension dims,
core::TexelFormat format,
core::Access access) const {
switch (dims) {
case core::type::TextureDimension::k1d:
return AsType(source, "texture_storage_1d", format, access);
case core::type::TextureDimension::k2d:
return AsType(source, "texture_storage_2d", format, access);
case core::type::TextureDimension::k2dArray:
return AsType(source, "texture_storage_2d_array", format, access);
case core::type::TextureDimension::k3d:
return AsType(source, "texture_storage_3d", format, access);
default:
break;
}
TINT_ICE() << "invalid storage_texture dimensions: " << dims;
}
ast::Type Builder::TypesBuilder::texel_buffer(core::TexelFormat format, core::Access access) const {
return texel_buffer(builder->source_, format, access);
}
ast::Type Builder::TypesBuilder::texel_buffer(const Source& source,
core::TexelFormat format,
core::Access access) const {
return AsType(source, "texel_buffer", format, access);
}
ast::Type Builder::TypesBuilder::input_attachment(ast::Type subtype) const {
return AsType("input_attachment", subtype);
}
ast::Type Builder::TypesBuilder::external_texture(const Source& source) const {
return AsType(source, "texture_external");
}
ast::Type Builder::TypesBuilder::external_texture() const {
return external_texture(builder->source_);
}
ast::Type Builder::TypesBuilder::subgroup_matrix_result(ast::Type el,
uint32_t cols,
uint32_t rows) const {
return subgroup_matrix_result(builder->source_, el, cols, rows);
}
ast::Type Builder::TypesBuilder::subgroup_matrix_result(const Source& source,
ast::Type el,
uint32_t cols,
uint32_t rows) const {
return subgroup_matrix_result(source, el, core::AInt(cols), core::AInt(rows));
}
ast::Type Builder::TypesBuilder::subgroup_matrix_right(ast::Type el,
uint32_t cols,
uint32_t rows) const {
return AsType("subgroup_matrix_right", el, core::AInt(cols), core::AInt(rows));
}
ast::Type Builder::TypesBuilder::subgroup_matrix_left(ast::Type el,
uint32_t cols,
uint32_t rows) const {
return AsType("subgroup_matrix_left", el, core::AInt(cols), core::AInt(rows));
}
ast::Type Builder::TypesBuilder::subgroup_matrix(core::SubgroupMatrixKind kind,
ast::Type el,
uint32_t cols,
uint32_t rows) const {
switch (kind) {
case core::SubgroupMatrixKind::kLeft:
return subgroup_matrix_left(el, cols, rows);
case core::SubgroupMatrixKind::kRight:
return subgroup_matrix_right(el, cols, rows);
case core::SubgroupMatrixKind::kResult:
return subgroup_matrix_result(el, cols, rows);
case core::SubgroupMatrixKind::kUndefined:
TINT_UNREACHABLE();
}
}
ast::Type Builder::TypesBuilder::buffer(uint32_t size) const {
if (size == 0) {
return AsType("buffer");
}
return buffer(core::AInt(size));
}
ast::Type Builder::TypesBuilder::Of(const ast::TypeDecl* type) const {
return AsType(type->name->symbol);
}
} // namespace tint::ast