blob: e94e1333803c9a016c7708ae5e575f8cc42857bc [file] [log] [blame]
Dan Sinclair6e581892020-03-02 15:47:43 -05001// Copyright 2020 The Tint Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Ben Clayton5f0ea112021-03-09 10:54:37 +000015#include "src/resolver/resolver.h"
Dan Sinclair6e581892020-03-02 15:47:43 -050016
Antonio Maioranofe2b4172021-03-01 20:01:39 +000017#include <algorithm>
Antonio Maiorano60dae242021-07-15 19:09:25 +000018#include <cmath>
19#include <iomanip>
Ben Claytond1d99bc2021-09-15 17:37:00 +000020#include <limits>
Ben Claytona6b9a8e2021-01-26 16:57:10 +000021#include <utility>
dan sinclair973bd6a2020-04-07 12:57:42 +000022
Ben Claytonfec63b72021-04-21 13:47:12 +000023#include "src/ast/alias.h"
24#include "src/ast/array.h"
dan sinclair6c498fc2020-04-07 12:47:23 +000025#include "src/ast/assignment_statement.h"
dan sinclaira7d498e2020-09-22 22:07:13 +000026#include "src/ast/bitcast_expression.h"
dan sinclairb7ea6e22020-04-07 12:54:10 +000027#include "src/ast/break_statement.h"
dan sinclair50080b72020-07-21 13:42:13 +000028#include "src/ast/call_statement.h"
dan sinclairaec965e2020-04-07 12:54:29 +000029#include "src/ast/continue_statement.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000030#include "src/ast/depth_texture.h"
Ben Clayton451f2cc2021-05-12 12:54:21 +000031#include "src/ast/disable_validation_decoration.h"
Ben Clayton1d8098a2020-11-30 23:30:58 +000032#include "src/ast/discard_statement.h"
Ben Clayton1d8098a2020-11-30 23:30:58 +000033#include "src/ast/fallthrough_statement.h"
Ben Claytonf4075a72021-07-02 19:27:42 +000034#include "src/ast/for_loop_statement.h"
dan sinclair91c44a52020-04-07 12:55:25 +000035#include "src/ast/if_statement.h"
Ben Claytonb502fdf2021-04-07 08:09:21 +000036#include "src/ast/internal_decoration.h"
James Price989a8e42021-06-28 23:04:43 +000037#include "src/ast/interpolate_decoration.h"
dan sinclairbc71eda2020-04-07 12:55:51 +000038#include "src/ast/loop_statement.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000039#include "src/ast/matrix.h"
James Pricee87ded82021-04-30 17:14:19 +000040#include "src/ast/override_decoration.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000041#include "src/ast/pointer.h"
dan sinclairbf0fff82020-04-07 12:56:24 +000042#include "src/ast/return_statement.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000043#include "src/ast/sampled_texture.h"
44#include "src/ast/sampler.h"
45#include "src/ast/storage_texture.h"
Antonio Maiorano9970ec62021-03-18 17:59:54 +000046#include "src/ast/struct_block_decoration.h"
dan sinclair18b32852020-04-07 12:56:45 +000047#include "src/ast/switch_statement.h"
Ben Claytonf164a4a2021-10-21 20:38:54 +000048#include "src/ast/traverse_expressions.h"
Ben Clayton02ebf0d2021-05-05 09:09:41 +000049#include "src/ast/type_name.h"
dan sinclair327ed1b2020-04-07 19:27:21 +000050#include "src/ast/unary_op_expression.h"
dan sinclairca893e32020-04-07 12:57:12 +000051#include "src/ast/variable_decl_statement.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000052#include "src/ast/vector.h"
Antonio Maioranobfc97942021-04-06 20:41:07 +000053#include "src/ast/workgroup_decoration.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000054#include "src/sem/array.h"
Ben Clayton313e6182021-06-17 19:56:14 +000055#include "src/sem/atomic_type.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000056#include "src/sem/call.h"
Ben Claytonfd35aa82021-07-26 22:19:48 +000057#include "src/sem/depth_multisampled_texture_type.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000058#include "src/sem/depth_texture_type.h"
Ben Clayton6e459fe2021-07-14 09:44:41 +000059#include "src/sem/for_loop_statement.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000060#include "src/sem/function.h"
Ben Clayton6e459fe2021-07-14 09:44:41 +000061#include "src/sem/if_statement.h"
62#include "src/sem/loop_statement.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000063#include "src/sem/member_accessor_expression.h"
Ryan Harrison83116d22021-04-20 16:09:21 +000064#include "src/sem/multisampled_texture_type.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000065#include "src/sem/pointer_type.h"
Ben Clayton9b54a2e2021-05-18 10:28:48 +000066#include "src/sem/reference_type.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000067#include "src/sem/sampled_texture_type.h"
68#include "src/sem/sampler_type.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000069#include "src/sem/statement.h"
Ryan Harrisonde8f1332021-04-20 20:47:51 +000070#include "src/sem/storage_texture_type.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000071#include "src/sem/struct.h"
Ben Clayton6e459fe2021-07-14 09:44:41 +000072#include "src/sem/switch_statement.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000073#include "src/sem/variable.h"
Ben Clayton1b03f0a2021-07-08 21:23:33 +000074#include "src/utils/defer.h"
Antonio Maiorano25436862021-04-13 13:32:33 +000075#include "src/utils/get_or_create.h"
Ben Claytona7520522021-03-15 13:37:41 +000076#include "src/utils/math.h"
Ben Claytonb7bcbf02021-09-08 15:18:36 +000077#include "src/utils/reverse.h"
Ben Claytonb3505002021-05-19 16:11:04 +000078#include "src/utils/scoped_assignment.h"
dan sinclairb7edc4c2020-04-07 12:46:30 +000079
Dan Sinclair6e581892020-03-02 15:47:43 -050080namespace tint {
Ben Claytonc7dcbae2021-03-09 15:08:48 +000081namespace resolver {
Ben Clayton052ab892021-02-08 19:53:42 +000082namespace {
83
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000084using IntrinsicType = tint::sem::IntrinsicType;
Ben Clayton052ab892021-02-08 19:53:42 +000085
Ben Claytonfec63b72021-04-21 13:47:12 +000086bool IsValidStorageTextureDimension(ast::TextureDimension dim) {
Ryan Harrisonde8f1332021-04-20 20:47:51 +000087 switch (dim) {
Ben Claytonfec63b72021-04-21 13:47:12 +000088 case ast::TextureDimension::k1d:
89 case ast::TextureDimension::k2d:
90 case ast::TextureDimension::k2dArray:
91 case ast::TextureDimension::k3d:
Ryan Harrisonde8f1332021-04-20 20:47:51 +000092 return true;
93 default:
94 return false;
95 }
96}
97
Ben Claytonfec63b72021-04-21 13:47:12 +000098bool IsValidStorageTextureImageFormat(ast::ImageFormat format) {
Ryan Harrisonde8f1332021-04-20 20:47:51 +000099 switch (format) {
Ben Claytonfec63b72021-04-21 13:47:12 +0000100 case ast::ImageFormat::kR32Uint:
101 case ast::ImageFormat::kR32Sint:
102 case ast::ImageFormat::kR32Float:
103 case ast::ImageFormat::kRg32Uint:
104 case ast::ImageFormat::kRg32Sint:
105 case ast::ImageFormat::kRg32Float:
106 case ast::ImageFormat::kRgba8Unorm:
107 case ast::ImageFormat::kRgba8Snorm:
108 case ast::ImageFormat::kRgba8Uint:
109 case ast::ImageFormat::kRgba8Sint:
110 case ast::ImageFormat::kRgba16Uint:
111 case ast::ImageFormat::kRgba16Sint:
112 case ast::ImageFormat::kRgba16Float:
113 case ast::ImageFormat::kRgba32Uint:
114 case ast::ImageFormat::kRgba32Sint:
115 case ast::ImageFormat::kRgba32Float:
Ryan Harrisonde8f1332021-04-20 20:47:51 +0000116 return true;
117 default:
118 return false;
119 }
120}
121
Ben Clayton451f2cc2021-05-12 12:54:21 +0000122/// @returns true if the decoration list contains a
123/// ast::DisableValidationDecoration with the validation mode equal to
124/// `validation`
125bool IsValidationDisabled(const ast::DecorationList& decorations,
126 ast::DisabledValidation validation) {
127 for (auto* decoration : decorations) {
128 if (auto* dv = decoration->As<ast::DisableValidationDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000129 if (dv->validation == validation) {
Ben Clayton451f2cc2021-05-12 12:54:21 +0000130 return true;
131 }
132 }
133 }
134 return false;
135}
136
Saraha8f58ef2021-06-30 19:22:30 +0000137/// @returns true if the decoration list does not contains a
138/// ast::DisableValidationDecoration with the validation mode equal to
139/// `validation`
140bool IsValidationEnabled(const ast::DecorationList& decorations,
141 ast::DisabledValidation validation) {
142 return !IsValidationDisabled(decorations, validation);
143}
144
Sarah443c41d2021-06-18 19:58:27 +0000145// Helper to stringify a pipeline IO decoration.
146std::string deco_to_str(const ast::Decoration* deco) {
147 std::stringstream str;
148 if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000149 str << "builtin(" << builtin->builtin << ")";
Sarah443c41d2021-06-18 19:58:27 +0000150 } else if (auto* location = deco->As<ast::LocationDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000151 str << "location(" << location->value << ")";
Sarah443c41d2021-06-18 19:58:27 +0000152 }
153 return str.str();
154}
Ben Clayton052ab892021-02-08 19:53:42 +0000155} // namespace
Dan Sinclair6e581892020-03-02 15:47:43 -0500156
Ben Clayton5f0ea112021-03-09 10:54:37 +0000157Resolver::Resolver(ProgramBuilder* builder)
Ben Claytonb82acac2021-05-06 16:04:03 +0000158 : builder_(builder),
159 diagnostics_(builder->Diagnostics()),
Ben Claytonb29a59d2021-06-01 19:06:31 +0000160 intrinsic_table_(IntrinsicTable::Create(*builder)) {}
Ben Claytond59cedb2021-01-25 18:14:08 +0000161
Ben Clayton5f0ea112021-03-09 10:54:37 +0000162Resolver::~Resolver() = default;
Dan Sinclair6e581892020-03-02 15:47:43 -0500163
Ben Clayton5f0ea112021-03-09 10:54:37 +0000164void Resolver::set_referenced_from_function_if_needed(VariableInfo* var,
165 bool local) {
dan sinclair13d2a3b2020-06-22 20:52:24 +0000166 if (current_function_ == nullptr) {
167 return;
168 }
Ryan Harrison3832b8e2021-06-09 20:45:09 +0000169
170 if (var->kind != VariableKind::kGlobal) {
dan sinclair13d2a3b2020-06-22 20:52:24 +0000171 return;
172 }
173
Ben Claytonf81df122021-02-17 13:10:49 +0000174 current_function_->referenced_module_vars.add(var);
Enrico Galli3d449d22020-12-08 21:07:24 +0000175 if (local) {
Ben Claytonf81df122021-02-17 13:10:49 +0000176 current_function_->local_referenced_module_vars.add(var);
Enrico Galli3d449d22020-12-08 21:07:24 +0000177 }
dan sinclair13d2a3b2020-06-22 20:52:24 +0000178}
179
Ben Clayton5f0ea112021-03-09 10:54:37 +0000180bool Resolver::Resolve() {
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000181 if (builder_->Diagnostics().contains_errors()) {
182 return false;
183 }
184
Ben Clayton5f0ea112021-03-09 10:54:37 +0000185 bool result = ResolveInternal();
Ben Claytonb17aea12021-02-03 17:51:09 +0000186
Ben Claytonb82acac2021-05-06 16:04:03 +0000187 if (!result && !diagnostics_.contains_errors()) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000188 TINT_ICE(Resolver, diagnostics_)
189 << "resolving failed, but no error was raised";
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000190 return false;
191 }
192
Ben Claytonb17aea12021-02-03 17:51:09 +0000193 // Even if resolving failed, create all the semantic nodes for information we
194 // did generate.
195 CreateSemanticNodes();
196
197 return result;
198}
199
James Price3b267172021-06-09 09:12:57 +0000200// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
Antonio Maioranof19e0e42021-06-21 20:51:16 +0000201bool Resolver::IsPlain(const sem::Type* type) const {
Ben Clayton313e6182021-06-17 19:56:14 +0000202 return type->is_scalar() || type->Is<sem::Atomic>() ||
203 type->Is<sem::Vector>() || type->Is<sem::Matrix>() ||
204 type->Is<sem::Array>() || type->Is<sem::Struct>();
James Price3b267172021-06-09 09:12:57 +0000205}
206
207// https://gpuweb.github.io/gpuweb/wgsl.html#storable-types
Antonio Maioranof19e0e42021-06-21 20:51:16 +0000208bool Resolver::IsStorable(const sem::Type* type) const {
Ben Clayton313e6182021-06-17 19:56:14 +0000209 return IsPlain(type) || type->Is<sem::Texture>() || type->Is<sem::Sampler>();
Ben Claytond614dd52021-03-15 10:43:11 +0000210}
211
Ben Clayton722b5a22021-03-18 20:46:24 +0000212// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
Antonio Maioranof19e0e42021-06-21 20:51:16 +0000213bool Resolver::IsHostShareable(const sem::Type* type) const {
Antonio Maiorano3751fd22021-04-19 22:51:23 +0000214 if (type->IsAnyOf<sem::I32, sem::U32, sem::F32>()) {
Ben Clayton722b5a22021-03-18 20:46:24 +0000215 return true;
216 }
Antonio Maiorano3751fd22021-04-19 22:51:23 +0000217 if (auto* vec = type->As<sem::Vector>()) {
Ben Clayton25eef8d2021-03-18 21:03:24 +0000218 return IsHostShareable(vec->type());
Ben Clayton722b5a22021-03-18 20:46:24 +0000219 }
Antonio Maiorano3751fd22021-04-19 22:51:23 +0000220 if (auto* mat = type->As<sem::Matrix>()) {
Ben Clayton25eef8d2021-03-18 21:03:24 +0000221 return IsHostShareable(mat->type());
Ben Clayton722b5a22021-03-18 20:46:24 +0000222 }
Ben Clayton4cd5eea2021-05-07 20:58:34 +0000223 if (auto* arr = type->As<sem::Array>()) {
224 return IsHostShareable(arr->ElemType());
Ben Clayton722b5a22021-03-18 20:46:24 +0000225 }
Ben Claytonba6ab5e2021-05-07 14:49:34 +0000226 if (auto* str = type->As<sem::Struct>()) {
227 for (auto* member : str->Members()) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000228 if (!IsHostShareable(member->Type())) {
Ben Clayton722b5a22021-03-18 20:46:24 +0000229 return false;
230 }
231 }
232 return true;
233 }
Ben Clayton313e6182021-06-17 19:56:14 +0000234 if (auto* atomic = type->As<sem::Atomic>()) {
235 return IsHostShareable(atomic->Type());
236 }
Ben Clayton722b5a22021-03-18 20:46:24 +0000237 return false;
238}
239
Ben Clayton5f0ea112021-03-09 10:54:37 +0000240bool Resolver::ResolveInternal() {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000241 Mark(&builder_->AST());
242
Antonio Maioranobb5617f2021-03-19 18:45:30 +0000243 // Process everything else in the order they appear in the module. This is
244 // necessary for validation of use-before-declaration.
245 for (auto* decl : builder_->AST().GlobalDeclarations()) {
Ben Clayton8758f102021-06-09 14:32:14 +0000246 if (auto* td = decl->As<ast::TypeDecl>()) {
247 Mark(td);
248 if (!TypeDecl(td)) {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000249 return false;
Antonio Maioranobb5617f2021-03-19 18:45:30 +0000250 }
251 } else if (auto* func = decl->As<ast::Function>()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000252 Mark(func);
Antonio Maioranobb5617f2021-03-19 18:45:30 +0000253 if (!Function(func)) {
254 return false;
255 }
256 } else if (auto* var = decl->As<ast::Variable>()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000257 Mark(var);
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000258 if (!GlobalVariable(var)) {
dan sinclair7be237a2020-06-15 20:55:09 +0000259 return false;
260 }
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000261 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +0000262 TINT_UNREACHABLE(Resolver, diagnostics_)
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000263 << "unhandled global declaration: " << decl->TypeInfo().name;
264 return false;
dan sinclair7be237a2020-06-15 20:55:09 +0000265 }
dan sinclair417a90d2020-04-06 21:07:41 +0000266 }
267
James Priceee23c172021-09-30 17:29:50 +0000268 AllocateOverridableConstantIds();
269
Ben Clayton71786c92021-06-03 16:07:34 +0000270 if (!ValidatePipelineStages()) {
271 return false;
272 }
273
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000274 bool result = true;
Ben Clayton6fcefe42021-04-19 19:16:12 +0000275 for (auto* node : builder_->ASTNodes().Objects()) {
276 if (marked_.count(node) == 0) {
Ben Clayton11ed0db2021-10-14 20:30:29 +0000277 TINT_ICE(Resolver, diagnostics_) << "AST node '" << node->TypeInfo().name
278 << "' was not reached by the resolver\n"
Ben Clayton4f3ff572021-10-15 17:33:10 +0000279 << "At: " << node->source << "\n"
Ben Clayton11ed0db2021-10-14 20:30:29 +0000280 << "Pointer: " << node;
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000281 result = false;
Ben Clayton6fcefe42021-04-19 19:16:12 +0000282 }
283 }
284
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000285 return result;
Ben Clayton6fcefe42021-04-19 19:16:12 +0000286}
287
Ben Claytonba6ab5e2021-05-07 14:49:34 +0000288sem::Type* Resolver::Type(const ast::Type* ty) {
Ben Claytonfec63b72021-04-21 13:47:12 +0000289 Mark(ty);
Ben Claytonba6ab5e2021-05-07 14:49:34 +0000290 auto* s = [&]() -> sem::Type* {
Ben Claytonfbec46f2021-04-30 20:20:19 +0000291 if (ty->Is<ast::Void>()) {
292 return builder_->create<sem::Void>();
293 }
294 if (ty->Is<ast::Bool>()) {
295 return builder_->create<sem::Bool>();
296 }
297 if (ty->Is<ast::I32>()) {
298 return builder_->create<sem::I32>();
299 }
300 if (ty->Is<ast::U32>()) {
301 return builder_->create<sem::U32>();
302 }
303 if (ty->Is<ast::F32>()) {
304 return builder_->create<sem::F32>();
305 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000306 if (auto* t = ty->As<ast::Vector>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000307 if (auto* el = Type(t->type)) {
Ben Clayton86481202021-10-19 18:38:54 +0000308 if (auto* vector = builder_->create<sem::Vector>(el, t->width)) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000309 if (ValidateVector(vector, t->source)) {
Ben Claytonffe79782021-07-05 20:21:35 +0000310 return vector;
311 }
312 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000313 }
314 return nullptr;
315 }
316 if (auto* t = ty->As<ast::Matrix>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000317 if (auto* el = Type(t->type)) {
Ben Clayton86481202021-10-19 18:38:54 +0000318 if (auto* column_type = builder_->create<sem::Vector>(el, t->rows)) {
Ben Claytonffe79782021-07-05 20:21:35 +0000319 if (auto* matrix =
Ben Clayton4f3ff572021-10-15 17:33:10 +0000320 builder_->create<sem::Matrix>(column_type, t->columns)) {
321 if (ValidateMatrix(matrix, t->source)) {
Ben Claytonffe79782021-07-05 20:21:35 +0000322 return matrix;
Sarah4d697512021-06-21 17:08:05 +0000323 }
324 }
325 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000326 }
327 return nullptr;
328 }
329 if (auto* t = ty->As<ast::Array>()) {
Ben Clayton4cd5eea2021-05-07 20:58:34 +0000330 return Array(t);
Ben Claytonfbec46f2021-04-30 20:20:19 +0000331 }
Ben Clayton313e6182021-06-17 19:56:14 +0000332 if (auto* t = ty->As<ast::Atomic>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000333 if (auto* el = Type(t->type)) {
Ben Clayton86481202021-10-19 18:38:54 +0000334 auto* a = builder_->create<sem::Atomic>(el);
Ben Clayton313e6182021-06-17 19:56:14 +0000335 if (!ValidateAtomic(t, a)) {
336 return nullptr;
337 }
338 return a;
339 }
340 return nullptr;
341 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000342 if (auto* t = ty->As<ast::Pointer>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000343 if (auto* el = Type(t->type)) {
344 auto access = t->access;
Ben Clayton18588542021-06-04 22:17:37 +0000345 if (access == ast::kUndefined) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000346 access = DefaultAccessForStorageClass(t->storage_class);
Ben Clayton18588542021-06-04 22:17:37 +0000347 }
Ben Clayton86481202021-10-19 18:38:54 +0000348 return builder_->create<sem::Pointer>(el, t->storage_class, access);
Ben Claytonfbec46f2021-04-30 20:20:19 +0000349 }
350 return nullptr;
351 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000352 if (auto* t = ty->As<ast::Sampler>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000353 return builder_->create<sem::Sampler>(t->kind);
Ben Claytonfbec46f2021-04-30 20:20:19 +0000354 }
355 if (auto* t = ty->As<ast::SampledTexture>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000356 if (auto* el = Type(t->type)) {
Ben Clayton86481202021-10-19 18:38:54 +0000357 return builder_->create<sem::SampledTexture>(t->dim, el);
Ben Claytonfbec46f2021-04-30 20:20:19 +0000358 }
359 return nullptr;
360 }
361 if (auto* t = ty->As<ast::MultisampledTexture>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000362 if (auto* el = Type(t->type)) {
Ben Clayton86481202021-10-19 18:38:54 +0000363 return builder_->create<sem::MultisampledTexture>(t->dim, el);
Ben Claytonfbec46f2021-04-30 20:20:19 +0000364 }
365 return nullptr;
366 }
367 if (auto* t = ty->As<ast::DepthTexture>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000368 return builder_->create<sem::DepthTexture>(t->dim);
Ben Claytonfbec46f2021-04-30 20:20:19 +0000369 }
Ben Claytonfd35aa82021-07-26 22:19:48 +0000370 if (auto* t = ty->As<ast::DepthMultisampledTexture>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000371 return builder_->create<sem::DepthMultisampledTexture>(t->dim);
Ben Claytonfd35aa82021-07-26 22:19:48 +0000372 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000373 if (auto* t = ty->As<ast::StorageTexture>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000374 if (auto* el = Type(t->type)) {
Ben Clayton93e8f522021-06-04 20:41:47 +0000375 if (!ValidateStorageTexture(t)) {
Antonio Maiorano6cf7f2e2021-05-21 14:32:38 +0000376 return nullptr;
Antonio Maioranodc4e6c12021-05-14 17:51:13 +0000377 }
Ben Clayton86481202021-10-19 18:38:54 +0000378 return builder_->create<sem::StorageTexture>(t->dim, t->format,
379 t->access, el);
Ben Claytonfbec46f2021-04-30 20:20:19 +0000380 }
381 return nullptr;
382 }
Ryan Harrison0aeb77c2021-05-06 08:20:52 +0000383 if (ty->As<ast::ExternalTexture>()) {
Ben Clayton58f93c92021-05-05 18:00:52 +0000384 return builder_->create<sem::ExternalTexture>();
385 }
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000386 if (auto* t = ty->As<ast::TypeName>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000387 auto it = named_type_info_.find(t->name);
Antonio Maioranoc5f5d362021-05-20 08:44:57 +0000388 if (it == named_type_info_.end()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000389 AddError("unknown type '" + builder_->Symbols().NameFor(t->name) + "'",
390 t->source);
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000391 return nullptr;
392 }
Antonio Maioranoc5f5d362021-05-20 08:44:57 +0000393 return it->second.sem;
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000394 }
Ben Claytonffd28e22021-06-24 11:27:36 +0000395 TINT_UNREACHABLE(Resolver, diagnostics_)
Ben Claytonfbec46f2021-04-30 20:20:19 +0000396 << "Unhandled ast::Type: " << ty->TypeInfo().name;
397 return nullptr;
398 }();
399
Ben Claytonba6ab5e2021-05-07 14:49:34 +0000400 if (s) {
401 builder_->Sem().Add(ty, s);
Ben Claytonfec63b72021-04-21 13:47:12 +0000402 }
Ben Claytonfec63b72021-04-21 13:47:12 +0000403 return s;
404}
405
Ben Clayton313e6182021-06-17 19:56:14 +0000406bool Resolver::ValidateAtomic(const ast::Atomic* a, const sem::Atomic* s) {
407 // https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
408 // T must be either u32 or i32.
409 if (!s->Type()->IsAnyOf<sem::U32, sem::I32>()) {
Ryan Harrison3bcbfc782021-08-11 19:59:44 +0000410 AddError("atomic only supports i32 or u32 types",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000411 a->type ? a->type->source : a->source);
Ben Clayton313e6182021-06-17 19:56:14 +0000412 return false;
413 }
414 return true;
415}
416
Ben Clayton93e8f522021-06-04 20:41:47 +0000417bool Resolver::ValidateStorageTexture(const ast::StorageTexture* t) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000418 switch (t->access) {
Ben Clayton93e8f522021-06-04 20:41:47 +0000419 case ast::Access::kWrite:
420 break;
Ben Claytonf3f2d0a2021-10-14 10:10:45 +0000421 case ast::Access::kUndefined:
Ben Clayton4f3ff572021-10-15 17:33:10 +0000422 AddError("storage texture missing access control", t->source);
Ben Claytonf3f2d0a2021-10-14 10:10:45 +0000423 return false;
424 default:
425 AddError("storage textures currently only support 'write' access control",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000426 t->source);
Ben Claytonf3f2d0a2021-10-14 10:10:45 +0000427 return false;
Ben Clayton93e8f522021-06-04 20:41:47 +0000428 }
429
Ben Clayton4f3ff572021-10-15 17:33:10 +0000430 if (!IsValidStorageTextureDimension(t->dim)) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000431 AddError("cube dimensions for storage textures are not supported",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000432 t->source);
Ben Clayton93e8f522021-06-04 20:41:47 +0000433 return false;
434 }
435
Ben Clayton4f3ff572021-10-15 17:33:10 +0000436 if (!IsValidStorageTextureImageFormat(t->format)) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000437 AddError(
Ben Clayton93e8f522021-06-04 20:41:47 +0000438 "image format must be one of the texel formats specified for storage "
439 "textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000440 t->source);
Ben Clayton93e8f522021-06-04 20:41:47 +0000441 return false;
442 }
443 return true;
444}
445
Ben Clayton86481202021-10-19 18:38:54 +0000446Resolver::VariableInfo* Resolver::Variable(const ast::Variable* var,
Ben Clayton4ffcf062021-07-22 13:24:59 +0000447 VariableKind kind,
448 uint32_t index /* = 0 */) {
Ben Clayton5df76612021-05-12 10:41:21 +0000449 if (variable_to_info_.count(var)) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000450 TINT_ICE(Resolver, diagnostics_)
Ben Clayton4f3ff572021-10-15 17:33:10 +0000451 << "Variable " << builder_->Symbols().NameFor(var->symbol)
Ben Claytonffd28e22021-06-24 11:27:36 +0000452 << " already resolved";
Ben Clayton5df76612021-05-12 10:41:21 +0000453 return nullptr;
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000454 }
455
Ben Clayton5df76612021-05-12 10:41:21 +0000456 std::string type_name;
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000457 const sem::Type* storage_type = nullptr;
458
459 // If the variable has a declared type, resolve it.
Ben Clayton4f3ff572021-10-15 17:33:10 +0000460 if (auto* ty = var->type) {
Ben Clayton5df76612021-05-12 10:41:21 +0000461 type_name = ty->FriendlyName(builder_->Symbols());
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000462 storage_type = Type(ty);
463 if (!storage_type) {
Ben Clayton5df76612021-05-12 10:41:21 +0000464 return nullptr;
465 }
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000466 }
Ben Clayton5df76612021-05-12 10:41:21 +0000467
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000468 std::string rhs_type_name;
469 const sem::Type* rhs_type = nullptr;
470
Ben Clayton5df76612021-05-12 10:41:21 +0000471 // Does the variable have a constructor?
Ben Clayton4f3ff572021-10-15 17:33:10 +0000472 if (auto* ctor = var->constructor) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000473 if (!Expression(var->constructor)) {
Ben Clayton5df76612021-05-12 10:41:21 +0000474 return nullptr;
475 }
476
477 // Fetch the constructor's type
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000478 rhs_type_name = TypeNameOf(ctor);
479 rhs_type = TypeOf(ctor);
Ben Clayton5df76612021-05-12 10:41:21 +0000480 if (!rhs_type) {
481 return nullptr;
482 }
483
484 // If the variable has no declared type, infer it from the RHS
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000485 if (!storage_type) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000486 if (!var->is_const && kind == VariableKind::kGlobal) {
487 AddError("global var declaration must specify a type", var->source);
Antonio Maiorano9834fef2021-06-04 15:28:47 +0000488 return nullptr;
489 }
490
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000491 type_name = rhs_type_name;
492 storage_type = rhs_type->UnwrapRef(); // Implicit load of RHS
Ben Clayton5df76612021-05-12 10:41:21 +0000493 }
Ben Clayton4f3ff572021-10-15 17:33:10 +0000494 } else if (var->is_const && kind != VariableKind::kParameter &&
495 !ast::HasDecoration<ast::OverrideDecoration>(var->decorations)) {
496 AddError("let declaration must have an initializer", var->source);
Ben Claytonb291cfc2021-07-19 19:50:52 +0000497 return nullptr;
Ben Clayton4f3ff572021-10-15 17:33:10 +0000498 } else if (!var->type) {
Ben Claytonb291cfc2021-07-19 19:50:52 +0000499 AddError(
500 (kind == VariableKind::kGlobal)
501 ? "module scope var declaration requires a type and initializer"
502 : "function scope var declaration requires a type or initializer",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000503 var->source);
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000504 return nullptr;
Ben Clayton109b18f2021-04-28 13:50:43 +0000505 }
506
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000507 if (!storage_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000508 TINT_ICE(Resolver, diagnostics_)
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000509 << "failed to determine storage type for variable '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +0000510 builder_->Symbols().NameFor(var->symbol) + "'\n"
511 << "Source: " << var->source;
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000512 return nullptr;
513 }
514
Ben Clayton4f3ff572021-10-15 17:33:10 +0000515 auto storage_class = var->declared_storage_class;
516 if (storage_class == ast::StorageClass::kNone && !var->is_const) {
Ben Clayton231648c2021-08-27 14:54:47 +0000517 // No declared storage class. Infer from usage / type.
518 if (kind == VariableKind::kLocal) {
519 storage_class = ast::StorageClass::kFunction;
520 } else if (storage_type->UnwrapRef()->is_handle()) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000521 // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
522 // If the store type is a texture type or a sampler type, then the
523 // variable declaration must not have a storage class decoration. The
524 // storage class will always be handle.
525 storage_class = ast::StorageClass::kUniformConstant;
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000526 }
527 }
528
Ben Clayton4f3ff572021-10-15 17:33:10 +0000529 auto access = var->declared_access;
Ben Clayton18588542021-06-04 22:17:37 +0000530 if (access == ast::Access::kUndefined) {
531 access = DefaultAccessForStorageClass(storage_class);
532 }
533
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000534 auto* type = storage_type;
Ben Clayton4f3ff572021-10-15 17:33:10 +0000535 if (!var->is_const) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000536 // Variable declaration. Unlike `let`, `var` has storage.
537 // Variables are always of a reference type to the declared storage type.
Ben Clayton18588542021-06-04 22:17:37 +0000538 type =
539 builder_->create<sem::Reference>(storage_type, storage_class, access);
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000540 }
541
Ben Clayton231648c2021-08-27 14:54:47 +0000542 if (rhs_type &&
543 !ValidateVariableConstructor(var, storage_class, storage_type, type_name,
544 rhs_type, rhs_type_name)) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000545 return nullptr;
546 }
547
Ben Clayton4ffcf062021-07-22 13:24:59 +0000548 auto* info =
549 variable_infos_.Create(var, const_cast<sem::Type*>(type), type_name,
550 storage_class, access, kind, index);
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000551 variable_to_info_.emplace(var, info);
552
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000553 return info;
554}
555
Ben Clayton9545fb72021-07-06 10:20:19 +0000556ast::Access Resolver::DefaultAccessForStorageClass(
Ben Clayton18588542021-06-04 22:17:37 +0000557 ast::StorageClass storage_class) {
558 // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
559 switch (storage_class) {
560 case ast::StorageClass::kStorage:
Ben Clayton18588542021-06-04 22:17:37 +0000561 case ast::StorageClass::kUniform:
562 case ast::StorageClass::kUniformConstant:
563 return ast::Access::kRead;
564 default:
565 break;
566 }
567 return ast::Access::kReadWrite;
568}
569
James Priceee23c172021-09-30 17:29:50 +0000570void Resolver::AllocateOverridableConstantIds() {
571 // The next pipeline constant ID to try to allocate.
572 uint16_t next_constant_id = 0;
573
574 // Allocate constant IDs in global declaration order, so that they are
575 // deterministic.
576 // TODO(crbug.com/tint/1192): If a transform changes the order or removes an
577 // unused constant, the allocation may change on the next Resolver pass.
578 for (auto* decl : builder_->AST().GlobalDeclarations()) {
579 auto* var = decl->As<ast::Variable>();
580 if (!var) {
581 continue;
582 }
583 auto* override_deco =
Ben Clayton4f3ff572021-10-15 17:33:10 +0000584 ast::GetDecoration<ast::OverrideDecoration>(var->decorations);
James Priceee23c172021-09-30 17:29:50 +0000585 if (!override_deco) {
586 continue;
587 }
588
589 uint16_t constant_id;
Ben Clayton4f3ff572021-10-15 17:33:10 +0000590 if (override_deco->has_value) {
591 constant_id = static_cast<uint16_t>(override_deco->value);
James Priceee23c172021-09-30 17:29:50 +0000592 } else {
593 // No ID was specified, so allocate the next available ID.
594 constant_id = next_constant_id;
595 while (constant_ids_.count(constant_id)) {
596 if (constant_id == UINT16_MAX) {
597 TINT_ICE(Resolver, builder_->Diagnostics())
598 << "no more pipeline constant IDs available";
599 return;
600 }
601 constant_id++;
602 }
603 next_constant_id = constant_id + 1;
604 }
605
606 variable_to_info_[var]->constant_id = constant_id;
607 }
608}
609
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000610bool Resolver::ValidateVariableConstructor(const ast::Variable* var,
Ben Clayton231648c2021-08-27 14:54:47 +0000611 ast::StorageClass storage_class,
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000612 const sem::Type* storage_type,
613 const std::string& type_name,
614 const sem::Type* rhs_type,
615 const std::string& rhs_type_name) {
616 auto* value_type = rhs_type->UnwrapRef(); // Implicit load of RHS
617
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000618 // Value type has to match storage type
Antonio Maioranobe607c02021-05-18 15:26:40 +0000619 if (storage_type != value_type) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000620 std::string decl = var->is_const ? "let" : "var";
Ben Claytonffd28e22021-06-24 11:27:36 +0000621 AddError("cannot initialize " + decl + " of type '" + type_name +
622 "' with value of type '" + rhs_type_name + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000623 var->source);
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000624 return false;
625 }
Ben Clayton231648c2021-08-27 14:54:47 +0000626
Ben Clayton4f3ff572021-10-15 17:33:10 +0000627 if (!var->is_const) {
Ben Clayton231648c2021-08-27 14:54:47 +0000628 switch (storage_class) {
629 case ast::StorageClass::kPrivate:
630 case ast::StorageClass::kFunction:
631 break; // Allowed an initializer
632 default:
633 // https://gpuweb.github.io/gpuweb/wgsl/#var-and-let
634 // Optionally has an initializer expression, if the variable is in the
635 // private or function storage classes.
636 AddError("var of storage class '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +0000637 std::string(ast::ToString(storage_class)) +
Ben Clayton231648c2021-08-27 14:54:47 +0000638 "' cannot have an initializer. var initializers are only "
639 "supported for the storage classes "
640 "'private' and 'function'",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000641 var->source);
Ben Clayton231648c2021-08-27 14:54:47 +0000642 return false;
643 }
644 }
645
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000646 return true;
647}
648
Ben Clayton86481202021-10-19 18:38:54 +0000649bool Resolver::GlobalVariable(const ast::Variable* var) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000650 if (!ValidateNoDuplicateDefinition(var->symbol, var->source,
Sarahc0353662021-06-29 21:30:37 +0000651 /* check_global_scope_only */ true)) {
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000652 return false;
653 }
654
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000655 auto* info = Variable(var, VariableKind::kGlobal);
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000656 if (!info) {
657 return false;
658 }
Ben Clayton4f3ff572021-10-15 17:33:10 +0000659 variable_stack_.set_global(var->symbol, info);
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000660
Ben Clayton4f3ff572021-10-15 17:33:10 +0000661 if (!var->is_const && info->storage_class == ast::StorageClass::kNone) {
662 AddError("global variables must have a storage class", var->source);
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000663 return false;
664 }
Ben Clayton4f3ff572021-10-15 17:33:10 +0000665 if (var->is_const && !(info->storage_class == ast::StorageClass::kNone)) {
666 AddError("global constants shouldn't have a storage class", var->source);
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000667 return false;
668 }
669
Ben Clayton4f3ff572021-10-15 17:33:10 +0000670 for (auto* deco : var->decorations) {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000671 Mark(deco);
James Pricef2f3bfc2021-05-13 20:32:32 +0000672
673 if (auto* override_deco = deco->As<ast::OverrideDecoration>()) {
674 // Track the constant IDs that are specified in the shader.
Ben Clayton4f3ff572021-10-15 17:33:10 +0000675 if (override_deco->has_value) {
676 constant_ids_.emplace(override_deco->value, info);
James Pricef2f3bfc2021-05-13 20:32:32 +0000677 }
678 }
Ben Clayton3f968e72021-05-10 19:16:46 +0000679 }
680
Ben Clayton4f3ff572021-10-15 17:33:10 +0000681 if (!ValidateNoDuplicateDecorations(var->decorations)) {
Ben Clayton241c16d2021-06-09 18:53:57 +0000682 return false;
683 }
684
Ben Clayton4f3ff572021-10-15 17:33:10 +0000685 if (auto bp = var->BindingPoint()) {
686 info->binding_point = {bp.group->value, bp.binding->value};
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000687 }
688
Ben Clayton85bfea62021-04-19 20:20:33 +0000689 if (!ValidateGlobalVariable(info)) {
690 return false;
691 }
692
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000693 if (!ApplyStorageClassUsageToType(
694 info->storage_class, const_cast<sem::Type*>(info->type->UnwrapRef()),
Ben Clayton4f3ff572021-10-15 17:33:10 +0000695 var->source)) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000696 AddNote("while instantiating variable " +
Ben Clayton4f3ff572021-10-15 17:33:10 +0000697 builder_->Symbols().NameFor(var->symbol),
698 var->source);
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000699 return false;
700 }
701
Antonio Maiorano60dae242021-07-15 19:09:25 +0000702 // TODO(bclayton): Call this at the end of resolve on all uniform and storage
703 // referenced structs
704 if (!ValidateStorageClassLayout(info)) {
705 return false;
706 }
707
708 return true;
709}
710
711bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
712 ast::StorageClass sc) {
713 // https://gpuweb.github.io/gpuweb/wgsl/#storage-class-layout-constraints
714
715 auto is_uniform_struct_or_array = [sc](const sem::Type* ty) {
716 return sc == ast::StorageClass::kUniform &&
717 ty->IsAnyOf<sem::Array, sem::Struct>();
718 };
719
720 auto is_uniform_struct = [sc](const sem::Type* ty) {
721 return sc == ast::StorageClass::kUniform && ty->Is<sem::Struct>();
722 };
723
724 auto required_alignment_of = [&](const sem::Type* ty) {
Ben Claytonfced3502021-07-22 18:56:54 +0000725 uint32_t actual_align = ty->Align();
Antonio Maiorano60dae242021-07-15 19:09:25 +0000726 uint32_t required_align = actual_align;
727 if (is_uniform_struct_or_array(ty)) {
728 required_align = utils::RoundUp(16u, actual_align);
729 }
730 return required_align;
731 };
732
733 auto member_name_of = [this](const sem::StructMember* sm) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000734 return builder_->Symbols().NameFor(sm->Declaration()->symbol);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000735 };
736
737 auto type_name_of = [this](const sem::StructMember* sm) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000738 return sm->Declaration()->type->FriendlyName(builder_->Symbols());
Antonio Maiorano60dae242021-07-15 19:09:25 +0000739 };
740
741 // TODO(amaiorano): Output struct and member decorations so that this output
742 // can be copied verbatim back into source
743 auto get_struct_layout_string = [&](const sem::Struct* st) -> std::string {
744 std::stringstream ss;
745
746 if (st->Members().empty()) {
747 TINT_ICE(Resolver, diagnostics_) << "Validation should have ensured that "
748 "structs have at least one member";
749 return {};
750 }
751 const auto* const last_member = st->Members().back();
752 const uint32_t last_member_struct_padding_offset =
753 last_member->Offset() + last_member->Size();
754
755 // Compute max widths to align output
756 const auto offset_w =
757 static_cast<int>(::log10(last_member_struct_padding_offset)) + 1;
758 const auto size_w = static_cast<int>(::log10(st->Size())) + 1;
759 const auto align_w = static_cast<int>(::log10(st->Align())) + 1;
760
761 auto print_struct_begin_line = [&](size_t align, size_t size,
762 std::string struct_name) {
763 ss << "/* " << std::setw(offset_w) << " "
764 << "align(" << std::setw(align_w) << align << ") size("
765 << std::setw(size_w) << size << ") */ struct " << struct_name
766 << " {\n";
767 };
768
769 auto print_struct_end_line = [&]() {
770 ss << "/* "
771 << std::setw(offset_w + size_w + align_w) << " "
772 << "*/ };";
773 };
774
775 auto print_member_line = [&](size_t offset, size_t align, size_t size,
776 std::string s) {
777 ss << "/* offset(" << std::setw(offset_w) << offset << ") align("
778 << std::setw(align_w) << align << ") size(" << std::setw(size_w)
779 << size << ") */ " << s << ";\n";
780 };
781
782 print_struct_begin_line(st->Align(), st->Size(),
783 st->FriendlyName(builder_->Symbols()));
784
785 for (size_t i = 0; i < st->Members().size(); ++i) {
786 auto* const m = st->Members()[i];
787
788 // Output field alignment padding, if any
789 auto* const prev_member = (i == 0) ? nullptr : str->Members()[i - 1];
790 if (prev_member) {
791 uint32_t padding =
792 m->Offset() - (prev_member->Offset() + prev_member->Size());
793 if (padding > 0) {
794 size_t padding_offset = m->Offset() - padding;
795 print_member_line(padding_offset, 1, padding,
796 "// -- implicit field alignment padding --");
797 }
798 }
799
800 // Output member
801 std::string member_name = member_name_of(m);
802 print_member_line(m->Offset(), m->Align(), m->Size(),
803 member_name_of(m) + " : " + type_name_of(m));
804 }
805
806 // Output struct size padding, if any
807 uint32_t struct_padding = st->Size() - last_member_struct_padding_offset;
808 if (struct_padding > 0) {
809 print_member_line(last_member_struct_padding_offset, 1, struct_padding,
810 "// -- implicit struct size padding --");
811 }
812
813 print_struct_end_line();
814
815 return ss.str();
816 };
817
818 if (!ast::IsHostShareable(sc)) {
819 return true;
820 }
821
822 for (size_t i = 0; i < str->Members().size(); ++i) {
823 auto* const m = str->Members()[i];
824 uint32_t required_align = required_alignment_of(m->Type());
825
826 // Validate that member is at a valid byte offset
827 if (m->Offset() % required_align != 0) {
828 AddError("the offset of a struct member of type '" + type_name_of(m) +
Ben Clayton4f3ff572021-10-15 17:33:10 +0000829 "' in storage class '" + ast::ToString(sc) +
Antonio Maiorano60dae242021-07-15 19:09:25 +0000830 "' must be a multiple of " + std::to_string(required_align) +
831 " bytes, but '" + member_name_of(m) +
832 "' is currently at offset " + std::to_string(m->Offset()) +
833 ". Consider setting [[align(" +
834 std::to_string(required_align) + ")]] on this member",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000835 m->Declaration()->source);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000836
837 AddNote("see layout of struct:\n" + get_struct_layout_string(str),
Ben Clayton4f3ff572021-10-15 17:33:10 +0000838 str->Declaration()->source);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000839
840 if (auto* member_str = m->Type()->As<sem::Struct>()) {
841 AddNote("and layout of struct member:\n" +
842 get_struct_layout_string(member_str),
Ben Clayton4f3ff572021-10-15 17:33:10 +0000843 member_str->Declaration()->source);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000844 }
845
846 return false;
847 }
848
849 // For uniform buffers, validate that the number of bytes between the
850 // previous member of type struct and the current is a multiple of 16 bytes.
851 auto* const prev_member = (i == 0) ? nullptr : str->Members()[i - 1];
852 if (prev_member && is_uniform_struct(prev_member->Type())) {
853 const uint32_t prev_to_curr_offset = m->Offset() - prev_member->Offset();
854 if (prev_to_curr_offset % 16 != 0) {
855 AddError(
856 "uniform storage requires that the number of bytes between the "
857 "start of the previous member of type struct and the current "
858 "member be a multiple of 16 bytes, but there are currently " +
859 std::to_string(prev_to_curr_offset) + " bytes between '" +
860 member_name_of(prev_member) + "' and '" + member_name_of(m) +
861 "'. Consider setting [[align(16)]] on this member",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000862 m->Declaration()->source);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000863
864 AddNote("see layout of struct:\n" + get_struct_layout_string(str),
Ben Clayton4f3ff572021-10-15 17:33:10 +0000865 str->Declaration()->source);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000866
867 auto* prev_member_str = prev_member->Type()->As<sem::Struct>();
868 AddNote("and layout of previous member struct:\n" +
869 get_struct_layout_string(prev_member_str),
Ben Clayton4f3ff572021-10-15 17:33:10 +0000870 prev_member_str->Declaration()->source);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000871 return false;
872 }
873 }
874
875 // For uniform buffer array members, validate that array elements are
876 // aligned to 16 bytes
877 if (auto* arr = m->Type()->As<sem::Array>()) {
878 if (sc == ast::StorageClass::kUniform) {
879 // We already validated that this array member is itself aligned to 16
880 // bytes above, so we only need to validate that stride is a multiple of
881 // 16 bytes.
882 if (arr->Stride() % 16 != 0) {
883 AddError(
884 "uniform storage requires that array elements be aligned to 16 "
885 "bytes, but array stride of '" +
886 member_name_of(m) + "' is currently " +
887 std::to_string(arr->Stride()) +
888 ". Consider setting [[stride(" +
889 std::to_string(
890 utils::RoundUp(required_align, arr->Stride())) +
891 ")]] on the array type",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000892 m->Declaration()->type->source);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000893 AddNote("see layout of struct:\n" + get_struct_layout_string(str),
Ben Clayton4f3ff572021-10-15 17:33:10 +0000894 str->Declaration()->source);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000895 return false;
896 }
897 }
898 }
899
900 // If member is struct, recurse
901 if (auto* str_member = m->Type()->As<sem::Struct>()) {
902 // Cache result of struct + storage class pair
903 if (valid_struct_storage_layouts_.emplace(str_member, sc).second) {
904 if (!ValidateStorageClassLayout(str_member, sc)) {
905 return false;
906 }
907 }
908 }
909 }
910
911 return true;
912}
913
914bool Resolver::ValidateStorageClassLayout(const VariableInfo* info) {
915 if (auto* str = info->type->UnwrapRef()->As<sem::Struct>()) {
916 if (!ValidateStorageClassLayout(str, info->storage_class)) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000917 AddNote("see declaration of variable", info->declaration->source);
Antonio Maiorano60dae242021-07-15 19:09:25 +0000918 return false;
919 }
920 }
921
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000922 return true;
923}
924
Ben Clayton85bfea62021-04-19 20:20:33 +0000925bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000926 if (!ValidateNoDuplicateDecorations(info->declaration->decorations)) {
Ben Clayton241c16d2021-06-09 18:53:57 +0000927 return false;
928 }
929
Ben Clayton4f3ff572021-10-15 17:33:10 +0000930 for (auto* deco : info->declaration->decorations) {
931 if (info->declaration->is_const) {
James Pricef2f3bfc2021-05-13 20:32:32 +0000932 if (auto* override_deco = deco->As<ast::OverrideDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000933 if (override_deco->has_value) {
934 uint32_t id = override_deco->value;
James Pricef2f3bfc2021-05-13 20:32:32 +0000935 auto itr = constant_ids_.find(id);
936 if (itr != constant_ids_.end() && itr->second != info) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000937 AddError("pipeline constant IDs must be unique", deco->source);
Ben Claytonffd28e22021-06-24 11:27:36 +0000938 AddNote("a pipeline constant with an ID of " + std::to_string(id) +
939 " was previously declared "
940 "here:",
941 ast::GetDecoration<ast::OverrideDecoration>(
Ben Clayton4f3ff572021-10-15 17:33:10 +0000942 itr->second->declaration->decorations)
943 ->source);
James Pricef2f3bfc2021-05-13 20:32:32 +0000944 return false;
945 }
946 if (id > 65535) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000947 AddError("pipeline constant IDs must be between 0 and 65535",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000948 deco->source);
James Pricef2f3bfc2021-05-13 20:32:32 +0000949 return false;
950 }
951 }
952 } else {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000953 AddError("decoration is not valid for constants", deco->source);
Ben Clayton3f968e72021-05-10 19:16:46 +0000954 return false;
955 }
956 } else {
James Price14c0b8a2021-06-24 15:53:26 +0000957 bool is_shader_io_decoration =
James Price989a8e42021-06-28 23:04:43 +0000958 deco->IsAnyOf<ast::BuiltinDecoration, ast::InterpolateDecoration,
James Price508d2492021-07-12 12:12:32 +0000959 ast::InvariantDecoration, ast::LocationDecoration>();
James Price14c0b8a2021-06-24 15:53:26 +0000960 bool has_io_storage_class =
961 info->storage_class == ast::StorageClass::kInput ||
962 info->storage_class == ast::StorageClass::kOutput;
963 if (!(deco->IsAnyOf<ast::BindingDecoration, ast::GroupDecoration,
964 ast::InternalDecoration>()) &&
965 (!is_shader_io_decoration || !has_io_storage_class)) {
Ben Clayton4f3ff572021-10-15 17:33:10 +0000966 AddError("decoration is not valid for variables", deco->source);
Ben Clayton3f968e72021-05-10 19:16:46 +0000967 return false;
968 }
969 }
970 }
971
Ben Clayton4f3ff572021-10-15 17:33:10 +0000972 auto binding_point = info->declaration->BindingPoint();
Ben Clayton3f968e72021-05-10 19:16:46 +0000973 switch (info->storage_class) {
974 case ast::StorageClass::kUniform:
975 case ast::StorageClass::kStorage:
976 case ast::StorageClass::kUniformConstant: {
977 // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
978 // Each resource variable must be declared with both group and binding
979 // attributes.
980 if (!binding_point) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000981 AddError(
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000982 "resource variables require [[group]] and [[binding]] "
983 "decorations",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000984 info->declaration->source);
Ben Clayton3f968e72021-05-10 19:16:46 +0000985 return false;
986 }
987 break;
988 }
989 default:
990 if (binding_point.binding || binding_point.group) {
991 // https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
992 // Must only be applied to a resource variable
Ben Claytonffd28e22021-06-24 11:27:36 +0000993 AddError(
Ben Clayton3f968e72021-05-10 19:16:46 +0000994 "non-resource variables must not have [[group]] or [[binding]] "
995 "decorations",
Ben Clayton4f3ff572021-10-15 17:33:10 +0000996 info->declaration->source);
Ben Clayton3f968e72021-05-10 19:16:46 +0000997 return false;
998 }
999 }
1000
Ben Clayton93e8f522021-06-04 20:41:47 +00001001 // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
1002 // The access mode always has a default, and except for variables in the
1003 // storage storage class, must not be written.
1004 if (info->storage_class != ast::StorageClass::kStorage &&
Ben Clayton4f3ff572021-10-15 17:33:10 +00001005 info->declaration->declared_access != ast::Access::kUndefined) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001006 AddError(
Sarah4038fa72021-08-05 15:18:29 +00001007 "only variables in <storage> storage class may declare an access mode",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001008 info->declaration->source);
Ben Clayton93e8f522021-06-04 20:41:47 +00001009 return false;
1010 }
1011
Ben Clayton42708342021-04-21 17:55:12 +00001012 switch (info->storage_class) {
1013 case ast::StorageClass::kStorage: {
Ben Clayton42708342021-04-21 17:55:12 +00001014 // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
1015 // A variable in the storage storage class is a storage buffer variable.
1016 // Its store type must be a host-shareable structure type with block
1017 // attribute, satisfying the storage class constraints.
Ben Clayton85bfea62021-04-19 20:20:33 +00001018
Ben Clayton93e8f522021-06-04 20:41:47 +00001019 auto* str = info->type->UnwrapRef()->As<sem::Struct>();
Antonio Maioranodc4e6c12021-05-14 17:51:13 +00001020
Ben Clayton42708342021-04-21 17:55:12 +00001021 if (!str) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001022 AddError(
Ben Clayton93e8f522021-06-04 20:41:47 +00001023 "variables declared in the <storage> storage class must be of a "
1024 "structure type",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001025 info->declaration->source);
Ben Clayton42708342021-04-21 17:55:12 +00001026 return false;
Ben Clayton85bfea62021-04-19 20:20:33 +00001027 }
Ben Clayton42708342021-04-21 17:55:12 +00001028
1029 if (!str->IsBlockDecorated()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001030 AddError(
Ben Clayton42708342021-04-21 17:55:12 +00001031 "structure used as a storage buffer must be declared with the "
1032 "[[block]] decoration",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001033 str->Declaration()->source);
1034 if (info->declaration->source.range.begin.line) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001035 AddNote("structure used as storage buffer here",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001036 info->declaration->source);
Ben Clayton42708342021-04-21 17:55:12 +00001037 }
1038 return false;
1039 }
1040 break;
Ben Clayton85bfea62021-04-19 20:20:33 +00001041 }
Ben Clayton42708342021-04-21 17:55:12 +00001042 case ast::StorageClass::kUniform: {
1043 // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
1044 // A variable in the uniform storage class is a uniform buffer variable.
1045 // Its store type must be a host-shareable structure type with block
1046 // attribute, satisfying the storage class constraints.
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001047 auto* str = info->type->UnwrapRef()->As<sem::Struct>();
Ben Clayton42708342021-04-21 17:55:12 +00001048 if (!str) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001049 AddError(
Ben Clayton42708342021-04-21 17:55:12 +00001050 "variables declared in the <uniform> storage class must be of a "
1051 "structure type",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001052 info->declaration->source);
Ben Clayton42708342021-04-21 17:55:12 +00001053 return false;
1054 }
1055
1056 if (!str->IsBlockDecorated()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001057 AddError(
Ben Clayton42708342021-04-21 17:55:12 +00001058 "structure used as a uniform buffer must be declared with the "
1059 "[[block]] decoration",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001060 str->Declaration()->source);
1061 if (info->declaration->source.range.begin.line) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001062 AddNote("structure used as uniform buffer here",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001063 info->declaration->source);
Ben Clayton42708342021-04-21 17:55:12 +00001064 }
1065 return false;
1066 }
Sarah52b6a002021-06-16 19:40:13 +00001067
1068 for (auto* member : str->Members()) {
1069 if (auto* arr = member->Type()->As<sem::Array>()) {
1070 if (arr->IsRuntimeSized()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001071 AddError(
Sarah52b6a002021-06-16 19:40:13 +00001072 "structure containing a runtime sized array "
1073 "cannot be used as a uniform buffer",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001074 info->declaration->source);
1075 AddNote("structure is declared here", str->Declaration()->source);
Sarah52b6a002021-06-16 19:40:13 +00001076 return false;
1077 }
1078 }
1079 }
1080
Ben Clayton42708342021-04-21 17:55:12 +00001081 break;
1082 }
1083 default:
1084 break;
Ben Clayton85bfea62021-04-19 20:20:33 +00001085 }
1086
Ben Clayton4f3ff572021-10-15 17:33:10 +00001087 if (!info->declaration->is_const) {
Sarah4038fa72021-08-05 15:18:29 +00001088 if (!ValidateAtomicVariable(info)) {
1089 return false;
1090 }
1091 }
1092
Ben Claytonfcda15e2021-05-10 18:01:51 +00001093 return ValidateVariable(info);
Ben Clayton85bfea62021-04-19 20:20:33 +00001094}
1095
Sarah4038fa72021-08-05 15:18:29 +00001096// https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
1097// Atomic types may only be instantiated by variables in the workgroup storage
1098// class or by storage buffer variables with a read_write access mode.
1099bool Resolver::ValidateAtomicVariable(const VariableInfo* info) {
1100 auto sc = info->storage_class;
1101 auto access = info->access;
1102 auto* type = info->type->UnwrapRef();
Ben Clayton4f3ff572021-10-15 17:33:10 +00001103 auto source = info->declaration->type ? info->declaration->type->source
1104 : info->declaration->source;
Sarah4038fa72021-08-05 15:18:29 +00001105
1106 if (type->Is<sem::Atomic>()) {
1107 if (sc != ast::StorageClass::kWorkgroup) {
1108 AddError(
1109 "atomic variables must have <storage> or <workgroup> storage class",
Ryan Harrison3bcbfc782021-08-11 19:59:44 +00001110 source);
Sarah4038fa72021-08-05 15:18:29 +00001111 return false;
1112 }
1113 } else if (type->IsAnyOf<sem::Struct, sem::Array>()) {
1114 auto found = atomic_composite_info_.find(type);
1115 if (found != atomic_composite_info_.end()) {
1116 if (sc != ast::StorageClass::kStorage &&
1117 sc != ast::StorageClass::kWorkgroup) {
1118 AddError(
1119 "atomic variables must have <storage> or <workgroup> storage class",
1120 source);
1121 AddNote("atomic sub-type of '" +
1122 type->FriendlyName(builder_->Symbols()) +
1123 "' is declared here",
1124 found->second);
1125 return false;
1126 } else if (sc == ast::StorageClass::kStorage &&
1127 access != ast::Access::kReadWrite) {
1128 AddError(
1129 "atomic variables in <storage> storage class must have read_write "
1130 "access mode",
1131 source);
1132 AddNote("atomic sub-type of '" +
1133 type->FriendlyName(builder_->Symbols()) +
1134 "' is declared here",
1135 found->second);
1136 return false;
1137 }
1138 }
1139 }
1140
1141 return true;
1142}
1143
Ben Claytonfcda15e2021-05-10 18:01:51 +00001144bool Resolver::ValidateVariable(const VariableInfo* info) {
1145 auto* var = info->declaration;
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001146 auto* storage_type = info->type->UnwrapRef();
James Price3b267172021-06-09 09:12:57 +00001147
Ben Clayton4f3ff572021-10-15 17:33:10 +00001148 if (!var->is_const && !IsStorable(storage_type)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001149 AddError(storage_type->FriendlyName(builder_->Symbols()) +
1150 " cannot be used as the type of a var",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001151 var->source);
James Price3b267172021-06-09 09:12:57 +00001152 return false;
1153 }
1154
Ben Clayton4f3ff572021-10-15 17:33:10 +00001155 if (var->is_const && info->kind != VariableKind::kParameter &&
James Priced12379a2021-07-26 22:11:58 +00001156 !(storage_type->IsConstructible() || storage_type->Is<sem::Pointer>())) {
1157 AddError(storage_type->FriendlyName(builder_->Symbols()) +
1158 " cannot be used as the type of a let",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001159 var->source);
James Priced12379a2021-07-26 22:11:58 +00001160 return false;
1161 }
1162
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001163 if (auto* r = storage_type->As<sem::Array>()) {
Ben Clayton4cd5eea2021-05-07 20:58:34 +00001164 if (r->IsRuntimeSized()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00001165 AddError("runtime arrays may only appear as the last member of a struct",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001166 var->source);
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001167 return false;
1168 }
1169 }
Ryan Harrison83116d22021-04-20 16:09:21 +00001170
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001171 if (auto* r = storage_type->As<sem::MultisampledTexture>()) {
Ben Claytonfec63b72021-04-21 13:47:12 +00001172 if (r->dim() != ast::TextureDimension::k2d) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001173 AddError("only 2d multisampled textures are supported", var->source);
Ryan Harrison83116d22021-04-20 16:09:21 +00001174 return false;
1175 }
1176
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001177 if (!r->type()->UnwrapRef()->is_numeric_scalar()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001178 AddError("texture_multisampled_2d<type>: type must be f32, i32 or u32",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001179 var->source);
Ryan Harrison83116d22021-04-20 16:09:21 +00001180 return false;
1181 }
1182 }
1183
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001184 if (storage_type->is_handle() &&
Ben Clayton4f3ff572021-10-15 17:33:10 +00001185 var->declared_storage_class != ast::StorageClass::kNone) {
Ben Claytonfcda15e2021-05-10 18:01:51 +00001186 // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001187 // If the store type is a texture type or a sampler type, then the
1188 // variable declaration must not have a storage class decoration. The
1189 // storage class will always be handle.
Ben Claytonffd28e22021-06-24 11:27:36 +00001190 AddError("variables of type '" + info->type_name +
1191 "' must not have a storage class",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001192 var->source);
Ben Claytonfcda15e2021-05-10 18:01:51 +00001193 return false;
1194 }
1195
Ben Clayton4f3ff572021-10-15 17:33:10 +00001196 if (IsValidationEnabled(var->decorations,
Saraha8f58ef2021-06-30 19:22:30 +00001197 ast::DisabledValidation::kIgnoreStorageClass) &&
Ben Clayton4f3ff572021-10-15 17:33:10 +00001198 (var->declared_storage_class == ast::StorageClass::kInput ||
1199 var->declared_storage_class == ast::StorageClass::kOutput)) {
1200 AddError("invalid use of input/output storage class", var->source);
James Price14c0b8a2021-06-24 15:53:26 +00001201 return false;
1202 }
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001203 return true;
1204}
1205
Sarah9432c972021-06-29 15:24:04 +00001206bool Resolver::ValidateFunctionParameter(const ast::Function* func,
1207 const VariableInfo* info) {
Sarah443c41d2021-06-18 19:58:27 +00001208 if (!ValidateVariable(info)) {
1209 return false;
1210 }
Sarahac5dbd22021-06-28 14:05:25 +00001211
Ben Clayton4f3ff572021-10-15 17:33:10 +00001212 for (auto* deco : info->declaration->decorations) {
Saraha8f58ef2021-06-30 19:22:30 +00001213 if (!func->IsEntryPoint() && !deco->Is<ast::InternalDecoration>()) {
Sarah99a78ad2021-07-08 14:02:56 +00001214 AddError(
1215 "decoration is not valid for non-entry point function parameters",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001216 deco->source);
James Pricec3f19082021-06-24 16:20:16 +00001217 return false;
Saraha4696682021-07-21 12:16:35 +00001218 } else if (!deco->IsAnyOf<ast::BuiltinDecoration, ast::InvariantDecoration,
Sarah465c5aa2021-07-23 13:23:20 +00001219 ast::LocationDecoration,
1220 ast::InterpolateDecoration,
James Pricec3f19082021-06-24 16:20:16 +00001221 ast::InternalDecoration>() &&
Saraha8f58ef2021-06-30 19:22:30 +00001222 (IsValidationEnabled(
Ben Clayton4f3ff572021-10-15 17:33:10 +00001223 info->declaration->decorations,
Saraha8f58ef2021-06-30 19:22:30 +00001224 ast::DisabledValidation::kEntryPointParameter) &&
1225 IsValidationEnabled(
Ben Clayton4f3ff572021-10-15 17:33:10 +00001226 info->declaration->decorations,
Ryan Harrison2f258d12021-07-07 20:41:00 +00001227 ast::DisabledValidation::
1228 kIgnoreConstructibleFunctionParameter))) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001229 AddError("decoration is not valid for function parameters", deco->source);
James Pricec3f19082021-06-24 16:20:16 +00001230 return false;
Sarahc58738a2021-06-09 16:01:29 +00001231 }
1232 }
Sarah9432c972021-06-29 15:24:04 +00001233
1234 if (auto* ref = info->type->As<sem::Pointer>()) {
1235 auto sc = ref->StorageClass();
1236 if (!(sc == ast::StorageClass::kFunction ||
1237 sc == ast::StorageClass::kPrivate ||
1238 sc == ast::StorageClass::kWorkgroup)) {
1239 std::stringstream ss;
1240 ss << "function parameter of pointer type cannot be in '" << sc
1241 << "' storage class";
Ben Clayton4f3ff572021-10-15 17:33:10 +00001242 AddError(ss.str(), info->declaration->source);
Sarah9432c972021-06-29 15:24:04 +00001243 return false;
1244 }
1245 }
1246
1247 if (IsPlain(info->type)) {
Antonio Maiorano68a6dd02021-07-20 18:28:31 +00001248 if (!info->type->IsConstructible() &&
Saraha8f58ef2021-06-30 19:22:30 +00001249 IsValidationEnabled(
Ben Clayton4f3ff572021-10-15 17:33:10 +00001250 info->declaration->decorations,
Ryan Harrison2f258d12021-07-07 20:41:00 +00001251 ast::DisabledValidation::kIgnoreConstructibleFunctionParameter)) {
1252 AddError("store type of function parameter must be a constructible type",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001253 info->declaration->source);
Sarah9432c972021-06-29 15:24:04 +00001254 return false;
1255 }
1256 } else if (!info->type->IsAnyOf<sem::Texture, sem::Sampler, sem::Pointer>()) {
1257 AddError("store type of function parameter cannot be " +
1258 info->type->FriendlyName(builder_->Symbols()),
Ben Clayton4f3ff572021-10-15 17:33:10 +00001259 info->declaration->source);
Sarah9432c972021-06-29 15:24:04 +00001260 return false;
1261 }
1262
Sarah443c41d2021-06-18 19:58:27 +00001263 return true;
1264}
Sarahc58738a2021-06-09 16:01:29 +00001265
Sarah443c41d2021-06-18 19:58:27 +00001266bool Resolver::ValidateBuiltinDecoration(const ast::BuiltinDecoration* deco,
Sarah99a78ad2021-07-08 14:02:56 +00001267 const sem::Type* storage_type,
James Priceceab1402021-10-05 15:02:17 +00001268 const bool is_input) {
Sarah443c41d2021-06-18 19:58:27 +00001269 auto* type = storage_type->UnwrapRef();
Sarah99a78ad2021-07-08 14:02:56 +00001270 const auto stage = current_function_
Ben Clayton4f3ff572021-10-15 17:33:10 +00001271 ? current_function_->declaration->PipelineStage()
Sarah99a78ad2021-07-08 14:02:56 +00001272 : ast::PipelineStage::kNone;
1273 std::stringstream stage_name;
1274 stage_name << stage;
1275 bool is_stage_mismatch = false;
Sarah465c5aa2021-07-23 13:23:20 +00001276 bool is_output = !is_input;
Ben Clayton4f3ff572021-10-15 17:33:10 +00001277 switch (deco->builtin) {
Sarah57a737b2021-06-23 17:35:42 +00001278 case ast::Builtin::kPosition:
Sarah99a78ad2021-07-08 14:02:56 +00001279 if (stage != ast::PipelineStage::kNone &&
Sarah465c5aa2021-07-23 13:23:20 +00001280 !((is_input && stage == ast::PipelineStage::kFragment) ||
1281 (is_output && stage == ast::PipelineStage::kVertex))) {
1282 is_stage_mismatch = true;
Sarah99a78ad2021-07-08 14:02:56 +00001283 }
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00001284 if (!(type->is_float_vector() && type->As<sem::Vector>()->Width() == 4)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001285 AddError("store type of " + deco_to_str(deco) + " must be 'vec4<f32>'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001286 deco->source);
Sarah57a737b2021-06-23 17:35:42 +00001287 return false;
1288 }
1289 break;
1290 case ast::Builtin::kGlobalInvocationId:
1291 case ast::Builtin::kLocalInvocationId:
James Price1bb63712021-09-13 17:11:58 +00001292 case ast::Builtin::kNumWorkgroups:
Sarah57a737b2021-06-23 17:35:42 +00001293 case ast::Builtin::kWorkgroupId:
Sarah99a78ad2021-07-08 14:02:56 +00001294 if (stage != ast::PipelineStage::kNone &&
1295 !(stage == ast::PipelineStage::kCompute && is_input)) {
1296 is_stage_mismatch = true;
1297 }
Sarah57a737b2021-06-23 17:35:42 +00001298 if (!(type->is_unsigned_integer_vector() &&
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00001299 type->As<sem::Vector>()->Width() == 3)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001300 AddError("store type of " + deco_to_str(deco) + " must be 'vec3<u32>'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001301 deco->source);
Sarah57a737b2021-06-23 17:35:42 +00001302 return false;
1303 }
1304 break;
1305 case ast::Builtin::kFragDepth:
Sarah99a78ad2021-07-08 14:02:56 +00001306 if (stage != ast::PipelineStage::kNone &&
1307 !(stage == ast::PipelineStage::kFragment && !is_input)) {
1308 is_stage_mismatch = true;
1309 }
Sarah57a737b2021-06-23 17:35:42 +00001310 if (!type->Is<sem::F32>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001311 AddError("store type of " + deco_to_str(deco) + " must be 'f32'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001312 deco->source);
Sarah57a737b2021-06-23 17:35:42 +00001313 return false;
1314 }
1315 break;
Sarah443c41d2021-06-18 19:58:27 +00001316 case ast::Builtin::kFrontFacing:
Sarah99a78ad2021-07-08 14:02:56 +00001317 if (stage != ast::PipelineStage::kNone &&
1318 !(stage == ast::PipelineStage::kFragment && is_input)) {
1319 is_stage_mismatch = true;
1320 }
Sarah443c41d2021-06-18 19:58:27 +00001321 if (!type->Is<sem::Bool>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001322 AddError("store type of " + deco_to_str(deco) + " must be 'bool'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001323 deco->source);
Sarah443c41d2021-06-18 19:58:27 +00001324 return false;
1325 }
1326 break;
Sarah57a737b2021-06-23 17:35:42 +00001327 case ast::Builtin::kLocalInvocationIndex:
Sarah99a78ad2021-07-08 14:02:56 +00001328 if (stage != ast::PipelineStage::kNone &&
1329 !(stage == ast::PipelineStage::kCompute && is_input)) {
1330 is_stage_mismatch = true;
1331 }
1332 if (!type->Is<sem::U32>()) {
1333 AddError("store type of " + deco_to_str(deco) + " must be 'u32'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001334 deco->source);
Sarah99a78ad2021-07-08 14:02:56 +00001335 return false;
1336 }
1337 break;
Sarah57a737b2021-06-23 17:35:42 +00001338 case ast::Builtin::kVertexIndex:
1339 case ast::Builtin::kInstanceIndex:
Sarah99a78ad2021-07-08 14:02:56 +00001340 if (stage != ast::PipelineStage::kNone &&
1341 !(stage == ast::PipelineStage::kVertex && is_input)) {
1342 is_stage_mismatch = true;
1343 }
1344 if (!type->Is<sem::U32>()) {
1345 AddError("store type of " + deco_to_str(deco) + " must be 'u32'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001346 deco->source);
Sarah99a78ad2021-07-08 14:02:56 +00001347 return false;
1348 }
1349 break;
Sarah443c41d2021-06-18 19:58:27 +00001350 case ast::Builtin::kSampleMask:
Sarah99a78ad2021-07-08 14:02:56 +00001351 if (stage != ast::PipelineStage::kNone &&
1352 !(stage == ast::PipelineStage::kFragment)) {
1353 is_stage_mismatch = true;
1354 }
1355 if (!type->Is<sem::U32>()) {
1356 AddError("store type of " + deco_to_str(deco) + " must be 'u32'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001357 deco->source);
Sarah99a78ad2021-07-08 14:02:56 +00001358 return false;
1359 }
1360 break;
Sarah443c41d2021-06-18 19:58:27 +00001361 case ast::Builtin::kSampleIndex:
Sarah99a78ad2021-07-08 14:02:56 +00001362 if (stage != ast::PipelineStage::kNone &&
1363 !(stage == ast::PipelineStage::kFragment && is_input)) {
1364 is_stage_mismatch = true;
1365 }
Sarah443c41d2021-06-18 19:58:27 +00001366 if (!type->Is<sem::U32>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001367 AddError("store type of " + deco_to_str(deco) + " must be 'u32'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001368 deco->source);
Sarah443c41d2021-06-18 19:58:27 +00001369 return false;
1370 }
1371 break;
1372 default:
1373 break;
1374 }
Sarah99a78ad2021-07-08 14:02:56 +00001375
James Priceceab1402021-10-05 15:02:17 +00001376 if (is_stage_mismatch) {
1377 AddError(deco_to_str(deco) + " cannot be used in " +
1378 (is_input ? "input of " : "output of ") + stage_name.str() +
1379 " pipeline stage",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001380 deco->source);
James Priceceab1402021-10-05 15:02:17 +00001381 return false;
Sarah99a78ad2021-07-08 14:02:56 +00001382 }
1383
Sarah443c41d2021-06-18 19:58:27 +00001384 return true;
Antonio Maiorano09356cc2021-04-06 14:07:07 +00001385}
1386
James Price989a8e42021-06-28 23:04:43 +00001387bool Resolver::ValidateInterpolateDecoration(
1388 const ast::InterpolateDecoration* deco,
1389 const sem::Type* storage_type) {
1390 auto* type = storage_type->UnwrapRef();
1391
James Pricea41694e2021-10-21 23:08:44 +00001392 if (type->is_integer_scalar_or_vector() &&
1393 deco->type != ast::InterpolationType::kFlat) {
James Price989a8e42021-06-28 23:04:43 +00001394 AddError(
James Pricea41694e2021-10-21 23:08:44 +00001395 "interpolation type must be 'flat' for integral user-defined IO types",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001396 deco->source);
James Price989a8e42021-06-28 23:04:43 +00001397 return false;
1398 }
1399
Ben Clayton4f3ff572021-10-15 17:33:10 +00001400 if (deco->type == ast::InterpolationType::kFlat &&
1401 deco->sampling != ast::InterpolationSampling::kNone) {
James Price989a8e42021-06-28 23:04:43 +00001402 AddError("flat interpolation attribute must not have a sampling parameter",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001403 deco->source);
James Price989a8e42021-06-28 23:04:43 +00001404 return false;
1405 }
1406
1407 return true;
1408}
1409
James Price2dd39372021-04-21 16:13:42 +00001410bool Resolver::ValidateFunction(const ast::Function* func,
1411 const FunctionInfo* info) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001412 if (!ValidateNoDuplicateDefinition(func->symbol, func->source,
Sarahc0353662021-06-29 21:30:37 +00001413 /* check_global_scope_only */ true)) {
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001414 return false;
1415 }
1416
James Price43f50ea2021-05-14 20:41:03 +00001417 auto workgroup_deco_count = 0;
Ben Clayton4f3ff572021-10-15 17:33:10 +00001418 for (auto* deco : func->decorations) {
Sarah99a78ad2021-07-08 14:02:56 +00001419 if (deco->Is<ast::WorkgroupDecoration>()) {
James Price43f50ea2021-05-14 20:41:03 +00001420 workgroup_deco_count++;
Ben Clayton4f3ff572021-10-15 17:33:10 +00001421 if (func->PipelineStage() != ast::PipelineStage::kCompute) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001422 AddError(
James Price43f50ea2021-05-14 20:41:03 +00001423 "the workgroup_size attribute is only valid for compute stages",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001424 deco->source);
James Price43f50ea2021-05-14 20:41:03 +00001425 return false;
1426 }
Sarah99a78ad2021-07-08 14:02:56 +00001427 } else if (!deco->IsAnyOf<ast::StageDecoration,
1428 ast::InternalDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001429 AddError("decoration is not valid for functions", deco->source);
James Price43f50ea2021-05-14 20:41:03 +00001430 return false;
1431 }
1432 }
James Price43f50ea2021-05-14 20:41:03 +00001433
Ben Clayton4f3ff572021-10-15 17:33:10 +00001434 if (func->params.size() > 255) {
1435 AddError("functions may declare at most 255 parameters", func->source);
Ben Clayton725159c2021-07-17 17:45:25 +00001436 return false;
1437 }
1438
Ben Clayton4f3ff572021-10-15 17:33:10 +00001439 for (auto* param : func->params) {
Sarah9432c972021-06-29 15:24:04 +00001440 if (!ValidateFunctionParameter(func, variable_to_info_.at(param))) {
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001441 return false;
1442 }
1443 }
1444
Ben Clayton3068dcb2021-04-30 19:24:29 +00001445 if (!info->return_type->Is<sem::Void>()) {
Antonio Maiorano68a6dd02021-07-20 18:28:31 +00001446 if (!info->return_type->IsConstructible()) {
Ryan Harrison2f258d12021-07-07 20:41:00 +00001447 AddError("function return type must be a constructible type",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001448 func->return_type->source);
Antonio Maioranof19e0e42021-06-21 20:51:16 +00001449 return false;
1450 }
1451
Ben Clayton4f3ff572021-10-15 17:33:10 +00001452 if (func->body) {
1453 if (!func->body->Last() ||
1454 !func->body->Last()->Is<ast::ReturnStatement>()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00001455 AddError("non-void function must end with a return statement",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001456 func->source);
Ben Claytonb502fdf2021-04-07 08:09:21 +00001457 return false;
1458 }
Saraha8f58ef2021-06-30 19:22:30 +00001459 } else if (IsValidationEnabled(
Ben Clayton4f3ff572021-10-15 17:33:10 +00001460 func->decorations,
Ben Clayton451f2cc2021-05-12 12:54:21 +00001461 ast::DisabledValidation::kFunctionHasNoBody)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001462 TINT_ICE(Resolver, diagnostics_)
Ben Clayton4f3ff572021-10-15 17:33:10 +00001463 << "Function " << builder_->Symbols().NameFor(func->symbol)
Ben Clayton451f2cc2021-05-12 12:54:21 +00001464 << " has no body";
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001465 }
1466
Ben Clayton4f3ff572021-10-15 17:33:10 +00001467 for (auto* deco : func->return_type_decorations) {
James Price1b1d9632021-06-28 09:53:37 +00001468 if (!func->IsEntryPoint()) {
Sarah99a78ad2021-07-08 14:02:56 +00001469 AddError(
1470 "decoration is not valid for non-entry point function return types",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001471 deco->source);
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001472 return false;
1473 }
Sarah465c5aa2021-07-23 13:23:20 +00001474 if (!deco->IsAnyOf<ast::BuiltinDecoration, ast::InternalDecoration,
1475 ast::LocationDecoration, ast::InterpolateDecoration,
1476 ast::InvariantDecoration>() &&
Ben Clayton4f3ff572021-10-15 17:33:10 +00001477 (IsValidationEnabled(info->declaration->decorations,
Sarah465c5aa2021-07-23 13:23:20 +00001478 ast::DisabledValidation::kEntryPointParameter) &&
Ben Clayton4f3ff572021-10-15 17:33:10 +00001479 IsValidationEnabled(info->declaration->decorations,
Sarah465c5aa2021-07-23 13:23:20 +00001480 ast::DisabledValidation::
1481 kIgnoreConstructibleFunctionParameter))) {
James Price1b1d9632021-06-28 09:53:37 +00001482 AddError("decoration is not valid for entry point return types",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001483 deco->source);
James Price1b1d9632021-06-28 09:53:37 +00001484 return false;
1485 }
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001486 }
1487 }
1488
James Price68f558f2021-04-06 15:51:47 +00001489 if (func->IsEntryPoint()) {
James Price2dd39372021-04-21 16:13:42 +00001490 if (!ValidateEntryPoint(func, info)) {
James Price68f558f2021-04-06 15:51:47 +00001491 return false;
1492 }
1493 }
1494
1495 return true;
1496}
1497
James Price2dd39372021-04-21 16:13:42 +00001498bool Resolver::ValidateEntryPoint(const ast::Function* func,
1499 const FunctionInfo* info) {
James Price68f558f2021-04-06 15:51:47 +00001500 // Use a lambda to validate the entry point decorations for a type.
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001501 // Persistent state is used to track which builtins and locations have
1502 // already been seen, in order to catch conflicts.
1503 // TODO(jrprice): This state could be stored in FunctionInfo instead, and
1504 // then passed to sem::Function since it would be useful there too.
James Price68f558f2021-04-06 15:51:47 +00001505 std::unordered_set<ast::Builtin> builtins;
1506 std::unordered_set<uint32_t> locations;
1507 enum class ParamOrRetType {
1508 kParameter,
1509 kReturnType,
1510 };
Sarah443c41d2021-06-18 19:58:27 +00001511
James Price68f558f2021-04-06 15:51:47 +00001512 // Inner lambda that is applied to a type and all of its members.
Ben Clayton86481202021-10-19 18:38:54 +00001513 auto validate_entry_point_decorations_inner = [&](const ast::DecorationList&
1514 decos,
1515 sem::Type* ty,
1516 Source source,
1517 ParamOrRetType param_or_ret,
1518 bool is_struct_member) {
1519 // Scan decorations for pipeline IO attributes.
1520 // Check for overlap with attributes that have been seen previously.
1521 const ast::Decoration* pipeline_io_attribute = nullptr;
James Pricea41694e2021-10-21 23:08:44 +00001522 const ast::InterpolateDecoration* interpolate_attribute = nullptr;
Ben Clayton86481202021-10-19 18:38:54 +00001523 const ast::InvariantDecoration* invariant_attribute = nullptr;
1524 for (auto* deco : decos) {
1525 auto is_invalid_compute_shader_decoration = false;
1526 if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
1527 if (pipeline_io_attribute) {
1528 AddError("multiple entry point IO attributes", deco->source);
1529 AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
Ben Clayton4f3ff572021-10-15 17:33:10 +00001530 pipeline_io_attribute->source);
Ben Clayton86481202021-10-19 18:38:54 +00001531 return false;
1532 }
1533 pipeline_io_attribute = deco;
James Price68f558f2021-04-06 15:51:47 +00001534
Ben Clayton86481202021-10-19 18:38:54 +00001535 if (builtins.count(builtin->builtin)) {
1536 AddError(deco_to_str(builtin) +
1537 " attribute appears multiple times as pipeline " +
1538 (param_or_ret == ParamOrRetType::kParameter ? "input"
1539 : "output"),
1540 func->source);
1541 return false;
Ben Claytonada48642021-07-29 16:55:27 +00001542 }
Ben Clayton08b0ab92021-07-08 15:12:36 +00001543
Ben Clayton86481202021-10-19 18:38:54 +00001544 if (!ValidateBuiltinDecoration(
1545 builtin, ty,
1546 /* is_input */ param_or_ret == ParamOrRetType::kParameter)) {
1547 return false;
1548 }
1549 builtins.emplace(builtin->builtin);
1550 } else if (auto* location = deco->As<ast::LocationDecoration>()) {
1551 if (pipeline_io_attribute) {
1552 AddError("multiple entry point IO attributes", deco->source);
1553 AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
1554 pipeline_io_attribute->source);
1555 return false;
1556 }
1557 pipeline_io_attribute = deco;
James Priceb3e6c0d2021-10-15 14:55:39 +00001558
Ben Clayton86481202021-10-19 18:38:54 +00001559 bool is_input = param_or_ret == ParamOrRetType::kParameter;
1560 if (!ValidateLocationDecoration(location, ty, locations, source,
1561 is_input)) {
1562 return false;
1563 }
1564 } else if (auto* interpolate = deco->As<ast::InterpolateDecoration>()) {
1565 if (func->PipelineStage() == ast::PipelineStage::kCompute) {
1566 is_invalid_compute_shader_decoration = true;
1567 } else if (!ValidateInterpolateDecoration(interpolate, ty)) {
1568 return false;
1569 }
James Pricea41694e2021-10-21 23:08:44 +00001570 interpolate_attribute = interpolate;
Ben Clayton86481202021-10-19 18:38:54 +00001571 } else if (auto* invariant = deco->As<ast::InvariantDecoration>()) {
1572 if (func->PipelineStage() == ast::PipelineStage::kCompute) {
1573 is_invalid_compute_shader_decoration = true;
1574 }
1575 invariant_attribute = invariant;
1576 }
1577 if (is_invalid_compute_shader_decoration) {
1578 std::string input_or_output =
1579 param_or_ret == ParamOrRetType::kParameter ? "inputs" : "output";
1580 AddError(
1581 "decoration is not valid for compute shader " + input_or_output,
1582 deco->source);
1583 return false;
1584 }
1585 }
Ben Clayton08b0ab92021-07-08 15:12:36 +00001586
Ben Clayton86481202021-10-19 18:38:54 +00001587 if (IsValidationEnabled(decos,
1588 ast::DisabledValidation::kEntryPointParameter)) {
1589 if (is_struct_member && ty->Is<sem::Struct>()) {
1590 AddError("nested structures cannot be used for entry point IO", source);
1591 return false;
1592 }
1593
1594 if (!ty->Is<sem::Struct>() && !pipeline_io_attribute) {
1595 std::string err = "missing entry point IO attribute";
1596 if (!is_struct_member) {
1597 err +=
1598 (param_or_ret == ParamOrRetType::kParameter ? " on parameter"
1599 : " on return type");
1600 }
1601 AddError(err, source);
1602 return false;
1603 }
1604
James Pricea41694e2021-10-21 23:08:44 +00001605 if (pipeline_io_attribute &&
1606 pipeline_io_attribute->Is<ast::LocationDecoration>()) {
1607 if (ty->is_integer_scalar_or_vector() && !interpolate_attribute) {
1608 // TODO(crbug.com/tint/1224): Make these errors once downstream
1609 // usages have caught up (no sooner than M99).
1610 if (func->PipelineStage() == ast::PipelineStage::kVertex &&
1611 param_or_ret == ParamOrRetType::kReturnType) {
1612 AddWarning(
1613 "integral user-defined vertex outputs must have a flat "
1614 "interpolation attribute",
1615 source);
1616 }
1617 if (func->PipelineStage() == ast::PipelineStage::kFragment &&
1618 param_or_ret == ParamOrRetType::kParameter) {
1619 AddWarning(
1620 "integral user-defined fragment inputs must have a flat "
1621 "interpolation attribute",
1622 source);
1623 }
1624 }
1625 }
1626
Ben Clayton86481202021-10-19 18:38:54 +00001627 if (invariant_attribute) {
1628 bool has_position = false;
1629 if (pipeline_io_attribute) {
1630 if (auto* builtin =
1631 pipeline_io_attribute->As<ast::BuiltinDecoration>()) {
1632 has_position = (builtin->builtin == ast::Builtin::kPosition);
Sarahc0f1ed42021-07-28 18:51:37 +00001633 }
1634 }
Ben Clayton86481202021-10-19 18:38:54 +00001635 if (!has_position) {
1636 AddError(
1637 "invariant attribute must only be applied to a position "
1638 "builtin",
1639 invariant_attribute->source);
1640 return false;
1641 }
1642 }
1643 }
1644 return true;
1645 };
James Price68f558f2021-04-06 15:51:47 +00001646
1647 // Outer lambda for validating the entry point decorations for a type.
1648 auto validate_entry_point_decorations = [&](const ast::DecorationList& decos,
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001649 sem::Type* ty, Source source,
James Price68f558f2021-04-06 15:51:47 +00001650 ParamOrRetType param_or_ret) {
James Price68f558f2021-04-06 15:51:47 +00001651 if (!validate_entry_point_decorations_inner(decos, ty, source, param_or_ret,
Sarahc0f1ed42021-07-28 18:51:37 +00001652 /*is_struct_member*/ false)) {
James Price68f558f2021-04-06 15:51:47 +00001653 return false;
1654 }
1655
Ben Claytona34fa0e2021-05-10 17:38:01 +00001656 if (auto* str = ty->As<sem::Struct>()) {
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001657 for (auto* member : str->Members()) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001658 if (!validate_entry_point_decorations_inner(
Ben Clayton4f3ff572021-10-15 17:33:10 +00001659 member->Declaration()->decorations, member->Type(),
1660 member->Declaration()->source, param_or_ret,
Sarahc0f1ed42021-07-28 18:51:37 +00001661 /*is_struct_member*/ true)) {
Sarah465c5aa2021-07-23 13:23:20 +00001662 AddNote("while analysing entry point '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +00001663 builder_->Symbols().NameFor(func->symbol) + "'",
1664 func->source);
James Price68f558f2021-04-06 15:51:47 +00001665 return false;
1666 }
1667 }
1668 }
1669
1670 return true;
1671 };
1672
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001673 for (auto* param : info->parameters) {
James Price68f558f2021-04-06 15:51:47 +00001674 if (!validate_entry_point_decorations(
Ben Clayton4f3ff572021-10-15 17:33:10 +00001675 param->declaration->decorations, param->type,
1676 param->declaration->source, ParamOrRetType::kParameter)) {
James Price68f558f2021-04-06 15:51:47 +00001677 return false;
1678 }
1679 }
1680
James Price2dd39372021-04-21 16:13:42 +00001681 // Clear IO sets after parameter validation. Builtin and location attributes
1682 // in return types should be validated independently from those used in
1683 // parameters.
1684 builtins.clear();
1685 locations.clear();
1686
Ben Clayton3068dcb2021-04-30 19:24:29 +00001687 if (!info->return_type->Is<sem::Void>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001688 if (!validate_entry_point_decorations(func->return_type_decorations,
1689 info->return_type, func->source,
James Price68f558f2021-04-06 15:51:47 +00001690 ParamOrRetType::kReturnType)) {
1691 return false;
1692 }
1693 }
1694
Ben Clayton4f3ff572021-10-15 17:33:10 +00001695 if (func->PipelineStage() == ast::PipelineStage::kVertex &&
James Price2dd39372021-04-21 16:13:42 +00001696 builtins.count(ast::Builtin::kPosition) == 0) {
1697 // Check module-scope variables, as the SPIR-V sanitizer generates these.
1698 bool found = false;
1699 for (auto* var : info->referenced_module_vars) {
1700 if (auto* builtin = ast::GetDecoration<ast::BuiltinDecoration>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00001701 var->declaration->decorations)) {
1702 if (builtin->builtin == ast::Builtin::kPosition) {
James Price2dd39372021-04-21 16:13:42 +00001703 found = true;
1704 break;
1705 }
1706 }
1707 }
Ben Clayton677437d2021-06-16 09:50:11 +00001708 if (!found) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001709 AddError(
James Price2dd39372021-04-21 16:13:42 +00001710 "a vertex shader must include the 'position' builtin in its return "
1711 "type",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001712 func->source);
James Price2dd39372021-04-21 16:13:42 +00001713 return false;
1714 }
1715 }
1716
Ben Clayton4f3ff572021-10-15 17:33:10 +00001717 if (func->PipelineStage() == ast::PipelineStage::kCompute) {
1718 if (!ast::HasDecoration<ast::WorkgroupDecoration>(func->decorations)) {
Sarahe6cb51e2021-06-29 18:39:44 +00001719 AddError(
1720 "a compute shader must include 'workgroup_size' in its "
1721 "attributes",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001722 func->source);
Sarahe6cb51e2021-06-29 18:39:44 +00001723 return false;
1724 }
1725 }
1726
Ben Clayton3f968e72021-05-10 19:16:46 +00001727 // Validate there are no resource variable binding collisions
1728 std::unordered_map<sem::BindingPoint, const ast::Variable*> binding_points;
1729 for (auto* var_info : info->referenced_module_vars) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001730 if (!var_info->declaration->BindingPoint()) {
Ben Clayton3f968e72021-05-10 19:16:46 +00001731 continue;
1732 }
1733 auto bp = var_info->binding_point;
1734 auto res = binding_points.emplace(bp, var_info->declaration);
Ben Clayton3103a1f2021-05-12 13:30:51 +00001735 if (!res.second &&
Ben Clayton4f3ff572021-10-15 17:33:10 +00001736 IsValidationEnabled(var_info->declaration->decorations,
Saraha8f58ef2021-06-30 19:22:30 +00001737 ast::DisabledValidation::kBindingPointCollision) &&
Ben Clayton4f3ff572021-10-15 17:33:10 +00001738 IsValidationEnabled(res.first->second->decorations,
Saraha8f58ef2021-06-30 19:22:30 +00001739 ast::DisabledValidation::kBindingPointCollision)) {
Ben Clayton3f968e72021-05-10 19:16:46 +00001740 // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
1741 // Bindings must not alias within a shader stage: two different
1742 // variables in the resource interface of a given shader must not have
1743 // the same group and binding values, when considered as a pair of
1744 // values.
Ben Clayton4f3ff572021-10-15 17:33:10 +00001745 auto func_name = builder_->Symbols().NameFor(info->declaration->symbol);
Ben Claytonffd28e22021-06-24 11:27:36 +00001746 AddError("entry point '" + func_name +
1747 "' references multiple variables that use the "
1748 "same resource binding [[group(" +
1749 std::to_string(bp.group) + "), binding(" +
1750 std::to_string(bp.binding) + ")]]",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001751 var_info->declaration->source);
Ben Claytonffd28e22021-06-24 11:27:36 +00001752 AddNote("first resource binding usage declared here",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001753 res.first->second->source);
Ben Clayton3f968e72021-05-10 19:16:46 +00001754 return false;
1755 }
1756 }
1757
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001758 return true;
1759}
1760
Ben Clayton86481202021-10-19 18:38:54 +00001761bool Resolver::Function(const ast::Function* func) {
Ben Clayton3068dcb2021-04-30 19:24:29 +00001762 auto* info = function_infos_.Create<FunctionInfo>(func);
Ben Claytonf97b9c92021-02-16 18:45:45 +00001763
Ben Clayton71786c92021-06-03 16:07:34 +00001764 if (func->IsEntryPoint()) {
1765 entry_points_.emplace_back(info);
1766 }
1767
Ben Claytonb3505002021-05-19 16:11:04 +00001768 TINT_SCOPED_ASSIGNMENT(current_function_, info);
dan sinclair13d2a3b2020-06-22 20:52:24 +00001769
dan sinclair417a90d2020-04-06 21:07:41 +00001770 variable_stack_.push_scope();
Ben Clayton4ffcf062021-07-22 13:24:59 +00001771 uint32_t parameter_index = 0;
Ben Clayton9021eb52021-08-26 15:40:06 +00001772 std::unordered_map<Symbol, Source> parameter_names;
Ben Clayton4f3ff572021-10-15 17:33:10 +00001773 for (auto* param : func->params) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00001774 Mark(param);
Ben Clayton6d60c042021-08-23 19:01:19 +00001775
Ben Clayton9021eb52021-08-26 15:40:06 +00001776 { // Check the parameter name is unique for the function
Ben Clayton4f3ff572021-10-15 17:33:10 +00001777 auto emplaced = parameter_names.emplace(param->symbol, param->source);
Ben Clayton9021eb52021-08-26 15:40:06 +00001778 if (!emplaced.second) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001779 auto name = builder_->Symbols().NameFor(param->symbol);
1780 AddError("redefinition of parameter '" + name + "'", param->source);
Ben Clayton9021eb52021-08-26 15:40:06 +00001781 AddNote("previous definition is here", emplaced.first->second);
1782 return false;
1783 }
Ben Clayton6d60c042021-08-23 19:01:19 +00001784 }
1785
Ben Clayton4ffcf062021-07-22 13:24:59 +00001786 auto* param_info =
1787 Variable(param, VariableKind::kParameter, parameter_index++);
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +00001788 if (!param_info) {
1789 return false;
1790 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00001791
Ben Clayton4f3ff572021-10-15 17:33:10 +00001792 for (auto* deco : param->decorations) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00001793 Mark(deco);
1794 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00001795 if (!ValidateNoDuplicateDecorations(param->decorations)) {
Ben Clayton241c16d2021-06-09 18:53:57 +00001796 return false;
1797 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00001798
Ben Clayton4f3ff572021-10-15 17:33:10 +00001799 variable_stack_.set(param->symbol, param_info);
Ben Clayton3068dcb2021-04-30 19:24:29 +00001800 info->parameters.emplace_back(param_info);
James Price494e82d2021-03-31 15:42:17 +00001801
Ben Clayton4f3ff572021-10-15 17:33:10 +00001802 if (!ApplyStorageClassUsageToType(param->declared_storage_class,
1803 param_info->type, param->source)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001804 AddNote("while instantiating parameter " +
Ben Clayton4f3ff572021-10-15 17:33:10 +00001805 builder_->Symbols().NameFor(param->symbol),
1806 param->source);
Ben Claytonc87ff9c2021-03-31 17:23:07 +00001807 return false;
1808 }
1809
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001810 if (auto* str = param_info->type->As<sem::Struct>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001811 switch (func->PipelineStage()) {
James Price494e82d2021-03-31 15:42:17 +00001812 case ast::PipelineStage::kVertex:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001813 str->AddUsage(sem::PipelineStageUsage::kVertexInput);
James Price494e82d2021-03-31 15:42:17 +00001814 break;
1815 case ast::PipelineStage::kFragment:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001816 str->AddUsage(sem::PipelineStageUsage::kFragmentInput);
James Price494e82d2021-03-31 15:42:17 +00001817 break;
1818 case ast::PipelineStage::kCompute:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001819 str->AddUsage(sem::PipelineStageUsage::kComputeInput);
James Price494e82d2021-03-31 15:42:17 +00001820 break;
1821 case ast::PipelineStage::kNone:
1822 break;
1823 }
1824 }
1825 }
1826
Ben Clayton4f3ff572021-10-15 17:33:10 +00001827 if (auto* ty = func->return_type) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001828 info->return_type = Type(ty);
1829 info->return_type_name = ty->FriendlyName(builder_->Symbols());
Ben Clayton3068dcb2021-04-30 19:24:29 +00001830 if (!info->return_type) {
1831 return false;
1832 }
1833 } else {
1834 info->return_type = builder_->create<sem::Void>();
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001835 info->return_type_name =
1836 info->return_type->FriendlyName(builder_->Symbols());
Ben Clayton3068dcb2021-04-30 19:24:29 +00001837 }
1838
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001839 if (auto* str = info->return_type->As<sem::Struct>()) {
James Price5c523f32021-03-31 15:44:07 +00001840 if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str,
Ben Clayton4f3ff572021-10-15 17:33:10 +00001841 func->source)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001842 AddNote("while instantiating return type for " +
Ben Clayton4f3ff572021-10-15 17:33:10 +00001843 builder_->Symbols().NameFor(func->symbol),
1844 func->source);
James Price5c523f32021-03-31 15:44:07 +00001845 return false;
1846 }
1847
Ben Clayton4f3ff572021-10-15 17:33:10 +00001848 switch (func->PipelineStage()) {
James Price494e82d2021-03-31 15:42:17 +00001849 case ast::PipelineStage::kVertex:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001850 str->AddUsage(sem::PipelineStageUsage::kVertexOutput);
James Price494e82d2021-03-31 15:42:17 +00001851 break;
1852 case ast::PipelineStage::kFragment:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001853 str->AddUsage(sem::PipelineStageUsage::kFragmentOutput);
James Price494e82d2021-03-31 15:42:17 +00001854 break;
1855 case ast::PipelineStage::kCompute:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001856 str->AddUsage(sem::PipelineStageUsage::kComputeOutput);
James Price494e82d2021-03-31 15:42:17 +00001857 break;
1858 case ast::PipelineStage::kNone:
1859 break;
1860 }
dan sinclair011aed92020-06-22 20:18:17 +00001861 }
1862
Ben Clayton4f3ff572021-10-15 17:33:10 +00001863 if (func->body) {
1864 Mark(func->body);
Ben Clayton6e459fe2021-07-14 09:44:41 +00001865 if (current_compound_statement_) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001866 TINT_ICE(Resolver, diagnostics_)
Ben Clayton6e459fe2021-07-14 09:44:41 +00001867 << "Resolver::Function() called with a current compound statement";
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00001868 return false;
1869 }
Ben Clayton22d891c2021-05-20 15:17:08 +00001870 auto* sem_block = builder_->create<sem::FunctionBlockStatement>(func);
Ben Clayton4f3ff572021-10-15 17:33:10 +00001871 builder_->Sem().Add(func->body, sem_block);
1872 if (!Scope(sem_block, [&] { return Statements(func->body->statements); })) {
Ben Claytonb502fdf2021-04-07 08:09:21 +00001873 return false;
1874 }
dan sinclair417a90d2020-04-06 21:07:41 +00001875 }
1876 variable_stack_.pop_scope();
1877
Ben Clayton4f3ff572021-10-15 17:33:10 +00001878 for (auto* deco : func->decorations) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00001879 Mark(deco);
1880 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00001881 if (!ValidateNoDuplicateDecorations(func->decorations)) {
Ben Clayton241c16d2021-06-09 18:53:57 +00001882 return false;
1883 }
1884
Ben Clayton4f3ff572021-10-15 17:33:10 +00001885 for (auto* deco : func->return_type_decorations) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00001886 Mark(deco);
1887 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00001888 if (!ValidateNoDuplicateDecorations(func->return_type_decorations)) {
Ben Clayton241c16d2021-06-09 18:53:57 +00001889 return false;
1890 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00001891
James Pricece8f8682021-05-19 08:15:18 +00001892 // Set work-group size defaults.
1893 for (int i = 0; i < 3; i++) {
1894 info->workgroup_size[i].value = 1;
1895 info->workgroup_size[i].overridable_const = nullptr;
1896 }
1897
1898 if (auto* workgroup =
Ben Clayton4f3ff572021-10-15 17:33:10 +00001899 ast::GetDecoration<ast::WorkgroupDecoration>(func->decorations)) {
1900 auto values = workgroup->Values();
Ben Clayton9ba65002021-07-28 21:24:06 +00001901 auto any_i32 = false;
1902 auto any_u32 = false;
James Price70f80bb2021-05-19 13:40:08 +00001903 for (int i = 0; i < 3; i++) {
1904 // Each argument to this decoration can either be a literal, an
1905 // identifier for a module-scope constants, or nullptr if not specified.
1906
Ben Clayton9ba65002021-07-28 21:24:06 +00001907 auto* expr = values[i];
1908 if (!expr) {
James Price70f80bb2021-05-19 13:40:08 +00001909 // Not specified, just use the default.
1910 continue;
1911 }
1912
Ben Clayton9ba65002021-07-28 21:24:06 +00001913 if (!Expression(expr)) {
1914 return false;
1915 }
James Price70f80bb2021-05-19 13:40:08 +00001916
Ben Clayton9ba65002021-07-28 21:24:06 +00001917 constexpr const char* kErrBadType =
James Price69ce5f72021-09-02 10:05:19 +00001918 "workgroup_size argument must be either literal or module-scope "
Ben Clayton9ba65002021-07-28 21:24:06 +00001919 "constant of type i32 or u32";
1920 constexpr const char* kErrInconsistentType =
James Price69ce5f72021-09-02 10:05:19 +00001921 "workgroup_size arguments must be of the same type, either i32 "
Ben Clayton9ba65002021-07-28 21:24:06 +00001922 "or u32";
1923
1924 auto* ty = TypeOf(expr);
1925 bool is_i32 = ty->UnwrapRef()->Is<sem::I32>();
1926 bool is_u32 = ty->UnwrapRef()->Is<sem::U32>();
1927 if (!is_i32 && !is_u32) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001928 AddError(kErrBadType, expr->source);
Ben Clayton9ba65002021-07-28 21:24:06 +00001929 return false;
1930 }
1931
1932 any_i32 = any_i32 || is_i32;
1933 any_u32 = any_u32 || is_u32;
1934 if (any_i32 && any_u32) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00001935 AddError(kErrInconsistentType, expr->source);
Ben Clayton9ba65002021-07-28 21:24:06 +00001936 return false;
1937 }
1938
1939 if (auto* ident = expr->As<ast::IdentifierExpression>()) {
James Price70f80bb2021-05-19 13:40:08 +00001940 // We have an identifier of a module-scope constant.
Ben Clayton9ba65002021-07-28 21:24:06 +00001941 VariableInfo* var = nullptr;
Ben Clayton4f3ff572021-10-15 17:33:10 +00001942 if (!variable_stack_.get(ident->symbol, &var) ||
1943 !(var->declaration->is_const)) {
1944 AddError(kErrBadType, expr->source);
James Price70f80bb2021-05-19 13:40:08 +00001945 return false;
1946 }
1947
1948 // Capture the constant if an [[override]] attribute is present.
1949 if (ast::HasDecoration<ast::OverrideDecoration>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00001950 var->declaration->decorations)) {
James Price70f80bb2021-05-19 13:40:08 +00001951 info->workgroup_size[i].overridable_const = var->declaration;
1952 }
1953
Ben Clayton4f3ff572021-10-15 17:33:10 +00001954 expr = var->declaration->constructor;
Ben Clayton9ba65002021-07-28 21:24:06 +00001955 if (!expr) {
James Price70f80bb2021-05-19 13:40:08 +00001956 // No constructor means this value must be overriden by the user.
1957 info->workgroup_size[i].value = 0;
1958 continue;
1959 }
James Price69ce5f72021-09-02 10:05:19 +00001960 } else if (!expr->Is<ast::ScalarConstructorExpression>()) {
1961 AddError(
1962 "workgroup_size argument must be either a literal or a "
1963 "module-scope constant",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001964 values[i]->source);
James Price69ce5f72021-09-02 10:05:19 +00001965 return false;
James Price70f80bb2021-05-19 13:40:08 +00001966 }
1967
Ben Clayton9ba65002021-07-28 21:24:06 +00001968 auto val = ConstantValueOf(expr);
1969 if (!val) {
1970 TINT_ICE(Resolver, diagnostics_)
1971 << "could not resolve constant workgroup_size constant value";
1972 continue;
1973 }
James Price70f80bb2021-05-19 13:40:08 +00001974 // Validate and set the default value for this dimension.
Ben Clayton9ba65002021-07-28 21:24:06 +00001975 if (is_i32 ? val.Elements()[0].i32 < 1 : val.Elements()[0].u32 < 1) {
James Price69ce5f72021-09-02 10:05:19 +00001976 AddError("workgroup_size argument must be at least 1",
Ben Clayton4f3ff572021-10-15 17:33:10 +00001977 values[i]->source);
James Price70f80bb2021-05-19 13:40:08 +00001978 return false;
1979 }
Ben Clayton9ba65002021-07-28 21:24:06 +00001980
1981 info->workgroup_size[i].value =
1982 is_i32 ? static_cast<uint32_t>(val.Elements()[0].i32)
1983 : val.Elements()[0].u32;
James Price70f80bb2021-05-19 13:40:08 +00001984 }
James Pricece8f8682021-05-19 08:15:18 +00001985 }
1986
Ben Clayton3068dcb2021-04-30 19:24:29 +00001987 if (!ValidateFunction(func, info)) {
Antonio Maiorano9ef17472021-03-26 12:47:58 +00001988 return false;
1989 }
1990
dan sinclairf8fa6cf2021-02-24 22:11:34 +00001991 // Register the function information _after_ processing the statements. This
1992 // allows us to catch a function calling itself when determining the call
1993 // information as this function doesn't exist until it's finished.
Ben Clayton4f3ff572021-10-15 17:33:10 +00001994 symbol_to_function_[func->symbol] = info;
Ben Clayton3068dcb2021-04-30 19:24:29 +00001995 function_to_info_.emplace(func, info);
dan sinclairf8fa6cf2021-02-24 22:11:34 +00001996
dan sinclair417a90d2020-04-06 21:07:41 +00001997 return true;
1998}
1999
Ben Clayton5f0ea112021-03-09 10:54:37 +00002000bool Resolver::Statements(const ast::StatementList& stmts) {
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002001 for (auto* stmt : stmts) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002002 Mark(stmt);
Ben Clayton5f0ea112021-03-09 10:54:37 +00002003 if (!Statement(stmt)) {
dan sinclair0975dd52020-07-27 15:25:00 +00002004 return false;
2005 }
2006 }
Sarahc3f8fdf2021-06-21 17:53:56 +00002007 if (!ValidateStatements(stmts)) {
2008 return false;
2009 }
2010
2011 return true;
2012}
2013
2014bool Resolver::ValidateStatements(const ast::StatementList& stmts) {
Ben Clayton25517e92021-09-09 12:38:19 +00002015 bool unreachable = false;
Sarahc3f8fdf2021-06-21 17:53:56 +00002016 for (auto* stmt : stmts) {
Ben Clayton25517e92021-09-09 12:38:19 +00002017 if (unreachable) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002018 AddError("code is unreachable", stmt->source);
Ben Clayton25517e92021-09-09 12:38:19 +00002019 return false;
2020 }
2021
2022 auto* nested_stmt = stmt;
2023 while (auto* block = nested_stmt->As<ast::BlockStatement>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002024 if (block->Empty()) {
Ben Clayton25517e92021-09-09 12:38:19 +00002025 break;
Sarahc3f8fdf2021-06-21 17:53:56 +00002026 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00002027 nested_stmt = block->statements.back();
Ben Clayton25517e92021-09-09 12:38:19 +00002028 }
2029 if (nested_stmt->IsAnyOf<ast::ReturnStatement, ast::BreakStatement,
2030 ast::ContinueStatement, ast::DiscardStatement>()) {
2031 unreachable = true;
Sarahc3f8fdf2021-06-21 17:53:56 +00002032 }
2033 }
dan sinclair0975dd52020-07-27 15:25:00 +00002034 return true;
2035}
2036
Ben Clayton86481202021-10-19 18:38:54 +00002037bool Resolver::Statement(const ast::Statement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002038 if (stmt->Is<ast::CaseStatement>()) {
2039 AddError("case statement can only be used inside a switch statement",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002040 stmt->source);
Ben Clayton6e459fe2021-07-14 09:44:41 +00002041 return false;
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002042 }
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002043 if (stmt->Is<ast::ElseStatement>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002044 TINT_ICE(Resolver, diagnostics_)
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002045 << "Resolver::Statement() encountered an Else statement. Else "
2046 "statements are embedded in If statements, so should never be "
2047 "encountered as top-level statements";
2048 return false;
2049 }
2050
Ben Clayton6e459fe2021-07-14 09:44:41 +00002051 // Compound statements. These create their own sem::CompoundStatement
2052 // bindings.
2053 if (auto* b = stmt->As<ast::BlockStatement>()) {
2054 return BlockStatement(b);
2055 }
2056 if (auto* l = stmt->As<ast::ForLoopStatement>()) {
2057 return ForLoopStatement(l);
2058 }
2059 if (auto* l = stmt->As<ast::LoopStatement>()) {
2060 return LoopStatement(l);
2061 }
2062 if (auto* i = stmt->As<ast::IfStatement>()) {
2063 return IfStatement(i);
2064 }
2065 if (auto* s = stmt->As<ast::SwitchStatement>()) {
2066 return SwitchStatement(s);
2067 }
2068
2069 // Non-Compound statements
2070 sem::Statement* sem_statement =
2071 builder_->create<sem::Statement>(stmt, current_compound_statement_);
2072 builder_->Sem().Add(stmt, sem_statement);
2073 TINT_SCOPED_ASSIGNMENT(current_statement_, sem_statement);
Ben Clayton1d8098a2020-11-30 23:30:58 +00002074 if (auto* a = stmt->As<ast::AssignmentStatement>()) {
Antonio Maioranoe09989a2021-03-31 13:26:43 +00002075 return Assignment(a);
dan sinclair6c498fc2020-04-07 12:47:23 +00002076 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002077 if (stmt->Is<ast::BreakStatement>()) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002078 if (!sem_statement->FindFirstParent<sem::LoopBlockStatement>() &&
2079 !sem_statement->FindFirstParent<sem::SwitchCaseBlockStatement>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002080 AddError("break statement must be in a loop or switch case",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002081 stmt->source);
Ben Clayton9430cb42021-03-09 15:06:37 +00002082 return false;
2083 }
dan sinclair6bd70612020-06-03 16:11:28 +00002084 return true;
dan sinclairb7ea6e22020-04-07 12:54:10 +00002085 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002086 if (auto* c = stmt->As<ast::CallStatement>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002087 if (!Expression(c->expr)) {
Ben Clayton7fe01062021-06-11 13:22:27 +00002088 return false;
2089 }
2090 if (!ValidateCallStatement(c)) {
2091 return false;
2092 }
2093 return true;
dan sinclair50080b72020-07-21 13:42:13 +00002094 }
James Price5ffae322021-09-30 17:29:50 +00002095 if (auto* c = stmt->As<ast::ContinueStatement>()) {
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002096 // Set if we've hit the first continue statement in our parent loop
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00002097 if (auto* block =
2098 current_block_->FindFirstParent<
2099 sem::LoopBlockStatement, sem::LoopContinuingBlockStatement>()) {
2100 if (auto* loop_block = block->As<sem::LoopBlockStatement>()) {
James Price5ffae322021-09-30 17:29:50 +00002101 if (!loop_block->FirstContinue()) {
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00002102 const_cast<sem::LoopBlockStatement*>(loop_block)
James Price5ffae322021-09-30 17:29:50 +00002103 ->SetFirstContinue(c, loop_block->Decls().size());
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00002104 }
2105 } else {
2106 AddError("continuing blocks must not contain a continue statement",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002107 stmt->source);
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00002108 return false;
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002109 }
2110 } else {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002111 AddError("continue statement must be in a loop", stmt->source);
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002112 return false;
2113 }
2114
dan sinclair6bd70612020-06-03 16:11:28 +00002115 return true;
dan sinclairaec965e2020-04-07 12:54:29 +00002116 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002117 if (stmt->Is<ast::DiscardStatement>()) {
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00002118 if (auto* continuing =
2119 sem_statement
2120 ->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
2121 AddError("continuing blocks must not contain a discard statement",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002122 stmt->source);
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00002123 if (continuing != sem_statement->Parent()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002124 AddNote("see continuing block here", continuing->Declaration()->source);
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00002125 }
2126 return false;
2127 }
dan sinclair8f3c6352020-07-25 14:33:50 +00002128 return true;
2129 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002130 if (stmt->Is<ast::FallthroughStatement>()) {
dan sinclair1913fc92020-04-07 12:54:59 +00002131 return true;
2132 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002133 if (auto* r = stmt->As<ast::ReturnStatement>()) {
Antonio Maiorano2e974352021-03-22 23:20:17 +00002134 return Return(r);
dan sinclairbf0fff82020-04-07 12:56:24 +00002135 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002136 if (auto* v = stmt->As<ast::VariableDeclStatement>()) {
Ben Claytona88090b2021-03-17 22:47:33 +00002137 return VariableDeclStatement(v);
dan sinclairca893e32020-04-07 12:57:12 +00002138 }
dan sinclair6c498fc2020-04-07 12:47:23 +00002139
Ben Clayton11ed0db2021-10-14 20:30:29 +00002140 AddError("unknown statement type for type determination: " +
2141 std::string(stmt->TypeInfo().name),
Ben Clayton4f3ff572021-10-15 17:33:10 +00002142 stmt->source);
dan sinclair417a90d2020-04-06 21:07:41 +00002143 return false;
2144}
2145
Ben Clayton86481202021-10-19 18:38:54 +00002146bool Resolver::CaseStatement(const ast::CaseStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002147 auto* sem = builder_->create<sem::SwitchCaseBlockStatement>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00002148 stmt->body, current_compound_statement_);
Ben Clayton6e459fe2021-07-14 09:44:41 +00002149 builder_->Sem().Add(stmt, sem);
Ben Clayton4f3ff572021-10-15 17:33:10 +00002150 builder_->Sem().Add(stmt->body, sem);
2151 Mark(stmt->body);
2152 for (auto* sel : stmt->selectors) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002153 Mark(sel);
2154 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00002155 return Scope(sem, [&] { return Statements(stmt->body->statements); });
Ben Clayton9430cb42021-03-09 15:06:37 +00002156}
2157
Ben Clayton86481202021-10-19 18:38:54 +00002158bool Resolver::IfStatement(const ast::IfStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002159 auto* sem =
2160 builder_->create<sem::IfStatement>(stmt, current_compound_statement_);
2161 builder_->Sem().Add(stmt, sem);
2162 return Scope(sem, [&] {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002163 if (!Expression(stmt->condition)) {
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002164 return false;
2165 }
Ben Clayton5fb87dd2021-03-09 15:17:28 +00002166
Ben Clayton4f3ff572021-10-15 17:33:10 +00002167 auto* cond_type = TypeOf(stmt->condition)->UnwrapRef();
Ben Clayton6e459fe2021-07-14 09:44:41 +00002168 if (!cond_type->Is<sem::Bool>()) {
2169 AddError("if statement condition must be bool, got " +
2170 cond_type->FriendlyName(builder_->Symbols()),
Ben Clayton4f3ff572021-10-15 17:33:10 +00002171 stmt->condition->source);
Ben Clayton6e459fe2021-07-14 09:44:41 +00002172 return false;
2173 }
2174
Ben Clayton4f3ff572021-10-15 17:33:10 +00002175 Mark(stmt->body);
Ben Clayton6e459fe2021-07-14 09:44:41 +00002176 auto* body = builder_->create<sem::BlockStatement>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00002177 stmt->body, current_compound_statement_);
2178 builder_->Sem().Add(stmt->body, body);
2179 if (!Scope(body, [&] { return Statements(stmt->body->statements); })) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002180 return false;
2181 }
2182
Ben Clayton4f3ff572021-10-15 17:33:10 +00002183 for (auto* else_stmt : stmt->else_statements) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002184 Mark(else_stmt);
2185 if (!ElseStatement(else_stmt)) {
2186 return false;
2187 }
2188 }
2189 return true;
2190 });
2191}
2192
Ben Clayton86481202021-10-19 18:38:54 +00002193bool Resolver::ElseStatement(const ast::ElseStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002194 auto* sem =
2195 builder_->create<sem::ElseStatement>(stmt, current_compound_statement_);
2196 builder_->Sem().Add(stmt, sem);
2197 return Scope(sem, [&] {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002198 if (auto* cond = stmt->condition) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002199 if (!Expression(cond)) {
2200 return false;
2201 }
Antonio Maiorano9fdfa1e2021-05-10 13:46:06 +00002202
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002203 auto* else_cond_type = TypeOf(cond)->UnwrapRef();
Ben Claytonc03d3bd2021-05-20 14:22:28 +00002204 if (!else_cond_type->Is<sem::Bool>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002205 AddError("else statement condition must be bool, got " +
2206 else_cond_type->FriendlyName(builder_->Symbols()),
Ben Clayton4f3ff572021-10-15 17:33:10 +00002207 cond->source);
Antonio Maiorano9fdfa1e2021-05-10 13:46:06 +00002208 return false;
2209 }
Ben Claytondba65b72021-03-31 20:35:46 +00002210 }
Ben Clayton6e459fe2021-07-14 09:44:41 +00002211
Ben Clayton4f3ff572021-10-15 17:33:10 +00002212 Mark(stmt->body);
Ben Clayton6e459fe2021-07-14 09:44:41 +00002213 auto* body = builder_->create<sem::BlockStatement>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00002214 stmt->body, current_compound_statement_);
2215 builder_->Sem().Add(stmt->body, body);
2216 return Scope(body, [&] { return Statements(stmt->body->statements); });
Ben Clayton6e459fe2021-07-14 09:44:41 +00002217 });
2218}
2219
Ben Clayton86481202021-10-19 18:38:54 +00002220bool Resolver::BlockStatement(const ast::BlockStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002221 auto* sem = builder_->create<sem::BlockStatement>(
2222 stmt->As<ast::BlockStatement>(), current_compound_statement_);
2223 builder_->Sem().Add(stmt, sem);
Ben Clayton4f3ff572021-10-15 17:33:10 +00002224 return Scope(sem, [&] { return Statements(stmt->statements); });
Ben Clayton5fb87dd2021-03-09 15:17:28 +00002225}
2226
Ben Clayton86481202021-10-19 18:38:54 +00002227bool Resolver::LoopStatement(const ast::LoopStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002228 auto* sem =
2229 builder_->create<sem::LoopStatement>(stmt, current_compound_statement_);
2230 builder_->Sem().Add(stmt, sem);
2231 return Scope(sem, [&] {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002232 Mark(stmt->body);
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002233
Ben Clayton6e459fe2021-07-14 09:44:41 +00002234 auto* body = builder_->create<sem::LoopBlockStatement>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00002235 stmt->body, current_compound_statement_);
2236 builder_->Sem().Add(stmt->body, body);
Ben Clayton6e459fe2021-07-14 09:44:41 +00002237 return Scope(body, [&] {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002238 if (!Statements(stmt->body->statements)) {
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002239 return false;
2240 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00002241 if (stmt->continuing) {
2242 Mark(stmt->continuing);
2243 if (!stmt->continuing->Empty()) {
2244 auto* continuing =
2245 builder_->create<sem::LoopContinuingBlockStatement>(
2246 stmt->continuing, current_compound_statement_);
2247 builder_->Sem().Add(stmt->continuing, continuing);
2248 if (!Scope(continuing, [&] {
2249 return Statements(stmt->continuing->statements);
2250 })) {
2251 return false;
2252 }
Ben Clayton6e459fe2021-07-14 09:44:41 +00002253 }
2254 }
2255 return true;
2256 });
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002257 });
2258}
2259
Ben Clayton86481202021-10-19 18:38:54 +00002260bool Resolver::ForLoopStatement(const ast::ForLoopStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002261 auto* sem = builder_->create<sem::ForLoopStatement>(
2262 stmt, current_compound_statement_);
2263 builder_->Sem().Add(stmt, sem);
2264 return Scope(sem, [&] {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002265 if (auto* initializer = stmt->initializer) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002266 Mark(initializer);
2267 if (!Statement(initializer)) {
2268 return false;
2269 }
Ben Claytonf4075a72021-07-02 19:27:42 +00002270 }
2271
Ben Clayton4f3ff572021-10-15 17:33:10 +00002272 if (auto* condition = stmt->condition) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002273 if (!Expression(condition)) {
2274 return false;
2275 }
Ben Claytonf4075a72021-07-02 19:27:42 +00002276
Ben Claytonada48642021-07-29 16:55:27 +00002277 if (!TypeOf(condition)->UnwrapRef()->Is<sem::Bool>()) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002278 AddError(
2279 "for-loop condition must be bool, got " + TypeNameOf(condition),
Ben Clayton4f3ff572021-10-15 17:33:10 +00002280 condition->source);
Ben Clayton6e459fe2021-07-14 09:44:41 +00002281 return false;
2282 }
Ben Claytonf4075a72021-07-02 19:27:42 +00002283 }
Ben Claytonf4075a72021-07-02 19:27:42 +00002284
Ben Clayton4f3ff572021-10-15 17:33:10 +00002285 if (auto* continuing = stmt->continuing) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002286 Mark(continuing);
2287 if (!Statement(continuing)) {
2288 return false;
2289 }
2290 }
2291
Ben Clayton4f3ff572021-10-15 17:33:10 +00002292 Mark(stmt->body);
Ben Clayton6e459fe2021-07-14 09:44:41 +00002293
2294 auto* body = builder_->create<sem::LoopBlockStatement>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00002295 stmt->body, current_compound_statement_);
2296 builder_->Sem().Add(stmt->body, body);
2297 return Scope(body, [&] { return Statements(stmt->body->statements); });
Ben Clayton6e459fe2021-07-14 09:44:41 +00002298 });
Ben Claytonf4075a72021-07-02 19:27:42 +00002299}
2300
Ben Clayton86481202021-10-19 18:38:54 +00002301bool Resolver::Expression(const ast::Expression* root) {
2302 std::vector<const ast::Expression*> sorted;
Ben Claytonf164a4a2021-10-21 20:38:54 +00002303 if (!ast::TraverseExpressions<ast::TraverseOrder::RightToLeft>(
2304 root, diagnostics_, [&](const ast::Expression* expr) {
2305 Mark(expr);
2306 sorted.emplace_back(expr);
2307 return ast::TraverseAction::Descend;
2308 })) {
Ben Clayton313e6182021-06-17 19:56:14 +00002309 return false;
2310 }
2311
Ben Claytonb7bcbf02021-09-08 15:18:36 +00002312 for (auto* expr : utils::Reverse(sorted)) {
2313 bool ok = false;
2314 if (auto* array = expr->As<ast::ArrayAccessorExpression>()) {
2315 ok = ArrayAccessor(array);
2316 } else if (auto* bin_op = expr->As<ast::BinaryExpression>()) {
2317 ok = Binary(bin_op);
2318 } else if (auto* bitcast = expr->As<ast::BitcastExpression>()) {
2319 ok = Bitcast(bitcast);
2320 } else if (auto* call = expr->As<ast::CallExpression>()) {
2321 ok = Call(call);
2322 } else if (auto* ctor = expr->As<ast::ConstructorExpression>()) {
2323 ok = Constructor(ctor);
2324 } else if (auto* ident = expr->As<ast::IdentifierExpression>()) {
2325 ok = Identifier(ident);
2326 } else if (auto* member = expr->As<ast::MemberAccessorExpression>()) {
2327 ok = MemberAccessor(member);
2328 } else if (auto* unary = expr->As<ast::UnaryOpExpression>()) {
2329 ok = UnaryOp(unary);
Ben Clayton1aa98e62021-10-21 23:04:44 +00002330 } else if (expr->Is<ast::PhonyExpression>()) {
2331 ok = true; // No-op
Ben Claytonb7bcbf02021-09-08 15:18:36 +00002332 } else {
2333 TINT_ICE(Resolver, diagnostics_)
2334 << "unhandled expression type: " << expr->TypeInfo().name;
2335 return false;
2336 }
2337 if (!ok) {
2338 return false;
2339 }
2340 }
2341
Ben Clayton313e6182021-06-17 19:56:14 +00002342 return true;
dan sinclair417a90d2020-04-06 21:07:41 +00002343}
2344
Ben Clayton86481202021-10-19 18:38:54 +00002345bool Resolver::ArrayAccessor(const ast::ArrayAccessorExpression* expr) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002346 auto* idx = expr->index;
2347 auto* res = TypeOf(expr->array);
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002348 auto* parent_type = res->UnwrapRef();
Ben Clayton4cd5eea2021-05-07 20:58:34 +00002349 const sem::Type* ret = nullptr;
2350 if (auto* arr = parent_type->As<sem::Array>()) {
2351 ret = arr->ElemType();
Antonio Maiorano3751fd22021-04-19 22:51:23 +00002352 } else if (auto* vec = parent_type->As<sem::Vector>()) {
Ben Clayton1b6a8ce2020-12-01 21:07:27 +00002353 ret = vec->type();
Antonio Maiorano3751fd22021-04-19 22:51:23 +00002354 } else if (auto* mat = parent_type->As<sem::Matrix>()) {
2355 ret = builder_->create<sem::Vector>(mat->type(), mat->rows());
dan sinclair973bd6a2020-04-07 12:57:42 +00002356 } else {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002357 AddError("cannot index type '" + TypeNameOf(expr->array) + "'",
2358 expr->source);
dan sinclair973bd6a2020-04-07 12:57:42 +00002359 return false;
2360 }
dan sinclair8eddb782020-04-23 22:26:52 +00002361
Sarah10442ef2021-06-16 18:50:13 +00002362 if (!TypeOf(idx)->UnwrapRef()->IsAnyOf<sem::I32, sem::U32>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002363 AddError("index must be of type 'i32' or 'u32', found: '" +
2364 TypeNameOf(idx) + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002365 idx->source);
Sarah10442ef2021-06-16 18:50:13 +00002366 return false;
2367 }
2368
2369 if (parent_type->Is<sem::Array>() || parent_type->Is<sem::Matrix>()) {
2370 if (!res->Is<sem::Reference>()) {
2371 // TODO(bclayton): expand this to allow any const_expr expression
2372 // https://github.com/gpuweb/gpuweb/issues/1272
2373 auto* scalar = idx->As<ast::ScalarConstructorExpression>();
Ben Clayton4f3ff572021-10-15 17:33:10 +00002374 if (!scalar || !scalar->literal->As<ast::IntLiteral>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002375 AddError("index must be signed or unsigned integer literal",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002376 idx->source);
Sarah10442ef2021-06-16 18:50:13 +00002377 return false;
2378 }
2379 }
2380 }
2381
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002382 // If we're extracting from a reference, we return a reference.
2383 if (auto* ref = res->As<sem::Reference>()) {
Ben Clayton18588542021-06-04 22:17:37 +00002384 ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
2385 ref->Access());
dan sinclair8eddb782020-04-23 22:26:52 +00002386 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002387 SetExprInfo(expr, ret);
dan sinclair8eddb782020-04-23 22:26:52 +00002388
dan sinclair973bd6a2020-04-07 12:57:42 +00002389 return true;
2390}
2391
Ben Clayton86481202021-10-19 18:38:54 +00002392bool Resolver::Bitcast(const ast::BitcastExpression* expr) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002393 auto* ty = Type(expr->type);
Ben Clayton0e66b402021-06-03 08:17:44 +00002394 if (!ty) {
2395 return false;
2396 }
Sarah4b1c9de2021-06-16 17:42:13 +00002397 if (ty->Is<sem::Pointer>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002398 AddError("cannot cast to a pointer", expr->source);
Sarah4b1c9de2021-06-16 17:42:13 +00002399 return false;
2400 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00002401 SetExprInfo(expr, ty, expr->type->FriendlyName(builder_->Symbols()));
dan sinclaira01777c2020-04-07 12:57:52 +00002402 return true;
2403}
2404
Ben Clayton86481202021-10-19 18:38:54 +00002405bool Resolver::Call(const ast::CallExpression* call) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002406 Mark(call->func);
2407 auto* ident = call->func;
2408 auto name = builder_->Symbols().NameFor(ident->symbol);
Ben Clayton1618f4b2021-02-03 21:02:25 +00002409
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00002410 auto intrinsic_type = sem::ParseIntrinsicType(name);
Ben Clayton316f9f62021-02-08 22:31:44 +00002411 if (intrinsic_type != IntrinsicType::kNone) {
Ben Clayton5f0ea112021-03-09 10:54:37 +00002412 if (!IntrinsicCall(call, intrinsic_type)) {
Ben Clayton1618f4b2021-02-03 21:02:25 +00002413 return false;
2414 }
Ben Clayton33352542021-01-29 16:43:41 +00002415 } else {
Antonio Maiorano14b34032021-06-09 20:17:59 +00002416 if (!FunctionCall(call)) {
Ben Clayton1618f4b2021-02-03 21:02:25 +00002417 return false;
2418 }
Sarah Mashayekhi844f6322020-08-18 02:10:03 +00002419 }
2420
Ben Clayton1fa6f5c2021-08-21 08:50:40 +00002421 return ValidateCall(call);
2422}
2423
Ben Clayton86481202021-10-19 18:38:54 +00002424bool Resolver::ValidateCall(const ast::CallExpression* call) {
Ben Clayton1fa6f5c2021-08-21 08:50:40 +00002425 if (TypeOf(call)->Is<sem::Void>()) {
2426 bool is_call_statement = false;
2427 if (current_statement_) {
2428 if (auto* call_stmt =
2429 As<ast::CallStatement>(current_statement_->Declaration())) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002430 if (call_stmt->expr == call) {
Ben Clayton1fa6f5c2021-08-21 08:50:40 +00002431 is_call_statement = true;
2432 }
2433 }
2434 }
2435 if (!is_call_statement) {
2436 // https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
2437 // If the called function does not return a value, a function call
2438 // statement should be used instead.
Ben Clayton4f3ff572021-10-15 17:33:10 +00002439 auto* ident = call->func;
2440 auto name = builder_->Symbols().NameFor(ident->symbol);
Ben Clayton1fa6f5c2021-08-21 08:50:40 +00002441 // A function call is made to either a user declared function or an
2442 // intrinsic. function_calls_ only maps CallExpression to user declared
2443 // functions
2444 bool is_function = function_calls_.count(call) != 0;
2445 AddError((is_function ? "function" : "intrinsic") + std::string(" '") +
2446 name + "' does not return a value",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002447 call->source);
Ben Clayton1fa6f5c2021-08-21 08:50:40 +00002448 return false;
2449 }
2450 }
2451
dan sinclair3ca87462020-04-07 16:41:10 +00002452 return true;
2453}
2454
Ben Clayton72789de2021-10-21 20:36:04 +00002455bool Resolver::ValidateCallStatement(const ast::CallStatement*) {
Ben Clayton7fe01062021-06-11 13:22:27 +00002456 return true;
2457}
2458
Ben Clayton86481202021-10-19 18:38:54 +00002459bool Resolver::IntrinsicCall(const ast::CallExpression* call,
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00002460 sem::IntrinsicType intrinsic_type) {
Ben Clayton12ed13d2021-04-28 12:38:13 +00002461 std::vector<const sem::Type*> arg_tys;
Ben Clayton4f3ff572021-10-15 17:33:10 +00002462 arg_tys.reserve(call->args.size());
2463 for (auto* expr : call->args) {
Ben Clayton316f9f62021-02-08 22:31:44 +00002464 arg_tys.emplace_back(TypeOf(expr));
2465 }
2466
Ben Claytonb29a59d2021-06-01 19:06:31 +00002467 auto* result =
Ben Clayton4f3ff572021-10-15 17:33:10 +00002468 intrinsic_table_->Lookup(intrinsic_type, arg_tys, call->source);
Ben Claytonb29a59d2021-06-01 19:06:31 +00002469 if (!result) {
dan sinclairb4fee2f2020-09-22 19:42:13 +00002470 return false;
2471 }
2472
Ben Clayton3e59eb02021-06-10 17:31:54 +00002473 if (result->IsDeprecated()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002474 AddWarning("use of deprecated intrinsic", call->source);
Ben Clayton3e59eb02021-06-10 17:31:54 +00002475 }
2476
Sarah71198432021-07-16 13:38:05 +00002477 auto* out = builder_->create<sem::Call>(call, result, current_statement_);
2478 builder_->Sem().Add(call, out);
Ben Clayton71f619b2021-07-13 12:18:13 +00002479 SetExprInfo(call, result->ReturnType());
Ben Clayton71786c92021-06-03 16:07:34 +00002480
2481 current_function_->intrinsic_calls.emplace_back(
2482 IntrinsicCallInfo{call, result});
2483
Sarah71198432021-07-16 13:38:05 +00002484 if (IsTextureIntrinsic(intrinsic_type) &&
2485 !ValidateTextureIntrinsicFunction(call, out)) {
2486 return false;
2487 }
2488
2489 return true;
2490}
2491
2492bool Resolver::ValidateTextureIntrinsicFunction(
2493 const ast::CallExpression* ast_call,
2494 const sem::Call* sem_call) {
2495 auto* intrinsic = sem_call->Target()->As<sem::Intrinsic>();
2496 if (!intrinsic) {
2497 return false;
2498 }
2499 std::string func_name = intrinsic->str();
Ben Clayton1364f202021-10-14 21:17:29 +00002500 auto& signature = intrinsic->Signature();
2501 auto index = signature.IndexOf(sem::ParameterUsage::kOffset);
Sarah71198432021-07-16 13:38:05 +00002502 if (index > -1) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002503 auto* param = ast_call->args[index];
Sarah71198432021-07-16 13:38:05 +00002504 if (param->Is<ast::TypeConstructorExpression>()) {
2505 auto values = ConstantValueOf(param);
2506 if (!values.IsValid()) {
Sarah36b49e82021-07-21 03:34:34 +00002507 AddError(
2508 "'" + func_name + "' offset parameter must be a const_expression",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002509 param->source);
Sarah71198432021-07-16 13:38:05 +00002510 return false;
2511 }
2512 if (!values.Type()->Is<sem::Vector>() ||
2513 !values.ElementType()->Is<sem::I32>()) {
2514 TINT_ICE(Resolver, diagnostics_)
2515 << "failed to resolve '" + func_name + "' offset parameter type";
2516 return false;
2517 }
2518 for (auto offset : values.Elements()) {
2519 auto offset_value = offset.i32;
2520 if (offset_value < -8 || offset_value > 7) {
2521 AddError("each offset component of '" + func_name +
2522 "' must be at least -8 and at most 7. "
2523 "found: '" +
2524 std::to_string(offset_value) + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002525 param->source);
Sarah71198432021-07-16 13:38:05 +00002526 return false;
2527 }
2528 }
2529 } else {
Sarah36b49e82021-07-21 03:34:34 +00002530 AddError(
2531 "'" + func_name + "' offset parameter must be a const_expression",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002532 param->source);
Sarah71198432021-07-16 13:38:05 +00002533 return false;
2534 }
2535 }
dan sinclairb4fee2f2020-09-22 19:42:13 +00002536 return true;
dan sinclair46e959d2020-06-01 13:43:22 +00002537}
2538
Antonio Maiorano14b34032021-06-09 20:17:59 +00002539bool Resolver::FunctionCall(const ast::CallExpression* call) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002540 auto* ident = call->func;
2541 auto name = builder_->Symbols().NameFor(ident->symbol);
Antonio Maiorano14b34032021-06-09 20:17:59 +00002542
Ben Clayton4f3ff572021-10-15 17:33:10 +00002543 auto callee_func_it = symbol_to_function_.find(ident->symbol);
Antonio Maiorano14b34032021-06-09 20:17:59 +00002544 if (callee_func_it == symbol_to_function_.end()) {
2545 if (current_function_ &&
Ben Clayton4f3ff572021-10-15 17:33:10 +00002546 current_function_->declaration->symbol == ident->symbol) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00002547 AddError("recursion is not permitted. '" + name +
Ben Claytonffd28e22021-06-24 11:27:36 +00002548 "' attempted to call itself.",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002549 call->source);
Antonio Maiorano14b34032021-06-09 20:17:59 +00002550 } else {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002551 AddError("unable to find called function: " + name, call->source);
Antonio Maiorano14b34032021-06-09 20:17:59 +00002552 }
2553 return false;
2554 }
2555 auto* callee_func = callee_func_it->second;
2556
2557 if (current_function_) {
2558 callee_func->callsites.push_back(call);
2559
2560 // Note: Requires called functions to be resolved first.
2561 // This is currently guaranteed as functions must be declared before
2562 // use.
2563 current_function_->transitive_calls.add(callee_func);
2564 for (auto* transitive_call : callee_func->transitive_calls) {
2565 current_function_->transitive_calls.add(transitive_call);
2566 }
2567
2568 // We inherit any referenced variables from the callee.
2569 for (auto* var : callee_func->referenced_module_vars) {
2570 set_referenced_from_function_if_needed(var, false);
2571 }
2572 }
2573
Sarah3d441d42021-07-20 18:14:02 +00002574 function_calls_.emplace(call,
2575 FunctionCallInfo{callee_func, current_statement_});
2576 SetExprInfo(call, callee_func->return_type, callee_func->return_type_name);
2577
2578 if (!ValidateFunctionCall(call, callee_func)) {
2579 return false;
2580 }
2581 return true;
2582}
2583
2584bool Resolver::ValidateFunctionCall(const ast::CallExpression* call,
Ben Claytonb09723e2021-08-31 16:14:46 +00002585 const FunctionInfo* target) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002586 auto* ident = call->func;
2587 auto name = builder_->Symbols().NameFor(ident->symbol);
Sarah3d441d42021-07-20 18:14:02 +00002588
Ben Claytonb09723e2021-08-31 16:14:46 +00002589 if (target->declaration->IsEntryPoint()) {
2590 // https://www.w3.org/TR/WGSL/#function-restriction
2591 // An entry point must never be the target of a function call.
2592 AddError("entry point functions cannot be the target of a function call",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002593 call->source);
Ben Claytonb09723e2021-08-31 16:14:46 +00002594 return false;
2595 }
2596
Ben Clayton4f3ff572021-10-15 17:33:10 +00002597 if (call->args.size() != target->parameters.size()) {
2598 bool more = call->args.size() > target->parameters.size();
Ben Claytonffd28e22021-06-24 11:27:36 +00002599 AddError("too " + (more ? std::string("many") : std::string("few")) +
2600 " arguments in call to '" + name + "', expected " +
Ben Claytonb09723e2021-08-31 16:14:46 +00002601 std::to_string(target->parameters.size()) + ", got " +
Ben Clayton4f3ff572021-10-15 17:33:10 +00002602 std::to_string(call->args.size()),
2603 call->source);
Antonio Maiorano14b34032021-06-09 20:17:59 +00002604 return false;
2605 }
2606
Ben Clayton4f3ff572021-10-15 17:33:10 +00002607 for (size_t i = 0; i < call->args.size(); ++i) {
Ben Claytonb09723e2021-08-31 16:14:46 +00002608 const VariableInfo* param = target->parameters[i];
Ben Clayton4f3ff572021-10-15 17:33:10 +00002609 const ast::Expression* arg_expr = call->args[i];
Antonio Maiorano14b34032021-06-09 20:17:59 +00002610 auto* arg_type = TypeOf(arg_expr)->UnwrapRef();
2611
2612 if (param->type != arg_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002613 AddError("type mismatch for argument " + std::to_string(i + 1) +
2614 " in call to '" + name + "', expected '" +
2615 param->type->FriendlyName(builder_->Symbols()) + "', got '" +
2616 arg_type->FriendlyName(builder_->Symbols()) + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002617 arg_expr->source);
Antonio Maiorano14b34032021-06-09 20:17:59 +00002618 return false;
2619 }
Sarah3d441d42021-07-20 18:14:02 +00002620
Ben Clayton4f3ff572021-10-15 17:33:10 +00002621 if (param->declaration->type->Is<ast::Pointer>()) {
Sarah3d441d42021-07-20 18:14:02 +00002622 auto is_valid = false;
2623 if (auto* ident_expr = arg_expr->As<ast::IdentifierExpression>()) {
2624 VariableInfo* var;
Ben Clayton4f3ff572021-10-15 17:33:10 +00002625 if (!variable_stack_.get(ident_expr->symbol, &var)) {
Sarah3d441d42021-07-20 18:14:02 +00002626 TINT_ICE(Resolver, diagnostics_) << "failed to resolve identifier";
2627 return false;
2628 }
2629 if (var->kind == VariableKind::kParameter) {
2630 is_valid = true;
2631 }
2632 } else if (auto* unary = arg_expr->As<ast::UnaryOpExpression>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002633 if (unary->op == ast::UnaryOp::kAddressOf) {
Sarah3d441d42021-07-20 18:14:02 +00002634 if (auto* ident_unary =
Ben Clayton4f3ff572021-10-15 17:33:10 +00002635 unary->expr->As<ast::IdentifierExpression>()) {
Sarah3d441d42021-07-20 18:14:02 +00002636 VariableInfo* var;
Ben Clayton4f3ff572021-10-15 17:33:10 +00002637 if (!variable_stack_.get(ident_unary->symbol, &var)) {
Sarah3d441d42021-07-20 18:14:02 +00002638 TINT_ICE(Resolver, diagnostics_)
2639 << "failed to resolve identifier";
2640 return false;
2641 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00002642 if (var->declaration->is_const) {
Sarah3d441d42021-07-20 18:14:02 +00002643 TINT_ICE(Resolver, diagnostics_)
2644 << "Resolver::FunctionCall() encountered an address-of "
2645 "expression of a constant identifier expression";
2646 return false;
2647 }
2648 is_valid = true;
2649 }
2650 }
2651 }
2652
James Price1ca6fba2021-09-29 18:56:17 +00002653 if (!is_valid &&
2654 IsValidationEnabled(
Ben Clayton4f3ff572021-10-15 17:33:10 +00002655 param->declaration->decorations,
James Price1ca6fba2021-09-29 18:56:17 +00002656 ast::DisabledValidation::kIgnoreInvalidPointerArgument)) {
Sarah3d441d42021-07-20 18:14:02 +00002657 AddError(
2658 "expected an address-of expression of a variable identifier "
2659 "expression or a function parameter",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002660 arg_expr->source);
Sarah3d441d42021-07-20 18:14:02 +00002661 return false;
2662 }
2663 }
Antonio Maiorano14b34032021-06-09 20:17:59 +00002664 }
Antonio Maiorano14b34032021-06-09 20:17:59 +00002665 return true;
2666}
2667
Ben Clayton86481202021-10-19 18:38:54 +00002668bool Resolver::Constructor(const ast::ConstructorExpression* expr) {
Arman Uguray3549e2e2021-03-15 21:21:33 +00002669 if (auto* type_ctor = expr->As<ast::TypeConstructorExpression>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002670 auto* type = Type(type_ctor->type);
Ben Clayton0e66b402021-06-03 08:17:44 +00002671 if (!type) {
2672 return false;
2673 }
Arman Uguray3549e2e2021-03-15 21:21:33 +00002674
Ben Clayton4f3ff572021-10-15 17:33:10 +00002675 auto type_name = type_ctor->type->FriendlyName(builder_->Symbols());
Ben Clayton02ebf0d2021-05-05 09:09:41 +00002676
Arman Uguray3549e2e2021-03-15 21:21:33 +00002677 // Now that the argument types have been determined, make sure that they
2678 // obey the constructor type rules laid out in
2679 // https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr.
Ben Clayton71f619b2021-07-13 12:18:13 +00002680 bool ok = true;
Ben Clayton02ebf0d2021-05-05 09:09:41 +00002681 if (auto* vec_type = type->As<sem::Vector>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00002682 ok = ValidateVectorConstructor(type_ctor, vec_type, type_name);
2683 } else if (auto* mat_type = type->As<sem::Matrix>()) {
2684 ok = ValidateMatrixConstructor(type_ctor, mat_type, type_name);
2685 } else if (type->is_scalar()) {
2686 ok = ValidateScalarConstructor(type_ctor, type, type_name);
2687 } else if (auto* arr_type = type->As<sem::Array>()) {
2688 ok = ValidateArrayConstructor(type_ctor, arr_type);
2689 } else if (auto* struct_type = type->As<sem::Struct>()) {
2690 ok = ValidateStructureConstructor(type_ctor, struct_type);
James Pricecbbb4202021-08-13 15:20:42 +00002691 } else {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002692 AddError("type is not constructible", type_ctor->source);
James Pricecbbb4202021-08-13 15:20:42 +00002693 return false;
Arman Uguray3549e2e2021-03-15 21:21:33 +00002694 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002695 if (!ok) {
2696 return false;
Arman Uguray097c75a2021-03-18 15:43:14 +00002697 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002698 SetExprInfo(expr, type, type_name);
2699 return true;
2700 }
2701
2702 if (auto* scalar_ctor = expr->As<ast::ScalarConstructorExpression>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002703 Mark(scalar_ctor->literal);
2704 auto* type = TypeOf(scalar_ctor->literal);
Ben Clayton0e66b402021-06-03 08:17:44 +00002705 if (!type) {
2706 return false;
2707 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002708 SetExprInfo(expr, type);
2709 return true;
Arman Uguray3549e2e2021-03-15 21:21:33 +00002710 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002711
2712 TINT_ICE(Resolver, diagnostics_) << "unexpected constructor expression type";
2713 return false;
Arman Uguray3549e2e2021-03-15 21:21:33 +00002714}
2715
Sarahe2859112021-07-09 16:32:00 +00002716bool Resolver::ValidateStructureConstructor(
2717 const ast::TypeConstructorExpression* ctor,
2718 const sem::Struct* struct_type) {
James Pricecbbb4202021-08-13 15:20:42 +00002719 if (!struct_type->IsConstructible()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002720 AddError("struct constructor has non-constructible type", ctor->source);
James Pricecbbb4202021-08-13 15:20:42 +00002721 return false;
2722 }
2723
Ben Clayton4f3ff572021-10-15 17:33:10 +00002724 if (ctor->values.size() > 0) {
2725 if (ctor->values.size() != struct_type->Members().size()) {
2726 std::string fm =
2727 ctor->values.size() < struct_type->Members().size() ? "few" : "many";
Sarahe2859112021-07-09 16:32:00 +00002728 AddError("struct constructor has too " + fm + " inputs: expected " +
2729 std::to_string(struct_type->Members().size()) + ", found " +
Ben Clayton4f3ff572021-10-15 17:33:10 +00002730 std::to_string(ctor->values.size()),
2731 ctor->source);
Sarahe2859112021-07-09 16:32:00 +00002732 return false;
2733 }
2734 for (auto* member : struct_type->Members()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002735 auto* value = ctor->values[member->Index()];
Sarahe2859112021-07-09 16:32:00 +00002736 if (member->Type() != TypeOf(value)->UnwrapRef()) {
2737 AddError(
2738 "type in struct constructor does not match struct member type: "
2739 "expected '" +
2740 member->Type()->FriendlyName(builder_->Symbols()) +
2741 "', found '" + TypeNameOf(value) + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002742 value->source);
Sarahe2859112021-07-09 16:32:00 +00002743 return false;
2744 }
2745 }
2746 }
2747 return true;
2748}
2749
Sarah5a4dc9a2021-06-11 15:51:26 +00002750bool Resolver::ValidateArrayConstructor(
2751 const ast::TypeConstructorExpression* ctor,
2752 const sem::Array* array_type) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002753 auto& values = ctor->values;
Sarah5a4dc9a2021-06-11 15:51:26 +00002754 auto* elem_type = array_type->ElemType();
2755 for (auto* value : values) {
2756 auto* value_type = TypeOf(value)->UnwrapRef();
2757 if (value_type != elem_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002758 AddError(
Sarah5a4dc9a2021-06-11 15:51:26 +00002759 "type in array constructor does not match array type: "
2760 "expected '" +
2761 elem_type->FriendlyName(builder_->Symbols()) + "', found '" +
2762 TypeNameOf(value) + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002763 value->source);
Sarah5a4dc9a2021-06-11 15:51:26 +00002764 return false;
2765 }
2766 }
2767
2768 if (array_type->IsRuntimeSized()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002769 AddError("cannot init a runtime-sized array", ctor->source);
Sarah5a4dc9a2021-06-11 15:51:26 +00002770 return false;
James Pricecbbb4202021-08-13 15:20:42 +00002771 } else if (!elem_type->IsConstructible()) {
2772 AddError("array constructor has non-constructible element type",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002773 ctor->type->As<ast::Array>()->type->source);
James Pricecbbb4202021-08-13 15:20:42 +00002774 return false;
Sarah5a4dc9a2021-06-11 15:51:26 +00002775 } else if (!values.empty() && (values.size() != array_type->Count())) {
2776 std::string fm = values.size() < array_type->Count() ? "few" : "many";
Ben Claytonffd28e22021-06-24 11:27:36 +00002777 AddError("array constructor has too " + fm + " elements: expected " +
2778 std::to_string(array_type->Count()) + ", found " +
2779 std::to_string(values.size()),
Ben Clayton4f3ff572021-10-15 17:33:10 +00002780 ctor->source);
Sarah5a4dc9a2021-06-11 15:51:26 +00002781 return false;
2782 } else if (values.size() > array_type->Count()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002783 AddError("array constructor has too many elements: expected " +
2784 std::to_string(array_type->Count()) + ", found " +
2785 std::to_string(values.size()),
Ben Clayton4f3ff572021-10-15 17:33:10 +00002786 ctor->source);
Sarah5a4dc9a2021-06-11 15:51:26 +00002787 return false;
2788 }
2789 return true;
2790}
2791
Ben Clayton109b18f2021-04-28 13:50:43 +00002792bool Resolver::ValidateVectorConstructor(
2793 const ast::TypeConstructorExpression* ctor,
Ben Clayton71f619b2021-07-13 12:18:13 +00002794 const sem::Vector* vec_type,
2795 const std::string& type_name) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002796 auto& values = ctor->values;
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002797 auto* elem_type = vec_type->type();
Arman Uguray3549e2e2021-03-15 21:21:33 +00002798 size_t value_cardinality_sum = 0;
2799 for (auto* value : values) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002800 auto* value_type = TypeOf(value)->UnwrapRef();
Arman Uguray3549e2e2021-03-15 21:21:33 +00002801 if (value_type->is_scalar()) {
2802 if (elem_type != value_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002803 AddError(
Arman Uguray3549e2e2021-03-15 21:21:33 +00002804 "type in vector constructor does not match vector type: "
2805 "expected '" +
2806 elem_type->FriendlyName(builder_->Symbols()) + "', found '" +
Ben Clayton109b18f2021-04-28 13:50:43 +00002807 TypeNameOf(value) + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002808 value->source);
Arman Uguray3549e2e2021-03-15 21:21:33 +00002809 return false;
2810 }
2811
2812 value_cardinality_sum++;
Antonio Maiorano3751fd22021-04-19 22:51:23 +00002813 } else if (auto* value_vec = value_type->As<sem::Vector>()) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002814 auto* value_elem_type = value_vec->type();
Arman Uguray3549e2e2021-03-15 21:21:33 +00002815 // A mismatch of vector type parameter T is only an error if multiple
2816 // arguments are present. A single argument constructor constitutes a
2817 // type conversion expression.
James Price1fa28ac2021-07-19 17:35:39 +00002818 if (elem_type != value_elem_type && values.size() > 1u) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002819 AddError(
Arman Uguray3549e2e2021-03-15 21:21:33 +00002820 "type in vector constructor does not match vector type: "
2821 "expected '" +
2822 elem_type->FriendlyName(builder_->Symbols()) + "', found '" +
2823 value_elem_type->FriendlyName(builder_->Symbols()) + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002824 value->source);
Arman Uguray3549e2e2021-03-15 21:21:33 +00002825 return false;
2826 }
2827
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00002828 value_cardinality_sum += value_vec->Width();
Arman Uguray3549e2e2021-03-15 21:21:33 +00002829 } else {
2830 // A vector constructor can only accept vectors and scalars.
Ben Claytonffd28e22021-06-24 11:27:36 +00002831 AddError("expected vector or scalar type in vector constructor; found: " +
2832 value_type->FriendlyName(builder_->Symbols()),
Ben Clayton4f3ff572021-10-15 17:33:10 +00002833 value->source);
Arman Uguray3549e2e2021-03-15 21:21:33 +00002834 return false;
2835 }
2836 }
2837
Antonio Maioranob5508fd2021-06-10 13:23:31 +00002838 // A correct vector constructor must either be a zero-value expression,
2839 // a single-value initializer (splat) expression, or the number of components
2840 // of all constructor arguments must add up to the vector cardinality.
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00002841 if (value_cardinality_sum > 1 && value_cardinality_sum != vec_type->Width()) {
Arman Uguray3549e2e2021-03-15 21:21:33 +00002842 if (values.empty()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002843 TINT_ICE(Resolver, diagnostics_)
Arman Uguray3549e2e2021-03-15 21:21:33 +00002844 << "constructor arguments expected to be non-empty!";
2845 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00002846 const Source& values_start = values[0]->source;
2847 const Source& values_end = values[values.size() - 1]->source;
Ben Clayton71f619b2021-07-13 12:18:13 +00002848 AddError("attempted to construct '" + type_name + "' with " +
Ben Claytonffd28e22021-06-24 11:27:36 +00002849 std::to_string(value_cardinality_sum) + " component(s)",
2850 Source::Combine(values_start, values_end));
Arman Uguray3549e2e2021-03-15 21:21:33 +00002851 return false;
dan sinclairb7edc4c2020-04-07 12:46:30 +00002852 }
2853 return true;
2854}
2855
Ben Claytonffe79782021-07-05 20:21:35 +00002856bool Resolver::ValidateVector(const sem::Vector* ty, const Source& source) {
2857 if (!ty->type()->is_scalar()) {
2858 AddError("vector element type must be 'bool', 'f32', 'i32' or 'u32'",
2859 source);
2860 return false;
2861 }
2862 return true;
2863}
2864
2865bool Resolver::ValidateMatrix(const sem::Matrix* ty, const Source& source) {
2866 if (!ty->is_float_matrix()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002867 AddError("matrix element type must be 'f32'", source);
Sarah4d697512021-06-21 17:08:05 +00002868 return false;
2869 }
2870 return true;
Ben Claytonffe79782021-07-05 20:21:35 +00002871}
Sarah4d697512021-06-21 17:08:05 +00002872
Ben Clayton109b18f2021-04-28 13:50:43 +00002873bool Resolver::ValidateMatrixConstructor(
2874 const ast::TypeConstructorExpression* ctor,
Ben Clayton71f619b2021-07-13 12:18:13 +00002875 const sem::Matrix* matrix_type,
2876 const std::string& type_name) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002877 auto& values = ctor->values;
Arman Uguray097c75a2021-03-18 15:43:14 +00002878 // Zero Value expression
2879 if (values.empty()) {
2880 return true;
2881 }
2882
Ben Clayton4f3ff572021-10-15 17:33:10 +00002883 if (!ValidateMatrix(matrix_type, ctor->source)) {
Sarah4d697512021-06-21 17:08:05 +00002884 return false;
2885 }
2886
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002887 auto* elem_type = matrix_type->type();
James Price91689fb2021-10-25 19:20:31 +00002888 auto num_elements = matrix_type->columns() * matrix_type->rows();
2889
2890 // Print a generic error for an invalid matrix constructor, showing the
2891 // available overloads.
2892 auto print_error = [&]() {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002893 const Source& values_start = values[0]->source;
2894 const Source& values_end = values[values.size() - 1]->source;
James Price91689fb2021-10-25 19:20:31 +00002895 auto elem_type_name = elem_type->FriendlyName(builder_->Symbols());
2896 std::stringstream ss;
2897 ss << "invalid constructor for " + type_name << std::endl << std::endl;
2898 ss << "3 candidates available:" << std::endl;
2899 ss << " " << type_name << "()" << std::endl;
2900 ss << " " << type_name << "(" << elem_type_name << ",...,"
2901 << elem_type_name << ")"
2902 << " // " << std::to_string(num_elements) << " arguments" << std::endl;
2903 ss << " " << type_name << "(";
2904 for (uint32_t c = 0; c < matrix_type->columns(); c++) {
2905 if (c > 0) {
2906 ss << ", ";
2907 }
2908 ss << VectorPretty(matrix_type->rows(), elem_type);
2909 }
2910 ss << ")" << std::endl;
2911 AddError(ss.str(), Source::Combine(values_start, values_end));
2912 };
2913
2914 const sem::Type* expected_arg_type = nullptr;
2915 if (num_elements == values.size()) {
2916 // Column-major construction from scalar elements.
2917 expected_arg_type = matrix_type->type();
2918 } else if (matrix_type->columns() == values.size()) {
2919 // Column-by-column construction from vectors.
2920 expected_arg_type = matrix_type->ColumnType();
2921 } else {
2922 print_error();
Arman Uguray097c75a2021-03-18 15:43:14 +00002923 return false;
2924 }
2925
2926 for (auto* value : values) {
James Price91689fb2021-10-25 19:20:31 +00002927 if (TypeOf(value)->UnwrapRef() != expected_arg_type) {
2928 print_error();
Arman Uguray097c75a2021-03-18 15:43:14 +00002929 return false;
2930 }
2931 }
2932
2933 return true;
2934}
2935
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002936bool Resolver::ValidateScalarConstructor(
2937 const ast::TypeConstructorExpression* ctor,
Ben Clayton71f619b2021-07-13 12:18:13 +00002938 const sem::Type* type,
2939 const std::string& type_name) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002940 if (ctor->values.size() == 0) {
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002941 return true;
2942 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00002943 if (ctor->values.size() > 1) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002944 AddError("expected zero or one value in constructor, got " +
Ben Clayton4f3ff572021-10-15 17:33:10 +00002945 std::to_string(ctor->values.size()),
2946 ctor->source);
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002947 return false;
2948 }
2949
2950 // Validate constructor
Ben Clayton4f3ff572021-10-15 17:33:10 +00002951 auto* value = ctor->values[0];
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002952 auto* value_type = TypeOf(value)->UnwrapRef();
2953
2954 using Bool = sem::Bool;
2955 using I32 = sem::I32;
2956 using U32 = sem::U32;
2957 using F32 = sem::F32;
2958
James Price1fa28ac2021-07-19 17:35:39 +00002959 const bool is_valid = (type->Is<Bool>() && value_type->is_scalar()) ||
2960 (type->Is<I32>() && value_type->is_scalar()) ||
2961 (type->Is<U32>() && value_type->is_scalar()) ||
2962 (type->Is<F32>() && value_type->is_scalar());
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002963 if (!is_valid) {
Ben Clayton71f619b2021-07-13 12:18:13 +00002964 AddError("cannot construct '" + type_name + "' with a value of type '" +
2965 TypeNameOf(value) + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00002966 ctor->source);
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002967
2968 return false;
2969 }
2970
2971 return true;
2972}
2973
Ben Clayton86481202021-10-19 18:38:54 +00002974bool Resolver::Identifier(const ast::IdentifierExpression* expr) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00002975 auto symbol = expr->symbol;
Ben Claytonb17aea12021-02-03 17:51:09 +00002976 VariableInfo* var;
dan sinclair795b6b52021-01-11 15:10:19 +00002977 if (variable_stack_.get(symbol, &var)) {
Ben Clayton71f619b2021-07-13 12:18:13 +00002978 SetExprInfo(expr, var->type, var->type_name);
dan sinclair13d2a3b2020-06-22 20:52:24 +00002979
James Pricec9af5972021-02-16 21:15:01 +00002980 var->users.push_back(expr);
Enrico Galli3d449d22020-12-08 21:07:24 +00002981 set_referenced_from_function_if_needed(var, true);
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002982
James Price7166f6b2021-09-30 17:29:50 +00002983 if (current_statement_) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002984 // If identifier is part of a loop continuing block, make sure it
2985 // doesn't refer to a variable that is bypassed by a continue statement
2986 // in the loop's body block.
Ben Clayton9a3ba022021-05-19 21:22:07 +00002987 if (auto* continuing_block =
James Price7166f6b2021-09-30 17:29:50 +00002988 current_statement_
Ben Clayton9a3ba022021-05-19 21:22:07 +00002989 ->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
James Pricea07d21a2021-03-22 17:25:56 +00002990 auto* loop_block =
Ben Clayton9a3ba022021-05-19 21:22:07 +00002991 continuing_block->FindFirstParent<sem::LoopBlockStatement>();
James Price5ffae322021-09-30 17:29:50 +00002992 if (loop_block->FirstContinue()) {
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002993 auto& decls = loop_block->Decls();
James Pricea07d21a2021-03-22 17:25:56 +00002994 // If our identifier is in loop_block->decls, make sure its index is
2995 // less than first_continue
Ben Clayton4f3ff572021-10-15 17:33:10 +00002996 auto iter =
2997 std::find_if(decls.begin(), decls.end(),
2998 [&symbol](auto* v) { return v->symbol == symbol; });
James Pricea07d21a2021-03-22 17:25:56 +00002999 if (iter != decls.end()) {
3000 auto var_decl_index =
3001 static_cast<size_t>(std::distance(decls.begin(), iter));
James Price5ffae322021-09-30 17:29:50 +00003002 if (var_decl_index >= loop_block->NumDeclsAtFirstContinue()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003003 AddError("continue statement bypasses declaration of '" +
James Price5ffae322021-09-30 17:29:50 +00003004 builder_->Symbols().NameFor(symbol) + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003005 loop_block->FirstContinue()->source);
James Price5ffae322021-09-30 17:29:50 +00003006 AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
3007 "' declared here",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003008 (*iter)->source);
James Price5ffae322021-09-30 17:29:50 +00003009 AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
3010 "' referenced in continuing block here",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003011 expr->source);
James Pricea07d21a2021-03-22 17:25:56 +00003012 return false;
3013 }
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00003014 }
3015 }
3016 }
3017 }
3018
dan sinclaircab0e732020-04-07 12:57:27 +00003019 return true;
3020 }
3021
Ben Claytonf6866a22021-01-11 22:02:42 +00003022 auto iter = symbol_to_function_.find(symbol);
dan sinclair4ac65682021-01-11 16:24:32 +00003023 if (iter != symbol_to_function_.end()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003024 AddError("missing '(' for function call", expr->source.End());
Ben Clayton33a8cdd2021-02-24 13:31:22 +00003025 return false;
dan sinclaircab0e732020-04-07 12:57:27 +00003026 }
3027
Ben Clayton1618f4b2021-02-03 21:02:25 +00003028 std::string name = builder_->Symbols().NameFor(symbol);
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003029 if (sem::ParseIntrinsicType(name) != IntrinsicType::kNone) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003030 AddError("missing '(' for intrinsic call", expr->source.End());
Ben Clayton33a8cdd2021-02-24 13:31:22 +00003031 return false;
dan sinclairff267ca2020-10-14 18:26:31 +00003032 }
Ben Clayton1618f4b2021-02-03 21:02:25 +00003033
Ben Clayton4f3ff572021-10-15 17:33:10 +00003034 AddError("identifier must be declared before use: " + name, expr->source);
Ben Clayton1618f4b2021-02-03 21:02:25 +00003035 return false;
dan sinclair8ee1d222020-04-07 16:41:33 +00003036}
3037
Ben Clayton86481202021-10-19 18:38:54 +00003038bool Resolver::MemberAccessor(const ast::MemberAccessorExpression* expr) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003039 auto* structure = TypeOf(expr->structure);
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003040 auto* storage_type = structure->UnwrapRef();
dan sinclairb445a9b2020-04-24 00:40:45 +00003041
Ben Clayton86481202021-10-19 18:38:54 +00003042 const sem::Type* ret = nullptr;
Ben Clayton6d612ad2021-02-24 14:15:02 +00003043 std::vector<uint32_t> swizzle;
Ben Claytonc1052a42021-02-03 23:55:56 +00003044
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003045 if (auto* str = storage_type->As<sem::Struct>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003046 Mark(expr->member);
3047 auto symbol = expr->member->symbol;
dan sinclair8ee1d222020-04-07 16:41:33 +00003048
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003049 const sem::StructMember* member = nullptr;
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003050 for (auto* m : str->Members()) {
Ben Clayton053559d2021-07-23 16:43:01 +00003051 if (m->Name() == symbol) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00003052 ret = m->Type();
Ben Claytone9c49842021-04-09 13:56:08 +00003053 member = m;
dan sinclair8eddb782020-04-23 22:26:52 +00003054 break;
dan sinclair8ee1d222020-04-07 16:41:33 +00003055 }
dan sinclair8ee1d222020-04-07 16:41:33 +00003056 }
3057
dan sinclair8eddb782020-04-23 22:26:52 +00003058 if (ret == nullptr) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003059 AddError(
Ben Clayton6b4924f2021-02-17 20:13:34 +00003060 "struct member " + builder_->Symbols().NameFor(symbol) + " not found",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003061 expr->source);
dan sinclair8eddb782020-04-23 22:26:52 +00003062 return false;
3063 }
dan sinclair7cac2452020-05-01 16:17:03 +00003064
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003065 // If we're extracting from a reference, we return a reference.
3066 if (auto* ref = structure->As<sem::Reference>()) {
Ben Clayton18588542021-06-04 22:17:37 +00003067 ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
3068 ref->Access());
dan sinclair7cac2452020-05-01 16:17:03 +00003069 }
Ben Claytone9c49842021-04-09 13:56:08 +00003070
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003071 builder_->Sem().Add(expr, builder_->create<sem::StructMemberAccess>(
Ben Claytone9c49842021-04-09 13:56:08 +00003072 expr, ret, current_statement_, member));
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003073 } else if (auto* vec = storage_type->As<sem::Vector>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003074 Mark(expr->member);
3075 std::string s = builder_->Symbols().NameFor(expr->member->symbol);
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003076 auto size = s.size();
3077 swizzle.reserve(s.size());
dan sinclaireb737c22021-01-11 16:24:32 +00003078
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003079 for (auto c : s) {
Ben Clayton6d612ad2021-02-24 14:15:02 +00003080 switch (c) {
3081 case 'x':
3082 case 'r':
3083 swizzle.emplace_back(0);
3084 break;
3085 case 'y':
3086 case 'g':
3087 swizzle.emplace_back(1);
3088 break;
3089 case 'z':
3090 case 'b':
3091 swizzle.emplace_back(2);
3092 break;
3093 case 'w':
3094 case 'a':
3095 swizzle.emplace_back(3);
3096 break;
3097 default:
Ben Claytonffd28e22021-06-24 11:27:36 +00003098 AddError("invalid vector swizzle character",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003099 expr->member->source.Begin() + swizzle.size());
Ben Clayton6d612ad2021-02-24 14:15:02 +00003100 return false;
3101 }
Antonio Maiorano39c05a92021-06-01 00:37:40 +00003102
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003103 if (swizzle.back() >= vec->Width()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003104 AddError("invalid vector swizzle member", expr->member->source);
Antonio Maiorano39c05a92021-06-01 00:37:40 +00003105 return false;
3106 }
Ben Clayton6d612ad2021-02-24 14:15:02 +00003107 }
3108
3109 if (size < 1 || size > 4) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003110 AddError("invalid vector swizzle size", expr->member->source);
Ben Clayton6d612ad2021-02-24 14:15:02 +00003111 return false;
3112 }
3113
Antonio Maioranofe2b4172021-03-01 20:01:39 +00003114 // All characters are valid, check if they're being mixed
3115 auto is_rgba = [](char c) {
3116 return c == 'r' || c == 'g' || c == 'b' || c == 'a';
3117 };
3118 auto is_xyzw = [](char c) {
3119 return c == 'x' || c == 'y' || c == 'z' || c == 'w';
3120 };
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003121 if (!std::all_of(s.begin(), s.end(), is_rgba) &&
3122 !std::all_of(s.begin(), s.end(), is_xyzw)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003123 AddError("invalid mixing of vector swizzle characters rgba with xyzw",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003124 expr->member->source);
Antonio Maioranofe2b4172021-03-01 20:01:39 +00003125 return false;
3126 }
3127
dan sinclairaac58652020-04-21 13:05:34 +00003128 if (size == 1) {
3129 // A single element swizzle is just the type of the vector.
dan sinclair8eddb782020-04-23 22:26:52 +00003130 ret = vec->type();
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003131 // If we're extracting from a reference, we return a reference.
3132 if (auto* ref = structure->As<sem::Reference>()) {
Ben Clayton18588542021-06-04 22:17:37 +00003133 ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
3134 ref->Access());
dan sinclair7cac2452020-05-01 16:17:03 +00003135 }
dan sinclairaac58652020-04-21 13:05:34 +00003136 } else {
Ben Clayton6d612ad2021-02-24 14:15:02 +00003137 // The vector will have a number of components equal to the length of
Antonio Maioranod15391e2021-04-08 14:08:47 +00003138 // the swizzle.
Antonio Maiorano3751fd22021-04-19 22:51:23 +00003139 ret = builder_->create<sem::Vector>(vec->type(),
3140 static_cast<uint32_t>(size));
dan sinclairaac58652020-04-21 13:05:34 +00003141 }
Ben Claytone9c49842021-04-09 13:56:08 +00003142 builder_->Sem().Add(
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003143 expr, builder_->create<sem::Swizzle>(expr, ret, current_statement_,
3144 std::move(swizzle)));
dan sinclair8eddb782020-04-23 22:26:52 +00003145 } else {
Sarahde767b12021-09-13 19:30:19 +00003146 AddError(
3147 "invalid member accessor expression. Expected vector or struct, got '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +00003148 TypeNameOf(expr->structure) + "'",
3149 expr->structure->source);
dan sinclair8eddb782020-04-23 22:26:52 +00003150 return false;
dan sinclair8ee1d222020-04-07 16:41:33 +00003151 }
3152
Ben Clayton71f619b2021-07-13 12:18:13 +00003153 SetExprInfo(expr, ret);
dan sinclair8eddb782020-04-23 22:26:52 +00003154
3155 return true;
dan sinclaircab0e732020-04-07 12:57:27 +00003156}
3157
Ben Clayton86481202021-10-19 18:38:54 +00003158bool Resolver::Binary(const ast::BinaryExpression* expr) {
Antonio Maiorano3751fd22021-04-19 22:51:23 +00003159 using Bool = sem::Bool;
3160 using F32 = sem::F32;
3161 using I32 = sem::I32;
3162 using U32 = sem::U32;
3163 using Matrix = sem::Matrix;
3164 using Vector = sem::Vector;
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003165
Ben Clayton86481202021-10-19 18:38:54 +00003166 auto* lhs_type = TypeOf(expr->lhs)->UnwrapRef();
3167 auto* rhs_type = TypeOf(expr->rhs)->UnwrapRef();
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003168
3169 auto* lhs_vec = lhs_type->As<Vector>();
Antonio Maiorano25436862021-04-13 13:32:33 +00003170 auto* lhs_vec_elem_type = lhs_vec ? lhs_vec->type() : nullptr;
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003171 auto* rhs_vec = rhs_type->As<Vector>();
Antonio Maiorano25436862021-04-13 13:32:33 +00003172 auto* rhs_vec_elem_type = rhs_vec ? rhs_vec->type() : nullptr;
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003173
Antonio Maiorano61dabab2021-04-01 19:58:37 +00003174 const bool matching_vec_elem_types =
3175 lhs_vec_elem_type && rhs_vec_elem_type &&
3176 (lhs_vec_elem_type == rhs_vec_elem_type) &&
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003177 (lhs_vec->Width() == rhs_vec->Width());
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003178
Antonio Maiorano15c6ed02021-04-01 14:59:27 +00003179 const bool matching_types = matching_vec_elem_types || (lhs_type == rhs_type);
3180
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003181 // Binary logical expressions
3182 if (expr->IsLogicalAnd() || expr->IsLogicalOr()) {
3183 if (matching_types && lhs_type->Is<Bool>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003184 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003185 return true;
3186 }
3187 }
3188 if (expr->IsOr() || expr->IsAnd()) {
3189 if (matching_types && lhs_type->Is<Bool>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003190 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003191 return true;
3192 }
3193 if (matching_types && lhs_vec_elem_type && lhs_vec_elem_type->Is<Bool>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003194 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003195 return true;
3196 }
3197 }
3198
3199 // Arithmetic expressions
3200 if (expr->IsArithmetic()) {
3201 // Binary arithmetic expressions over scalars
Antonio Maiorano0131ce22021-05-27 18:25:06 +00003202 if (matching_types && lhs_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003203 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003204 return true;
3205 }
3206
3207 // Binary arithmetic expressions over vectors
3208 if (matching_types && lhs_vec_elem_type &&
Antonio Maiorano0131ce22021-05-27 18:25:06 +00003209 lhs_vec_elem_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003210 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003211 return true;
3212 }
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003213
3214 // Binary arithmetic expressions with mixed scalar and vector operands
3215 if (lhs_vec_elem_type && (lhs_vec_elem_type == rhs_type)) {
3216 if (expr->IsModulo()) {
3217 if (rhs_type->is_integer_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003218 SetExprInfo(expr, lhs_type);
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003219 return true;
3220 }
3221 } else if (rhs_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003222 SetExprInfo(expr, lhs_type);
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003223 return true;
3224 }
3225 }
3226 if (rhs_vec_elem_type && (rhs_vec_elem_type == lhs_type)) {
3227 if (expr->IsModulo()) {
3228 if (lhs_type->is_integer_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003229 SetExprInfo(expr, rhs_type);
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003230 return true;
3231 }
3232 } else if (lhs_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003233 SetExprInfo(expr, rhs_type);
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003234 return true;
3235 }
3236 }
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003237 }
3238
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003239 // Matrix arithmetic
Antonio Maioranoc91f8f22021-05-31 15:53:20 +00003240 auto* lhs_mat = lhs_type->As<Matrix>();
3241 auto* lhs_mat_elem_type = lhs_mat ? lhs_mat->type() : nullptr;
3242 auto* rhs_mat = rhs_type->As<Matrix>();
3243 auto* rhs_mat_elem_type = rhs_mat ? rhs_mat->type() : nullptr;
3244 // Addition and subtraction of float matrices
3245 if ((expr->IsAdd() || expr->IsSubtract()) && lhs_mat_elem_type &&
3246 lhs_mat_elem_type->Is<F32>() && rhs_mat_elem_type &&
3247 rhs_mat_elem_type->Is<F32>() &&
3248 (lhs_mat->columns() == rhs_mat->columns()) &&
3249 (lhs_mat->rows() == rhs_mat->rows())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003250 SetExprInfo(expr, rhs_type);
Antonio Maioranoc91f8f22021-05-31 15:53:20 +00003251 return true;
3252 }
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003253 if (expr->IsMultiply()) {
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003254 // Multiplication of a matrix and a scalar
3255 if (lhs_type->Is<F32>() && rhs_mat_elem_type &&
3256 rhs_mat_elem_type->Is<F32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003257 SetExprInfo(expr, rhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003258 return true;
3259 }
3260 if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() &&
3261 rhs_type->Is<F32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003262 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003263 return true;
3264 }
3265
3266 // Vector times matrix
3267 if (lhs_vec_elem_type && lhs_vec_elem_type->Is<F32>() &&
Antonio Maiorano61dabab2021-04-01 19:58:37 +00003268 rhs_mat_elem_type && rhs_mat_elem_type->Is<F32>() &&
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003269 (lhs_vec->Width() == rhs_mat->rows())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003270 SetExprInfo(expr, builder_->create<sem::Vector>(lhs_vec->type(),
3271 rhs_mat->columns()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003272 return true;
3273 }
3274
3275 // Matrix times vector
3276 if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() &&
Antonio Maiorano61dabab2021-04-01 19:58:37 +00003277 rhs_vec_elem_type && rhs_vec_elem_type->Is<F32>() &&
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003278 (lhs_mat->columns() == rhs_vec->Width())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003279 SetExprInfo(expr, builder_->create<sem::Vector>(rhs_vec->type(),
3280 lhs_mat->rows()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003281 return true;
3282 }
3283
3284 // Matrix times matrix
3285 if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() &&
Antonio Maiorano61dabab2021-04-01 19:58:37 +00003286 rhs_mat_elem_type && rhs_mat_elem_type->Is<F32>() &&
3287 (lhs_mat->columns() == rhs_mat->rows())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003288 SetExprInfo(expr, builder_->create<sem::Matrix>(
3289 builder_->create<sem::Vector>(lhs_mat_elem_type,
3290 lhs_mat->rows()),
3291 rhs_mat->columns()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003292 return true;
3293 }
3294 }
3295
3296 // Comparison expressions
3297 if (expr->IsComparison()) {
3298 if (matching_types) {
3299 // Special case for bools: only == and !=
3300 if (lhs_type->Is<Bool>() && (expr->IsEqual() || expr->IsNotEqual())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003301 SetExprInfo(expr, builder_->create<sem::Bool>());
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003302 return true;
3303 }
3304
3305 // For the rest, we can compare i32, u32, and f32
3306 if (lhs_type->IsAnyOf<I32, U32, F32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003307 SetExprInfo(expr, builder_->create<sem::Bool>());
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003308 return true;
3309 }
3310 }
3311
3312 // Same for vectors
3313 if (matching_vec_elem_types) {
3314 if (lhs_vec_elem_type->Is<Bool>() &&
3315 (expr->IsEqual() || expr->IsNotEqual())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003316 SetExprInfo(expr, builder_->create<sem::Vector>(
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003317 builder_->create<sem::Bool>(), lhs_vec->Width()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003318 return true;
3319 }
3320
Antonio Maiorano0131ce22021-05-27 18:25:06 +00003321 if (lhs_vec_elem_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003322 SetExprInfo(expr, builder_->create<sem::Vector>(
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003323 builder_->create<sem::Bool>(), lhs_vec->Width()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003324 return true;
3325 }
3326 }
3327 }
3328
3329 // Binary bitwise operations
3330 if (expr->IsBitwise()) {
Antonio Maiorano0895c232021-06-01 17:42:41 +00003331 if (matching_types && lhs_type->is_integer_scalar_or_vector()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003332 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003333 return true;
3334 }
3335 }
3336
3337 // Bit shift expressions
3338 if (expr->IsBitshift()) {
3339 // Type validation rules are the same for left or right shift, despite
3340 // differences in computation rules (i.e. right shift can be arithmetic or
3341 // logical depending on lhs type).
3342
3343 if (lhs_type->IsAnyOf<I32, U32>() && rhs_type->Is<U32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003344 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003345 return true;
3346 }
3347
3348 if (lhs_vec_elem_type && lhs_vec_elem_type->IsAnyOf<I32, U32>() &&
3349 rhs_vec_elem_type && rhs_vec_elem_type->Is<U32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003350 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003351 return true;
3352 }
3353 }
3354
Ben Claytonffd28e22021-06-24 11:27:36 +00003355 AddError("Binary expression operand types are invalid for this operation: " +
3356 lhs_type->FriendlyName(builder_->Symbols()) + " " +
Ben Clayton4f3ff572021-10-15 17:33:10 +00003357 FriendlyName(expr->op) + " " +
Ben Claytonffd28e22021-06-24 11:27:36 +00003358 rhs_type->FriendlyName(builder_->Symbols()),
Ben Clayton4f3ff572021-10-15 17:33:10 +00003359 expr->source);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003360 return false;
3361}
3362
Ben Clayton86481202021-10-19 18:38:54 +00003363bool Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003364 auto* expr_type = TypeOf(unary->expr);
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003365 if (!expr_type) {
3366 return false;
3367 }
3368
3369 std::string type_name;
3370 const sem::Type* type = nullptr;
3371
Ben Clayton4f3ff572021-10-15 17:33:10 +00003372 switch (unary->op) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003373 case ast::UnaryOp::kNot:
3374 // Result type matches the deref'd inner type.
Ben Clayton4f3ff572021-10-15 17:33:10 +00003375 type_name = TypeNameOf(unary->expr);
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003376 type = expr_type->UnwrapRef();
Saraha5715e32021-06-28 14:09:33 +00003377 if (!type->Is<sem::Bool>() && !type->is_bool_vector()) {
3378 AddError("cannot logical negate expression of type '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +00003379 TypeNameOf(unary->expr),
3380 unary->expr->source);
Saraha5715e32021-06-28 14:09:33 +00003381 return false;
3382 }
3383 break;
3384
3385 case ast::UnaryOp::kComplement:
3386 // Result type matches the deref'd inner type.
Ben Clayton4f3ff572021-10-15 17:33:10 +00003387 type_name = TypeNameOf(unary->expr);
Saraha5715e32021-06-28 14:09:33 +00003388 type = expr_type->UnwrapRef();
3389 if (!type->is_integer_scalar_or_vector()) {
3390 AddError("cannot bitwise complement expression of type '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +00003391 TypeNameOf(unary->expr),
3392 unary->expr->source);
Saraha5715e32021-06-28 14:09:33 +00003393 return false;
3394 }
3395 break;
3396
3397 case ast::UnaryOp::kNegation:
3398 // Result type matches the deref'd inner type.
Ben Clayton4f3ff572021-10-15 17:33:10 +00003399 type_name = TypeNameOf(unary->expr);
Saraha5715e32021-06-28 14:09:33 +00003400 type = expr_type->UnwrapRef();
3401 if (!(type->IsAnyOf<sem::F32, sem::I32>() ||
3402 type->is_signed_integer_vector() || type->is_float_vector())) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003403 AddError("cannot negate expression of type '" + TypeNameOf(unary->expr),
3404 unary->expr->source);
Saraha5715e32021-06-28 14:09:33 +00003405 return false;
3406 }
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003407 break;
3408
3409 case ast::UnaryOp::kAddressOf:
3410 if (auto* ref = expr_type->As<sem::Reference>()) {
Sarahedecbb12021-07-28 03:57:22 +00003411 if (ref->StoreType()->UnwrapRef()->is_handle()) {
3412 AddError(
3413 "cannot take the address of expression in handle storage class",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003414 unary->expr->source);
Sarahedecbb12021-07-28 03:57:22 +00003415 return false;
3416 }
Ben Clayton18588542021-06-04 22:17:37 +00003417 type = builder_->create<sem::Pointer>(
3418 ref->StoreType(), ref->StorageClass(), ref->Access());
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003419 } else {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003420 AddError("cannot take the address of expression", unary->expr->source);
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003421 return false;
3422 }
3423 break;
3424
3425 case ast::UnaryOp::kIndirection:
3426 if (auto* ptr = expr_type->As<sem::Pointer>()) {
Ben Clayton18588542021-06-04 22:17:37 +00003427 type = builder_->create<sem::Reference>(
3428 ptr->StoreType(), ptr->StorageClass(), ptr->Access());
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003429 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00003430 AddError("cannot dereference expression of type '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +00003431 TypeNameOf(unary->expr) + "'",
3432 unary->expr->source);
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003433 return false;
3434 }
3435 break;
3436 }
3437
Ben Clayton71f619b2021-07-13 12:18:13 +00003438 SetExprInfo(unary, type);
dan sinclair327ed1b2020-04-07 19:27:21 +00003439 return true;
dan sinclair0e257622020-04-07 19:27:11 +00003440}
3441
Ben Clayton5f0ea112021-03-09 10:54:37 +00003442bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
Ben Clayton86481202021-10-19 18:38:54 +00003443 const ast::Variable* var = stmt->variable;
Ben Clayton6fcefe42021-04-19 19:16:12 +00003444 Mark(var);
3445
Ben Clayton4f3ff572021-10-15 17:33:10 +00003446 if (!ValidateNoDuplicateDefinition(var->symbol, var->source)) {
Antonio Maiorano09356cc2021-04-06 14:07:07 +00003447 return false;
3448 }
3449
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003450 auto* info = Variable(var, VariableKind::kLocal);
Ben Clayton5df76612021-05-12 10:41:21 +00003451 if (!info) {
3452 return false;
Ben Claytona88090b2021-03-17 22:47:33 +00003453 }
3454
Ben Clayton4f3ff572021-10-15 17:33:10 +00003455 for (auto* deco : var->decorations) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00003456 Mark(deco);
James Priced47a7ef2021-08-17 16:09:00 +00003457 if (!deco->Is<ast::InternalDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003458 AddError("decorations are not valid on local variables", deco->source);
James Priced47a7ef2021-08-17 16:09:00 +00003459 return false;
3460 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00003461 }
3462
Ben Clayton4f3ff572021-10-15 17:33:10 +00003463 variable_stack_.set(var->symbol, info);
Ben Clayton6e459fe2021-07-14 09:44:41 +00003464 if (current_block_) { // Not all statements are inside a block
3465 current_block_->AddDecl(var);
3466 }
Ben Claytona88090b2021-03-17 22:47:33 +00003467
Ben Claytonfcda15e2021-05-10 18:01:51 +00003468 if (!ValidateVariable(info)) {
Antonio Maiorano09356cc2021-04-06 14:07:07 +00003469 return false;
3470 }
3471
Ben Clayton4f3ff572021-10-15 17:33:10 +00003472 if (!var->is_const &&
3473 IsValidationEnabled(var->decorations,
Sarah72494042021-07-28 22:43:36 +00003474 ast::DisabledValidation::kIgnoreStorageClass)) {
3475 if (!info->type->UnwrapRef()->IsConstructible()) {
3476 AddError("function variable must have a constructible type",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003477 var->type ? var->type->source : var->source);
Sarah72494042021-07-28 22:43:36 +00003478 return false;
3479 }
3480 if (info->storage_class != ast::StorageClass::kFunction) {
Ben Claytona88090b2021-03-17 22:47:33 +00003481 if (info->storage_class != ast::StorageClass::kNone) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003482 AddError("function variable has a non-function storage class",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003483 stmt->source);
Ben Claytona88090b2021-03-17 22:47:33 +00003484 return false;
3485 }
3486 info->storage_class = ast::StorageClass::kFunction;
3487 }
3488 }
3489
Antonio Maiorano9ef17472021-03-26 12:47:58 +00003490 if (!ApplyStorageClassUsageToType(info->storage_class, info->type,
Ben Clayton4f3ff572021-10-15 17:33:10 +00003491 var->source)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003492 AddNote("while instantiating variable " +
Ben Clayton4f3ff572021-10-15 17:33:10 +00003493 builder_->Symbols().NameFor(var->symbol),
3494 var->source);
Ben Claytona88090b2021-03-17 22:47:33 +00003495 return false;
Antonio Maiorano6ce2edf2021-02-26 18:25:56 +00003496 }
3497
3498 return true;
3499}
3500
Ben Clayton8758f102021-06-09 14:32:14 +00003501sem::Type* Resolver::TypeDecl(const ast::TypeDecl* named_type) {
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003502 sem::Type* result = nullptr;
3503 if (auto* alias = named_type->As<ast::Alias>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003504 result = Type(alias->type);
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003505 } else if (auto* str = named_type->As<ast::Struct>()) {
3506 result = Structure(str);
3507 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00003508 TINT_UNREACHABLE(Resolver, diagnostics_) << "Unhandled TypeDecl";
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003509 }
3510
3511 if (!result) {
3512 return nullptr;
3513 }
3514
Ben Clayton4f3ff572021-10-15 17:33:10 +00003515 named_type_info_.emplace(named_type->name, TypeDeclInfo{named_type, result});
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003516
Ben Clayton8758f102021-06-09 14:32:14 +00003517 if (!ValidateTypeDecl(named_type)) {
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003518 return nullptr;
3519 }
3520
3521 builder_->Sem().Add(named_type, result);
3522 return result;
3523}
3524
Ben Clayton8758f102021-06-09 14:32:14 +00003525bool Resolver::ValidateTypeDecl(const ast::TypeDecl* named_type) const {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003526 auto iter = named_type_info_.find(named_type->name);
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003527 if (iter == named_type_info_.end()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003528 TINT_ICE(Resolver, diagnostics_)
3529 << "ValidateTypeDecl called() before TypeDecl()";
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003530 }
3531 if (iter->second.ast != named_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003532 AddError("type with the name '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +00003533 builder_->Symbols().NameFor(named_type->name) +
Ben Claytonffd28e22021-06-24 11:27:36 +00003534 "' was already declared",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003535 named_type->source);
3536 AddNote("first declared here", iter->second.ast->source);
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003537 return false;
3538 }
3539 return true;
3540}
3541
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003542sem::Type* Resolver::TypeOf(const ast::Expression* expr) {
Ben Claytonf97b9c92021-02-16 18:45:45 +00003543 auto it = expr_info_.find(expr);
3544 if (it != expr_info_.end()) {
Ben Clayton19d32052021-05-20 15:10:48 +00003545 return const_cast<sem::Type*>(it->second.type);
Ben Clayton7b7d6982021-02-09 17:38:05 +00003546 }
3547 return nullptr;
3548}
3549
Ben Clayton109b18f2021-04-28 13:50:43 +00003550std::string Resolver::TypeNameOf(const ast::Expression* expr) {
3551 auto it = expr_info_.find(expr);
3552 if (it != expr_info_.end()) {
3553 return it->second.type_name;
3554 }
3555 return "";
3556}
3557
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003558sem::Type* Resolver::TypeOf(const ast::Literal* lit) {
Ben Clayton109b18f2021-04-28 13:50:43 +00003559 if (lit->Is<ast::SintLiteral>()) {
3560 return builder_->create<sem::I32>();
3561 }
3562 if (lit->Is<ast::UintLiteral>()) {
3563 return builder_->create<sem::U32>();
3564 }
3565 if (lit->Is<ast::FloatLiteral>()) {
3566 return builder_->create<sem::F32>();
3567 }
3568 if (lit->Is<ast::BoolLiteral>()) {
3569 return builder_->create<sem::Bool>();
3570 }
Ben Claytonffd28e22021-06-24 11:27:36 +00003571 TINT_UNREACHABLE(Resolver, diagnostics_)
Ben Clayton109b18f2021-04-28 13:50:43 +00003572 << "Unhandled literal type: " << lit->TypeInfo().name;
3573 return nullptr;
3574}
3575
Ben Clayton71f619b2021-07-13 12:18:13 +00003576void Resolver::SetExprInfo(const ast::Expression* expr,
3577 const sem::Type* type,
3578 std::string type_name) {
Ben Clayton90f43cf2021-03-31 20:43:26 +00003579 if (expr_info_.count(expr)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003580 TINT_ICE(Resolver, diagnostics_)
Ben Clayton71f619b2021-07-13 12:18:13 +00003581 << "SetExprInfo() called twice for the same expression";
Ben Clayton90f43cf2021-03-31 20:43:26 +00003582 }
Ben Clayton71f619b2021-07-13 12:18:13 +00003583 if (type_name.empty()) {
3584 type_name = type->FriendlyName(builder_->Symbols());
3585 }
3586 auto constant_value = EvaluateConstantValue(expr, type);
3587 expr_info_.emplace(
3588 expr, ExpressionInfo{type, std::move(type_name), current_statement_,
3589 std::move(constant_value)});
Ben Clayton33352542021-01-29 16:43:41 +00003590}
3591
Ben Clayton71786c92021-06-03 16:07:34 +00003592bool Resolver::ValidatePipelineStages() {
Sarah95485312021-06-24 08:56:16 +00003593 auto check_workgroup_storage = [&](FunctionInfo* func,
3594 FunctionInfo* entry_point) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003595 auto stage = entry_point->declaration->PipelineStage();
Sarah95485312021-06-24 08:56:16 +00003596 if (stage != ast::PipelineStage::kCompute) {
3597 for (auto* var : func->local_referenced_module_vars) {
3598 if (var->storage_class == ast::StorageClass::kWorkgroup) {
3599 std::stringstream stage_name;
3600 stage_name << stage;
3601 for (auto* user : var->users) {
3602 auto it = expr_info_.find(user->As<ast::Expression>());
3603 if (it != expr_info_.end()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003604 if (func->declaration->symbol ==
3605 it->second.statement->Function()->symbol) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003606 AddError("workgroup memory cannot be used by " +
3607 stage_name.str() + " pipeline stage",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003608 user->source);
Sarah95485312021-06-24 08:56:16 +00003609 break;
3610 }
3611 }
3612 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00003613 AddNote("variable is declared here", var->declaration->source);
Sarah95485312021-06-24 08:56:16 +00003614 if (func != entry_point) {
3615 TraverseCallChain(entry_point, func, [&](FunctionInfo* f) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003616 AddNote("called by function '" +
3617 builder_->Symbols().NameFor(f->declaration->symbol) +
3618 "'",
3619 f->declaration->source);
Sarah95485312021-06-24 08:56:16 +00003620 });
Ben Claytonffd28e22021-06-24 11:27:36 +00003621 AddNote("called by entry point '" +
3622 builder_->Symbols().NameFor(
Ben Clayton4f3ff572021-10-15 17:33:10 +00003623 entry_point->declaration->symbol) +
Ben Claytonffd28e22021-06-24 11:27:36 +00003624 "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003625 entry_point->declaration->source);
Sarah95485312021-06-24 08:56:16 +00003626 }
3627 return false;
3628 }
3629 }
3630 }
3631 return true;
3632 };
3633
3634 for (auto* entry_point : entry_points_) {
3635 if (!check_workgroup_storage(entry_point, entry_point)) {
3636 return false;
3637 }
3638 for (auto* func : entry_point->transitive_calls) {
3639 if (!check_workgroup_storage(func, entry_point)) {
3640 return false;
3641 }
3642 }
3643 }
3644
Ben Clayton71786c92021-06-03 16:07:34 +00003645 auto check_intrinsic_calls = [&](FunctionInfo* func,
3646 FunctionInfo* entry_point) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003647 auto stage = entry_point->declaration->PipelineStage();
Ben Clayton71786c92021-06-03 16:07:34 +00003648 for (auto& call : func->intrinsic_calls) {
3649 if (!call.intrinsic->SupportedStages().Contains(stage)) {
3650 std::stringstream err;
3651 err << "built-in cannot be used by " << stage << " pipeline stage";
Ben Clayton4f3ff572021-10-15 17:33:10 +00003652 AddError(err.str(), call.call->source);
Ben Clayton71786c92021-06-03 16:07:34 +00003653 if (func != entry_point) {
3654 TraverseCallChain(entry_point, func, [&](FunctionInfo* f) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003655 AddNote("called by function '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +00003656 builder_->Symbols().NameFor(f->declaration->symbol) +
Ben Claytonffd28e22021-06-24 11:27:36 +00003657 "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003658 f->declaration->source);
Ben Clayton71786c92021-06-03 16:07:34 +00003659 });
Ben Claytonffd28e22021-06-24 11:27:36 +00003660 AddNote("called by entry point '" +
3661 builder_->Symbols().NameFor(
Ben Clayton4f3ff572021-10-15 17:33:10 +00003662 entry_point->declaration->symbol) +
Ben Claytonffd28e22021-06-24 11:27:36 +00003663 "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00003664 entry_point->declaration->source);
Ben Clayton71786c92021-06-03 16:07:34 +00003665 }
3666 return false;
3667 }
3668 }
3669 return true;
3670 };
3671
3672 for (auto* entry_point : entry_points_) {
3673 if (!check_intrinsic_calls(entry_point, entry_point)) {
3674 return false;
3675 }
3676 for (auto* func : entry_point->transitive_calls) {
3677 if (!check_intrinsic_calls(func, entry_point)) {
3678 return false;
3679 }
3680 }
3681 }
3682 return true;
3683}
3684
3685template <typename CALLBACK>
3686void Resolver::TraverseCallChain(FunctionInfo* from,
3687 FunctionInfo* to,
3688 CALLBACK&& callback) const {
3689 for (auto* f : from->transitive_calls) {
3690 if (f == to) {
3691 callback(f);
3692 return;
3693 }
3694 if (f->transitive_calls.contains(to)) {
3695 TraverseCallChain(f, to, callback);
3696 callback(f);
3697 return;
3698 }
3699 }
Ben Claytonffd28e22021-06-24 11:27:36 +00003700 TINT_ICE(Resolver, diagnostics_)
Ben Clayton71786c92021-06-03 16:07:34 +00003701 << "TraverseCallChain() 'from' does not transitively call 'to'";
3702}
3703
Ben Clayton5f0ea112021-03-09 10:54:37 +00003704void Resolver::CreateSemanticNodes() const {
Ben Claytonb17aea12021-02-03 17:51:09 +00003705 auto& sem = builder_->Sem();
3706
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003707 // Collate all the 'ancestor_entry_points' - this is a map of function
3708 // symbol to all the entry points that transitively call the function.
Ben Clayton5a132582021-03-03 19:54:44 +00003709 std::unordered_map<Symbol, std::vector<Symbol>> ancestor_entry_points;
Ben Clayton71786c92021-06-03 16:07:34 +00003710 for (auto* entry_point : entry_points_) {
3711 for (auto* call : entry_point->transitive_calls) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003712 auto& vec = ancestor_entry_points[call->declaration->symbol];
3713 vec.emplace_back(entry_point->declaration->symbol);
Ben Clayton5a132582021-03-03 19:54:44 +00003714 }
3715 }
3716
Ben Clayton7b7d6982021-02-09 17:38:05 +00003717 // Create semantic nodes for all ast::Variables
Ben Clayton4ffcf062021-07-22 13:24:59 +00003718 std::unordered_map<const tint::ast::Variable*, sem::Parameter*> sem_params;
Ben Claytonb17aea12021-02-03 17:51:09 +00003719 for (auto it : variable_to_info_) {
3720 auto* var = it.first;
3721 auto* info = it.second;
James Pricef2f3bfc2021-05-13 20:32:32 +00003722
3723 sem::Variable* sem_var = nullptr;
3724
Ben Clayton4f3ff572021-10-15 17:33:10 +00003725 if (ast::HasDecoration<ast::OverrideDecoration>(var->decorations)) {
James Pricef2f3bfc2021-05-13 20:32:32 +00003726 // Create a pipeline overridable constant.
James Priceee23c172021-09-30 17:29:50 +00003727 sem_var = builder_->create<sem::GlobalVariable>(var, info->type,
3728 info->constant_id);
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003729 } else {
3730 switch (info->kind) {
3731 case VariableKind::kGlobal:
3732 sem_var = builder_->create<sem::GlobalVariable>(
3733 var, info->type, info->storage_class, info->access,
3734 info->binding_point);
3735 break;
3736 case VariableKind::kLocal:
3737 sem_var = builder_->create<sem::LocalVariable>(
3738 var, info->type, info->storage_class, info->access);
3739 break;
Ben Clayton4ffcf062021-07-22 13:24:59 +00003740 case VariableKind::kParameter: {
3741 auto* param = builder_->create<sem::Parameter>(
3742 var, info->index, info->type, info->storage_class, info->access);
3743 sem_var = param;
3744 sem_params.emplace(var, param);
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003745 break;
Ben Clayton4ffcf062021-07-22 13:24:59 +00003746 }
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003747 }
James Pricef2f3bfc2021-05-13 20:32:32 +00003748 }
3749
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003750 std::vector<const sem::VariableUser*> users;
James Pricec9af5972021-02-16 21:15:01 +00003751 for (auto* user : info->users) {
3752 // Create semantic node for the identifier expression if necessary
3753 auto* sem_expr = sem.Get(user);
3754 if (sem_expr == nullptr) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003755 auto& expr_info = expr_info_.at(user);
3756 auto* type = expr_info.type;
3757 auto* stmt = expr_info.statement;
3758 auto* sem_user = builder_->create<sem::VariableUser>(
3759 user, type, stmt, sem_var, expr_info.constant_value);
Ben Clayton86c2cbf2021-04-07 08:09:01 +00003760 sem_var->AddUser(sem_user);
3761 sem.Add(user, sem_user);
3762 } else {
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003763 auto* sem_user = sem_expr->As<sem::VariableUser>();
Ben Clayton86c2cbf2021-04-07 08:09:01 +00003764 if (!sem_user) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003765 TINT_ICE(Resolver, diagnostics_) << "expected sem::VariableUser, got "
3766 << sem_expr->TypeInfo().name;
Ben Clayton86c2cbf2021-04-07 08:09:01 +00003767 }
3768 sem_var->AddUser(sem_user);
James Pricec9af5972021-02-16 21:15:01 +00003769 }
James Pricec9af5972021-02-16 21:15:01 +00003770 }
Ben Clayton86c2cbf2021-04-07 08:09:01 +00003771 sem.Add(var, sem_var);
Ben Claytonb17aea12021-02-03 17:51:09 +00003772 }
3773
3774 auto remap_vars = [&sem](const std::vector<VariableInfo*>& in) {
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003775 std::vector<const sem::Variable*> out;
Ben Claytonb17aea12021-02-03 17:51:09 +00003776 out.reserve(in.size());
3777 for (auto* info : in) {
3778 out.emplace_back(sem.Get(info->declaration));
3779 }
3780 return out;
3781 };
3782
Ben Clayton7b7d6982021-02-09 17:38:05 +00003783 // Create semantic nodes for all ast::Functions
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003784 std::unordered_map<FunctionInfo*, sem::Function*> func_info_to_sem_func;
Ben Clayton87c78dd2021-02-03 16:43:20 +00003785 for (auto it : function_to_info_) {
3786 auto* func = it.first;
3787 auto* info = it.second;
Ben Clayton5a132582021-03-03 19:54:44 +00003788
Ben Clayton4ffcf062021-07-22 13:24:59 +00003789 std::vector<sem::Parameter*> parameters;
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003790 parameters.reserve(info->parameters.size());
3791 for (auto* p : info->parameters) {
Ben Clayton4ffcf062021-07-22 13:24:59 +00003792 parameters.emplace_back(sem_params.at(p->declaration));
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003793 }
3794
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003795 auto* sem_func = builder_->create<sem::Function>(
Ben Clayton86481202021-10-19 18:38:54 +00003796 info->declaration, info->return_type, parameters,
3797 remap_vars(info->referenced_module_vars),
James Price4ffd3e22021-03-17 14:24:04 +00003798 remap_vars(info->local_referenced_module_vars), info->return_statements,
Ben Clayton4f3ff572021-10-15 17:33:10 +00003799 info->callsites, ancestor_entry_points[func->symbol],
James Pricebcefe462021-05-22 12:48:24 +00003800 info->workgroup_size);
Ben Clayton316f9f62021-02-08 22:31:44 +00003801 func_info_to_sem_func.emplace(info, sem_func);
3802 sem.Add(func, sem_func);
3803 }
3804
Ben Clayton7b7d6982021-02-09 17:38:05 +00003805 // Create semantic nodes for all ast::CallExpressions
Ben Clayton316f9f62021-02-08 22:31:44 +00003806 for (auto it : function_calls_) {
3807 auto* call = it.first;
Ben Claytonf97b9c92021-02-16 18:45:45 +00003808 auto info = it.second;
3809 auto* sem_func = func_info_to_sem_func.at(info.function);
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003810 sem.Add(call, builder_->create<sem::Call>(call, sem_func, info.statement));
Ben Clayton7b7d6982021-02-09 17:38:05 +00003811 }
3812
3813 // Create semantic nodes for all remaining expression types
Ben Claytonf97b9c92021-02-16 18:45:45 +00003814 for (auto it : expr_info_) {
Ben Clayton7b7d6982021-02-09 17:38:05 +00003815 auto* expr = it.first;
Ben Claytonf97b9c92021-02-16 18:45:45 +00003816 auto& info = it.second;
Ben Clayton7b7d6982021-02-09 17:38:05 +00003817 if (sem.Get(expr)) {
3818 // Expression has already been assigned a semantic node
3819 continue;
3820 }
Ben Clayton71f619b2021-07-13 12:18:13 +00003821 sem.Add(expr, builder_->create<sem::Expression>(
Ben Clayton86481202021-10-19 18:38:54 +00003822 expr, info.type, info.statement, info.constant_value));
Ben Clayton87c78dd2021-02-03 16:43:20 +00003823 }
3824}
3825
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003826sem::Array* Resolver::Array(const ast::Array* arr) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003827 auto source = arr->source;
Ben Claytond614dd52021-03-15 10:43:11 +00003828
Ben Clayton4f3ff572021-10-15 17:33:10 +00003829 auto* elem_type = Type(arr->type);
Sarah4038fa72021-08-05 15:18:29 +00003830 if (!elem_type) {
Ben Claytond614dd52021-03-15 10:43:11 +00003831 return nullptr;
3832 }
3833
Sarah4038fa72021-08-05 15:18:29 +00003834 if (!IsPlain(elem_type)) { // Check must come before GetDefaultAlignAndSize()
3835 AddError(elem_type->FriendlyName(builder_->Symbols()) +
Ben Claytonffd28e22021-06-24 11:27:36 +00003836 " cannot be used as an element type of an array",
3837 source);
Ben Claytonefb741f2021-06-03 08:24:55 +00003838 return nullptr;
3839 }
3840
Sarah4038fa72021-08-05 15:18:29 +00003841 uint32_t el_align = elem_type->Align();
3842 uint32_t el_size = elem_type->Size();
Ben Claytond614dd52021-03-15 10:43:11 +00003843
Ben Clayton4f3ff572021-10-15 17:33:10 +00003844 if (!ValidateNoDuplicateDecorations(arr->decorations)) {
Ben Clayton241c16d2021-06-09 18:53:57 +00003845 return nullptr;
3846 }
3847
Ben Claytond614dd52021-03-15 10:43:11 +00003848 // Look for explicit stride via [[stride(n)]] decoration
Ben Clayton6fcefe42021-04-19 19:16:12 +00003849 uint32_t explicit_stride = 0;
Ben Clayton4f3ff572021-10-15 17:33:10 +00003850 for (auto* deco : arr->decorations) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00003851 Mark(deco);
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003852 if (auto* sd = deco->As<ast::StrideDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003853 explicit_stride = sd->stride;
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003854 if (!ValidateArrayStrideDecoration(sd, el_size, el_align, source)) {
Antonio Maioranofc03a462021-04-16 02:36:44 +00003855 return nullptr;
3856 }
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003857 continue;
Ben Claytond614dd52021-03-15 10:43:11 +00003858 }
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003859
Ben Clayton4f3ff572021-10-15 17:33:10 +00003860 AddError("decoration is not valid for array types", deco->source);
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003861 return nullptr;
Ben Clayton6fcefe42021-04-19 19:16:12 +00003862 }
Ben Claytond614dd52021-03-15 10:43:11 +00003863
3864 // Calculate implicit stride
Ben Claytond1d99bc2021-09-15 17:37:00 +00003865 uint64_t implicit_stride = utils::RoundUp<uint64_t>(el_align, el_size);
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003866
Ben Claytond1d99bc2021-09-15 17:37:00 +00003867 uint64_t stride = explicit_stride ? explicit_stride : implicit_stride;
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003868
James Price4cc43152021-09-02 13:49:59 +00003869 // Evaluate the constant array size expression.
3870 // sem::Array uses a size of 0 for a runtime-sized array.
3871 uint32_t count = 0;
Ben Clayton4f3ff572021-10-15 17:33:10 +00003872 if (auto* count_expr = arr->count) {
James Price4cc43152021-09-02 13:49:59 +00003873 if (!Expression(count_expr)) {
3874 return nullptr;
3875 }
3876
Ben Clayton4f3ff572021-10-15 17:33:10 +00003877 auto size_source = count_expr->source;
James Price4cc43152021-09-02 13:49:59 +00003878
3879 auto* ty = TypeOf(count_expr)->UnwrapRef();
3880 if (!ty->is_integer_scalar()) {
3881 AddError("array size must be integer scalar", size_source);
3882 return nullptr;
3883 }
3884
3885 if (auto* ident = count_expr->As<ast::IdentifierExpression>()) {
3886 // Make sure the identifier is a non-overridable module-scope constant.
3887 VariableInfo* var = nullptr;
3888 bool is_global = false;
Ben Clayton4f3ff572021-10-15 17:33:10 +00003889 if (!variable_stack_.get(ident->symbol, &var, &is_global) || !is_global ||
3890 !var->declaration->is_const) {
James Price4cc43152021-09-02 13:49:59 +00003891 AddError("array size identifier must be a module-scope constant",
3892 size_source);
3893 return nullptr;
3894 }
3895 if (ast::HasDecoration<ast::OverrideDecoration>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00003896 var->declaration->decorations)) {
James Price4cc43152021-09-02 13:49:59 +00003897 AddError("array size expression must not be pipeline-overridable",
3898 size_source);
3899 return nullptr;
3900 }
3901
Ben Clayton4f3ff572021-10-15 17:33:10 +00003902 count_expr = var->declaration->constructor;
James Price4cc43152021-09-02 13:49:59 +00003903 } else if (!count_expr->Is<ast::ScalarConstructorExpression>()) {
3904 AddError(
3905 "array size expression must be either a literal or a module-scope "
3906 "constant",
3907 size_source);
3908 return nullptr;
3909 }
3910
3911 auto count_val = ConstantValueOf(count_expr);
3912 if (!count_val) {
3913 TINT_ICE(Resolver, diagnostics_)
3914 << "could not resolve array size expression";
3915 return nullptr;
3916 }
3917
3918 if (ty->is_signed_integer_scalar() ? count_val.Elements()[0].i32 < 1
3919 : count_val.Elements()[0].u32 < 1u) {
3920 AddError("array size must be at least 1", size_source);
3921 return nullptr;
3922 }
3923
3924 count = count_val.Elements()[0].u32;
3925 }
3926
Ben Claytond1d99bc2021-09-15 17:37:00 +00003927 auto size = std::max<uint64_t>(count, 1) * stride;
3928 if (size > std::numeric_limits<uint32_t>::max()) {
3929 std::stringstream msg;
3930 msg << "array size in bytes must not exceed 0x" << std::hex
3931 << std::numeric_limits<uint32_t>::max() << ", but is 0x" << std::hex
3932 << size;
Ben Clayton4f3ff572021-10-15 17:33:10 +00003933 AddError(msg.str(), arr->source);
Ben Claytond1d99bc2021-09-15 17:37:00 +00003934 return nullptr;
3935 }
3936 if (stride > std::numeric_limits<uint32_t>::max() ||
3937 implicit_stride > std::numeric_limits<uint32_t>::max()) {
3938 TINT_ICE(Resolver, diagnostics_)
3939 << "calculated array stride exceeds uint32";
3940 return nullptr;
3941 }
3942 auto* out = builder_->create<sem::Array>(
3943 elem_type, count, el_align, static_cast<uint32_t>(size),
3944 static_cast<uint32_t>(stride), static_cast<uint32_t>(implicit_stride));
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003945
Sarah4038fa72021-08-05 15:18:29 +00003946 if (!ValidateArray(out, source)) {
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003947 return nullptr;
3948 }
3949
Sarah4038fa72021-08-05 15:18:29 +00003950 if (elem_type->Is<sem::Atomic>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003951 atomic_composite_info_.emplace(out, arr->type->source);
Sarah4038fa72021-08-05 15:18:29 +00003952 } else {
3953 auto found = atomic_composite_info_.find(elem_type);
3954 if (found != atomic_composite_info_.end()) {
3955 atomic_composite_info_.emplace(out, found->second);
3956 }
3957 }
3958
3959 return out;
Ben Claytond614dd52021-03-15 10:43:11 +00003960}
3961
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003962bool Resolver::ValidateArray(const sem::Array* arr, const Source& source) {
3963 auto* el_ty = arr->ElemType();
Ben Clayton8db81882021-04-21 16:45:02 +00003964
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003965 if (auto* el_str = el_ty->As<sem::Struct>()) {
3966 if (el_str->IsBlockDecorated()) {
Ben Clayton8db81882021-04-21 16:45:02 +00003967 // https://gpuweb.github.io/gpuweb/wgsl/#attributes
3968 // A structure type with the block attribute must not be:
3969 // * the element type of an array type
3970 // * the member type in another structure
Ben Claytonffd28e22021-06-24 11:27:36 +00003971 AddError(
Ben Clayton8db81882021-04-21 16:45:02 +00003972 "A structure type with a [[block]] decoration cannot be used as an "
3973 "element of an array",
3974 source);
3975 return false;
3976 }
3977 }
3978 return true;
3979}
3980
3981bool Resolver::ValidateArrayStrideDecoration(const ast::StrideDecoration* deco,
3982 uint32_t el_size,
3983 uint32_t el_align,
3984 const Source& source) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00003985 auto stride = deco->stride;
Ben Clayton8db81882021-04-21 16:45:02 +00003986 bool is_valid_stride =
3987 (stride >= el_size) && (stride >= el_align) && (stride % el_align == 0);
3988 if (!is_valid_stride) {
3989 // https://gpuweb.github.io/gpuweb/wgsl/#array-layout-rules
3990 // Arrays decorated with the stride attribute must have a stride that is
3991 // at least the size of the element type, and be a multiple of the
3992 // element type's alignment value.
Ben Claytonffd28e22021-06-24 11:27:36 +00003993 AddError(
Ben Clayton8db81882021-04-21 16:45:02 +00003994 "arrays decorated with the stride attribute must have a stride "
3995 "that is at least the size of the element type, and be a multiple "
3996 "of the element type's alignment value.",
3997 source);
3998 return false;
3999 }
4000 return true;
4001}
4002
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004003bool Resolver::ValidateStructure(const sem::Struct* str) {
James Price37cabbb2021-07-01 08:13:41 +00004004 if (str->Members().empty()) {
4005 AddError("structures must have at least one member",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004006 str->Declaration()->source);
James Price37cabbb2021-07-01 08:13:41 +00004007 return false;
4008 }
4009
Sarahc0f1ed42021-07-28 18:51:37 +00004010 std::unordered_set<uint32_t> locations;
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004011 for (auto* member : str->Members()) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004012 if (auto* r = member->Type()->As<sem::Array>()) {
Ben Clayton4cd5eea2021-05-07 20:58:34 +00004013 if (r->IsRuntimeSized()) {
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004014 if (member != str->Members().back()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004015 AddError(
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004016 "runtime arrays may only appear as the last member of a struct",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004017 member->Declaration()->source);
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004018 return false;
4019 }
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004020 if (!str->IsBlockDecorated()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004021 AddError(
4022 "a struct containing a runtime-sized array "
4023 "requires the [[block]] attribute: '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +00004024 builder_->Symbols().NameFor(str->Declaration()->name) + "'",
4025 member->Declaration()->source);
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004026 return false;
4027 }
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004028 }
4029 }
4030
Saraha4696682021-07-21 12:16:35 +00004031 auto has_position = false;
Ben Clayton86481202021-10-19 18:38:54 +00004032 const ast::InvariantDecoration* invariant_attribute = nullptr;
Ben Clayton4f3ff572021-10-15 17:33:10 +00004033 for (auto* deco : member->Declaration()->decorations) {
Ben Clayton97668c82021-07-27 08:17:29 +00004034 if (!deco->IsAnyOf<ast::BuiltinDecoration, //
4035 ast::InternalDecoration, //
4036 ast::InterpolateDecoration, //
4037 ast::InvariantDecoration, //
4038 ast::LocationDecoration, //
4039 ast::StructMemberOffsetDecoration, //
4040 ast::StructMemberSizeDecoration, //
4041 ast::StructMemberAlignDecoration>()) {
4042 if (deco->Is<ast::StrideDecoration>() &&
4043 IsValidationDisabled(
Ben Clayton4f3ff572021-10-15 17:33:10 +00004044 member->Declaration()->decorations,
Ben Clayton97668c82021-07-27 08:17:29 +00004045 ast::DisabledValidation::kIgnoreStrideDecoration)) {
4046 continue;
4047 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004048 AddError("decoration is not valid for structure members", deco->source);
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004049 return false;
4050 }
Sarahc0f1ed42021-07-28 18:51:37 +00004051
Saraha4696682021-07-21 12:16:35 +00004052 if (auto* invariant = deco->As<ast::InvariantDecoration>()) {
4053 invariant_attribute = invariant;
Sarahc0f1ed42021-07-28 18:51:37 +00004054 } else if (auto* location = deco->As<ast::LocationDecoration>()) {
4055 if (!ValidateLocationDecoration(location, member->Type(), locations,
Ben Clayton4f3ff572021-10-15 17:33:10 +00004056 member->Declaration()->source)) {
Sarahc0f1ed42021-07-28 18:51:37 +00004057 return false;
4058 }
4059 } else if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
Sarah465c5aa2021-07-23 13:23:20 +00004060 if (!ValidateBuiltinDecoration(builtin, member->Type(),
James Priceceab1402021-10-05 15:02:17 +00004061 /* is_input */ false)) {
Sarah443c41d2021-06-18 19:58:27 +00004062 return false;
Sarahc58738a2021-06-09 16:01:29 +00004063 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004064 if (builtin->builtin == ast::Builtin::kPosition) {
Saraha4696682021-07-21 12:16:35 +00004065 has_position = true;
4066 }
James Price989a8e42021-06-28 23:04:43 +00004067 } else if (auto* interpolate = deco->As<ast::InterpolateDecoration>()) {
4068 if (!ValidateInterpolateDecoration(interpolate, member->Type())) {
4069 return false;
4070 }
Sarahc58738a2021-06-09 16:01:29 +00004071 }
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004072 }
Antonio Maiorano8b2be2d2021-06-18 19:57:57 +00004073
Saraha4696682021-07-21 12:16:35 +00004074 if (invariant_attribute && !has_position) {
4075 AddError("invariant attribute must only be applied to a position builtin",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004076 invariant_attribute->source);
Saraha4696682021-07-21 12:16:35 +00004077 return false;
4078 }
4079
Antonio Maiorano8b2be2d2021-06-18 19:57:57 +00004080 if (auto* member_struct_type = member->Type()->As<sem::Struct>()) {
4081 if (auto* member_struct_type_block_decoration =
4082 ast::GetDecoration<ast::StructBlockDecoration>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00004083 member_struct_type->Declaration()->decorations)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004084 AddError("structs must not contain [[block]] decorated struct members",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004085 member->Declaration()->source);
Ben Claytonffd28e22021-06-24 11:27:36 +00004086 AddNote("see member's struct decoration here",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004087 member_struct_type_block_decoration->source);
Antonio Maiorano8b2be2d2021-06-18 19:57:57 +00004088 return false;
4089 }
4090 }
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004091 }
4092
Ben Clayton4f3ff572021-10-15 17:33:10 +00004093 for (auto* deco : str->Declaration()->decorations) {
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004094 if (!(deco->Is<ast::StructBlockDecoration>())) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004095 AddError("decoration is not valid for struct declarations", deco->source);
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004096 return false;
4097 }
4098 }
4099
4100 return true;
4101}
4102
Sarahc0f1ed42021-07-28 18:51:37 +00004103bool Resolver::ValidateLocationDecoration(
4104 const ast::LocationDecoration* location,
4105 const sem::Type* type,
4106 std::unordered_set<uint32_t>& locations,
4107 const Source& source,
4108 const bool is_input) {
4109 std::string inputs_or_output = is_input ? "inputs" : "output";
Ben Clayton4f3ff572021-10-15 17:33:10 +00004110 if (current_function_ && current_function_->declaration->PipelineStage() ==
Sarahc0f1ed42021-07-28 18:51:37 +00004111 ast::PipelineStage::kCompute) {
4112 AddError("decoration is not valid for compute shader " + inputs_or_output,
Ben Clayton4f3ff572021-10-15 17:33:10 +00004113 location->source);
Sarahc0f1ed42021-07-28 18:51:37 +00004114 return false;
4115 }
4116
4117 if (!type->is_numeric_scalar_or_vector()) {
4118 std::string invalid_type = type->FriendlyName(builder_->Symbols());
4119 AddError("cannot apply 'location' attribute to declaration of type '" +
4120 invalid_type + "'",
4121 source);
4122 AddNote(
4123 "'location' attribute must only be applied to declarations of "
4124 "numeric scalar or numeric vector type",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004125 location->source);
Sarahc0f1ed42021-07-28 18:51:37 +00004126 return false;
4127 }
4128
Ben Clayton4f3ff572021-10-15 17:33:10 +00004129 if (locations.count(location->value)) {
Sarahc0f1ed42021-07-28 18:51:37 +00004130 AddError(deco_to_str(location) + " attribute appears multiple times",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004131 location->source);
Sarahc0f1ed42021-07-28 18:51:37 +00004132 return false;
4133 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004134 locations.emplace(location->value);
Sarahc0f1ed42021-07-28 18:51:37 +00004135
4136 return true;
4137}
4138
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004139sem::Struct* Resolver::Structure(const ast::Struct* str) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004140 if (!ValidateNoDuplicateDecorations(str->decorations)) {
Ben Clayton241c16d2021-06-09 18:53:57 +00004141 return nullptr;
4142 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004143 for (auto* deco : str->decorations) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00004144 Mark(deco);
4145 }
4146
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00004147 sem::StructMemberList sem_members;
Ben Clayton4f3ff572021-10-15 17:33:10 +00004148 sem_members.reserve(str->members.size());
Ben Claytond614dd52021-03-15 10:43:11 +00004149
4150 // Calculate the effective size and alignment of each field, and the overall
4151 // size of the structure.
4152 // For size, use the size attribute if provided, otherwise use the default
4153 // size for the type.
4154 // For alignment, use the alignment attribute if provided, otherwise use the
4155 // default alignment for the member type.
4156 // Diagnostic errors are raised if a basic rule is violated.
4157 // Validation of storage-class rules requires analysing the actual variable
4158 // usage of the structure, and so is performed as part of the variable
4159 // validation.
Ben Claytond1d99bc2021-09-15 17:37:00 +00004160 uint64_t struct_size = 0;
4161 uint64_t struct_align = 1;
Ben Clayton86481202021-10-19 18:38:54 +00004162 std::unordered_map<Symbol, const ast::StructMember*> member_map;
Ben Claytond614dd52021-03-15 10:43:11 +00004163
Ben Clayton4f3ff572021-10-15 17:33:10 +00004164 for (auto* member : str->members) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00004165 Mark(member);
Ben Clayton4f3ff572021-10-15 17:33:10 +00004166 auto result = member_map.emplace(member->symbol, member);
Sarah0bbe24d2021-07-19 17:38:20 +00004167 if (!result.second) {
4168 AddError("redefinition of '" +
Ben Clayton4f3ff572021-10-15 17:33:10 +00004169 builder_->Symbols().NameFor(member->symbol) + "'",
4170 member->source);
4171 AddNote("previous definition is here", result.first->second->source);
Sarah0bbe24d2021-07-19 17:38:20 +00004172 return nullptr;
4173 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00004174
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004175 // Resolve member type
Ben Clayton4f3ff572021-10-15 17:33:10 +00004176 auto* type = Type(member->type);
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004177 if (!type) {
4178 return nullptr;
4179 }
Ben Clayton2ac55fe2021-04-28 14:13:13 +00004180
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004181 // Validate member type
James Price3b267172021-06-09 09:12:57 +00004182 if (!IsPlain(type)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004183 AddError(type->FriendlyName(builder_->Symbols()) +
4184 " cannot be used as the type of a structure member",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004185 member->source);
Ben Claytond614dd52021-03-15 10:43:11 +00004186 return nullptr;
4187 }
4188
Ben Claytond1d99bc2021-09-15 17:37:00 +00004189 uint64_t offset = struct_size;
4190 uint64_t align = type->Align();
4191 uint64_t size = type->Size();
Ben Claytond614dd52021-03-15 10:43:11 +00004192
Ben Clayton4f3ff572021-10-15 17:33:10 +00004193 if (!ValidateNoDuplicateDecorations(member->decorations)) {
Ben Clayton241c16d2021-06-09 18:53:57 +00004194 return nullptr;
4195 }
4196
Ben Clayton2f9ced02021-03-15 20:34:22 +00004197 bool has_offset_deco = false;
4198 bool has_align_deco = false;
4199 bool has_size_deco = false;
Ben Clayton4f3ff572021-10-15 17:33:10 +00004200 for (auto* deco : member->decorations) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00004201 Mark(deco);
Ben Claytond614dd52021-03-15 10:43:11 +00004202 if (auto* o = deco->As<ast::StructMemberOffsetDecoration>()) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004203 // Offset decorations are not part of the WGSL spec, but are emitted
4204 // by the SPIR-V reader.
Ben Clayton4f3ff572021-10-15 17:33:10 +00004205 if (o->offset < struct_size) {
4206 AddError("offsets must be in ascending order", o->source);
Ben Claytond614dd52021-03-15 10:43:11 +00004207 return nullptr;
4208 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004209 offset = o->offset;
Ben Claytond614dd52021-03-15 10:43:11 +00004210 align = 1;
Ben Clayton2f9ced02021-03-15 20:34:22 +00004211 has_offset_deco = true;
Ben Claytond614dd52021-03-15 10:43:11 +00004212 } else if (auto* a = deco->As<ast::StructMemberAlignDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004213 if (a->align <= 0 || !utils::IsPowerOfTwo(a->align)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004214 AddError("align value must be a positive, power-of-two integer",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004215 a->source);
Ben Claytond614dd52021-03-15 10:43:11 +00004216 return nullptr;
4217 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004218 align = a->align;
Ben Clayton2f9ced02021-03-15 20:34:22 +00004219 has_align_deco = true;
Ben Claytond614dd52021-03-15 10:43:11 +00004220 } else if (auto* s = deco->As<ast::StructMemberSizeDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004221 if (s->size < size) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004222 AddError("size must be at least as big as the type's size (" +
4223 std::to_string(size) + ")",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004224 s->source);
Ben Claytond614dd52021-03-15 10:43:11 +00004225 return nullptr;
4226 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004227 size = s->size;
Ben Clayton2f9ced02021-03-15 20:34:22 +00004228 has_size_deco = true;
Ben Claytond614dd52021-03-15 10:43:11 +00004229 }
4230 }
4231
Ben Clayton2f9ced02021-03-15 20:34:22 +00004232 if (has_offset_deco && (has_align_deco || has_size_deco)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004233 AddError(
Ben Clayton2f9ced02021-03-15 20:34:22 +00004234 "offset decorations cannot be used with align or size decorations",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004235 member->source);
Ben Clayton2f9ced02021-03-15 20:34:22 +00004236 return nullptr;
4237 }
4238
Ben Claytona7520522021-03-15 13:37:41 +00004239 offset = utils::RoundUp(align, offset);
Ben Claytond1d99bc2021-09-15 17:37:00 +00004240 if (offset > std::numeric_limits<uint32_t>::max()) {
4241 std::stringstream msg;
4242 msg << "struct member has byte offset 0x" << std::hex << offset
4243 << ", but must not exceed 0x" << std::hex
4244 << std::numeric_limits<uint32_t>::max();
Ben Clayton4f3ff572021-10-15 17:33:10 +00004245 AddError(msg.str(), member->source);
Ben Claytond1d99bc2021-09-15 17:37:00 +00004246 return nullptr;
4247 }
Ben Claytond614dd52021-03-15 10:43:11 +00004248
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004249 auto* sem_member = builder_->create<sem::StructMember>(
Ben Clayton86481202021-10-19 18:38:54 +00004250 member, member->symbol, type, static_cast<uint32_t>(sem_members.size()),
Ben Claytonc40d15d2021-10-14 22:43:21 +00004251 static_cast<uint32_t>(offset), static_cast<uint32_t>(align),
4252 static_cast<uint32_t>(size));
Ben Claytond614dd52021-03-15 10:43:11 +00004253 builder_->Sem().Add(member, sem_member);
4254 sem_members.emplace_back(sem_member);
4255
4256 struct_size = offset + size;
4257 struct_align = std::max(struct_align, align);
4258 }
4259
Ben Claytond1d99bc2021-09-15 17:37:00 +00004260 uint64_t size_no_padding = struct_size;
Ben Claytona7520522021-03-15 13:37:41 +00004261 struct_size = utils::RoundUp(struct_align, struct_size);
Ben Claytond614dd52021-03-15 10:43:11 +00004262
Ben Claytond1d99bc2021-09-15 17:37:00 +00004263 if (struct_size > std::numeric_limits<uint32_t>::max()) {
4264 std::stringstream msg;
4265 msg << "struct size in bytes must not exceed 0x" << std::hex
4266 << std::numeric_limits<uint32_t>::max() << ", but is 0x" << std::hex
4267 << struct_size;
Ben Clayton4f3ff572021-10-15 17:33:10 +00004268 AddError(msg.str(), str->source);
Ben Claytond1d99bc2021-09-15 17:37:00 +00004269 return nullptr;
4270 }
4271 if (struct_align > std::numeric_limits<uint32_t>::max()) {
4272 TINT_ICE(Resolver, diagnostics_)
4273 << "calculated struct stride exceeds uint32";
4274 return nullptr;
4275 }
4276
4277 auto* out = builder_->create<sem::Struct>(
Ben Clayton4f3ff572021-10-15 17:33:10 +00004278 str, str->name, sem_members, static_cast<uint32_t>(struct_align),
Ben Claytond1d99bc2021-09-15 17:37:00 +00004279 static_cast<uint32_t>(struct_size),
4280 static_cast<uint32_t>(size_no_padding));
Ben Clayton313e6182021-06-17 19:56:14 +00004281
Ben Clayton313e6182021-06-17 19:56:14 +00004282 for (size_t i = 0; i < sem_members.size(); i++) {
Sarah4038fa72021-08-05 15:18:29 +00004283 auto* mem_type = sem_members[i]->Type();
4284 if (mem_type->Is<sem::Atomic>()) {
4285 atomic_composite_info_.emplace(out,
Ben Clayton4f3ff572021-10-15 17:33:10 +00004286 sem_members[i]->Declaration()->source);
Sarah4038fa72021-08-05 15:18:29 +00004287 break;
4288 } else {
4289 auto found = atomic_composite_info_.find(mem_type);
4290 if (found != atomic_composite_info_.end()) {
4291 atomic_composite_info_.emplace(out, found->second);
4292 break;
4293 }
Ben Clayton313e6182021-06-17 19:56:14 +00004294 }
4295 }
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004296
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004297 if (!ValidateStructure(out)) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004298 return nullptr;
4299 }
4300
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004301 return out;
Ben Claytond614dd52021-03-15 10:43:11 +00004302}
4303
Antonio Maiorano2e974352021-03-22 23:20:17 +00004304bool Resolver::ValidateReturn(const ast::ReturnStatement* ret) {
Ben Clayton3068dcb2021-04-30 19:24:29 +00004305 auto* func_type = current_function_->return_type;
Antonio Maiorano2e974352021-03-22 23:20:17 +00004306
Ben Clayton4f3ff572021-10-15 17:33:10 +00004307 auto* ret_type = ret->value ? TypeOf(ret->value)->UnwrapRef()
4308 : builder_->create<sem::Void>();
Antonio Maiorano2e974352021-03-22 23:20:17 +00004309
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004310 if (func_type->UnwrapRef() != ret_type) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004311 AddError(
4312 "return statement type must match its function "
4313 "return type, returned '" +
4314 ret_type->FriendlyName(builder_->Symbols()) + "', expected '" +
4315 current_function_->return_type_name + "'",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004316 ret->source);
Antonio Maiorano2e974352021-03-22 23:20:17 +00004317 return false;
4318 }
4319
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00004320 auto* sem = builder_->Sem().Get(ret);
4321 if (auto* continuing =
4322 sem->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
4323 AddError("continuing blocks must not contain a return statement",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004324 ret->source);
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00004325 if (continuing != sem->Parent()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004326 AddNote("see continuing block here", continuing->Declaration()->source);
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00004327 }
4328 return false;
4329 }
4330
Antonio Maiorano2e974352021-03-22 23:20:17 +00004331 return true;
4332}
4333
Ben Clayton86481202021-10-19 18:38:54 +00004334bool Resolver::Return(const ast::ReturnStatement* ret) {
Antonio Maiorano2e974352021-03-22 23:20:17 +00004335 current_function_->return_statements.push_back(ret);
4336
Ben Clayton4f3ff572021-10-15 17:33:10 +00004337 if (auto* value = ret->value) {
James Price7e221962021-06-15 15:00:57 +00004338 if (!Expression(value)) {
4339 return false;
4340 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00004341 }
4342
James Price7e221962021-06-15 15:00:57 +00004343 // Validate after processing the return value expression so that its type is
4344 // available for validation.
4345 return ValidateReturn(ret);
Antonio Maiorano2e974352021-03-22 23:20:17 +00004346}
4347
Antonio Maioranocea744d2021-03-25 12:55:27 +00004348bool Resolver::ValidateSwitch(const ast::SwitchStatement* s) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004349 auto* cond_type = TypeOf(s->condition)->UnwrapRef();
Antonio Maioranocea744d2021-03-25 12:55:27 +00004350 if (!cond_type->is_integer_scalar()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004351 AddError(
4352 "switch statement selector expression must be of a "
4353 "scalar integer type",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004354 s->condition->source);
Antonio Maioranocea744d2021-03-25 12:55:27 +00004355 return false;
4356 }
4357
4358 bool has_default = false;
Ben Clayton11ed0db2021-10-14 20:30:29 +00004359 std::unordered_map<uint32_t, Source> selectors;
Antonio Maioranocea744d2021-03-25 12:55:27 +00004360
Ben Clayton4f3ff572021-10-15 17:33:10 +00004361 for (auto* case_stmt : s->body) {
Antonio Maioranocea744d2021-03-25 12:55:27 +00004362 if (case_stmt->IsDefault()) {
4363 if (has_default) {
4364 // More than one default clause
Ben Clayton5a88ec82021-06-29 14:42:19 +00004365 AddError("switch statement must have exactly one default clause",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004366 case_stmt->source);
Antonio Maioranocea744d2021-03-25 12:55:27 +00004367 return false;
4368 }
4369 has_default = true;
4370 }
4371
Ben Clayton4f3ff572021-10-15 17:33:10 +00004372 for (auto* selector : case_stmt->selectors) {
Ben Clayton109b18f2021-04-28 13:50:43 +00004373 if (cond_type != TypeOf(selector)) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004374 AddError(
4375 "the case selector values must have the same "
4376 "type as the selector expression.",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004377 case_stmt->source);
Antonio Maioranocea744d2021-03-25 12:55:27 +00004378 return false;
4379 }
4380
Ben Clayton4f3ff572021-10-15 17:33:10 +00004381 auto v = selector->ValueAsU32();
Ben Clayton11ed0db2021-10-14 20:30:29 +00004382 auto it = selectors.find(v);
4383 if (it != selectors.end()) {
4384 auto val = selector->Is<ast::IntLiteral>()
Ben Clayton4f3ff572021-10-15 17:33:10 +00004385 ? std::to_string(selector->ValueAsI32())
4386 : std::to_string(selector->ValueAsU32());
4387 AddError("duplicate switch case '" + val + "'", selector->source);
Ben Clayton11ed0db2021-10-14 20:30:29 +00004388 AddNote("previous case declared here", it->second);
Antonio Maioranocea744d2021-03-25 12:55:27 +00004389 return false;
4390 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004391 selectors.emplace(v, selector->source);
Antonio Maioranocea744d2021-03-25 12:55:27 +00004392 }
4393 }
4394
4395 if (!has_default) {
4396 // No default clause
Ben Clayton4f3ff572021-10-15 17:33:10 +00004397 AddError("switch statement must have a default clause", s->source);
Antonio Maioranocea744d2021-03-25 12:55:27 +00004398 return false;
4399 }
4400
Ben Clayton4f3ff572021-10-15 17:33:10 +00004401 if (!s->body.empty()) {
4402 auto* last_clause = s->body.back()->As<ast::CaseStatement>();
4403 auto* last_stmt = last_clause->body->Last();
Antonio Maioranocea744d2021-03-25 12:55:27 +00004404 if (last_stmt && last_stmt->Is<ast::FallthroughStatement>()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004405 AddError(
4406 "a fallthrough statement must not appear as "
4407 "the last statement in last clause of a switch",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004408 last_stmt->source);
Antonio Maioranocea744d2021-03-25 12:55:27 +00004409 return false;
4410 }
4411 }
4412
4413 return true;
4414}
4415
Ben Clayton86481202021-10-19 18:38:54 +00004416bool Resolver::SwitchStatement(const ast::SwitchStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00004417 auto* sem =
4418 builder_->create<sem::SwitchStatement>(stmt, current_compound_statement_);
4419 builder_->Sem().Add(stmt, sem);
4420 return Scope(sem, [&] {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004421 if (!Expression(stmt->condition)) {
Antonio Maioranocea744d2021-03-25 12:55:27 +00004422 return false;
4423 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004424 for (auto* case_stmt : stmt->body) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00004425 Mark(case_stmt);
4426 if (!CaseStatement(case_stmt)) {
4427 return false;
4428 }
4429 }
4430 if (!ValidateSwitch(stmt)) {
4431 return false;
4432 }
4433 return true;
4434 });
Antonio Maioranocea744d2021-03-25 12:55:27 +00004435}
4436
Ben Clayton86481202021-10-19 18:38:54 +00004437bool Resolver::Assignment(const ast::AssignmentStatement* a) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004438 if (!Expression(a->lhs) || !Expression(a->rhs)) {
Antonio Maioranoe09989a2021-03-31 13:26:43 +00004439 return false;
4440 }
Ben Clayton1aa98e62021-10-21 23:04:44 +00004441
Antonio Maioranoe09989a2021-03-31 13:26:43 +00004442 return ValidateAssignment(a);
4443}
4444
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004445bool Resolver::ValidateAssignment(const ast::AssignmentStatement* a) {
Ben Clayton1aa98e62021-10-21 23:04:44 +00004446 auto const* rhs_type = TypeOf(a->rhs);
4447
4448 if (a->lhs->Is<ast::PhonyExpression>()) {
4449 // https://www.w3.org/TR/WGSL/#phony-assignment-section
4450 auto* ty = rhs_type->UnwrapRef();
4451 if (!ty->IsConstructible() &&
4452 !ty->IsAnyOf<sem::Pointer, sem::Texture, sem::Sampler>()) {
4453 AddError(
4454 "cannot assign '" + TypeNameOf(a->rhs) +
Ben Claytonc73b57f2021-10-25 14:26:55 +00004455 "' to '_'. '_' can only be assigned a constructible, pointer, "
Ben Clayton1aa98e62021-10-21 23:04:44 +00004456 "texture or sampler type",
4457 a->rhs->source);
4458 return false;
4459 }
4460 return true; // RHS can be anything.
4461 }
4462
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004463 // https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
Ben Clayton4f3ff572021-10-15 17:33:10 +00004464 auto const* lhs_type = TypeOf(a->lhs);
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004465
Ben Clayton4f3ff572021-10-15 17:33:10 +00004466 if (auto* ident = a->lhs->As<ast::IdentifierExpression>()) {
Sarahcb0309e2021-06-28 20:44:31 +00004467 VariableInfo* var;
Ben Clayton4f3ff572021-10-15 17:33:10 +00004468 if (variable_stack_.get(ident->symbol, &var)) {
Sarahcb0309e2021-06-28 20:44:31 +00004469 if (var->kind == VariableKind::kParameter) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004470 AddError("cannot assign to function parameter", a->lhs->source);
4471 AddNote("'" + builder_->Symbols().NameFor(ident->symbol) +
Sarahcb0309e2021-06-28 20:44:31 +00004472 "' is declared here:",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004473 var->declaration->source);
Sarahcb0309e2021-06-28 20:44:31 +00004474 return false;
4475 }
Ben Clayton4f3ff572021-10-15 17:33:10 +00004476 if (var->declaration->is_const) {
4477 AddError("cannot assign to const", a->lhs->source);
4478 AddNote("'" + builder_->Symbols().NameFor(ident->symbol) +
Sarahcb0309e2021-06-28 20:44:31 +00004479 "' is declared here:",
Ben Clayton4f3ff572021-10-15 17:33:10 +00004480 var->declaration->source);
Sarahcb0309e2021-06-28 20:44:31 +00004481 return false;
4482 }
4483 }
4484 }
4485
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004486 auto* lhs_ref = lhs_type->As<sem::Reference>();
4487 if (!lhs_ref) {
4488 // LHS is not a reference, so it has no storage.
Ben Clayton4f3ff572021-10-15 17:33:10 +00004489 AddError("cannot assign to value of type '" + TypeNameOf(a->lhs) + "'",
4490 a->lhs->source);
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004491 return false;
4492 }
4493
Antonio Maioranobe607c02021-05-18 15:26:40 +00004494 auto* storage_type = lhs_ref->StoreType();
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004495 auto* value_type = rhs_type->UnwrapRef(); // Implicit load of RHS
4496
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004497 // Value type has to match storage type
4498 if (storage_type != value_type) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004499 AddError("cannot assign '" + TypeNameOf(a->rhs) + "' to '" +
4500 TypeNameOf(a->lhs) + "'",
4501 a->source);
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004502 return false;
4503 }
James Price06c86a52021-08-13 15:20:42 +00004504 if (!storage_type->IsConstructible()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004505 AddError("storage type of assignment must be constructible", a->source);
James Price06c86a52021-08-13 15:20:42 +00004506 return false;
4507 }
Sarahebaa4b42021-06-15 22:39:19 +00004508 if (lhs_ref->Access() == ast::Access::kRead) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004509 AddError("cannot store into a read-only type '" + TypeNameOf(a->lhs) + "'",
4510 a->source);
Sarahebaa4b42021-06-15 22:39:19 +00004511 return false;
4512 }
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004513 return true;
4514}
4515
Sarahc0353662021-06-29 21:30:37 +00004516bool Resolver::ValidateNoDuplicateDefinition(Symbol sym,
4517 const Source& source,
4518 bool check_global_scope_only) {
4519 if (check_global_scope_only) {
4520 bool is_global = false;
4521 VariableInfo* var;
4522 if (variable_stack_.get(sym, &var, &is_global)) {
4523 if (is_global) {
4524 AddError("redefinition of '" + builder_->Symbols().NameFor(sym) + "'",
4525 source);
Ben Clayton4f3ff572021-10-15 17:33:10 +00004526 AddNote("previous definition is here", var->declaration->source);
Sarahc0353662021-06-29 21:30:37 +00004527 return false;
4528 }
4529 }
4530 auto it = symbol_to_function_.find(sym);
4531 if (it != symbol_to_function_.end()) {
4532 AddError("redefinition of '" + builder_->Symbols().NameFor(sym) + "'",
4533 source);
Ben Clayton4f3ff572021-10-15 17:33:10 +00004534 AddNote("previous definition is here", it->second->declaration->source);
Sarahc0353662021-06-29 21:30:37 +00004535 return false;
4536 }
4537 } else {
4538 VariableInfo* var;
4539 if (variable_stack_.get(sym, &var)) {
4540 AddError("redefinition of '" + builder_->Symbols().NameFor(sym) + "'",
4541 source);
Ben Clayton4f3ff572021-10-15 17:33:10 +00004542 AddNote("previous definition is here", var->declaration->source);
Sarahc0353662021-06-29 21:30:37 +00004543 return false;
4544 }
4545 }
4546 return true;
4547}
4548
Ben Clayton241c16d2021-06-09 18:53:57 +00004549bool Resolver::ValidateNoDuplicateDecorations(
4550 const ast::DecorationList& decorations) {
4551 std::unordered_map<const TypeInfo*, Source> seen;
4552 for (auto* d : decorations) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004553 auto res = seen.emplace(&d->TypeInfo(), d->source);
James Price4daac0e2021-06-15 16:33:57 +00004554 if (!res.second && !d->Is<ast::InternalDecoration>()) {
Ben Clayton4f3ff572021-10-15 17:33:10 +00004555 AddError("duplicate " + d->Name() + " decoration", d->source);
Ben Claytonffd28e22021-06-24 11:27:36 +00004556 AddNote("first decoration declared here", res.first->second);
Ben Clayton241c16d2021-06-09 18:53:57 +00004557 return false;
4558 }
4559 }
4560 return true;
4561}
4562
Ben Claytona88090b2021-03-17 22:47:33 +00004563bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004564 sem::Type* ty,
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +00004565 const Source& usage) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004566 ty = const_cast<sem::Type*>(ty->UnwrapRef());
Ben Claytona88090b2021-03-17 22:47:33 +00004567
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004568 if (auto* str = ty->As<sem::Struct>()) {
4569 if (str->StorageClassUsage().count(sc)) {
Ben Claytona88090b2021-03-17 22:47:33 +00004570 return true; // Already applied
4571 }
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004572
4573 str->AddUsage(sc);
4574
4575 for (auto* member : str->Members()) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004576 if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
Ben Claytona88090b2021-03-17 22:47:33 +00004577 std::stringstream err;
Ben Clayton722b5a22021-03-18 20:46:24 +00004578 err << "while analysing structure member "
4579 << str->FriendlyName(builder_->Symbols()) << "."
Ben Clayton4f3ff572021-10-15 17:33:10 +00004580 << builder_->Symbols().NameFor(member->Declaration()->symbol);
4581 AddNote(err.str(), member->Declaration()->source);
Ben Claytona88090b2021-03-17 22:47:33 +00004582 return false;
4583 }
4584 }
Ben Clayton722b5a22021-03-18 20:46:24 +00004585 return true;
Ben Claytona88090b2021-03-17 22:47:33 +00004586 }
4587
Ben Clayton4cd5eea2021-05-07 20:58:34 +00004588 if (auto* arr = ty->As<sem::Array>()) {
4589 return ApplyStorageClassUsageToType(
4590 sc, const_cast<sem::Type*>(arr->ElemType()), usage);
Ben Clayton722b5a22021-03-18 20:46:24 +00004591 }
4592
Ben Clayton25eef8d2021-03-18 21:03:24 +00004593 if (ast::IsHostShareable(sc) && !IsHostShareable(ty)) {
Ben Clayton722b5a22021-03-18 20:46:24 +00004594 std::stringstream err;
4595 err << "Type '" << ty->FriendlyName(builder_->Symbols())
4596 << "' cannot be used in storage class '" << sc
Ben Clayton25eef8d2021-03-18 21:03:24 +00004597 << "' as it is non-host-shareable";
Ben Claytonffd28e22021-06-24 11:27:36 +00004598 AddError(err.str(), usage);
Ben Clayton722b5a22021-03-18 20:46:24 +00004599 return false;
Ben Claytona88090b2021-03-17 22:47:33 +00004600 }
4601
4602 return true;
4603}
4604
Ben Clayton9430cb42021-03-09 15:06:37 +00004605template <typename F>
Ben Clayton6e459fe2021-07-14 09:44:41 +00004606bool Resolver::Scope(sem::CompoundStatement* stmt, F&& callback) {
4607 auto* prev_current_statement = current_statement_;
4608 auto* prev_current_compound_statement = current_compound_statement_;
4609 auto* prev_current_block = current_block_;
4610 current_statement_ = stmt;
4611 current_compound_statement_ = stmt;
4612 current_block_ = stmt->As<sem::BlockStatement>();
Antonio Maiorano4682e3f2021-03-22 17:38:45 +00004613 variable_stack_.push_scope();
Ben Clayton6e459fe2021-07-14 09:44:41 +00004614
4615 TINT_DEFER({
4616 TINT_DEFER(variable_stack_.pop_scope());
4617 current_block_ = prev_current_block;
4618 current_compound_statement_ = prev_current_compound_statement;
4619 current_statement_ = prev_current_statement;
4620 });
4621
Ben Clayton1b03f0a2021-07-08 21:23:33 +00004622 return callback();
Ben Clayton9430cb42021-03-09 15:06:37 +00004623}
4624
Ben Clayton4cd5eea2021-05-07 20:58:34 +00004625std::string Resolver::VectorPretty(uint32_t size,
4626 const sem::Type* element_type) {
Antonio Maiorano3751fd22021-04-19 22:51:23 +00004627 sem::Vector vec_type(element_type, size);
Arman Uguray097c75a2021-03-18 15:43:14 +00004628 return vec_type.FriendlyName(builder_->Symbols());
4629}
4630
Ben Clayton12ed13d2021-04-28 12:38:13 +00004631void Resolver::Mark(const ast::Node* node) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00004632 if (node == nullptr) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004633 TINT_ICE(Resolver, diagnostics_) << "Resolver::Mark() called with nullptr";
Ben Clayton6fcefe42021-04-19 19:16:12 +00004634 }
4635 if (marked_.emplace(node).second) {
4636 return;
4637 }
Ben Claytonffd28e22021-06-24 11:27:36 +00004638 TINT_ICE(Resolver, diagnostics_)
Ben Clayton6fcefe42021-04-19 19:16:12 +00004639 << "AST node '" << node->TypeInfo().name
4640 << "' was encountered twice in the same AST of a Program\n"
Ben Clayton4f3ff572021-10-15 17:33:10 +00004641 << "At: " << node->source << "\n"
Ben Claytonf0756e32021-04-29 20:57:55 +00004642 << "Pointer: " << node;
Ben Clayton6fcefe42021-04-19 19:16:12 +00004643}
4644
Ben Claytonffd28e22021-06-24 11:27:36 +00004645void Resolver::AddError(const std::string& msg, const Source& source) const {
4646 diagnostics_.add_error(diag::System::Resolver, msg, source);
4647}
4648
4649void Resolver::AddWarning(const std::string& msg, const Source& source) const {
4650 diagnostics_.add_warning(diag::System::Resolver, msg, source);
4651}
4652
4653void Resolver::AddNote(const std::string& msg, const Source& source) const {
4654 diagnostics_.add_note(diag::System::Resolver, msg, source);
4655}
4656
Ben Clayton12ed13d2021-04-28 12:38:13 +00004657Resolver::VariableInfo::VariableInfo(const ast::Variable* decl,
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004658 sem::Type* ty,
Antonio Maioranodc4e6c12021-05-14 17:51:13 +00004659 const std::string& tn,
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004660 ast::StorageClass sc,
Ryan Harrison3832b8e2021-06-09 20:45:09 +00004661 ast::Access ac,
Ben Clayton4ffcf062021-07-22 13:24:59 +00004662 VariableKind k,
4663 uint32_t idx)
Antonio Maiorano9ef17472021-03-26 12:47:58 +00004664 : declaration(decl),
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004665 type(ty),
Ben Clayton109b18f2021-04-28 13:50:43 +00004666 type_name(tn),
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004667 storage_class(sc),
Ryan Harrison3832b8e2021-06-09 20:45:09 +00004668 access(ac),
Ben Clayton4ffcf062021-07-22 13:24:59 +00004669 kind(k),
4670 index(idx) {}
Ben Claytonb17aea12021-02-03 17:51:09 +00004671
Ben Clayton5f0ea112021-03-09 10:54:37 +00004672Resolver::VariableInfo::~VariableInfo() = default;
Ben Claytonb17aea12021-02-03 17:51:09 +00004673
Ben Clayton86481202021-10-19 18:38:54 +00004674Resolver::FunctionInfo::FunctionInfo(const ast::Function* decl)
4675 : declaration(decl) {}
Ben Clayton5f0ea112021-03-09 10:54:37 +00004676Resolver::FunctionInfo::~FunctionInfo() = default;
Ben Clayton87c78dd2021-02-03 16:43:20 +00004677
Ben Claytonc7dcbae2021-03-09 15:08:48 +00004678} // namespace resolver
Dan Sinclair6e581892020-03-02 15:47:43 -05004679} // namespace tint