tint/ast: Derive off ast::Variable

Add the new classes:
* `ast::Let`
* `ast::Override`
* `ast::Parameter`
* `ast::Var`

Limit the fields to those that are only applicable for their type.

Note: The resolver and validator is a tangled mess for each of the
variable types. This CL tries to keep the functionality exactly the
same. I'll clean this up in another change.

Bug: tint:1582
Change-Id: Iee83324167ffd4d92ae3032b2134677629c90079
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/93780
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton
2022-06-17 12:48:51 +00:00
committed by Dawn LUCI CQ
parent be6fb2a8d2
commit dcdf66ed5b
66 changed files with 1652 additions and 1193 deletions

View File

@@ -54,8 +54,8 @@ void AddSpirvBlockAttribute::Run(CloneContext& ctx, const DataMap&, DataMap&) co
// contains it in the destination program.
std::unordered_map<const sem::Type*, const ast::Struct*> wrapper_structs;
// Process global variables that are buffers.
for (auto* var : ctx.src->AST().GlobalVariables()) {
// Process global 'var' declarations that are buffers.
for (auto* var : ctx.src->AST().Globals<ast::Var>()) {
auto* sem_var = sem.Get<sem::GlobalVariable>(var);
if (var->declared_storage_class != ast::StorageClass::kStorage &&
var->declared_storage_class != ast::StorageClass::kUniform) {

View File

@@ -67,8 +67,8 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co
}
auto* func = ctx.src->Sem().Get(func_ast);
std::unordered_map<sem::BindingPoint, int> binding_point_counts;
for (auto* var : func->TransitivelyReferencedGlobals()) {
if (auto binding_point = var->Declaration()->BindingPoint()) {
for (auto* global : func->TransitivelyReferencedGlobals()) {
if (auto binding_point = global->Declaration()->BindingPoint()) {
BindingPoint from{binding_point.group->value, binding_point.binding->value};
auto bp_it = remappings->binding_points.find(from);
if (bp_it != remappings->binding_points.end()) {
@@ -88,7 +88,7 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co
}
}
for (auto* var : ctx.src->AST().GlobalVariables()) {
for (auto* var : ctx.src->AST().Globals<ast::Var>()) {
if (auto binding_point = var->BindingPoint()) {
// The original binding point
BindingPoint from{binding_point.group->value, binding_point.binding->value};
@@ -130,10 +130,10 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co
}
auto* ty = sem->Type()->UnwrapRef();
const ast::Type* inner_ty = CreateASTTypeFor(ctx, ty);
auto* new_var = ctx.dst->create<ast::Variable>(
ctx.Clone(var->source), ctx.Clone(var->symbol), var->declared_storage_class, ac,
inner_ty, false, false, ctx.Clone(var->constructor),
ctx.Clone(var->attributes));
auto* new_var =
ctx.dst->Var(ctx.Clone(var->source), ctx.Clone(var->symbol), inner_ty,
var->declared_storage_class, ac, ctx.Clone(var->constructor),
ctx.Clone(var->attributes));
ctx.Replace(var, new_var);
}

View File

@@ -147,16 +147,16 @@ struct CombineSamplers::State {
// Remove all texture and sampler global variables. These will be replaced
// by combined samplers.
for (auto* var : ctx.src->AST().GlobalVariables()) {
auto* type = sem.Get(var->type);
if (type && type->IsAnyOf<sem::Texture, sem::Sampler>() &&
for (auto* global : ctx.src->AST().GlobalVariables()) {
auto* type = sem.Get(global->type);
if (tint::IsAnyOf<sem::Texture, sem::Sampler>(type) &&
!type->Is<sem::StorageTexture>()) {
ctx.Remove(ctx.src->AST().GlobalDeclarations(), var);
} else if (auto binding_point = var->BindingPoint()) {
ctx.Remove(ctx.src->AST().GlobalDeclarations(), global);
} else if (auto binding_point = global->BindingPoint()) {
if (binding_point.group->value == 0 && binding_point.binding->value == 0) {
auto* attribute =
ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision);
ctx.InsertFront(var->attributes, attribute);
ctx.InsertFront(global->attributes, attribute);
}
}
}
@@ -188,9 +188,8 @@ struct CombineSamplers::State {
} else {
// Either texture or sampler (or both) is a function parameter;
// add a new function parameter to represent the combined sampler.
const ast::Type* type = CreateCombinedASTTypeFor(texture_var, sampler_var);
const ast::Variable* var =
ctx.dst->Param(ctx.dst->Symbols().New(name), type);
auto* type = CreateCombinedASTTypeFor(texture_var, sampler_var);
auto* var = ctx.dst->Param(ctx.dst->Symbols().New(name), type);
params.push_back(var);
function_combined_texture_samplers_[func][pair] = var;
}

View File

@@ -31,11 +31,11 @@ const ast::VariableDeclStatement* AsTrivialLetDecl(const ast::Statement* stmt) {
if (!var_decl) {
return nullptr;
}
auto* var = var_decl->variable;
if (!var->is_const) {
auto* let = var_decl->variable->As<ast::Let>();
if (!let) {
return nullptr;
}
auto* ctor = var->constructor;
auto* ctor = let->constructor;
if (!IsAnyOf<ast::IdentifierExpression, ast::LiteralExpression>(ctor)) {
return nullptr;
}

View File

@@ -155,9 +155,13 @@ struct ModuleScopeVarToEntryPointParam::State {
return workgroup_parameter_symbol;
};
for (auto* var : func_sem->TransitivelyReferencedGlobals()) {
auto sc = var->StorageClass();
auto* ty = var->Type()->UnwrapRef();
for (auto* global : func_sem->TransitivelyReferencedGlobals()) {
auto* var = global->Declaration()->As<ast::Var>();
if (!var) {
continue;
}
auto sc = global->StorageClass();
auto* ty = global->Type()->UnwrapRef();
if (sc == ast::StorageClass::kNone) {
continue;
}
@@ -182,12 +186,12 @@ struct ModuleScopeVarToEntryPointParam::State {
bool is_wrapped = false;
if (is_entry_point) {
if (var->Type()->UnwrapRef()->is_handle()) {
if (global->Type()->UnwrapRef()->is_handle()) {
// For a texture or sampler variable, redeclare it as an entry point
// parameter. Disable entry point parameter validation.
auto* disable_validation =
ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter);
auto attrs = ctx.Clone(var->Declaration()->attributes);
auto attrs = ctx.Clone(var->attributes);
attrs.push_back(disable_validation);
auto* param = ctx.dst->Param(new_var_symbol, store_type(), attrs);
ctx.InsertFront(func_ast->params, param);
@@ -195,7 +199,7 @@ struct ModuleScopeVarToEntryPointParam::State {
sc == ast::StorageClass::kUniform) {
// Variables into the Storage and Uniform storage classes are
// redeclared as entry point parameters with a pointer type.
auto attributes = ctx.Clone(var->Declaration()->attributes);
auto attributes = ctx.Clone(var->attributes);
attributes.push_back(
ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter));
attributes.push_back(
@@ -214,22 +218,22 @@ struct ModuleScopeVarToEntryPointParam::State {
is_wrapped = true;
}
param_type = ctx.dst->ty.pointer(param_type, sc,
var->Declaration()->declared_access);
param_type = ctx.dst->ty.pointer(param_type, sc, var->declared_access);
auto* param = ctx.dst->Param(new_var_symbol, param_type, attributes);
ctx.InsertFront(func_ast->params, param);
is_pointer = true;
} else if (sc == ast::StorageClass::kWorkgroup && ContainsMatrix(var->Type())) {
} else if (sc == ast::StorageClass::kWorkgroup &&
ContainsMatrix(global->Type())) {
// Due to a bug in the MSL compiler, we use a threadgroup memory
// argument for any workgroup allocation that contains a matrix.
// See crbug.com/tint/938.
// TODO(jrprice): Do this for all other workgroup variables too.
// Create a member in the workgroup parameter struct.
auto member = ctx.Clone(var->Declaration()->symbol);
auto member = ctx.Clone(var->symbol);
workgroup_parameter_members.push_back(
ctx.dst->Member(member, store_type()));
CloneStructTypes(var->Type()->UnwrapRef());
CloneStructTypes(global->Type()->UnwrapRef());
// Create a function-scope variable that is a pointer to the member.
auto* member_ptr = ctx.dst->AddressOf(
@@ -246,7 +250,7 @@ struct ModuleScopeVarToEntryPointParam::State {
// this variable.
auto* disable_validation =
ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass);
auto* constructor = ctx.Clone(var->Declaration()->constructor);
auto* constructor = ctx.Clone(var->constructor);
auto* local_var =
ctx.dst->Var(new_var_symbol, store_type(), sc, constructor,
ast::AttributeList{disable_validation});
@@ -257,9 +261,8 @@ struct ModuleScopeVarToEntryPointParam::State {
// Use a pointer for non-handle types.
auto* param_type = store_type();
ast::AttributeList attributes;
if (!var->Type()->UnwrapRef()->is_handle()) {
param_type = ctx.dst->ty.pointer(param_type, sc,
var->Declaration()->declared_access);
if (!global->Type()->UnwrapRef()->is_handle()) {
param_type = ctx.dst->ty.pointer(param_type, sc, var->declared_access);
is_pointer = true;
// Disable validation of the parameter's storage class and of
@@ -275,7 +278,7 @@ struct ModuleScopeVarToEntryPointParam::State {
// Replace all uses of the module-scope variable.
// For non-entry points, dereference non-handle pointer parameters.
for (auto* user : var->Users()) {
for (auto* user : global->Users()) {
if (user->Stmt()->Function()->Declaration() == func_ast) {
const ast::Expression* expr = ctx.dst->Expr(new_var_symbol);
if (is_pointer) {
@@ -298,7 +301,7 @@ struct ModuleScopeVarToEntryPointParam::State {
}
}
var_to_newvar[var] = {new_var_symbol, is_pointer, is_wrapped};
var_to_newvar[global] = {new_var_symbol, is_pointer, is_wrapped};
}
if (!workgroup_parameter_members.empty()) {

View File

@@ -86,8 +86,8 @@ struct MultiplanarExternalTexture::State {
// binding and create two additional bindings (one texture_2d<f32> to
// represent the secondary plane and one uniform buffer for the
// ExternalTextureParams struct).
for (auto* var : ctx.src->AST().GlobalVariables()) {
auto* sem_var = sem.Get(var);
for (auto* global : ctx.src->AST().GlobalVariables()) {
auto* sem_var = sem.Get(global);
if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
continue;
}
@@ -95,7 +95,7 @@ struct MultiplanarExternalTexture::State {
// If the attributes are empty, then this must be a texture_external
// passed as a function parameter. These variables are transformed
// elsewhere.
if (var->attributes.empty()) {
if (global->attributes.empty()) {
continue;
}
@@ -109,8 +109,8 @@ struct MultiplanarExternalTexture::State {
// provided to this transform. We fetch the new binding points by
// providing the original texture_external binding points into the
// passed map.
BindingPoint bp = {var->BindingPoint().group->value,
var->BindingPoint().binding->value};
BindingPoint bp = {global->BindingPoint().group->value,
global->BindingPoint().binding->value};
BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
if (it == new_binding_points->bindings_map.end()) {
@@ -129,7 +129,7 @@ struct MultiplanarExternalTexture::State {
// corresponds with the new destination bindings.
// NewBindingSymbols new_binding_syms;
auto& syms = new_binding_symbols[sem_var];
syms.plane_0 = ctx.Clone(var->symbol);
syms.plane_0 = ctx.Clone(global->symbol);
syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
b.Global(syms.plane_1, b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
b.GroupAndBinding(bps.plane_1.group, bps.plane_1.binding));
@@ -140,13 +140,13 @@ struct MultiplanarExternalTexture::State {
// Replace the original texture_external binding with a texture_2d<f32>
// binding.
ast::AttributeList cloned_attributes = ctx.Clone(var->attributes);
const ast::Expression* cloned_constructor = ctx.Clone(var->constructor);
ast::AttributeList cloned_attributes = ctx.Clone(global->attributes);
const ast::Expression* cloned_constructor = ctx.Clone(global->constructor);
auto* replacement =
b.Var(syms.plane_0, b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
cloned_constructor, cloned_attributes);
ctx.Replace(var, replacement);
ctx.Replace(global, replacement);
}
// We must update all the texture_external parameters for user declared

View File

@@ -133,8 +133,8 @@ void NumWorkgroupsFromUniform::Run(CloneContext& ctx, const DataMap& inputs, Dat
// plus 1, or group 0 if no resource bound.
group = 0;
for (auto* var : ctx.src->AST().GlobalVariables()) {
if (auto binding_point = var->BindingPoint()) {
for (auto* global : ctx.src->AST().GlobalVariables()) {
if (auto binding_point = global->BindingPoint()) {
if (binding_point.group->value >= group) {
group = binding_point.group->value + 1;
}

View File

@@ -109,8 +109,8 @@ struct SimplifyPointers::State {
}
if (auto* user = ctx.src->Sem().Get<sem::VariableUser>(op.expr)) {
auto* var = user->Variable();
if (var->Is<sem::LocalVariable>() && //
var->Declaration()->is_const && //
if (var->Is<sem::LocalVariable>() && //
var->Declaration()->Is<ast::Let>() && //
var->Type()->Is<sem::Pointer>()) {
op.expr = var->Declaration()->constructor;
continue;
@@ -161,7 +161,7 @@ struct SimplifyPointers::State {
// permitted.
for (auto* node : ctx.src->ASTNodes().Objects()) {
if (auto* let = node->As<ast::VariableDeclStatement>()) {
if (!let->variable->is_const) {
if (!let->variable->Is<ast::Let>()) {
continue; // Not a `let` declaration. Ignore.
}

View File

@@ -64,38 +64,43 @@ void SingleEntryPoint::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) c
referenced_vars.emplace(var->Declaration());
}
// Clone any module-scope variables, types, and functions that are statically
// referenced by the target entry point.
// Clone any module-scope variables, types, and functions that are statically referenced by the
// target entry point.
for (auto* decl : ctx.src->AST().GlobalDeclarations()) {
if (auto* ty = decl->As<ast::TypeDecl>()) {
// TODO(jrprice): Strip unused types.
ctx.dst->AST().AddTypeDecl(ctx.Clone(ty));
} else if (auto* var = decl->As<ast::Variable>()) {
if (referenced_vars.count(var)) {
if (var->is_overridable) {
// It is an overridable constant
if (!ast::HasAttribute<ast::IdAttribute>(var->attributes)) {
Switch(
decl, //
[&](const ast::TypeDecl* ty) {
// TODO(jrprice): Strip unused types.
ctx.dst->AST().AddTypeDecl(ctx.Clone(ty));
},
[&](const ast::Override* override) {
if (referenced_vars.count(override)) {
if (!ast::HasAttribute<ast::IdAttribute>(override->attributes)) {
// If the constant doesn't already have an @id() attribute, add one
// so that its allocated ID so that it won't be affected by other
// stripped away constants
auto* global = sem.Get(var)->As<sem::GlobalVariable>();
auto* global = sem.Get(override);
const auto* id = ctx.dst->Id(global->ConstantId());
ctx.InsertFront(var->attributes, id);
ctx.InsertFront(override->attributes, id);
}
ctx.dst->AST().AddGlobalVariable(ctx.Clone(override));
}
ctx.dst->AST().AddGlobalVariable(ctx.Clone(var));
}
} else if (auto* func = decl->As<ast::Function>()) {
if (sem.Get(func)->HasAncestorEntryPoint(entry_point->symbol)) {
ctx.dst->AST().AddFunction(ctx.Clone(func));
}
} else if (auto* ext = decl->As<ast::Enable>()) {
ctx.dst->AST().AddEnable(ctx.Clone(ext));
} else {
TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
<< "unhandled global declaration: " << decl->TypeInfo().name;
return;
}
},
[&](const ast::Variable* v) { // var, let
if (referenced_vars.count(v)) {
ctx.dst->AST().AddGlobalVariable(ctx.Clone(v));
}
},
[&](const ast::Function* func) {
if (sem.Get(func)->HasAncestorEntryPoint(entry_point->symbol)) {
ctx.dst->AST().AddFunction(ctx.Clone(func));
}
},
[&](const ast::Enable* ext) { ctx.dst->AST().AddEnable(ctx.Clone(ext)); },
[&](Default) {
TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
<< "unhandled global declaration: " << decl->TypeInfo().name;
});
}
// Clone the entry point.

View File

@@ -44,28 +44,42 @@ struct Unshadow::State {
// Maps a variable to its new name.
std::unordered_map<const sem::Variable*, Symbol> renamed_to;
auto rename = [&](const sem::Variable* var) -> const ast::Variable* {
auto* decl = var->Declaration();
auto rename = [&](const sem::Variable* v) -> const ast::Variable* {
auto* decl = v->Declaration();
auto name = ctx.src->Symbols().NameFor(decl->symbol);
auto symbol = ctx.dst->Symbols().New(name);
renamed_to.emplace(var, symbol);
renamed_to.emplace(v, symbol);
auto source = ctx.Clone(decl->source);
auto* type = ctx.Clone(decl->type);
auto* constructor = ctx.Clone(decl->constructor);
auto attributes = ctx.Clone(decl->attributes);
return ctx.dst->create<ast::Variable>(source, symbol, decl->declared_storage_class,
decl->declared_access, type, decl->is_const,
decl->is_overridable, constructor, attributes);
return Switch(
decl, //
[&](const ast::Var* var) {
return ctx.dst->Var(source, symbol, type, var->declared_storage_class,
var->declared_access, constructor, attributes);
},
[&](const ast::Let*) {
return ctx.dst->Let(source, symbol, type, constructor, attributes);
},
[&](const ast::Parameter*) {
return ctx.dst->Param(source, symbol, type, attributes);
},
[&](Default) {
TINT_ICE(Transform, ctx.dst->Diagnostics())
<< "unexpected variable type: " << decl->TypeInfo().name;
return nullptr;
});
};
ctx.ReplaceAll([&](const ast::Variable* var) -> const ast::Variable* {
if (auto* local = sem.Get<sem::LocalVariable>(var)) {
ctx.ReplaceAll([&](const ast::Variable* v) -> const ast::Variable* {
if (auto* local = sem.Get<sem::LocalVariable>(v)) {
if (local->Shadows()) {
return rename(local);
}
}
if (auto* param = sem.Get<sem::Parameter>(var)) {
if (auto* param = sem.Get<sem::Parameter>(v)) {
if (param->Shadows()) {
return rename(param);
}

View File

@@ -189,18 +189,18 @@ class HoistToDeclBefore::State {
/// before `before_expr`.
/// @param before_expr expression to insert `expr` before
/// @param expr expression to hoist
/// @param as_const hoist to `let` if true, otherwise to `var`
/// @param as_let hoist to `let` if true, otherwise to `var`
/// @param decl_name optional name to use for the variable/constant name
/// @return true on success
bool Add(const sem::Expression* before_expr,
const ast::Expression* expr,
bool as_const,
bool as_let,
const char* decl_name) {
auto name = b.Symbols().New(decl_name);
// Construct the let/var that holds the hoisted expr
auto* v = as_const ? b.Let(name, nullptr, ctx.Clone(expr))
: b.Var(name, nullptr, ctx.Clone(expr));
auto* v = as_let ? static_cast<const ast::Variable*>(b.Let(name, nullptr, ctx.Clone(expr)))
: static_cast<const ast::Variable*>(b.Var(name, nullptr, ctx.Clone(expr)));
auto* decl = b.Decl(v);
if (!InsertBefore(before_expr->Stmt(), decl)) {
@@ -330,9 +330,9 @@ HoistToDeclBefore::~HoistToDeclBefore() {}
bool HoistToDeclBefore::Add(const sem::Expression* before_expr,
const ast::Expression* expr,
bool as_const,
bool as_let,
const char* decl_name) {
return state_->Add(before_expr, expr, as_const, decl_name);
return state_->Add(before_expr, expr, as_let, decl_name);
}
bool HoistToDeclBefore::InsertBefore(const sem::Statement* before_stmt,

View File

@@ -695,7 +695,7 @@ struct State {
/// vertex_index and instance_index builtins if present.
/// @param func the entry point function
/// @param param the parameter to process
void ProcessNonStructParameter(const ast::Function* func, const ast::Variable* param) {
void ProcessNonStructParameter(const ast::Function* func, const ast::Parameter* param) {
if (auto* location = ast::GetAttribute<ast::LocationAttribute>(param->attributes)) {
// Create a function-scope variable to replace the parameter.
auto func_var_sym = ctx.Clone(param->symbol);
@@ -733,7 +733,7 @@ struct State {
/// @param param the parameter to process
/// @param struct_ty the structure type
void ProcessStructParameter(const ast::Function* func,
const ast::Variable* param,
const ast::Parameter* param,
const ast::Struct* struct_ty) {
auto param_sym = ctx.Clone(param->symbol);

View File

@@ -416,8 +416,8 @@ ZeroInitWorkgroupMemory::ZeroInitWorkgroupMemory() = default;
ZeroInitWorkgroupMemory::~ZeroInitWorkgroupMemory() = default;
bool ZeroInitWorkgroupMemory::ShouldRun(const Program* program, const DataMap&) const {
for (auto* decl : program->AST().GlobalDeclarations()) {
if (auto* var = decl->As<ast::Variable>()) {
for (auto* global : program->AST().GlobalVariables()) {
if (auto* var = global->As<ast::Var>()) {
if (var->declared_storage_class == ast::StorageClass::kWorkgroup) {
return true;
}