blob: 264b41be1cd56cd71db7e5303b6e7eb0b866f569 [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 Claytona6b9a8e2021-01-26 16:57:10 +000020#include <utility>
dan sinclair973bd6a2020-04-07 12:57:42 +000021
Ben Claytonfec63b72021-04-21 13:47:12 +000022#include "src/ast/alias.h"
23#include "src/ast/array.h"
dan sinclair6c498fc2020-04-07 12:47:23 +000024#include "src/ast/assignment_statement.h"
dan sinclaira7d498e2020-09-22 22:07:13 +000025#include "src/ast/bitcast_expression.h"
dan sinclairb7ea6e22020-04-07 12:54:10 +000026#include "src/ast/break_statement.h"
dan sinclair50080b72020-07-21 13:42:13 +000027#include "src/ast/call_statement.h"
dan sinclairaec965e2020-04-07 12:54:29 +000028#include "src/ast/continue_statement.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000029#include "src/ast/depth_texture.h"
Ben Clayton451f2cc2021-05-12 12:54:21 +000030#include "src/ast/disable_validation_decoration.h"
Ben Clayton1d8098a2020-11-30 23:30:58 +000031#include "src/ast/discard_statement.h"
Ben Clayton1d8098a2020-11-30 23:30:58 +000032#include "src/ast/fallthrough_statement.h"
Ben Claytonf4075a72021-07-02 19:27:42 +000033#include "src/ast/for_loop_statement.h"
dan sinclair91c44a52020-04-07 12:55:25 +000034#include "src/ast/if_statement.h"
Ben Claytonb502fdf2021-04-07 08:09:21 +000035#include "src/ast/internal_decoration.h"
James Price989a8e42021-06-28 23:04:43 +000036#include "src/ast/interpolate_decoration.h"
dan sinclairbc71eda2020-04-07 12:55:51 +000037#include "src/ast/loop_statement.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000038#include "src/ast/matrix.h"
James Pricee87ded82021-04-30 17:14:19 +000039#include "src/ast/override_decoration.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000040#include "src/ast/pointer.h"
dan sinclairbf0fff82020-04-07 12:56:24 +000041#include "src/ast/return_statement.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000042#include "src/ast/sampled_texture.h"
43#include "src/ast/sampler.h"
44#include "src/ast/storage_texture.h"
Antonio Maiorano9970ec62021-03-18 17:59:54 +000045#include "src/ast/struct_block_decoration.h"
dan sinclair18b32852020-04-07 12:56:45 +000046#include "src/ast/switch_statement.h"
Ben Clayton02ebf0d2021-05-05 09:09:41 +000047#include "src/ast/type_name.h"
dan sinclair327ed1b2020-04-07 19:27:21 +000048#include "src/ast/unary_op_expression.h"
dan sinclairca893e32020-04-07 12:57:12 +000049#include "src/ast/variable_decl_statement.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000050#include "src/ast/vector.h"
Antonio Maioranobfc97942021-04-06 20:41:07 +000051#include "src/ast/workgroup_decoration.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000052#include "src/sem/array.h"
Ben Clayton313e6182021-06-17 19:56:14 +000053#include "src/sem/atomic_type.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000054#include "src/sem/call.h"
Ben Claytonfd35aa82021-07-26 22:19:48 +000055#include "src/sem/depth_multisampled_texture_type.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000056#include "src/sem/depth_texture_type.h"
Ben Clayton6e459fe2021-07-14 09:44:41 +000057#include "src/sem/for_loop_statement.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000058#include "src/sem/function.h"
Ben Clayton6e459fe2021-07-14 09:44:41 +000059#include "src/sem/if_statement.h"
60#include "src/sem/loop_statement.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000061#include "src/sem/member_accessor_expression.h"
Ryan Harrison83116d22021-04-20 16:09:21 +000062#include "src/sem/multisampled_texture_type.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000063#include "src/sem/pointer_type.h"
Ben Clayton9b54a2e2021-05-18 10:28:48 +000064#include "src/sem/reference_type.h"
Ben Claytonfec63b72021-04-21 13:47:12 +000065#include "src/sem/sampled_texture_type.h"
66#include "src/sem/sampler_type.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000067#include "src/sem/statement.h"
Ryan Harrisonde8f1332021-04-20 20:47:51 +000068#include "src/sem/storage_texture_type.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000069#include "src/sem/struct.h"
Ben Clayton6e459fe2021-07-14 09:44:41 +000070#include "src/sem/switch_statement.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000071#include "src/sem/variable.h"
Ben Clayton1b03f0a2021-07-08 21:23:33 +000072#include "src/utils/defer.h"
Antonio Maiorano25436862021-04-13 13:32:33 +000073#include "src/utils/get_or_create.h"
Ben Claytona7520522021-03-15 13:37:41 +000074#include "src/utils/math.h"
Ben Claytonb3505002021-05-19 16:11:04 +000075#include "src/utils/scoped_assignment.h"
dan sinclairb7edc4c2020-04-07 12:46:30 +000076
Dan Sinclair6e581892020-03-02 15:47:43 -050077namespace tint {
Ben Claytonc7dcbae2021-03-09 15:08:48 +000078namespace resolver {
Ben Clayton052ab892021-02-08 19:53:42 +000079namespace {
80
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000081using IntrinsicType = tint::sem::IntrinsicType;
Ben Clayton052ab892021-02-08 19:53:42 +000082
Ben Claytonfec63b72021-04-21 13:47:12 +000083bool IsValidStorageTextureDimension(ast::TextureDimension dim) {
Ryan Harrisonde8f1332021-04-20 20:47:51 +000084 switch (dim) {
Ben Claytonfec63b72021-04-21 13:47:12 +000085 case ast::TextureDimension::k1d:
86 case ast::TextureDimension::k2d:
87 case ast::TextureDimension::k2dArray:
88 case ast::TextureDimension::k3d:
Ryan Harrisonde8f1332021-04-20 20:47:51 +000089 return true;
90 default:
91 return false;
92 }
93}
94
Ben Claytonfec63b72021-04-21 13:47:12 +000095bool IsValidStorageTextureImageFormat(ast::ImageFormat format) {
Ryan Harrisonde8f1332021-04-20 20:47:51 +000096 switch (format) {
Ben Claytonfec63b72021-04-21 13:47:12 +000097 case ast::ImageFormat::kR32Uint:
98 case ast::ImageFormat::kR32Sint:
99 case ast::ImageFormat::kR32Float:
100 case ast::ImageFormat::kRg32Uint:
101 case ast::ImageFormat::kRg32Sint:
102 case ast::ImageFormat::kRg32Float:
103 case ast::ImageFormat::kRgba8Unorm:
104 case ast::ImageFormat::kRgba8Snorm:
105 case ast::ImageFormat::kRgba8Uint:
106 case ast::ImageFormat::kRgba8Sint:
107 case ast::ImageFormat::kRgba16Uint:
108 case ast::ImageFormat::kRgba16Sint:
109 case ast::ImageFormat::kRgba16Float:
110 case ast::ImageFormat::kRgba32Uint:
111 case ast::ImageFormat::kRgba32Sint:
112 case ast::ImageFormat::kRgba32Float:
Ryan Harrisonde8f1332021-04-20 20:47:51 +0000113 return true;
114 default:
115 return false;
116 }
117}
118
Ben Clayton451f2cc2021-05-12 12:54:21 +0000119/// @returns true if the decoration list contains a
120/// ast::DisableValidationDecoration with the validation mode equal to
121/// `validation`
122bool IsValidationDisabled(const ast::DecorationList& decorations,
123 ast::DisabledValidation validation) {
124 for (auto* decoration : decorations) {
125 if (auto* dv = decoration->As<ast::DisableValidationDecoration>()) {
126 if (dv->Validation() == validation) {
127 return true;
128 }
129 }
130 }
131 return false;
132}
133
Saraha8f58ef2021-06-30 19:22:30 +0000134/// @returns true if the decoration list does not contains a
135/// ast::DisableValidationDecoration with the validation mode equal to
136/// `validation`
137bool IsValidationEnabled(const ast::DecorationList& decorations,
138 ast::DisabledValidation validation) {
139 return !IsValidationDisabled(decorations, validation);
140}
141
Sarah443c41d2021-06-18 19:58:27 +0000142// Helper to stringify a pipeline IO decoration.
143std::string deco_to_str(const ast::Decoration* deco) {
144 std::stringstream str;
145 if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
146 str << "builtin(" << builtin->value() << ")";
147 } else if (auto* location = deco->As<ast::LocationDecoration>()) {
148 str << "location(" << location->value() << ")";
149 }
150 return str.str();
151}
Ben Clayton052ab892021-02-08 19:53:42 +0000152} // namespace
Dan Sinclair6e581892020-03-02 15:47:43 -0500153
Ben Clayton5f0ea112021-03-09 10:54:37 +0000154Resolver::Resolver(ProgramBuilder* builder)
Ben Claytonb82acac2021-05-06 16:04:03 +0000155 : builder_(builder),
156 diagnostics_(builder->Diagnostics()),
Ben Claytonb29a59d2021-06-01 19:06:31 +0000157 intrinsic_table_(IntrinsicTable::Create(*builder)) {}
Ben Claytond59cedb2021-01-25 18:14:08 +0000158
Ben Clayton5f0ea112021-03-09 10:54:37 +0000159Resolver::~Resolver() = default;
Dan Sinclair6e581892020-03-02 15:47:43 -0500160
Ben Clayton5f0ea112021-03-09 10:54:37 +0000161void Resolver::set_referenced_from_function_if_needed(VariableInfo* var,
162 bool local) {
dan sinclair13d2a3b2020-06-22 20:52:24 +0000163 if (current_function_ == nullptr) {
164 return;
165 }
Ryan Harrison3832b8e2021-06-09 20:45:09 +0000166
167 if (var->kind != VariableKind::kGlobal) {
dan sinclair13d2a3b2020-06-22 20:52:24 +0000168 return;
169 }
170
Ben Claytonf81df122021-02-17 13:10:49 +0000171 current_function_->referenced_module_vars.add(var);
Enrico Galli3d449d22020-12-08 21:07:24 +0000172 if (local) {
Ben Claytonf81df122021-02-17 13:10:49 +0000173 current_function_->local_referenced_module_vars.add(var);
Enrico Galli3d449d22020-12-08 21:07:24 +0000174 }
dan sinclair13d2a3b2020-06-22 20:52:24 +0000175}
176
Ben Clayton5f0ea112021-03-09 10:54:37 +0000177bool Resolver::Resolve() {
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000178 if (builder_->Diagnostics().contains_errors()) {
179 return false;
180 }
181
Ben Clayton5f0ea112021-03-09 10:54:37 +0000182 bool result = ResolveInternal();
Ben Claytonb17aea12021-02-03 17:51:09 +0000183
Ben Claytonb82acac2021-05-06 16:04:03 +0000184 if (!result && !diagnostics_.contains_errors()) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000185 TINT_ICE(Resolver, diagnostics_)
186 << "resolving failed, but no error was raised";
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000187 return false;
188 }
189
Ben Claytonb17aea12021-02-03 17:51:09 +0000190 // Even if resolving failed, create all the semantic nodes for information we
191 // did generate.
192 CreateSemanticNodes();
193
194 return result;
195}
196
James Price3b267172021-06-09 09:12:57 +0000197// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
Antonio Maioranof19e0e42021-06-21 20:51:16 +0000198bool Resolver::IsPlain(const sem::Type* type) const {
Ben Clayton313e6182021-06-17 19:56:14 +0000199 return type->is_scalar() || type->Is<sem::Atomic>() ||
200 type->Is<sem::Vector>() || type->Is<sem::Matrix>() ||
201 type->Is<sem::Array>() || type->Is<sem::Struct>();
James Price3b267172021-06-09 09:12:57 +0000202}
203
204// https://gpuweb.github.io/gpuweb/wgsl.html#storable-types
Antonio Maioranof19e0e42021-06-21 20:51:16 +0000205bool Resolver::IsStorable(const sem::Type* type) const {
Ben Clayton313e6182021-06-17 19:56:14 +0000206 return IsPlain(type) || type->Is<sem::Texture>() || type->Is<sem::Sampler>();
Ben Claytond614dd52021-03-15 10:43:11 +0000207}
208
Ben Clayton722b5a22021-03-18 20:46:24 +0000209// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
Antonio Maioranof19e0e42021-06-21 20:51:16 +0000210bool Resolver::IsHostShareable(const sem::Type* type) const {
Antonio Maiorano3751fd22021-04-19 22:51:23 +0000211 if (type->IsAnyOf<sem::I32, sem::U32, sem::F32>()) {
Ben Clayton722b5a22021-03-18 20:46:24 +0000212 return true;
213 }
Antonio Maiorano3751fd22021-04-19 22:51:23 +0000214 if (auto* vec = type->As<sem::Vector>()) {
Ben Clayton25eef8d2021-03-18 21:03:24 +0000215 return IsHostShareable(vec->type());
Ben Clayton722b5a22021-03-18 20:46:24 +0000216 }
Antonio Maiorano3751fd22021-04-19 22:51:23 +0000217 if (auto* mat = type->As<sem::Matrix>()) {
Ben Clayton25eef8d2021-03-18 21:03:24 +0000218 return IsHostShareable(mat->type());
Ben Clayton722b5a22021-03-18 20:46:24 +0000219 }
Ben Clayton4cd5eea2021-05-07 20:58:34 +0000220 if (auto* arr = type->As<sem::Array>()) {
221 return IsHostShareable(arr->ElemType());
Ben Clayton722b5a22021-03-18 20:46:24 +0000222 }
Ben Claytonba6ab5e2021-05-07 14:49:34 +0000223 if (auto* str = type->As<sem::Struct>()) {
224 for (auto* member : str->Members()) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000225 if (!IsHostShareable(member->Type())) {
Ben Clayton722b5a22021-03-18 20:46:24 +0000226 return false;
227 }
228 }
229 return true;
230 }
Ben Clayton313e6182021-06-17 19:56:14 +0000231 if (auto* atomic = type->As<sem::Atomic>()) {
232 return IsHostShareable(atomic->Type());
233 }
Ben Clayton722b5a22021-03-18 20:46:24 +0000234 return false;
235}
236
Ben Clayton5f0ea112021-03-09 10:54:37 +0000237bool Resolver::ResolveInternal() {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000238 Mark(&builder_->AST());
239
Antonio Maioranobb5617f2021-03-19 18:45:30 +0000240 // Process everything else in the order they appear in the module. This is
241 // necessary for validation of use-before-declaration.
242 for (auto* decl : builder_->AST().GlobalDeclarations()) {
Ben Clayton8758f102021-06-09 14:32:14 +0000243 if (auto* td = decl->As<ast::TypeDecl>()) {
244 Mark(td);
245 if (!TypeDecl(td)) {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000246 return false;
Antonio Maioranobb5617f2021-03-19 18:45:30 +0000247 }
248 } else if (auto* func = decl->As<ast::Function>()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000249 Mark(func);
Antonio Maioranobb5617f2021-03-19 18:45:30 +0000250 if (!Function(func)) {
251 return false;
252 }
253 } else if (auto* var = decl->As<ast::Variable>()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000254 Mark(var);
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000255 if (!GlobalVariable(var)) {
dan sinclair7be237a2020-06-15 20:55:09 +0000256 return false;
257 }
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000258 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +0000259 TINT_UNREACHABLE(Resolver, diagnostics_)
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000260 << "unhandled global declaration: " << decl->TypeInfo().name;
261 return false;
dan sinclair7be237a2020-06-15 20:55:09 +0000262 }
dan sinclair417a90d2020-04-06 21:07:41 +0000263 }
264
Ben Clayton71786c92021-06-03 16:07:34 +0000265 if (!ValidatePipelineStages()) {
266 return false;
267 }
Ben Clayton313e6182021-06-17 19:56:14 +0000268 if (!ValidateAtomicUses()) {
269 return false;
270 }
Ben Clayton71786c92021-06-03 16:07:34 +0000271
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000272 bool result = true;
273
Ben Clayton6fcefe42021-04-19 19:16:12 +0000274 for (auto* node : builder_->ASTNodes().Objects()) {
275 if (marked_.count(node) == 0) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000276 TINT_ICE(Resolver, diagnostics_)
277 << "AST node '" << node->TypeInfo().name
278 << "' was not reached by the resolver\n"
279 << "At: " << node->source() << "\n"
280 << "Content: " << builder_->str(node) << "\n"
281 << "Pointer: " << node;
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000282 result = false;
Ben Clayton6fcefe42021-04-19 19:16:12 +0000283 }
284 }
285
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000286 return result;
Ben Clayton6fcefe42021-04-19 19:16:12 +0000287}
288
Ben Claytonba6ab5e2021-05-07 14:49:34 +0000289sem::Type* Resolver::Type(const ast::Type* ty) {
Ben Claytonfec63b72021-04-21 13:47:12 +0000290 Mark(ty);
Ben Claytonba6ab5e2021-05-07 14:49:34 +0000291 auto* s = [&]() -> sem::Type* {
Ben Claytonfbec46f2021-04-30 20:20:19 +0000292 if (ty->Is<ast::Void>()) {
293 return builder_->create<sem::Void>();
294 }
295 if (ty->Is<ast::Bool>()) {
296 return builder_->create<sem::Bool>();
297 }
298 if (ty->Is<ast::I32>()) {
299 return builder_->create<sem::I32>();
300 }
301 if (ty->Is<ast::U32>()) {
302 return builder_->create<sem::U32>();
303 }
304 if (ty->Is<ast::F32>()) {
305 return builder_->create<sem::F32>();
306 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000307 if (auto* t = ty->As<ast::Vector>()) {
308 if (auto* el = Type(t->type())) {
Ben Claytonffe79782021-07-05 20:21:35 +0000309 if (auto* vector = builder_->create<sem::Vector>(
310 const_cast<sem::Type*>(el), t->size())) {
311 if (ValidateVector(vector, t->source())) {
312 return vector;
313 }
314 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000315 }
316 return nullptr;
317 }
318 if (auto* t = ty->As<ast::Matrix>()) {
319 if (auto* el = Type(t->type())) {
Sarah4d697512021-06-21 17:08:05 +0000320 if (auto* column_type = builder_->create<sem::Vector>(
321 const_cast<sem::Type*>(el), t->rows())) {
Ben Claytonffe79782021-07-05 20:21:35 +0000322 if (auto* matrix =
Sarah4d697512021-06-21 17:08:05 +0000323 builder_->create<sem::Matrix>(column_type, t->columns())) {
Ben Claytonffe79782021-07-05 20:21:35 +0000324 if (ValidateMatrix(matrix, t->source())) {
325 return matrix;
Sarah4d697512021-06-21 17:08:05 +0000326 }
327 }
328 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000329 }
330 return nullptr;
331 }
332 if (auto* t = ty->As<ast::Array>()) {
Ben Clayton4cd5eea2021-05-07 20:58:34 +0000333 return Array(t);
Ben Claytonfbec46f2021-04-30 20:20:19 +0000334 }
Ben Clayton313e6182021-06-17 19:56:14 +0000335 if (auto* t = ty->As<ast::Atomic>()) {
336 if (auto* el = Type(t->type())) {
337 auto* a = builder_->create<sem::Atomic>(const_cast<sem::Type*>(el));
338 if (!ValidateAtomic(t, a)) {
339 return nullptr;
340 }
341 return a;
342 }
343 return nullptr;
344 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000345 if (auto* t = ty->As<ast::Pointer>()) {
346 if (auto* el = Type(t->type())) {
Ben Clayton18588542021-06-04 22:17:37 +0000347 auto access = t->access();
348 if (access == ast::kUndefined) {
349 access = DefaultAccessForStorageClass(t->storage_class());
350 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000351 return builder_->create<sem::Pointer>(const_cast<sem::Type*>(el),
Ben Clayton18588542021-06-04 22:17:37 +0000352 t->storage_class(), access);
Ben Claytonfbec46f2021-04-30 20:20:19 +0000353 }
354 return nullptr;
355 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000356 if (auto* t = ty->As<ast::Sampler>()) {
357 return builder_->create<sem::Sampler>(t->kind());
358 }
359 if (auto* t = ty->As<ast::SampledTexture>()) {
360 if (auto* el = Type(t->type())) {
361 return builder_->create<sem::SampledTexture>(
362 t->dim(), const_cast<sem::Type*>(el));
363 }
364 return nullptr;
365 }
366 if (auto* t = ty->As<ast::MultisampledTexture>()) {
367 if (auto* el = Type(t->type())) {
368 return builder_->create<sem::MultisampledTexture>(
369 t->dim(), const_cast<sem::Type*>(el));
370 }
371 return nullptr;
372 }
373 if (auto* t = ty->As<ast::DepthTexture>()) {
374 return builder_->create<sem::DepthTexture>(t->dim());
375 }
Ben Claytonfd35aa82021-07-26 22:19:48 +0000376 if (auto* t = ty->As<ast::DepthMultisampledTexture>()) {
377 return builder_->create<sem::DepthMultisampledTexture>(t->dim());
378 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000379 if (auto* t = ty->As<ast::StorageTexture>()) {
380 if (auto* el = Type(t->type())) {
Ben Clayton93e8f522021-06-04 20:41:47 +0000381 if (!ValidateStorageTexture(t)) {
Antonio Maiorano6cf7f2e2021-05-21 14:32:38 +0000382 return nullptr;
Antonio Maioranodc4e6c12021-05-14 17:51:13 +0000383 }
Ben Claytonfbec46f2021-04-30 20:20:19 +0000384 return builder_->create<sem::StorageTexture>(
Ben Clayton93e8f522021-06-04 20:41:47 +0000385 t->dim(), t->image_format(), t->access(),
Antonio Maiorano6cf7f2e2021-05-21 14:32:38 +0000386 const_cast<sem::Type*>(el));
Ben Claytonfbec46f2021-04-30 20:20:19 +0000387 }
388 return nullptr;
389 }
Ryan Harrison0aeb77c2021-05-06 08:20:52 +0000390 if (ty->As<ast::ExternalTexture>()) {
Ben Clayton58f93c92021-05-05 18:00:52 +0000391 return builder_->create<sem::ExternalTexture>();
392 }
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000393 if (auto* t = ty->As<ast::TypeName>()) {
Antonio Maioranoc5f5d362021-05-20 08:44:57 +0000394 auto it = named_type_info_.find(t->name());
395 if (it == named_type_info_.end()) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000396 AddError(
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000397 "unknown type '" + builder_->Symbols().NameFor(t->name()) + "'",
398 t->source());
399 return nullptr;
400 }
Antonio Maioranoc5f5d362021-05-20 08:44:57 +0000401 return it->second.sem;
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000402 }
Ben Claytonffd28e22021-06-24 11:27:36 +0000403 TINT_UNREACHABLE(Resolver, diagnostics_)
Ben Claytonfbec46f2021-04-30 20:20:19 +0000404 << "Unhandled ast::Type: " << ty->TypeInfo().name;
405 return nullptr;
406 }();
407
Ben Claytonba6ab5e2021-05-07 14:49:34 +0000408 if (s) {
409 builder_->Sem().Add(ty, s);
Ben Claytonfec63b72021-04-21 13:47:12 +0000410 }
Ben Claytonfec63b72021-04-21 13:47:12 +0000411 return s;
412}
413
Ben Clayton313e6182021-06-17 19:56:14 +0000414bool Resolver::ValidateAtomic(const ast::Atomic* a, const sem::Atomic* s) {
415 // https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
416 // T must be either u32 or i32.
417 if (!s->Type()->IsAnyOf<sem::U32, sem::I32>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000418 AddError("atomic only supports i32 or u32 types", a->type()->source());
Ben Clayton313e6182021-06-17 19:56:14 +0000419 return false;
420 }
421 return true;
422}
423
424bool Resolver::ValidateAtomicUses() {
425 // https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
426 // Atomic types may only be instantiated by variables in the workgroup storage
427 // class or by storage buffer variables with a read_write access mode.
428 for (auto sm : atomic_members_) {
429 auto* structure = sm.structure;
430 for (auto usage : structure->StorageClassUsage()) {
431 if (usage == ast::StorageClass::kWorkgroup) {
432 continue;
433 }
434 if (usage != ast::StorageClass::kStorage) {
435 // TODO(crbug.com/tint/901): Validate that the access mode is
436 // read_write.
437 auto* member = structure->Members()[sm.index];
Ben Claytonffd28e22021-06-24 11:27:36 +0000438 AddError(
Ben Clayton313e6182021-06-17 19:56:14 +0000439 "atomic types can only be used in storage classes workgroup or "
440 "storage, but was used by storage class " +
441 std::string(ast::str(usage)),
442 member->Declaration()->type()->source());
443 // TODO(crbug.com/tint/901): Add note pointing at where the usage came
444 // from.
445 return false;
446 }
447 }
448 }
449 return true;
450}
451
Ben Clayton93e8f522021-06-04 20:41:47 +0000452bool Resolver::ValidateStorageTexture(const ast::StorageTexture* t) {
453 switch (t->access()) {
454 case ast::Access::kUndefined:
Ben Claytonffd28e22021-06-24 11:27:36 +0000455 AddError("storage textures must have access control", t->source());
Ben Clayton93e8f522021-06-04 20:41:47 +0000456 return false;
457 case ast::Access::kReadWrite:
Ben Claytonffd28e22021-06-24 11:27:36 +0000458 AddError("storage textures only support read-only and write-only access",
459 t->source());
Ben Clayton93e8f522021-06-04 20:41:47 +0000460 return false;
461
462 case ast::Access::kRead:
463 case ast::Access::kWrite:
464 break;
465 }
466
467 if (!IsValidStorageTextureDimension(t->dim())) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000468 AddError("cube dimensions for storage textures are not supported",
469 t->source());
Ben Clayton93e8f522021-06-04 20:41:47 +0000470 return false;
471 }
472
473 if (!IsValidStorageTextureImageFormat(t->image_format())) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000474 AddError(
Ben Clayton93e8f522021-06-04 20:41:47 +0000475 "image format must be one of the texel formats specified for storage "
476 "textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
477 t->source());
478 return false;
479 }
480 return true;
481}
482
Ben Clayton5df76612021-05-12 10:41:21 +0000483Resolver::VariableInfo* Resolver::Variable(ast::Variable* var,
Ben Clayton4ffcf062021-07-22 13:24:59 +0000484 VariableKind kind,
485 uint32_t index /* = 0 */) {
Ben Clayton5df76612021-05-12 10:41:21 +0000486 if (variable_to_info_.count(var)) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000487 TINT_ICE(Resolver, diagnostics_)
488 << "Variable " << builder_->Symbols().NameFor(var->symbol())
489 << " already resolved";
Ben Clayton5df76612021-05-12 10:41:21 +0000490 return nullptr;
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000491 }
492
Ben Clayton5df76612021-05-12 10:41:21 +0000493 std::string type_name;
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000494 const sem::Type* storage_type = nullptr;
495
496 // If the variable has a declared type, resolve it.
Ben Clayton5df76612021-05-12 10:41:21 +0000497 if (auto* ty = var->type()) {
498 type_name = ty->FriendlyName(builder_->Symbols());
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000499 storage_type = Type(ty);
500 if (!storage_type) {
Ben Clayton5df76612021-05-12 10:41:21 +0000501 return nullptr;
502 }
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000503 }
Ben Clayton5df76612021-05-12 10:41:21 +0000504
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000505 std::string rhs_type_name;
506 const sem::Type* rhs_type = nullptr;
507
Ben Clayton5df76612021-05-12 10:41:21 +0000508 // Does the variable have a constructor?
509 if (auto* ctor = var->constructor()) {
510 Mark(var->constructor());
511 if (!Expression(var->constructor())) {
512 return nullptr;
513 }
514
515 // Fetch the constructor's type
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000516 rhs_type_name = TypeNameOf(ctor);
517 rhs_type = TypeOf(ctor);
Ben Clayton5df76612021-05-12 10:41:21 +0000518 if (!rhs_type) {
519 return nullptr;
520 }
521
522 // If the variable has no declared type, infer it from the RHS
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000523 if (!storage_type) {
Antonio Maiorano9834fef2021-06-04 15:28:47 +0000524 if (!var->is_const() && kind == VariableKind::kGlobal) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000525 AddError("global var declaration must specify a type", var->source());
Antonio Maiorano9834fef2021-06-04 15:28:47 +0000526 return nullptr;
527 }
528
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000529 type_name = rhs_type_name;
530 storage_type = rhs_type->UnwrapRef(); // Implicit load of RHS
Ben Clayton5df76612021-05-12 10:41:21 +0000531 }
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000532 } else if (var->is_const() && kind != VariableKind::kParameter &&
Ben Clayton5df76612021-05-12 10:41:21 +0000533 !ast::HasDecoration<ast::OverrideDecoration>(var->decorations())) {
Ben Claytonb291cfc2021-07-19 19:50:52 +0000534 AddError("let declaration must have an initializer", var->source());
535 return nullptr;
536 } else if (!var->type()) {
537 AddError(
538 (kind == VariableKind::kGlobal)
539 ? "module scope var declaration requires a type and initializer"
540 : "function scope var declaration requires a type or initializer",
541 var->source());
Ben Clayton02ebf0d2021-05-05 09:09:41 +0000542 return nullptr;
Ben Clayton109b18f2021-04-28 13:50:43 +0000543 }
544
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000545 if (!storage_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000546 TINT_ICE(Resolver, diagnostics_)
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000547 << "failed to determine storage type for variable '" +
548 builder_->Symbols().NameFor(var->symbol()) + "'\n"
549 << "Source: " << var->source();
550 return nullptr;
551 }
552
553 auto storage_class = var->declared_storage_class();
554 if (storage_class == ast::StorageClass::kNone) {
555 if (storage_type->UnwrapRef()->is_handle()) {
556 // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
557 // If the store type is a texture type or a sampler type, then the
558 // variable declaration must not have a storage class decoration. The
559 // storage class will always be handle.
560 storage_class = ast::StorageClass::kUniformConstant;
561 } else if (kind == VariableKind::kLocal && !var->is_const()) {
562 storage_class = ast::StorageClass::kFunction;
563 }
564 }
565
Ben Clayton18588542021-06-04 22:17:37 +0000566 auto access = var->declared_access();
567 if (access == ast::Access::kUndefined) {
568 access = DefaultAccessForStorageClass(storage_class);
569 }
570
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000571 auto* type = storage_type;
572 if (!var->is_const()) {
573 // Variable declaration. Unlike `let`, `var` has storage.
574 // Variables are always of a reference type to the declared storage type.
Ben Clayton18588542021-06-04 22:17:37 +0000575 type =
576 builder_->create<sem::Reference>(storage_type, storage_class, access);
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000577 }
578
579 if (rhs_type && !ValidateVariableConstructor(var, storage_type, type_name,
580 rhs_type, rhs_type_name)) {
581 return nullptr;
582 }
583
Ben Clayton4ffcf062021-07-22 13:24:59 +0000584 auto* info =
585 variable_infos_.Create(var, const_cast<sem::Type*>(type), type_name,
586 storage_class, access, kind, index);
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000587 variable_to_info_.emplace(var, info);
588
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000589 return info;
590}
591
Ben Clayton9545fb72021-07-06 10:20:19 +0000592ast::Access Resolver::DefaultAccessForStorageClass(
Ben Clayton18588542021-06-04 22:17:37 +0000593 ast::StorageClass storage_class) {
594 // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
595 switch (storage_class) {
596 case ast::StorageClass::kStorage:
Ben Clayton18588542021-06-04 22:17:37 +0000597 case ast::StorageClass::kUniform:
598 case ast::StorageClass::kUniformConstant:
599 return ast::Access::kRead;
600 default:
601 break;
602 }
603 return ast::Access::kReadWrite;
604}
605
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000606bool Resolver::ValidateVariableConstructor(const ast::Variable* var,
607 const sem::Type* storage_type,
608 const std::string& type_name,
609 const sem::Type* rhs_type,
610 const std::string& rhs_type_name) {
611 auto* value_type = rhs_type->UnwrapRef(); // Implicit load of RHS
612
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000613 // Value type has to match storage type
Antonio Maioranobe607c02021-05-18 15:26:40 +0000614 if (storage_type != value_type) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000615 std::string decl = var->is_const() ? "let" : "var";
Ben Claytonffd28e22021-06-24 11:27:36 +0000616 AddError("cannot initialize " + decl + " of type '" + type_name +
617 "' with value of type '" + rhs_type_name + "'",
618 var->source());
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000619 return false;
620 }
621 return true;
622}
623
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000624bool Resolver::GlobalVariable(ast::Variable* var) {
Sarahc0353662021-06-29 21:30:37 +0000625 if (!ValidateNoDuplicateDefinition(var->symbol(), var->source(),
626 /* check_global_scope_only */ true)) {
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000627 return false;
628 }
629
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000630 auto* info = Variable(var, VariableKind::kGlobal);
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +0000631 if (!info) {
632 return false;
633 }
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000634 variable_stack_.set_global(var->symbol(), info);
635
636 if (!var->is_const() && info->storage_class == ast::StorageClass::kNone) {
Ben Clayton5a88ec82021-06-29 14:42:19 +0000637 AddError("global variables must have a storage class", var->source());
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000638 return false;
639 }
640 if (var->is_const() && !(info->storage_class == ast::StorageClass::kNone)) {
Ben Clayton5a88ec82021-06-29 14:42:19 +0000641 AddError("global constants shouldn't have a storage class", var->source());
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000642 return false;
643 }
644
645 for (auto* deco : var->decorations()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +0000646 Mark(deco);
James Pricef2f3bfc2021-05-13 20:32:32 +0000647
648 if (auto* override_deco = deco->As<ast::OverrideDecoration>()) {
649 // Track the constant IDs that are specified in the shader.
650 if (override_deco->HasValue()) {
651 constant_ids_.emplace(override_deco->value(), info);
652 }
653 }
Ben Clayton3f968e72021-05-10 19:16:46 +0000654 }
655
Ben Clayton241c16d2021-06-09 18:53:57 +0000656 if (!ValidateNoDuplicateDecorations(var->decorations())) {
657 return false;
658 }
659
Ben Clayton3f968e72021-05-10 19:16:46 +0000660 if (auto bp = var->binding_point()) {
661 info->binding_point = {bp.group->value(), bp.binding->value()};
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000662 }
663
Ben Clayton85bfea62021-04-19 20:20:33 +0000664 if (!ValidateGlobalVariable(info)) {
665 return false;
666 }
667
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000668 if (!ApplyStorageClassUsageToType(
669 info->storage_class, const_cast<sem::Type*>(info->type->UnwrapRef()),
670 var->source())) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000671 AddNote("while instantiating variable " +
672 builder_->Symbols().NameFor(var->symbol()),
673 var->source());
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000674 return false;
675 }
676
Antonio Maiorano60dae242021-07-15 19:09:25 +0000677 // TODO(bclayton): Call this at the end of resolve on all uniform and storage
678 // referenced structs
679 if (!ValidateStorageClassLayout(info)) {
680 return false;
681 }
682
683 return true;
684}
685
686bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
687 ast::StorageClass sc) {
688 // https://gpuweb.github.io/gpuweb/wgsl/#storage-class-layout-constraints
689
690 auto is_uniform_struct_or_array = [sc](const sem::Type* ty) {
691 return sc == ast::StorageClass::kUniform &&
692 ty->IsAnyOf<sem::Array, sem::Struct>();
693 };
694
695 auto is_uniform_struct = [sc](const sem::Type* ty) {
696 return sc == ast::StorageClass::kUniform && ty->Is<sem::Struct>();
697 };
698
699 auto required_alignment_of = [&](const sem::Type* ty) {
Ben Claytonfced3502021-07-22 18:56:54 +0000700 uint32_t actual_align = ty->Align();
Antonio Maiorano60dae242021-07-15 19:09:25 +0000701 uint32_t required_align = actual_align;
702 if (is_uniform_struct_or_array(ty)) {
703 required_align = utils::RoundUp(16u, actual_align);
704 }
705 return required_align;
706 };
707
708 auto member_name_of = [this](const sem::StructMember* sm) {
709 return builder_->Symbols().NameFor(sm->Declaration()->symbol());
710 };
711
712 auto type_name_of = [this](const sem::StructMember* sm) {
713 return sm->Declaration()->type()->FriendlyName(builder_->Symbols());
714 };
715
716 // TODO(amaiorano): Output struct and member decorations so that this output
717 // can be copied verbatim back into source
718 auto get_struct_layout_string = [&](const sem::Struct* st) -> std::string {
719 std::stringstream ss;
720
721 if (st->Members().empty()) {
722 TINT_ICE(Resolver, diagnostics_) << "Validation should have ensured that "
723 "structs have at least one member";
724 return {};
725 }
726 const auto* const last_member = st->Members().back();
727 const uint32_t last_member_struct_padding_offset =
728 last_member->Offset() + last_member->Size();
729
730 // Compute max widths to align output
731 const auto offset_w =
732 static_cast<int>(::log10(last_member_struct_padding_offset)) + 1;
733 const auto size_w = static_cast<int>(::log10(st->Size())) + 1;
734 const auto align_w = static_cast<int>(::log10(st->Align())) + 1;
735
736 auto print_struct_begin_line = [&](size_t align, size_t size,
737 std::string struct_name) {
738 ss << "/* " << std::setw(offset_w) << " "
739 << "align(" << std::setw(align_w) << align << ") size("
740 << std::setw(size_w) << size << ") */ struct " << struct_name
741 << " {\n";
742 };
743
744 auto print_struct_end_line = [&]() {
745 ss << "/* "
746 << std::setw(offset_w + size_w + align_w) << " "
747 << "*/ };";
748 };
749
750 auto print_member_line = [&](size_t offset, size_t align, size_t size,
751 std::string s) {
752 ss << "/* offset(" << std::setw(offset_w) << offset << ") align("
753 << std::setw(align_w) << align << ") size(" << std::setw(size_w)
754 << size << ") */ " << s << ";\n";
755 };
756
757 print_struct_begin_line(st->Align(), st->Size(),
758 st->FriendlyName(builder_->Symbols()));
759
760 for (size_t i = 0; i < st->Members().size(); ++i) {
761 auto* const m = st->Members()[i];
762
763 // Output field alignment padding, if any
764 auto* const prev_member = (i == 0) ? nullptr : str->Members()[i - 1];
765 if (prev_member) {
766 uint32_t padding =
767 m->Offset() - (prev_member->Offset() + prev_member->Size());
768 if (padding > 0) {
769 size_t padding_offset = m->Offset() - padding;
770 print_member_line(padding_offset, 1, padding,
771 "// -- implicit field alignment padding --");
772 }
773 }
774
775 // Output member
776 std::string member_name = member_name_of(m);
777 print_member_line(m->Offset(), m->Align(), m->Size(),
778 member_name_of(m) + " : " + type_name_of(m));
779 }
780
781 // Output struct size padding, if any
782 uint32_t struct_padding = st->Size() - last_member_struct_padding_offset;
783 if (struct_padding > 0) {
784 print_member_line(last_member_struct_padding_offset, 1, struct_padding,
785 "// -- implicit struct size padding --");
786 }
787
788 print_struct_end_line();
789
790 return ss.str();
791 };
792
793 if (!ast::IsHostShareable(sc)) {
794 return true;
795 }
796
797 for (size_t i = 0; i < str->Members().size(); ++i) {
798 auto* const m = str->Members()[i];
799 uint32_t required_align = required_alignment_of(m->Type());
800
801 // Validate that member is at a valid byte offset
802 if (m->Offset() % required_align != 0) {
803 AddError("the offset of a struct member of type '" + type_name_of(m) +
804 "' in storage class '" + ast::str(sc) +
805 "' must be a multiple of " + std::to_string(required_align) +
806 " bytes, but '" + member_name_of(m) +
807 "' is currently at offset " + std::to_string(m->Offset()) +
808 ". Consider setting [[align(" +
809 std::to_string(required_align) + ")]] on this member",
810 m->Declaration()->source());
811
812 AddNote("see layout of struct:\n" + get_struct_layout_string(str),
813 str->Declaration()->source());
814
815 if (auto* member_str = m->Type()->As<sem::Struct>()) {
816 AddNote("and layout of struct member:\n" +
817 get_struct_layout_string(member_str),
818 member_str->Declaration()->source());
819 }
820
821 return false;
822 }
823
824 // For uniform buffers, validate that the number of bytes between the
825 // previous member of type struct and the current is a multiple of 16 bytes.
826 auto* const prev_member = (i == 0) ? nullptr : str->Members()[i - 1];
827 if (prev_member && is_uniform_struct(prev_member->Type())) {
828 const uint32_t prev_to_curr_offset = m->Offset() - prev_member->Offset();
829 if (prev_to_curr_offset % 16 != 0) {
830 AddError(
831 "uniform storage requires that the number of bytes between the "
832 "start of the previous member of type struct and the current "
833 "member be a multiple of 16 bytes, but there are currently " +
834 std::to_string(prev_to_curr_offset) + " bytes between '" +
835 member_name_of(prev_member) + "' and '" + member_name_of(m) +
836 "'. Consider setting [[align(16)]] on this member",
837 m->Declaration()->source());
838
839 AddNote("see layout of struct:\n" + get_struct_layout_string(str),
840 str->Declaration()->source());
841
842 auto* prev_member_str = prev_member->Type()->As<sem::Struct>();
843 AddNote("and layout of previous member struct:\n" +
844 get_struct_layout_string(prev_member_str),
845 prev_member_str->Declaration()->source());
846 return false;
847 }
848 }
849
850 // For uniform buffer array members, validate that array elements are
851 // aligned to 16 bytes
852 if (auto* arr = m->Type()->As<sem::Array>()) {
853 if (sc == ast::StorageClass::kUniform) {
854 // We already validated that this array member is itself aligned to 16
855 // bytes above, so we only need to validate that stride is a multiple of
856 // 16 bytes.
857 if (arr->Stride() % 16 != 0) {
858 AddError(
859 "uniform storage requires that array elements be aligned to 16 "
860 "bytes, but array stride of '" +
861 member_name_of(m) + "' is currently " +
862 std::to_string(arr->Stride()) +
863 ". Consider setting [[stride(" +
864 std::to_string(
865 utils::RoundUp(required_align, arr->Stride())) +
866 ")]] on the array type",
867 m->Declaration()->type()->source());
868 AddNote("see layout of struct:\n" + get_struct_layout_string(str),
869 str->Declaration()->source());
870 return false;
871 }
872 }
873 }
874
875 // If member is struct, recurse
876 if (auto* str_member = m->Type()->As<sem::Struct>()) {
877 // Cache result of struct + storage class pair
878 if (valid_struct_storage_layouts_.emplace(str_member, sc).second) {
879 if (!ValidateStorageClassLayout(str_member, sc)) {
880 return false;
881 }
882 }
883 }
884 }
885
886 return true;
887}
888
889bool Resolver::ValidateStorageClassLayout(const VariableInfo* info) {
890 if (auto* str = info->type->UnwrapRef()->As<sem::Struct>()) {
891 if (!ValidateStorageClassLayout(str, info->storage_class)) {
892 AddNote("see declaration of variable", info->declaration->source());
893 return false;
894 }
895 }
896
Antonio Maioranobbbb0ed2021-04-06 20:18:57 +0000897 return true;
898}
899
Ben Clayton85bfea62021-04-19 20:20:33 +0000900bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
Ben Clayton241c16d2021-06-09 18:53:57 +0000901 if (!ValidateNoDuplicateDecorations(info->declaration->decorations())) {
902 return false;
903 }
904
Ben Clayton3f968e72021-05-10 19:16:46 +0000905 for (auto* deco : info->declaration->decorations()) {
906 if (info->declaration->is_const()) {
James Pricef2f3bfc2021-05-13 20:32:32 +0000907 if (auto* override_deco = deco->As<ast::OverrideDecoration>()) {
908 if (override_deco->HasValue()) {
909 uint32_t id = override_deco->value();
910 auto itr = constant_ids_.find(id);
911 if (itr != constant_ids_.end() && itr->second != info) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000912 AddError("pipeline constant IDs must be unique", deco->source());
913 AddNote("a pipeline constant with an ID of " + std::to_string(id) +
914 " was previously declared "
915 "here:",
916 ast::GetDecoration<ast::OverrideDecoration>(
917 itr->second->declaration->decorations())
918 ->source());
James Pricef2f3bfc2021-05-13 20:32:32 +0000919 return false;
920 }
921 if (id > 65535) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000922 AddError("pipeline constant IDs must be between 0 and 65535",
923 deco->source());
James Pricef2f3bfc2021-05-13 20:32:32 +0000924 return false;
925 }
926 }
927 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +0000928 AddError("decoration is not valid for constants", deco->source());
Ben Clayton3f968e72021-05-10 19:16:46 +0000929 return false;
930 }
931 } else {
James Price14c0b8a2021-06-24 15:53:26 +0000932 bool is_shader_io_decoration =
James Price989a8e42021-06-28 23:04:43 +0000933 deco->IsAnyOf<ast::BuiltinDecoration, ast::InterpolateDecoration,
James Price508d2492021-07-12 12:12:32 +0000934 ast::InvariantDecoration, ast::LocationDecoration>();
James Price14c0b8a2021-06-24 15:53:26 +0000935 bool has_io_storage_class =
936 info->storage_class == ast::StorageClass::kInput ||
937 info->storage_class == ast::StorageClass::kOutput;
938 if (!(deco->IsAnyOf<ast::BindingDecoration, ast::GroupDecoration,
939 ast::InternalDecoration>()) &&
940 (!is_shader_io_decoration || !has_io_storage_class)) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000941 AddError("decoration is not valid for variables", deco->source());
Ben Clayton3f968e72021-05-10 19:16:46 +0000942 return false;
943 }
944 }
945 }
946
947 auto binding_point = info->declaration->binding_point();
948 switch (info->storage_class) {
949 case ast::StorageClass::kUniform:
950 case ast::StorageClass::kStorage:
951 case ast::StorageClass::kUniformConstant: {
952 // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
953 // Each resource variable must be declared with both group and binding
954 // attributes.
955 if (!binding_point) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000956 AddError(
Ben Clayton9b54a2e2021-05-18 10:28:48 +0000957 "resource variables require [[group]] and [[binding]] "
958 "decorations",
Ben Clayton3f968e72021-05-10 19:16:46 +0000959 info->declaration->source());
960 return false;
961 }
962 break;
963 }
964 default:
965 if (binding_point.binding || binding_point.group) {
966 // https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
967 // Must only be applied to a resource variable
Ben Claytonffd28e22021-06-24 11:27:36 +0000968 AddError(
Ben Clayton3f968e72021-05-10 19:16:46 +0000969 "non-resource variables must not have [[group]] or [[binding]] "
970 "decorations",
971 info->declaration->source());
972 return false;
973 }
974 }
975
Ben Clayton93e8f522021-06-04 20:41:47 +0000976 // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
977 // The access mode always has a default, and except for variables in the
978 // storage storage class, must not be written.
979 if (info->storage_class != ast::StorageClass::kStorage &&
980 info->declaration->declared_access() != ast::Access::kUndefined) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000981 AddError(
Sarah085dcbb2021-07-28 09:59:35 +0000982 "variables not in <storage> storage class must not declare an access "
983 "mode",
Ben Clayton93e8f522021-06-04 20:41:47 +0000984 info->declaration->source());
985 return false;
986 }
987
Ben Clayton42708342021-04-21 17:55:12 +0000988 switch (info->storage_class) {
989 case ast::StorageClass::kStorage: {
Ben Clayton42708342021-04-21 17:55:12 +0000990 // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
991 // A variable in the storage storage class is a storage buffer variable.
992 // Its store type must be a host-shareable structure type with block
993 // attribute, satisfying the storage class constraints.
Ben Clayton85bfea62021-04-19 20:20:33 +0000994
Ben Clayton93e8f522021-06-04 20:41:47 +0000995 auto* str = info->type->UnwrapRef()->As<sem::Struct>();
Antonio Maioranodc4e6c12021-05-14 17:51:13 +0000996
Ben Clayton42708342021-04-21 17:55:12 +0000997 if (!str) {
Ben Claytonffd28e22021-06-24 11:27:36 +0000998 AddError(
Ben Clayton93e8f522021-06-04 20:41:47 +0000999 "variables declared in the <storage> storage class must be of a "
1000 "structure type",
Ben Clayton42708342021-04-21 17:55:12 +00001001 info->declaration->source());
1002 return false;
Ben Clayton85bfea62021-04-19 20:20:33 +00001003 }
Ben Clayton42708342021-04-21 17:55:12 +00001004
1005 if (!str->IsBlockDecorated()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001006 AddError(
Ben Clayton42708342021-04-21 17:55:12 +00001007 "structure used as a storage buffer must be declared with the "
1008 "[[block]] decoration",
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001009 str->Declaration()->source());
Ben Clayton42708342021-04-21 17:55:12 +00001010 if (info->declaration->source().range.begin.line) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001011 AddNote("structure used as storage buffer here",
1012 info->declaration->source());
Ben Clayton42708342021-04-21 17:55:12 +00001013 }
1014 return false;
1015 }
1016 break;
Ben Clayton85bfea62021-04-19 20:20:33 +00001017 }
Ben Clayton42708342021-04-21 17:55:12 +00001018 case ast::StorageClass::kUniform: {
1019 // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
1020 // A variable in the uniform storage class is a uniform buffer variable.
1021 // Its store type must be a host-shareable structure type with block
1022 // attribute, satisfying the storage class constraints.
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001023 auto* str = info->type->UnwrapRef()->As<sem::Struct>();
Ben Clayton42708342021-04-21 17:55:12 +00001024 if (!str) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001025 AddError(
Ben Clayton42708342021-04-21 17:55:12 +00001026 "variables declared in the <uniform> storage class must be of a "
1027 "structure type",
1028 info->declaration->source());
1029 return false;
1030 }
1031
1032 if (!str->IsBlockDecorated()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001033 AddError(
Ben Clayton42708342021-04-21 17:55:12 +00001034 "structure used as a uniform buffer must be declared with the "
1035 "[[block]] decoration",
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001036 str->Declaration()->source());
Ben Clayton42708342021-04-21 17:55:12 +00001037 if (info->declaration->source().range.begin.line) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001038 AddNote("structure used as uniform buffer here",
1039 info->declaration->source());
Ben Clayton42708342021-04-21 17:55:12 +00001040 }
1041 return false;
1042 }
Sarah52b6a002021-06-16 19:40:13 +00001043
1044 for (auto* member : str->Members()) {
1045 if (auto* arr = member->Type()->As<sem::Array>()) {
1046 if (arr->IsRuntimeSized()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001047 AddError(
Sarah52b6a002021-06-16 19:40:13 +00001048 "structure containing a runtime sized array "
1049 "cannot be used as a uniform buffer",
1050 info->declaration->source());
Ben Claytonffd28e22021-06-24 11:27:36 +00001051 AddNote("structure is declared here", str->Declaration()->source());
Sarah52b6a002021-06-16 19:40:13 +00001052 return false;
1053 }
1054 }
1055 }
1056
Ben Clayton42708342021-04-21 17:55:12 +00001057 break;
1058 }
1059 default:
1060 break;
Ben Clayton85bfea62021-04-19 20:20:33 +00001061 }
1062
Ben Claytonfcda15e2021-05-10 18:01:51 +00001063 return ValidateVariable(info);
Ben Clayton85bfea62021-04-19 20:20:33 +00001064}
1065
Ben Claytonfcda15e2021-05-10 18:01:51 +00001066bool Resolver::ValidateVariable(const VariableInfo* info) {
1067 auto* var = info->declaration;
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001068 auto* storage_type = info->type->UnwrapRef();
James Price3b267172021-06-09 09:12:57 +00001069
1070 if (!var->is_const() && !IsStorable(storage_type)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001071 AddError(storage_type->FriendlyName(builder_->Symbols()) +
1072 " cannot be used as the type of a var",
1073 var->source());
James Price3b267172021-06-09 09:12:57 +00001074 return false;
1075 }
1076
James Priced12379a2021-07-26 22:11:58 +00001077 if (var->is_const() && info->kind != VariableKind::kParameter &&
1078 !(storage_type->IsConstructible() || storage_type->Is<sem::Pointer>())) {
1079 AddError(storage_type->FriendlyName(builder_->Symbols()) +
1080 " cannot be used as the type of a let",
1081 var->source());
1082 return false;
1083 }
1084
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001085 if (auto* r = storage_type->As<sem::Array>()) {
Ben Clayton4cd5eea2021-05-07 20:58:34 +00001086 if (r->IsRuntimeSized()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00001087 AddError("runtime arrays may only appear as the last member of a struct",
Ben Claytonffd28e22021-06-24 11:27:36 +00001088 var->source());
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001089 return false;
1090 }
1091 }
Ryan Harrison83116d22021-04-20 16:09:21 +00001092
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001093 if (auto* r = storage_type->As<sem::MultisampledTexture>()) {
Ben Claytonfec63b72021-04-21 13:47:12 +00001094 if (r->dim() != ast::TextureDimension::k2d) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001095 AddError("only 2d multisampled textures are supported", var->source());
Ryan Harrison83116d22021-04-20 16:09:21 +00001096 return false;
1097 }
1098
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001099 if (!r->type()->UnwrapRef()->is_numeric_scalar()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001100 AddError("texture_multisampled_2d<type>: type must be f32, i32 or u32",
1101 var->source());
Ryan Harrison83116d22021-04-20 16:09:21 +00001102 return false;
1103 }
1104 }
1105
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001106 if (storage_type->is_handle() &&
Ben Claytonfcda15e2021-05-10 18:01:51 +00001107 var->declared_storage_class() != ast::StorageClass::kNone) {
1108 // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001109 // If the store type is a texture type or a sampler type, then the
1110 // variable declaration must not have a storage class decoration. The
1111 // storage class will always be handle.
Ben Claytonffd28e22021-06-24 11:27:36 +00001112 AddError("variables of type '" + info->type_name +
1113 "' must not have a storage class",
1114 var->source());
Ben Claytonfcda15e2021-05-10 18:01:51 +00001115 return false;
1116 }
1117
Saraha8f58ef2021-06-30 19:22:30 +00001118 if (IsValidationEnabled(var->decorations(),
1119 ast::DisabledValidation::kIgnoreStorageClass) &&
James Price14c0b8a2021-06-24 15:53:26 +00001120 (var->declared_storage_class() == ast::StorageClass::kInput ||
1121 var->declared_storage_class() == ast::StorageClass::kOutput)) {
1122 AddError("invalid use of input/output storage class", var->source());
1123 return false;
1124 }
1125
Ben Clayton313e6182021-06-17 19:56:14 +00001126 // https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
1127 // Atomic types may only be instantiated by variables in the workgroup storage
1128 // class or by storage buffer variables with a read_write access mode.
Ben Claytonf2ec7f32021-06-29 11:53:15 +00001129 if (info->type->UnwrapRef()->Is<sem::Atomic>() &&
1130 info->storage_class != ast::StorageClass::kWorkgroup) {
1131 // Storage buffers require a structure, so just check for workgroup
1132 // storage here.
1133 AddError("atomic var requires workgroup storage",
1134 info->declaration->type()->source());
1135 return false;
Ben Clayton313e6182021-06-17 19:56:14 +00001136 }
1137
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001138 return true;
1139}
1140
Sarah9432c972021-06-29 15:24:04 +00001141bool Resolver::ValidateFunctionParameter(const ast::Function* func,
1142 const VariableInfo* info) {
Sarah443c41d2021-06-18 19:58:27 +00001143 if (!ValidateVariable(info)) {
1144 return false;
1145 }
Sarahac5dbd22021-06-28 14:05:25 +00001146
Sarah443c41d2021-06-18 19:58:27 +00001147 for (auto* deco : info->declaration->decorations()) {
Saraha8f58ef2021-06-30 19:22:30 +00001148 if (!func->IsEntryPoint() && !deco->Is<ast::InternalDecoration>()) {
Sarah99a78ad2021-07-08 14:02:56 +00001149 AddError(
1150 "decoration is not valid for non-entry point function parameters",
1151 deco->source());
James Pricec3f19082021-06-24 16:20:16 +00001152 return false;
Saraha4696682021-07-21 12:16:35 +00001153 } else if (!deco->IsAnyOf<ast::BuiltinDecoration, ast::InvariantDecoration,
Sarah465c5aa2021-07-23 13:23:20 +00001154 ast::LocationDecoration,
1155 ast::InterpolateDecoration,
James Pricec3f19082021-06-24 16:20:16 +00001156 ast::InternalDecoration>() &&
Saraha8f58ef2021-06-30 19:22:30 +00001157 (IsValidationEnabled(
1158 info->declaration->decorations(),
1159 ast::DisabledValidation::kEntryPointParameter) &&
1160 IsValidationEnabled(
1161 info->declaration->decorations(),
Ryan Harrison2f258d12021-07-07 20:41:00 +00001162 ast::DisabledValidation::
1163 kIgnoreConstructibleFunctionParameter))) {
James Pricec3f19082021-06-24 16:20:16 +00001164 AddError("decoration is not valid for function parameters",
1165 deco->source());
1166 return false;
Sarahc58738a2021-06-09 16:01:29 +00001167 }
1168 }
Sarah9432c972021-06-29 15:24:04 +00001169
1170 if (auto* ref = info->type->As<sem::Pointer>()) {
1171 auto sc = ref->StorageClass();
1172 if (!(sc == ast::StorageClass::kFunction ||
1173 sc == ast::StorageClass::kPrivate ||
1174 sc == ast::StorageClass::kWorkgroup)) {
1175 std::stringstream ss;
1176 ss << "function parameter of pointer type cannot be in '" << sc
1177 << "' storage class";
1178 AddError(ss.str(), info->declaration->source());
1179 return false;
1180 }
1181 }
1182
1183 if (IsPlain(info->type)) {
Antonio Maiorano68a6dd02021-07-20 18:28:31 +00001184 if (!info->type->IsConstructible() &&
Saraha8f58ef2021-06-30 19:22:30 +00001185 IsValidationEnabled(
Sarah9432c972021-06-29 15:24:04 +00001186 info->declaration->decorations(),
Ryan Harrison2f258d12021-07-07 20:41:00 +00001187 ast::DisabledValidation::kIgnoreConstructibleFunctionParameter)) {
1188 AddError("store type of function parameter must be a constructible type",
Sarah9432c972021-06-29 15:24:04 +00001189 info->declaration->source());
1190 return false;
1191 }
1192 } else if (!info->type->IsAnyOf<sem::Texture, sem::Sampler, sem::Pointer>()) {
1193 AddError("store type of function parameter cannot be " +
1194 info->type->FriendlyName(builder_->Symbols()),
1195 info->declaration->source());
1196 return false;
1197 }
1198
Sarah443c41d2021-06-18 19:58:27 +00001199 return true;
1200}
Sarahc58738a2021-06-09 16:01:29 +00001201
Sarah443c41d2021-06-18 19:58:27 +00001202bool Resolver::ValidateBuiltinDecoration(const ast::BuiltinDecoration* deco,
Sarah99a78ad2021-07-08 14:02:56 +00001203 const sem::Type* storage_type,
Sarah465c5aa2021-07-23 13:23:20 +00001204 const bool is_input,
1205 const bool is_struct_member) {
Sarah443c41d2021-06-18 19:58:27 +00001206 auto* type = storage_type->UnwrapRef();
Sarah99a78ad2021-07-08 14:02:56 +00001207 const auto stage = current_function_
1208 ? current_function_->declaration->pipeline_stage()
1209 : ast::PipelineStage::kNone;
1210 std::stringstream stage_name;
1211 stage_name << stage;
1212 bool is_stage_mismatch = false;
Sarah465c5aa2021-07-23 13:23:20 +00001213 bool is_output = !is_input;
Sarah443c41d2021-06-18 19:58:27 +00001214 switch (deco->value()) {
Sarah57a737b2021-06-23 17:35:42 +00001215 case ast::Builtin::kPosition:
Sarah99a78ad2021-07-08 14:02:56 +00001216 if (stage != ast::PipelineStage::kNone &&
Sarah465c5aa2021-07-23 13:23:20 +00001217 !((is_input && stage == ast::PipelineStage::kFragment) ||
1218 (is_output && stage == ast::PipelineStage::kVertex))) {
1219 is_stage_mismatch = true;
Sarah99a78ad2021-07-08 14:02:56 +00001220 }
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00001221 if (!(type->is_float_vector() && type->As<sem::Vector>()->Width() == 4)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001222 AddError("store type of " + deco_to_str(deco) + " must be 'vec4<f32>'",
1223 deco->source());
Sarah57a737b2021-06-23 17:35:42 +00001224 return false;
1225 }
1226 break;
1227 case ast::Builtin::kGlobalInvocationId:
1228 case ast::Builtin::kLocalInvocationId:
1229 case ast::Builtin::kWorkgroupId:
Sarah99a78ad2021-07-08 14:02:56 +00001230 if (stage != ast::PipelineStage::kNone &&
1231 !(stage == ast::PipelineStage::kCompute && is_input)) {
1232 is_stage_mismatch = true;
1233 }
Sarah57a737b2021-06-23 17:35:42 +00001234 if (!(type->is_unsigned_integer_vector() &&
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00001235 type->As<sem::Vector>()->Width() == 3)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001236 AddError("store type of " + deco_to_str(deco) + " must be 'vec3<u32>'",
1237 deco->source());
Sarah57a737b2021-06-23 17:35:42 +00001238 return false;
1239 }
1240 break;
1241 case ast::Builtin::kFragDepth:
Sarah99a78ad2021-07-08 14:02:56 +00001242 if (stage != ast::PipelineStage::kNone &&
1243 !(stage == ast::PipelineStage::kFragment && !is_input)) {
1244 is_stage_mismatch = true;
1245 }
Sarah57a737b2021-06-23 17:35:42 +00001246 if (!type->Is<sem::F32>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001247 AddError("store type of " + deco_to_str(deco) + " must be 'f32'",
1248 deco->source());
Sarah57a737b2021-06-23 17:35:42 +00001249 return false;
1250 }
1251 break;
Sarah443c41d2021-06-18 19:58:27 +00001252 case ast::Builtin::kFrontFacing:
Sarah99a78ad2021-07-08 14:02:56 +00001253 if (stage != ast::PipelineStage::kNone &&
1254 !(stage == ast::PipelineStage::kFragment && is_input)) {
1255 is_stage_mismatch = true;
1256 }
Sarah443c41d2021-06-18 19:58:27 +00001257 if (!type->Is<sem::Bool>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001258 AddError("store type of " + deco_to_str(deco) + " must be 'bool'",
1259 deco->source());
Sarah443c41d2021-06-18 19:58:27 +00001260 return false;
1261 }
1262 break;
Sarah57a737b2021-06-23 17:35:42 +00001263 case ast::Builtin::kLocalInvocationIndex:
Sarah99a78ad2021-07-08 14:02:56 +00001264 if (stage != ast::PipelineStage::kNone &&
1265 !(stage == ast::PipelineStage::kCompute && is_input)) {
1266 is_stage_mismatch = true;
1267 }
1268 if (!type->Is<sem::U32>()) {
1269 AddError("store type of " + deco_to_str(deco) + " must be 'u32'",
1270 deco->source());
1271 return false;
1272 }
1273 break;
Sarah57a737b2021-06-23 17:35:42 +00001274 case ast::Builtin::kVertexIndex:
1275 case ast::Builtin::kInstanceIndex:
Sarah99a78ad2021-07-08 14:02:56 +00001276 if (stage != ast::PipelineStage::kNone &&
1277 !(stage == ast::PipelineStage::kVertex && is_input)) {
1278 is_stage_mismatch = true;
1279 }
1280 if (!type->Is<sem::U32>()) {
1281 AddError("store type of " + deco_to_str(deco) + " must be 'u32'",
1282 deco->source());
1283 return false;
1284 }
1285 break;
Sarah443c41d2021-06-18 19:58:27 +00001286 case ast::Builtin::kSampleMask:
Sarah99a78ad2021-07-08 14:02:56 +00001287 if (stage != ast::PipelineStage::kNone &&
1288 !(stage == ast::PipelineStage::kFragment)) {
1289 is_stage_mismatch = true;
1290 }
1291 if (!type->Is<sem::U32>()) {
1292 AddError("store type of " + deco_to_str(deco) + " must be 'u32'",
1293 deco->source());
1294 return false;
1295 }
1296 break;
Sarah443c41d2021-06-18 19:58:27 +00001297 case ast::Builtin::kSampleIndex:
Sarah99a78ad2021-07-08 14:02:56 +00001298 if (stage != ast::PipelineStage::kNone &&
1299 !(stage == ast::PipelineStage::kFragment && is_input)) {
1300 is_stage_mismatch = true;
1301 }
Sarah443c41d2021-06-18 19:58:27 +00001302 if (!type->Is<sem::U32>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001303 AddError("store type of " + deco_to_str(deco) + " must be 'u32'",
1304 deco->source());
Sarah443c41d2021-06-18 19:58:27 +00001305 return false;
1306 }
1307 break;
James Pricec41d9402021-07-19 21:32:27 +00001308 case ast::Builtin::kNumWorkgroups:
1309 // TODO(crbug.com/tint/752): Backend support (needs extra work for HLSL).
1310 AddError("num_workgroups builtin is not yet implemented", deco->source());
1311 return false;
Sarah443c41d2021-06-18 19:58:27 +00001312 default:
1313 break;
1314 }
Sarah99a78ad2021-07-08 14:02:56 +00001315
Sarah465c5aa2021-07-23 13:23:20 +00001316 // ignore builtin attribute on struct members to facillate data movement
1317 // between stages
1318 if (!is_struct_member) {
1319 if (is_stage_mismatch) {
1320 AddError(deco_to_str(deco) + " cannot be used in " +
1321 (is_input ? "input of " : "output of ") + stage_name.str() +
1322 " pipeline stage",
1323 deco->source());
1324 return false;
1325 }
Sarah99a78ad2021-07-08 14:02:56 +00001326 }
1327
Sarah443c41d2021-06-18 19:58:27 +00001328 return true;
Antonio Maiorano09356cc2021-04-06 14:07:07 +00001329}
1330
James Price989a8e42021-06-28 23:04:43 +00001331bool Resolver::ValidateInterpolateDecoration(
1332 const ast::InterpolateDecoration* deco,
1333 const sem::Type* storage_type) {
1334 auto* type = storage_type->UnwrapRef();
1335
1336 if (!type->is_float_scalar_or_vector()) {
1337 AddError(
1338 "store type of interpolate attribute must be floating point scalar or "
1339 "vector",
1340 deco->source());
1341 return false;
1342 }
1343
1344 if (deco->type() == ast::InterpolationType::kFlat &&
1345 deco->sampling() != ast::InterpolationSampling::kNone) {
1346 AddError("flat interpolation attribute must not have a sampling parameter",
1347 deco->source());
1348 return false;
1349 }
1350
1351 return true;
1352}
1353
James Price2dd39372021-04-21 16:13:42 +00001354bool Resolver::ValidateFunction(const ast::Function* func,
1355 const FunctionInfo* info) {
Sarahc0353662021-06-29 21:30:37 +00001356 if (!ValidateNoDuplicateDefinition(func->symbol(), func->source(),
1357 /* check_global_scope_only */ true)) {
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001358 return false;
1359 }
1360
James Price43f50ea2021-05-14 20:41:03 +00001361 auto workgroup_deco_count = 0;
1362 for (auto* deco : func->decorations()) {
Sarah99a78ad2021-07-08 14:02:56 +00001363 if (deco->Is<ast::WorkgroupDecoration>()) {
James Price43f50ea2021-05-14 20:41:03 +00001364 workgroup_deco_count++;
1365 if (func->pipeline_stage() != ast::PipelineStage::kCompute) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001366 AddError(
James Price43f50ea2021-05-14 20:41:03 +00001367 "the workgroup_size attribute is only valid for compute stages",
1368 deco->source());
1369 return false;
1370 }
Sarah99a78ad2021-07-08 14:02:56 +00001371 } else if (!deco->IsAnyOf<ast::StageDecoration,
1372 ast::InternalDecoration>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001373 AddError("decoration is not valid for functions", deco->source());
James Price43f50ea2021-05-14 20:41:03 +00001374 return false;
1375 }
1376 }
James Price43f50ea2021-05-14 20:41:03 +00001377
Ben Clayton725159c2021-07-17 17:45:25 +00001378 if (func->params().size() > 255) {
1379 AddError("functions may declare at most 255 parameters", func->source());
1380 return false;
1381 }
1382
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001383 for (auto* param : func->params()) {
Sarah9432c972021-06-29 15:24:04 +00001384 if (!ValidateFunctionParameter(func, variable_to_info_.at(param))) {
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001385 return false;
1386 }
1387 }
1388
Ben Clayton3068dcb2021-04-30 19:24:29 +00001389 if (!info->return_type->Is<sem::Void>()) {
Antonio Maiorano68a6dd02021-07-20 18:28:31 +00001390 if (!info->return_type->IsConstructible()) {
Ryan Harrison2f258d12021-07-07 20:41:00 +00001391 AddError("function return type must be a constructible type",
Ben Claytonffd28e22021-06-24 11:27:36 +00001392 func->return_type()->source());
Antonio Maioranof19e0e42021-06-21 20:51:16 +00001393 return false;
1394 }
1395
Ben Claytonb502fdf2021-04-07 08:09:21 +00001396 if (func->body()) {
1397 if (!func->get_last_statement() ||
1398 !func->get_last_statement()->Is<ast::ReturnStatement>()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00001399 AddError("non-void function must end with a return statement",
Ben Claytonffd28e22021-06-24 11:27:36 +00001400 func->source());
Ben Claytonb502fdf2021-04-07 08:09:21 +00001401 return false;
1402 }
Saraha8f58ef2021-06-30 19:22:30 +00001403 } else if (IsValidationEnabled(
Ben Clayton451f2cc2021-05-12 12:54:21 +00001404 func->decorations(),
1405 ast::DisabledValidation::kFunctionHasNoBody)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001406 TINT_ICE(Resolver, diagnostics_)
Ben Claytonb502fdf2021-04-07 08:09:21 +00001407 << "Function " << builder_->Symbols().NameFor(func->symbol())
Ben Clayton451f2cc2021-05-12 12:54:21 +00001408 << " has no body";
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001409 }
1410
1411 for (auto* deco : func->return_type_decorations()) {
James Price1b1d9632021-06-28 09:53:37 +00001412 if (!func->IsEntryPoint()) {
Sarah99a78ad2021-07-08 14:02:56 +00001413 AddError(
1414 "decoration is not valid for non-entry point function return types",
1415 deco->source());
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001416 return false;
1417 }
Sarah465c5aa2021-07-23 13:23:20 +00001418 if (!deco->IsAnyOf<ast::BuiltinDecoration, ast::InternalDecoration,
1419 ast::LocationDecoration, ast::InterpolateDecoration,
1420 ast::InvariantDecoration>() &&
1421 (IsValidationEnabled(info->declaration->decorations(),
1422 ast::DisabledValidation::kEntryPointParameter) &&
1423 IsValidationEnabled(info->declaration->decorations(),
1424 ast::DisabledValidation::
1425 kIgnoreConstructibleFunctionParameter))) {
James Price1b1d9632021-06-28 09:53:37 +00001426 AddError("decoration is not valid for entry point return types",
1427 deco->source());
1428 return false;
1429 }
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001430 }
1431 }
1432
James Price68f558f2021-04-06 15:51:47 +00001433 if (func->IsEntryPoint()) {
James Price2dd39372021-04-21 16:13:42 +00001434 if (!ValidateEntryPoint(func, info)) {
James Price68f558f2021-04-06 15:51:47 +00001435 return false;
1436 }
1437 }
1438
1439 return true;
1440}
1441
James Price2dd39372021-04-21 16:13:42 +00001442bool Resolver::ValidateEntryPoint(const ast::Function* func,
1443 const FunctionInfo* info) {
James Price68f558f2021-04-06 15:51:47 +00001444 // Use a lambda to validate the entry point decorations for a type.
Ben Clayton9b54a2e2021-05-18 10:28:48 +00001445 // Persistent state is used to track which builtins and locations have
1446 // already been seen, in order to catch conflicts.
1447 // TODO(jrprice): This state could be stored in FunctionInfo instead, and
1448 // then passed to sem::Function since it would be useful there too.
James Price68f558f2021-04-06 15:51:47 +00001449 std::unordered_set<ast::Builtin> builtins;
1450 std::unordered_set<uint32_t> locations;
1451 enum class ParamOrRetType {
1452 kParameter,
1453 kReturnType,
1454 };
Sarah443c41d2021-06-18 19:58:27 +00001455
James Price68f558f2021-04-06 15:51:47 +00001456 // Inner lambda that is applied to a type and all of its members.
Ben Clayton08b0ab92021-07-08 15:12:36 +00001457 auto validate_entry_point_decorations_inner = [&](const ast::DecorationList&
1458 decos,
1459 sem::Type* ty,
1460 Source source,
1461 ParamOrRetType param_or_ret,
1462 bool is_struct_member) {
1463 // Scan decorations for pipeline IO attributes.
1464 // Check for overlap with attributes that have been seen previously.
1465 ast::Decoration* pipeline_io_attribute = nullptr;
James Price508d2492021-07-12 12:12:32 +00001466 ast::InvariantDecoration* invariant_attribute = nullptr;
Ben Clayton08b0ab92021-07-08 15:12:36 +00001467 for (auto* deco : decos) {
Sarah465c5aa2021-07-23 13:23:20 +00001468 auto is_invalid_compute_shader_decoration = false;
Ben Clayton08b0ab92021-07-08 15:12:36 +00001469 if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
1470 if (pipeline_io_attribute) {
1471 AddError("multiple entry point IO attributes", deco->source());
1472 AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
James Price68f558f2021-04-06 15:51:47 +00001473 pipeline_io_attribute->source());
Ben Clayton08b0ab92021-07-08 15:12:36 +00001474 return false;
1475 }
1476 pipeline_io_attribute = deco;
James Price68f558f2021-04-06 15:51:47 +00001477
Ben Clayton08b0ab92021-07-08 15:12:36 +00001478 if (builtins.count(builtin->value())) {
1479 AddError(deco_to_str(builtin) +
1480 " attribute appears multiple times as pipeline " +
1481 (param_or_ret == ParamOrRetType::kParameter ? "input"
1482 : "output"),
1483 func->source());
1484 return false;
1485 }
James Price68f558f2021-04-06 15:51:47 +00001486
Ben Clayton08b0ab92021-07-08 15:12:36 +00001487 if (!ValidateBuiltinDecoration(
1488 builtin, ty,
Sarah465c5aa2021-07-23 13:23:20 +00001489 /* is_input */ param_or_ret == ParamOrRetType::kParameter,
1490 /* is_struct_member */ is_struct_member)) {
Ben Clayton08b0ab92021-07-08 15:12:36 +00001491 return false;
James Price68f558f2021-04-06 15:51:47 +00001492 }
Sarah465c5aa2021-07-23 13:23:20 +00001493 builtins.emplace(builtin->value());
Ben Clayton08b0ab92021-07-08 15:12:36 +00001494 } else if (auto* location = deco->As<ast::LocationDecoration>()) {
1495 if (pipeline_io_attribute) {
1496 AddError("multiple entry point IO attributes", deco->source());
1497 AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
1498 pipeline_io_attribute->source());
1499 return false;
James Price68f558f2021-04-06 15:51:47 +00001500 }
Ben Clayton08b0ab92021-07-08 15:12:36 +00001501 pipeline_io_attribute = deco;
James Price68f558f2021-04-06 15:51:47 +00001502
Ben Clayton08b0ab92021-07-08 15:12:36 +00001503 if (locations.count(location->value())) {
1504 AddError(deco_to_str(location) +
1505 " attribute appears multiple times as pipeline " +
1506 (param_or_ret == ParamOrRetType::kParameter ? "input"
1507 : "output"),
1508 func->source());
1509 return false;
1510 }
Sarah465c5aa2021-07-23 13:23:20 +00001511
1512 if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
1513 is_invalid_compute_shader_decoration = true;
1514 }
Ben Clayton08b0ab92021-07-08 15:12:36 +00001515 locations.emplace(location->value());
Sarah465c5aa2021-07-23 13:23:20 +00001516 } else if (auto* interpolate = deco->As<ast::InterpolateDecoration>()) {
1517 if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
1518 is_invalid_compute_shader_decoration = true;
1519 } else if (!ValidateInterpolateDecoration(interpolate, ty)) {
1520 return false;
1521 }
James Price508d2492021-07-12 12:12:32 +00001522 } else if (auto* invariant = deco->As<ast::InvariantDecoration>()) {
Sarah465c5aa2021-07-23 13:23:20 +00001523 if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
1524 is_invalid_compute_shader_decoration = true;
1525 }
James Price508d2492021-07-12 12:12:32 +00001526 invariant_attribute = invariant;
Ben Clayton08b0ab92021-07-08 15:12:36 +00001527 }
Sarah465c5aa2021-07-23 13:23:20 +00001528 if (is_invalid_compute_shader_decoration) {
1529 std::string input_or_output =
1530 param_or_ret == ParamOrRetType::kParameter ? "inputs" : "output";
1531 AddError(
1532 "decoration is not valid for compute shader " + input_or_output,
1533 deco->source());
1534 return false;
1535 }
Ben Clayton08b0ab92021-07-08 15:12:36 +00001536 }
1537
1538 // Check that we saw a pipeline IO attribute iff we need one.
1539 if (ty->Is<sem::Struct>()) {
1540 if (pipeline_io_attribute) {
1541 AddError("entry point IO attributes must not be used on structure " +
1542 std::string(param_or_ret == ParamOrRetType::kParameter
1543 ? "parameters"
1544 : "return types"),
1545 pipeline_io_attribute->source());
1546 return false;
1547 }
1548 } else if (IsValidationEnabled(
1549 decos, ast::DisabledValidation::kEntryPointParameter)) {
1550 if (!pipeline_io_attribute) {
1551 std::string err = "missing entry point IO attribute";
1552 if (!is_struct_member) {
1553 err +=
1554 (param_or_ret == ParamOrRetType::kParameter ? " on parameter"
1555 : " on return type");
1556 }
1557 AddError(err, source);
1558 return false;
1559 }
1560
James Price508d2492021-07-12 12:12:32 +00001561 auto* builtin = pipeline_io_attribute->As<ast::BuiltinDecoration>();
1562 if (invariant_attribute &&
1563 !(builtin && builtin->value() == ast::Builtin::kPosition)) {
1564 AddError(
1565 "invariant attribute must only be applied to a position builtin",
1566 invariant_attribute->source());
1567 return false;
1568 }
1569
Ben Clayton08b0ab92021-07-08 15:12:36 +00001570 // Check that all user defined attributes are numeric scalars, vectors
1571 // of numeric scalars.
1572 // Testing for being a struct is handled by the if portion above.
James Price508d2492021-07-12 12:12:32 +00001573 if (!builtin) {
Ben Clayton08b0ab92021-07-08 15:12:36 +00001574 if (!ty->is_numeric_scalar_or_vector()) {
1575 AddError(
1576 "User defined entry point IO types must be a numeric scalar, "
1577 "a numeric vector, or a structure",
1578 source);
1579 return false;
1580 }
1581 }
1582 }
1583
1584 return true;
1585 };
James Price68f558f2021-04-06 15:51:47 +00001586
1587 // Outer lambda for validating the entry point decorations for a type.
1588 auto validate_entry_point_decorations = [&](const ast::DecorationList& decos,
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001589 sem::Type* ty, Source source,
James Price68f558f2021-04-06 15:51:47 +00001590 ParamOrRetType param_or_ret) {
1591 // Validate the decorations for the type.
1592 if (!validate_entry_point_decorations_inner(decos, ty, source, param_or_ret,
1593 false)) {
1594 return false;
1595 }
1596
Ben Claytona34fa0e2021-05-10 17:38:01 +00001597 if (auto* str = ty->As<sem::Struct>()) {
James Price68f558f2021-04-06 15:51:47 +00001598 // Validate the decorations for each struct members, and also check for
1599 // invalid member types.
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001600 for (auto* member : str->Members()) {
Ben Claytona34fa0e2021-05-10 17:38:01 +00001601 if (member->Type()->Is<sem::Struct>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001602 AddError("entry point IO types cannot contain nested structures",
1603 member->Declaration()->source());
Sarah465c5aa2021-07-23 13:23:20 +00001604 AddNote("while analysing entry point '" +
1605 builder_->Symbols().NameFor(func->symbol()) + "'",
Ben Claytonffd28e22021-06-24 11:27:36 +00001606 func->source());
James Price68f558f2021-04-06 15:51:47 +00001607 return false;
Ben Claytona34fa0e2021-05-10 17:38:01 +00001608 }
1609
1610 if (auto* arr = member->Type()->As<sem::Array>()) {
Ben Clayton4cd5eea2021-05-07 20:58:34 +00001611 if (arr->IsRuntimeSized()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001612 AddError("entry point IO types cannot contain runtime sized arrays",
1613 member->Declaration()->source());
Sarah465c5aa2021-07-23 13:23:20 +00001614 AddNote("while analysing entry point '" +
1615 builder_->Symbols().NameFor(func->symbol()) + "'",
Ben Claytonffd28e22021-06-24 11:27:36 +00001616 func->source());
James Price68f558f2021-04-06 15:51:47 +00001617 return false;
1618 }
1619 }
1620
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001621 if (!validate_entry_point_decorations_inner(
Ben Claytona34fa0e2021-05-10 17:38:01 +00001622 member->Declaration()->decorations(), member->Type(),
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001623 member->Declaration()->source(), param_or_ret, true)) {
Sarah465c5aa2021-07-23 13:23:20 +00001624 AddNote("while analysing entry point '" +
1625 builder_->Symbols().NameFor(func->symbol()) + "'",
Ben Claytonffd28e22021-06-24 11:27:36 +00001626 func->source());
James Price68f558f2021-04-06 15:51:47 +00001627 return false;
1628 }
1629 }
1630 }
1631
1632 return true;
1633 };
1634
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001635 for (auto* param : info->parameters) {
James Price68f558f2021-04-06 15:51:47 +00001636 if (!validate_entry_point_decorations(
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001637 param->declaration->decorations(), param->type,
1638 param->declaration->source(), ParamOrRetType::kParameter)) {
James Price68f558f2021-04-06 15:51:47 +00001639 return false;
1640 }
1641 }
1642
James Price2dd39372021-04-21 16:13:42 +00001643 // Clear IO sets after parameter validation. Builtin and location attributes
1644 // in return types should be validated independently from those used in
1645 // parameters.
1646 builtins.clear();
1647 locations.clear();
1648
Ben Clayton3068dcb2021-04-30 19:24:29 +00001649 if (!info->return_type->Is<sem::Void>()) {
James Price68f558f2021-04-06 15:51:47 +00001650 if (!validate_entry_point_decorations(func->return_type_decorations(),
Ben Clayton3068dcb2021-04-30 19:24:29 +00001651 info->return_type, func->source(),
James Price68f558f2021-04-06 15:51:47 +00001652 ParamOrRetType::kReturnType)) {
1653 return false;
1654 }
1655 }
1656
James Price2dd39372021-04-21 16:13:42 +00001657 if (func->pipeline_stage() == ast::PipelineStage::kVertex &&
1658 builtins.count(ast::Builtin::kPosition) == 0) {
1659 // Check module-scope variables, as the SPIR-V sanitizer generates these.
1660 bool found = false;
1661 for (auto* var : info->referenced_module_vars) {
1662 if (auto* builtin = ast::GetDecoration<ast::BuiltinDecoration>(
1663 var->declaration->decorations())) {
1664 if (builtin->value() == ast::Builtin::kPosition) {
1665 found = true;
1666 break;
1667 }
1668 }
1669 }
Ben Clayton677437d2021-06-16 09:50:11 +00001670 if (!found) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001671 AddError(
James Price2dd39372021-04-21 16:13:42 +00001672 "a vertex shader must include the 'position' builtin in its return "
1673 "type",
1674 func->source());
1675 return false;
1676 }
1677 }
1678
Sarahe6cb51e2021-06-29 18:39:44 +00001679 if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
1680 if (!ast::HasDecoration<ast::WorkgroupDecoration>(func->decorations())) {
1681 AddError(
1682 "a compute shader must include 'workgroup_size' in its "
1683 "attributes",
1684 func->source());
1685 return false;
1686 }
1687 }
1688
Ben Clayton3f968e72021-05-10 19:16:46 +00001689 // Validate there are no resource variable binding collisions
1690 std::unordered_map<sem::BindingPoint, const ast::Variable*> binding_points;
1691 for (auto* var_info : info->referenced_module_vars) {
1692 if (!var_info->declaration->binding_point()) {
1693 continue;
1694 }
1695 auto bp = var_info->binding_point;
1696 auto res = binding_points.emplace(bp, var_info->declaration);
Ben Clayton3103a1f2021-05-12 13:30:51 +00001697 if (!res.second &&
Saraha8f58ef2021-06-30 19:22:30 +00001698 IsValidationEnabled(var_info->declaration->decorations(),
1699 ast::DisabledValidation::kBindingPointCollision) &&
1700 IsValidationEnabled(res.first->second->decorations(),
1701 ast::DisabledValidation::kBindingPointCollision)) {
Ben Clayton3f968e72021-05-10 19:16:46 +00001702 // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
1703 // Bindings must not alias within a shader stage: two different
1704 // variables in the resource interface of a given shader must not have
1705 // the same group and binding values, when considered as a pair of
1706 // values.
1707 auto func_name = builder_->Symbols().NameFor(info->declaration->symbol());
Ben Claytonffd28e22021-06-24 11:27:36 +00001708 AddError("entry point '" + func_name +
1709 "' references multiple variables that use the "
1710 "same resource binding [[group(" +
1711 std::to_string(bp.group) + "), binding(" +
1712 std::to_string(bp.binding) + ")]]",
1713 var_info->declaration->source());
1714 AddNote("first resource binding usage declared here",
1715 res.first->second->source());
Ben Clayton3f968e72021-05-10 19:16:46 +00001716 return false;
1717 }
1718 }
1719
Antonio Maiorano03c01b52021-03-19 14:04:51 +00001720 return true;
1721}
1722
Ben Clayton5f0ea112021-03-09 10:54:37 +00001723bool Resolver::Function(ast::Function* func) {
Ben Clayton3068dcb2021-04-30 19:24:29 +00001724 auto* info = function_infos_.Create<FunctionInfo>(func);
Ben Claytonf97b9c92021-02-16 18:45:45 +00001725
Ben Clayton71786c92021-06-03 16:07:34 +00001726 if (func->IsEntryPoint()) {
1727 entry_points_.emplace_back(info);
1728 }
1729
Ben Claytonb3505002021-05-19 16:11:04 +00001730 TINT_SCOPED_ASSIGNMENT(current_function_, info);
dan sinclair13d2a3b2020-06-22 20:52:24 +00001731
dan sinclair417a90d2020-04-06 21:07:41 +00001732 variable_stack_.push_scope();
Ben Clayton4ffcf062021-07-22 13:24:59 +00001733 uint32_t parameter_index = 0;
Ben Claytonb053acf2020-11-16 16:31:07 +00001734 for (auto* param : func->params()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00001735 Mark(param);
Ben Clayton4ffcf062021-07-22 13:24:59 +00001736 auto* param_info =
1737 Variable(param, VariableKind::kParameter, parameter_index++);
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +00001738 if (!param_info) {
1739 return false;
1740 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00001741
Ben Clayton6fcefe42021-04-19 19:16:12 +00001742 for (auto* deco : param->decorations()) {
1743 Mark(deco);
1744 }
Ben Clayton241c16d2021-06-09 18:53:57 +00001745 if (!ValidateNoDuplicateDecorations(param->decorations())) {
1746 return false;
1747 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00001748
Ben Claytone9c49842021-04-09 13:56:08 +00001749 variable_stack_.set(param->symbol(), param_info);
Ben Clayton3068dcb2021-04-30 19:24:29 +00001750 info->parameters.emplace_back(param_info);
James Price494e82d2021-03-31 15:42:17 +00001751
Ben Claytonc87ff9c2021-03-31 17:23:07 +00001752 if (!ApplyStorageClassUsageToType(param->declared_storage_class(),
Ben Clayton3068dcb2021-04-30 19:24:29 +00001753 param_info->type, param->source())) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001754 AddNote("while instantiating parameter " +
1755 builder_->Symbols().NameFor(param->symbol()),
1756 param->source());
Ben Claytonc87ff9c2021-03-31 17:23:07 +00001757 return false;
1758 }
1759
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001760 if (auto* str = param_info->type->As<sem::Struct>()) {
James Price494e82d2021-03-31 15:42:17 +00001761 switch (func->pipeline_stage()) {
1762 case ast::PipelineStage::kVertex:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001763 str->AddUsage(sem::PipelineStageUsage::kVertexInput);
James Price494e82d2021-03-31 15:42:17 +00001764 break;
1765 case ast::PipelineStage::kFragment:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001766 str->AddUsage(sem::PipelineStageUsage::kFragmentInput);
James Price494e82d2021-03-31 15:42:17 +00001767 break;
1768 case ast::PipelineStage::kCompute:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001769 str->AddUsage(sem::PipelineStageUsage::kComputeInput);
James Price494e82d2021-03-31 15:42:17 +00001770 break;
1771 case ast::PipelineStage::kNone:
1772 break;
1773 }
1774 }
1775 }
1776
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001777 if (auto* ty = func->return_type()) {
1778 info->return_type = Type(ty);
1779 info->return_type_name = ty->FriendlyName(builder_->Symbols());
Ben Clayton3068dcb2021-04-30 19:24:29 +00001780 if (!info->return_type) {
1781 return false;
1782 }
1783 } else {
1784 info->return_type = builder_->create<sem::Void>();
Ben Clayton02ebf0d2021-05-05 09:09:41 +00001785 info->return_type_name =
1786 info->return_type->FriendlyName(builder_->Symbols());
Ben Clayton3068dcb2021-04-30 19:24:29 +00001787 }
1788
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001789 if (auto* str = info->return_type->As<sem::Struct>()) {
James Price5c523f32021-03-31 15:44:07 +00001790 if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str,
1791 func->source())) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001792 AddNote("while instantiating return type for " +
1793 builder_->Symbols().NameFor(func->symbol()),
1794 func->source());
James Price5c523f32021-03-31 15:44:07 +00001795 return false;
1796 }
1797
James Price494e82d2021-03-31 15:42:17 +00001798 switch (func->pipeline_stage()) {
1799 case ast::PipelineStage::kVertex:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001800 str->AddUsage(sem::PipelineStageUsage::kVertexOutput);
James Price494e82d2021-03-31 15:42:17 +00001801 break;
1802 case ast::PipelineStage::kFragment:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001803 str->AddUsage(sem::PipelineStageUsage::kFragmentOutput);
James Price494e82d2021-03-31 15:42:17 +00001804 break;
1805 case ast::PipelineStage::kCompute:
Ben Claytonba6ab5e2021-05-07 14:49:34 +00001806 str->AddUsage(sem::PipelineStageUsage::kComputeOutput);
James Price494e82d2021-03-31 15:42:17 +00001807 break;
1808 case ast::PipelineStage::kNone:
1809 break;
1810 }
dan sinclair011aed92020-06-22 20:18:17 +00001811 }
1812
Ben Claytonb502fdf2021-04-07 08:09:21 +00001813 if (func->body()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00001814 Mark(func->body());
Ben Clayton6e459fe2021-07-14 09:44:41 +00001815 if (current_compound_statement_) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001816 TINT_ICE(Resolver, diagnostics_)
Ben Clayton6e459fe2021-07-14 09:44:41 +00001817 << "Resolver::Function() called with a current compound statement";
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00001818 return false;
1819 }
Ben Clayton22d891c2021-05-20 15:17:08 +00001820 auto* sem_block = builder_->create<sem::FunctionBlockStatement>(func);
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00001821 builder_->Sem().Add(func->body(), sem_block);
Ben Clayton6e459fe2021-07-14 09:44:41 +00001822 if (!Scope(sem_block, [&] { return Statements(func->body()->list()); })) {
Ben Claytonb502fdf2021-04-07 08:09:21 +00001823 return false;
1824 }
dan sinclair417a90d2020-04-06 21:07:41 +00001825 }
1826 variable_stack_.pop_scope();
1827
Ben Clayton6fcefe42021-04-19 19:16:12 +00001828 for (auto* deco : func->decorations()) {
1829 Mark(deco);
1830 }
Ben Clayton241c16d2021-06-09 18:53:57 +00001831 if (!ValidateNoDuplicateDecorations(func->decorations())) {
1832 return false;
1833 }
1834
Ben Clayton6fcefe42021-04-19 19:16:12 +00001835 for (auto* deco : func->return_type_decorations()) {
1836 Mark(deco);
1837 }
Ben Clayton241c16d2021-06-09 18:53:57 +00001838 if (!ValidateNoDuplicateDecorations(func->return_type_decorations())) {
1839 return false;
1840 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00001841
James Pricece8f8682021-05-19 08:15:18 +00001842 // Set work-group size defaults.
1843 for (int i = 0; i < 3; i++) {
1844 info->workgroup_size[i].value = 1;
1845 info->workgroup_size[i].overridable_const = nullptr;
1846 }
1847
1848 if (auto* workgroup =
1849 ast::GetDecoration<ast::WorkgroupDecoration>(func->decorations())) {
James Price70f80bb2021-05-19 13:40:08 +00001850 auto values = workgroup->values();
Sarah58bbe322021-07-14 23:33:24 +00001851 auto is_i32 = false;
1852 auto is_less_than_one = true;
James Price70f80bb2021-05-19 13:40:08 +00001853 for (int i = 0; i < 3; i++) {
1854 // Each argument to this decoration can either be a literal, an
1855 // identifier for a module-scope constants, or nullptr if not specified.
1856
1857 if (!values[i]) {
1858 // Not specified, just use the default.
1859 continue;
1860 }
1861
1862 Mark(values[i]);
1863
Sarah58bbe322021-07-14 23:33:24 +00001864 uint32_t value = 0;
James Price70f80bb2021-05-19 13:40:08 +00001865 if (auto* ident = values[i]->As<ast::IdentifierExpression>()) {
1866 // We have an identifier of a module-scope constant.
1867 if (!Identifier(ident)) {
1868 return false;
1869 }
1870
1871 VariableInfo* var;
1872 if (!variable_stack_.get(ident->symbol(), &var) ||
Sarah58bbe322021-07-14 23:33:24 +00001873 !(var->declaration->is_const() && var->type->is_integer_scalar())) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001874 AddError(
Sarah58bbe322021-07-14 23:33:24 +00001875 "workgroup_size parameter must be either literal or module-scope "
1876 "constant of type i32 or u32",
James Price70f80bb2021-05-19 13:40:08 +00001877 values[i]->source());
1878 return false;
1879 }
1880
1881 // Capture the constant if an [[override]] attribute is present.
1882 if (ast::HasDecoration<ast::OverrideDecoration>(
1883 var->declaration->decorations())) {
1884 info->workgroup_size[i].overridable_const = var->declaration;
1885 }
1886
1887 auto* constructor = var->declaration->constructor();
1888 if (constructor) {
1889 // Resolve the constructor expression to use as the default value.
Ben Claytonaf6fc5f2021-07-13 12:18:13 +00001890 auto val = ConstantValueOf(constructor);
Sarah58bbe322021-07-14 23:33:24 +00001891 if (!val.IsValid() || !val.Type()->is_integer_scalar()) {
Ben Claytonaf6fc5f2021-07-13 12:18:13 +00001892 TINT_ICE(Resolver, diagnostics_)
1893 << "failed to resolve workgroup_size constant value";
James Price70f80bb2021-05-19 13:40:08 +00001894 return false;
1895 }
Sarah58bbe322021-07-14 23:33:24 +00001896
1897 if (i == 0) {
1898 is_i32 = val.Type()->Is<sem::I32>();
1899 } else {
1900 if (is_i32 != val.Type()->Is<sem::I32>()) {
1901 AddError(
1902 "workgroup_size parameters must be of the same type, "
1903 "either i32 or u32",
1904 values[i]->source());
1905 return false;
1906 }
1907 }
1908 is_less_than_one =
1909 is_i32 ? val.Elements()[0].i32 < 1 : val.Elements()[0].u32 < 1;
1910
1911 value = is_i32 ? static_cast<uint32_t>(val.Elements()[0].i32)
1912 : val.Elements()[0].u32;
James Price70f80bb2021-05-19 13:40:08 +00001913 } else {
1914 // No constructor means this value must be overriden by the user.
1915 info->workgroup_size[i].value = 0;
1916 continue;
1917 }
1918 } else if (auto* scalar =
1919 values[i]->As<ast::ScalarConstructorExpression>()) {
1920 // We have a literal.
1921 Mark(scalar->literal());
Sarah58bbe322021-07-14 23:33:24 +00001922 auto* literal = scalar->literal()->As<ast::IntLiteral>();
1923 if (!literal) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001924 AddError(
Sarah58bbe322021-07-14 23:33:24 +00001925 "workgroup_size parameter must be either literal or module-scope "
1926 "constant of type i32 or u32",
James Price70f80bb2021-05-19 13:40:08 +00001927 values[i]->source());
1928 return false;
1929 }
1930
Sarah58bbe322021-07-14 23:33:24 +00001931 if (i == 0) {
1932 is_i32 = literal->Is<ast::SintLiteral>();
1933 } else {
1934 if (literal->Is<ast::SintLiteral>() != is_i32) {
1935 AddError(
1936 "workgroup_size parameters must be of the same type, "
1937 "either i32 or u32",
1938 values[i]->source());
1939 return false;
1940 }
1941 }
1942
1943 is_less_than_one =
1944 is_i32 ? literal->value_as_i32() < 1 : literal->value_as_u32() < 1;
1945 value = is_i32 ? static_cast<uint32_t>(literal->value_as_i32())
1946 : literal->value_as_u32();
James Price70f80bb2021-05-19 13:40:08 +00001947 }
1948
1949 // Validate and set the default value for this dimension.
Sarah58bbe322021-07-14 23:33:24 +00001950 if (is_less_than_one) {
1951 AddError("workgroup_size parameter must be at least 1",
Ben Claytonffd28e22021-06-24 11:27:36 +00001952 values[i]->source());
James Price70f80bb2021-05-19 13:40:08 +00001953 return false;
1954 }
1955 info->workgroup_size[i].value = value;
1956 }
James Pricece8f8682021-05-19 08:15:18 +00001957 }
1958
Ben Clayton3068dcb2021-04-30 19:24:29 +00001959 if (!ValidateFunction(func, info)) {
Antonio Maiorano9ef17472021-03-26 12:47:58 +00001960 return false;
1961 }
1962
dan sinclairf8fa6cf2021-02-24 22:11:34 +00001963 // Register the function information _after_ processing the statements. This
1964 // allows us to catch a function calling itself when determining the call
1965 // information as this function doesn't exist until it's finished.
Ben Clayton3068dcb2021-04-30 19:24:29 +00001966 symbol_to_function_[func->symbol()] = info;
1967 function_to_info_.emplace(func, info);
dan sinclairf8fa6cf2021-02-24 22:11:34 +00001968
dan sinclair417a90d2020-04-06 21:07:41 +00001969 return true;
1970}
1971
Ben Clayton5f0ea112021-03-09 10:54:37 +00001972bool Resolver::Statements(const ast::StatementList& stmts) {
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00001973 for (auto* stmt : stmts) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00001974 Mark(stmt);
Ben Clayton5f0ea112021-03-09 10:54:37 +00001975 if (!Statement(stmt)) {
dan sinclair0975dd52020-07-27 15:25:00 +00001976 return false;
1977 }
1978 }
Sarahc3f8fdf2021-06-21 17:53:56 +00001979 if (!ValidateStatements(stmts)) {
1980 return false;
1981 }
1982
1983 return true;
1984}
1985
1986bool Resolver::ValidateStatements(const ast::StatementList& stmts) {
1987 auto next_stmt = stmts.begin();
1988 for (auto* stmt : stmts) {
1989 next_stmt++;
1990 if (stmt->IsAnyOf<ast::ReturnStatement, ast::BreakStatement,
1991 ast::ContinueStatement>()) {
1992 if (stmt != stmts.back()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00001993 AddError("code is unreachable", (*next_stmt)->source());
Sarahc3f8fdf2021-06-21 17:53:56 +00001994 return false;
1995 }
1996 }
1997 }
dan sinclair0975dd52020-07-27 15:25:00 +00001998 return true;
1999}
2000
Ben Clayton5f0ea112021-03-09 10:54:37 +00002001bool Resolver::Statement(ast::Statement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002002 if (stmt->Is<ast::CaseStatement>()) {
2003 AddError("case statement can only be used inside a switch statement",
2004 stmt->source());
2005 return false;
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002006 }
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002007 if (stmt->Is<ast::ElseStatement>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002008 TINT_ICE(Resolver, diagnostics_)
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002009 << "Resolver::Statement() encountered an Else statement. Else "
2010 "statements are embedded in If statements, so should never be "
2011 "encountered as top-level statements";
2012 return false;
2013 }
2014
Ben Clayton6e459fe2021-07-14 09:44:41 +00002015 // Compound statements. These create their own sem::CompoundStatement
2016 // bindings.
2017 if (auto* b = stmt->As<ast::BlockStatement>()) {
2018 return BlockStatement(b);
2019 }
2020 if (auto* l = stmt->As<ast::ForLoopStatement>()) {
2021 return ForLoopStatement(l);
2022 }
2023 if (auto* l = stmt->As<ast::LoopStatement>()) {
2024 return LoopStatement(l);
2025 }
2026 if (auto* i = stmt->As<ast::IfStatement>()) {
2027 return IfStatement(i);
2028 }
2029 if (auto* s = stmt->As<ast::SwitchStatement>()) {
2030 return SwitchStatement(s);
2031 }
2032
2033 // Non-Compound statements
2034 sem::Statement* sem_statement =
2035 builder_->create<sem::Statement>(stmt, current_compound_statement_);
2036 builder_->Sem().Add(stmt, sem_statement);
2037 TINT_SCOPED_ASSIGNMENT(current_statement_, sem_statement);
Ben Clayton1d8098a2020-11-30 23:30:58 +00002038 if (auto* a = stmt->As<ast::AssignmentStatement>()) {
Antonio Maioranoe09989a2021-03-31 13:26:43 +00002039 return Assignment(a);
dan sinclair6c498fc2020-04-07 12:47:23 +00002040 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002041 if (stmt->Is<ast::BreakStatement>()) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002042 if (!sem_statement->FindFirstParent<sem::LoopBlockStatement>() &&
2043 !sem_statement->FindFirstParent<sem::SwitchCaseBlockStatement>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002044 AddError("break statement must be in a loop or switch case",
2045 stmt->source());
Ben Clayton9430cb42021-03-09 15:06:37 +00002046 return false;
2047 }
dan sinclair6bd70612020-06-03 16:11:28 +00002048 return true;
dan sinclairb7ea6e22020-04-07 12:54:10 +00002049 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002050 if (auto* c = stmt->As<ast::CallStatement>()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002051 Mark(c->expr());
Ben Clayton7fe01062021-06-11 13:22:27 +00002052 if (!Expression(c->expr())) {
2053 return false;
2054 }
2055 if (!ValidateCallStatement(c)) {
2056 return false;
2057 }
2058 return true;
dan sinclair50080b72020-07-21 13:42:13 +00002059 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002060 if (stmt->Is<ast::ContinueStatement>()) {
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002061 // Set if we've hit the first continue statement in our parent loop
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00002062 if (auto* block =
2063 current_block_->FindFirstParent<
2064 sem::LoopBlockStatement, sem::LoopContinuingBlockStatement>()) {
2065 if (auto* loop_block = block->As<sem::LoopBlockStatement>()) {
2066 if (loop_block->FirstContinue() == size_t(~0)) {
2067 const_cast<sem::LoopBlockStatement*>(loop_block)
2068 ->SetFirstContinue(loop_block->Decls().size());
2069 }
2070 } else {
2071 AddError("continuing blocks must not contain a continue statement",
2072 stmt->source());
2073 return false;
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002074 }
2075 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00002076 AddError("continue statement must be in a loop", stmt->source());
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002077 return false;
2078 }
2079
dan sinclair6bd70612020-06-03 16:11:28 +00002080 return true;
dan sinclairaec965e2020-04-07 12:54:29 +00002081 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002082 if (stmt->Is<ast::DiscardStatement>()) {
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00002083 if (auto* continuing =
2084 sem_statement
2085 ->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
2086 AddError("continuing blocks must not contain a discard statement",
2087 stmt->source());
2088 if (continuing != sem_statement->Parent()) {
2089 AddNote("see continuing block here",
2090 continuing->Declaration()->source());
2091 }
2092 return false;
2093 }
dan sinclair8f3c6352020-07-25 14:33:50 +00002094 return true;
2095 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002096 if (stmt->Is<ast::FallthroughStatement>()) {
dan sinclair1913fc92020-04-07 12:54:59 +00002097 return true;
2098 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002099 if (auto* r = stmt->As<ast::ReturnStatement>()) {
Antonio Maiorano2e974352021-03-22 23:20:17 +00002100 return Return(r);
dan sinclairbf0fff82020-04-07 12:56:24 +00002101 }
Ben Clayton1d8098a2020-11-30 23:30:58 +00002102 if (auto* v = stmt->As<ast::VariableDeclStatement>()) {
Ben Claytona88090b2021-03-17 22:47:33 +00002103 return VariableDeclStatement(v);
dan sinclairca893e32020-04-07 12:57:12 +00002104 }
dan sinclair6c498fc2020-04-07 12:47:23 +00002105
Ben Claytonffd28e22021-06-24 11:27:36 +00002106 AddError(
Ben Clayton6b4924f2021-02-17 20:13:34 +00002107 "unknown statement type for type determination: " + builder_->str(stmt),
2108 stmt->source());
dan sinclair417a90d2020-04-06 21:07:41 +00002109 return false;
2110}
2111
Ben Clayton9430cb42021-03-09 15:06:37 +00002112bool Resolver::CaseStatement(ast::CaseStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002113 auto* sem = builder_->create<sem::SwitchCaseBlockStatement>(
2114 stmt->body(), current_compound_statement_);
2115 builder_->Sem().Add(stmt, sem);
2116 builder_->Sem().Add(stmt->body(), sem);
Ben Clayton6fcefe42021-04-19 19:16:12 +00002117 Mark(stmt->body());
2118 for (auto* sel : stmt->selectors()) {
2119 Mark(sel);
2120 }
Ben Clayton6e459fe2021-07-14 09:44:41 +00002121 return Scope(sem, [&] { return Statements(stmt->body()->list()); });
Ben Clayton9430cb42021-03-09 15:06:37 +00002122}
2123
Ben Clayton5fb87dd2021-03-09 15:17:28 +00002124bool Resolver::IfStatement(ast::IfStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002125 auto* sem =
2126 builder_->create<sem::IfStatement>(stmt, current_compound_statement_);
2127 builder_->Sem().Add(stmt, sem);
2128 return Scope(sem, [&] {
2129 Mark(stmt->condition());
2130 if (!Expression(stmt->condition())) {
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002131 return false;
2132 }
Ben Clayton5fb87dd2021-03-09 15:17:28 +00002133
Ben Clayton6e459fe2021-07-14 09:44:41 +00002134 auto* cond_type = TypeOf(stmt->condition())->UnwrapRef();
2135 if (!cond_type->Is<sem::Bool>()) {
2136 AddError("if statement condition must be bool, got " +
2137 cond_type->FriendlyName(builder_->Symbols()),
2138 stmt->condition()->source());
2139 return false;
2140 }
2141
2142 Mark(stmt->body());
2143 auto* body = builder_->create<sem::BlockStatement>(
2144 stmt->body(), current_compound_statement_);
2145 builder_->Sem().Add(stmt->body(), body);
2146 if (!Scope(body, [&] { return Statements(stmt->body()->list()); })) {
2147 return false;
2148 }
2149
2150 for (auto* else_stmt : stmt->else_statements()) {
2151 Mark(else_stmt);
2152 if (!ElseStatement(else_stmt)) {
2153 return false;
2154 }
2155 }
2156 return true;
2157 });
2158}
2159
2160bool Resolver::ElseStatement(ast::ElseStatement* stmt) {
2161 auto* sem =
2162 builder_->create<sem::ElseStatement>(stmt, current_compound_statement_);
2163 builder_->Sem().Add(stmt, sem);
2164 return Scope(sem, [&] {
2165 if (auto* cond = stmt->condition()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002166 Mark(cond);
2167 if (!Expression(cond)) {
2168 return false;
2169 }
Antonio Maiorano9fdfa1e2021-05-10 13:46:06 +00002170
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002171 auto* else_cond_type = TypeOf(cond)->UnwrapRef();
Ben Claytonc03d3bd2021-05-20 14:22:28 +00002172 if (!else_cond_type->Is<sem::Bool>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002173 AddError("else statement condition must be bool, got " +
2174 else_cond_type->FriendlyName(builder_->Symbols()),
2175 cond->source());
Antonio Maiorano9fdfa1e2021-05-10 13:46:06 +00002176 return false;
2177 }
Ben Claytondba65b72021-03-31 20:35:46 +00002178 }
Ben Clayton6e459fe2021-07-14 09:44:41 +00002179
2180 Mark(stmt->body());
2181 auto* body = builder_->create<sem::BlockStatement>(
2182 stmt->body(), current_compound_statement_);
2183 builder_->Sem().Add(stmt->body(), body);
2184 return Scope(body, [&] { return Statements(stmt->body()->list()); });
2185 });
2186}
2187
2188bool Resolver::BlockStatement(ast::BlockStatement* stmt) {
2189 auto* sem = builder_->create<sem::BlockStatement>(
2190 stmt->As<ast::BlockStatement>(), current_compound_statement_);
2191 builder_->Sem().Add(stmt, sem);
2192 return Scope(sem, [&] { return Statements(stmt->list()); });
Ben Clayton5fb87dd2021-03-09 15:17:28 +00002193}
2194
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002195bool Resolver::LoopStatement(ast::LoopStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002196 auto* sem =
2197 builder_->create<sem::LoopStatement>(stmt, current_compound_statement_);
2198 builder_->Sem().Add(stmt, sem);
2199 return Scope(sem, [&] {
2200 Mark(stmt->body());
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002201
Ben Clayton6e459fe2021-07-14 09:44:41 +00002202 auto* body = builder_->create<sem::LoopBlockStatement>(
2203 stmt->body(), current_compound_statement_);
2204 builder_->Sem().Add(stmt->body(), body);
2205 return Scope(body, [&] {
2206 if (!Statements(stmt->body()->list())) {
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002207 return false;
2208 }
Ben Clayton6e459fe2021-07-14 09:44:41 +00002209 if (stmt->continuing()) { // has_continuing() also checks for empty()
2210 Mark(stmt->continuing());
2211 }
2212 if (stmt->has_continuing()) {
2213 auto* continuing = builder_->create<sem::LoopContinuingBlockStatement>(
2214 stmt->continuing(), current_compound_statement_);
2215 builder_->Sem().Add(stmt->continuing(), continuing);
2216 if (!Scope(continuing,
2217 [&] { return Statements(stmt->continuing()->list()); })) {
2218 return false;
2219 }
2220 }
2221 return true;
2222 });
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002223 });
2224}
2225
Ben Claytonf4075a72021-07-02 19:27:42 +00002226bool Resolver::ForLoopStatement(ast::ForLoopStatement* stmt) {
Ben Clayton6e459fe2021-07-14 09:44:41 +00002227 auto* sem = builder_->create<sem::ForLoopStatement>(
2228 stmt, current_compound_statement_);
2229 builder_->Sem().Add(stmt, sem);
2230 return Scope(sem, [&] {
2231 if (auto* initializer = stmt->initializer()) {
2232 Mark(initializer);
2233 if (!Statement(initializer)) {
2234 return false;
2235 }
Ben Claytonf4075a72021-07-02 19:27:42 +00002236 }
2237
Ben Clayton6e459fe2021-07-14 09:44:41 +00002238 if (auto* condition = stmt->condition()) {
2239 Mark(condition);
2240 if (!Expression(condition)) {
2241 return false;
2242 }
Ben Claytonf4075a72021-07-02 19:27:42 +00002243
Ben Clayton6e459fe2021-07-14 09:44:41 +00002244 if (!TypeOf(condition)->Is<sem::Bool>()) {
2245 AddError(
2246 "for-loop condition must be bool, got " + TypeNameOf(condition),
2247 condition->source());
2248 return false;
2249 }
Ben Claytonf4075a72021-07-02 19:27:42 +00002250 }
Ben Claytonf4075a72021-07-02 19:27:42 +00002251
Ben Clayton6e459fe2021-07-14 09:44:41 +00002252 if (auto* continuing = stmt->continuing()) {
2253 Mark(continuing);
2254 if (!Statement(continuing)) {
2255 return false;
2256 }
2257 }
2258
2259 Mark(stmt->body());
2260
2261 auto* body = builder_->create<sem::LoopBlockStatement>(
2262 stmt->body(), current_compound_statement_);
2263 builder_->Sem().Add(stmt->body(), body);
2264 return Scope(body, [&] { return Statements(stmt->body()->statements()); });
2265 });
Ben Claytonf4075a72021-07-02 19:27:42 +00002266}
2267
Ben Clayton5f0ea112021-03-09 10:54:37 +00002268bool Resolver::Expressions(const ast::ExpressionList& list) {
Ben Claytonb053acf2020-11-16 16:31:07 +00002269 for (auto* expr : list) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002270 Mark(expr);
Ben Clayton5f0ea112021-03-09 10:54:37 +00002271 if (!Expression(expr)) {
dan sinclairfd5d4ca2020-04-20 15:46:18 +00002272 return false;
2273 }
2274 }
2275 return true;
2276}
2277
Ben Clayton5f0ea112021-03-09 10:54:37 +00002278bool Resolver::Expression(ast::Expression* expr) {
Ben Clayton33352542021-01-29 16:43:41 +00002279 if (TypeOf(expr)) {
2280 return true; // Already resolved
2281 }
2282
Ben Clayton313e6182021-06-17 19:56:14 +00002283 bool ok = false;
2284 if (auto* array = expr->As<ast::ArrayAccessorExpression>()) {
2285 ok = ArrayAccessor(array);
2286 } else if (auto* bin_op = expr->As<ast::BinaryExpression>()) {
2287 ok = Binary(bin_op);
2288 } else if (auto* bitcast = expr->As<ast::BitcastExpression>()) {
2289 ok = Bitcast(bitcast);
2290 } else if (auto* call = expr->As<ast::CallExpression>()) {
2291 ok = Call(call);
2292 } else if (auto* ctor = expr->As<ast::ConstructorExpression>()) {
2293 ok = Constructor(ctor);
2294 } else if (auto* ident = expr->As<ast::IdentifierExpression>()) {
2295 ok = Identifier(ident);
2296 } else if (auto* member = expr->As<ast::MemberAccessorExpression>()) {
2297 ok = MemberAccessor(member);
2298 } else if (auto* unary = expr->As<ast::UnaryOpExpression>()) {
2299 ok = UnaryOp(unary);
2300 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00002301 AddError("unknown expression for type determination", expr->source());
dan sinclair0e257622020-04-07 19:27:11 +00002302 }
dan sinclairb7edc4c2020-04-07 12:46:30 +00002303
Ben Clayton313e6182021-06-17 19:56:14 +00002304 if (!ok) {
2305 return false;
2306 }
2307
2308 auto* ty = TypeOf(expr);
2309 if (ty->Is<sem::Atomic>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002310 AddError("an expression must not evaluate to an atomic type",
2311 expr->source());
Ben Clayton313e6182021-06-17 19:56:14 +00002312 return false;
2313 }
2314
2315 return true;
dan sinclair417a90d2020-04-06 21:07:41 +00002316}
2317
Ben Clayton5f0ea112021-03-09 10:54:37 +00002318bool Resolver::ArrayAccessor(ast::ArrayAccessorExpression* expr) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002319 Mark(expr->array());
Ben Clayton5f0ea112021-03-09 10:54:37 +00002320 if (!Expression(expr->array())) {
dan sinclair973bd6a2020-04-07 12:57:42 +00002321 return false;
2322 }
Sarah10442ef2021-06-16 18:50:13 +00002323 auto* idx = expr->idx_expr();
2324 Mark(idx);
2325 if (!Expression(idx)) {
dan sinclair7cac2452020-05-01 16:17:03 +00002326 return false;
2327 }
dan sinclair8eddb782020-04-23 22:26:52 +00002328
Ben Clayton33352542021-01-29 16:43:41 +00002329 auto* res = TypeOf(expr->array());
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002330 auto* parent_type = res->UnwrapRef();
Ben Clayton4cd5eea2021-05-07 20:58:34 +00002331 const sem::Type* ret = nullptr;
2332 if (auto* arr = parent_type->As<sem::Array>()) {
2333 ret = arr->ElemType();
Antonio Maiorano3751fd22021-04-19 22:51:23 +00002334 } else if (auto* vec = parent_type->As<sem::Vector>()) {
Ben Clayton1b6a8ce2020-12-01 21:07:27 +00002335 ret = vec->type();
Antonio Maiorano3751fd22021-04-19 22:51:23 +00002336 } else if (auto* mat = parent_type->As<sem::Matrix>()) {
2337 ret = builder_->create<sem::Vector>(mat->type(), mat->rows());
dan sinclair973bd6a2020-04-07 12:57:42 +00002338 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00002339 AddError("invalid parent type (" + parent_type->type_name() +
2340 ") in array accessor",
2341 expr->source());
dan sinclair973bd6a2020-04-07 12:57:42 +00002342 return false;
2343 }
dan sinclair8eddb782020-04-23 22:26:52 +00002344
Sarah10442ef2021-06-16 18:50:13 +00002345 if (!TypeOf(idx)->UnwrapRef()->IsAnyOf<sem::I32, sem::U32>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002346 AddError("index must be of type 'i32' or 'u32', found: '" +
2347 TypeNameOf(idx) + "'",
2348 idx->source());
Sarah10442ef2021-06-16 18:50:13 +00002349 return false;
2350 }
2351
2352 if (parent_type->Is<sem::Array>() || parent_type->Is<sem::Matrix>()) {
2353 if (!res->Is<sem::Reference>()) {
2354 // TODO(bclayton): expand this to allow any const_expr expression
2355 // https://github.com/gpuweb/gpuweb/issues/1272
2356 auto* scalar = idx->As<ast::ScalarConstructorExpression>();
2357 if (!scalar || !scalar->literal()->As<ast::IntLiteral>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002358 AddError("index must be signed or unsigned integer literal",
2359 idx->source());
Sarah10442ef2021-06-16 18:50:13 +00002360 return false;
2361 }
2362 }
2363 }
2364
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002365 // If we're extracting from a reference, we return a reference.
2366 if (auto* ref = res->As<sem::Reference>()) {
Ben Clayton18588542021-06-04 22:17:37 +00002367 ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
2368 ref->Access());
dan sinclair8eddb782020-04-23 22:26:52 +00002369 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002370 SetExprInfo(expr, ret);
dan sinclair8eddb782020-04-23 22:26:52 +00002371
dan sinclair973bd6a2020-04-07 12:57:42 +00002372 return true;
2373}
2374
Ben Clayton5f0ea112021-03-09 10:54:37 +00002375bool Resolver::Bitcast(ast::BitcastExpression* expr) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002376 Mark(expr->expr());
Ben Clayton5f0ea112021-03-09 10:54:37 +00002377 if (!Expression(expr->expr())) {
dan sinclair8b48b262020-06-18 18:02:46 +00002378 return false;
2379 }
Ben Clayton0e66b402021-06-03 08:17:44 +00002380 auto* ty = Type(expr->type());
2381 if (!ty) {
2382 return false;
2383 }
Sarah4b1c9de2021-06-16 17:42:13 +00002384 if (ty->Is<sem::Pointer>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002385 AddError("cannot cast to a pointer", expr->source());
Sarah4b1c9de2021-06-16 17:42:13 +00002386 return false;
2387 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002388 SetExprInfo(expr, ty, expr->type()->FriendlyName(builder_->Symbols()));
dan sinclaira01777c2020-04-07 12:57:52 +00002389 return true;
2390}
2391
Ben Clayton5f0ea112021-03-09 10:54:37 +00002392bool Resolver::Call(ast::CallExpression* call) {
2393 if (!Expressions(call->params())) {
dan sinclairfd5d4ca2020-04-20 15:46:18 +00002394 return false;
dan sinclairccb52dc2020-04-20 14:18:54 +00002395 }
2396
Ben Clayton6fcefe42021-04-19 19:16:12 +00002397 Mark(call->func());
James Price28ec9682021-05-22 12:42:14 +00002398 auto* ident = call->func();
Ben Clayton1618f4b2021-02-03 21:02:25 +00002399 auto name = builder_->Symbols().NameFor(ident->symbol());
2400
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00002401 auto intrinsic_type = sem::ParseIntrinsicType(name);
Ben Clayton316f9f62021-02-08 22:31:44 +00002402 if (intrinsic_type != IntrinsicType::kNone) {
Ben Clayton5f0ea112021-03-09 10:54:37 +00002403 if (!IntrinsicCall(call, intrinsic_type)) {
Ben Clayton1618f4b2021-02-03 21:02:25 +00002404 return false;
2405 }
Ben Clayton33352542021-01-29 16:43:41 +00002406 } else {
Antonio Maiorano14b34032021-06-09 20:17:59 +00002407 if (!FunctionCall(call)) {
Ben Clayton1618f4b2021-02-03 21:02:25 +00002408 return false;
2409 }
Sarah Mashayekhi844f6322020-08-18 02:10:03 +00002410 }
2411
dan sinclair3ca87462020-04-07 16:41:10 +00002412 return true;
2413}
2414
Ben Clayton7fe01062021-06-11 13:22:27 +00002415bool Resolver::ValidateCallStatement(ast::CallStatement* stmt) {
2416 const sem::Type* return_type = nullptr;
2417 // A function call is made to either a user declared function or an intrinsic.
2418 // function_calls_ only maps CallExpression to user declared functions
2419 auto it = function_calls_.find(stmt->expr());
2420 if (it != function_calls_.end()) {
2421 return_type = it->second.function->return_type;
2422 } else {
2423 // Must be an intrinsic call
2424 auto* target = builder_->Sem().Get(stmt->expr())->Target();
2425 if (auto* intrinsic = target->As<sem::Intrinsic>()) {
2426 return_type = intrinsic->ReturnType();
2427 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00002428 TINT_ICE(Resolver, diagnostics_)
2429 << "call target was not an intrinsic, but a "
2430 << intrinsic->TypeInfo().name;
Ben Clayton7fe01062021-06-11 13:22:27 +00002431 }
2432 }
2433
2434 if (!return_type->Is<sem::Void>()) {
2435 // https://gpuweb.github.io/gpuweb/wgsl/#function-call-statement
2436 // A function call statement executes a function call where the called
2437 // function does not return a value. If the called function returns a value,
2438 // that value must be consumed either through assignment, evaluation in
2439 // another expression or through use of the ignore built-in function (see
2440 // § 16.13 Value-steering functions).
Ben Claytonffd28e22021-06-24 11:27:36 +00002441 AddError(
Ben Clayton7fe01062021-06-11 13:22:27 +00002442 "result of called function was not used. If this was intentional wrap "
2443 "the function call in ignore()",
2444 stmt->source());
2445 return false;
2446 }
2447 return true;
2448}
2449
Ben Clayton5f0ea112021-03-09 10:54:37 +00002450bool Resolver::IntrinsicCall(ast::CallExpression* call,
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00002451 sem::IntrinsicType intrinsic_type) {
Ben Clayton12ed13d2021-04-28 12:38:13 +00002452 std::vector<const sem::Type*> arg_tys;
Ben Clayton316f9f62021-02-08 22:31:44 +00002453 arg_tys.reserve(call->params().size());
2454 for (auto* expr : call->params()) {
2455 arg_tys.emplace_back(TypeOf(expr));
2456 }
2457
Ben Claytonb29a59d2021-06-01 19:06:31 +00002458 auto* result =
2459 intrinsic_table_->Lookup(intrinsic_type, arg_tys, call->source());
2460 if (!result) {
dan sinclairb4fee2f2020-09-22 19:42:13 +00002461 return false;
2462 }
2463
Ben Clayton3e59eb02021-06-10 17:31:54 +00002464 if (result->IsDeprecated()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002465 AddWarning("use of deprecated intrinsic", call->source());
Ben Clayton3e59eb02021-06-10 17:31:54 +00002466 }
2467
Sarah71198432021-07-16 13:38:05 +00002468 auto* out = builder_->create<sem::Call>(call, result, current_statement_);
2469 builder_->Sem().Add(call, out);
Ben Clayton71f619b2021-07-13 12:18:13 +00002470 SetExprInfo(call, result->ReturnType());
Ben Clayton71786c92021-06-03 16:07:34 +00002471
2472 current_function_->intrinsic_calls.emplace_back(
2473 IntrinsicCallInfo{call, result});
2474
Sarah71198432021-07-16 13:38:05 +00002475 if (IsTextureIntrinsic(intrinsic_type) &&
2476 !ValidateTextureIntrinsicFunction(call, out)) {
2477 return false;
2478 }
2479
2480 return true;
2481}
2482
2483bool Resolver::ValidateTextureIntrinsicFunction(
2484 const ast::CallExpression* ast_call,
2485 const sem::Call* sem_call) {
2486 auto* intrinsic = sem_call->Target()->As<sem::Intrinsic>();
2487 if (!intrinsic) {
2488 return false;
2489 }
2490 std::string func_name = intrinsic->str();
2491 auto index =
2492 sem::IndexOf(intrinsic->Parameters(), sem::ParameterUsage::kOffset);
2493 if (index > -1) {
2494 auto* param = ast_call->params()[index];
2495 if (param->Is<ast::TypeConstructorExpression>()) {
2496 auto values = ConstantValueOf(param);
2497 if (!values.IsValid()) {
Sarah36b49e82021-07-21 03:34:34 +00002498 AddError(
2499 "'" + func_name + "' offset parameter must be a const_expression",
2500 param->source());
Sarah71198432021-07-16 13:38:05 +00002501 return false;
2502 }
2503 if (!values.Type()->Is<sem::Vector>() ||
2504 !values.ElementType()->Is<sem::I32>()) {
2505 TINT_ICE(Resolver, diagnostics_)
2506 << "failed to resolve '" + func_name + "' offset parameter type";
2507 return false;
2508 }
2509 for (auto offset : values.Elements()) {
2510 auto offset_value = offset.i32;
2511 if (offset_value < -8 || offset_value > 7) {
2512 AddError("each offset component of '" + func_name +
2513 "' must be at least -8 and at most 7. "
2514 "found: '" +
2515 std::to_string(offset_value) + "'",
2516 param->source());
2517 return false;
2518 }
2519 }
2520 } else {
Sarah36b49e82021-07-21 03:34:34 +00002521 AddError(
2522 "'" + func_name + "' offset parameter must be a const_expression",
2523 param->source());
Sarah71198432021-07-16 13:38:05 +00002524 return false;
2525 }
2526 }
dan sinclairb4fee2f2020-09-22 19:42:13 +00002527 return true;
dan sinclair46e959d2020-06-01 13:43:22 +00002528}
2529
Antonio Maiorano14b34032021-06-09 20:17:59 +00002530bool Resolver::FunctionCall(const ast::CallExpression* call) {
2531 auto* ident = call->func();
2532 auto name = builder_->Symbols().NameFor(ident->symbol());
2533
2534 auto callee_func_it = symbol_to_function_.find(ident->symbol());
2535 if (callee_func_it == symbol_to_function_.end()) {
2536 if (current_function_ &&
2537 current_function_->declaration->symbol() == ident->symbol()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00002538 AddError("recursion is not permitted. '" + name +
Ben Claytonffd28e22021-06-24 11:27:36 +00002539 "' attempted to call itself.",
2540 call->source());
Antonio Maiorano14b34032021-06-09 20:17:59 +00002541 } else {
Ben Clayton5a88ec82021-06-29 14:42:19 +00002542 AddError("unable to find called function: " + name, call->source());
Antonio Maiorano14b34032021-06-09 20:17:59 +00002543 }
2544 return false;
2545 }
2546 auto* callee_func = callee_func_it->second;
2547
2548 if (current_function_) {
2549 callee_func->callsites.push_back(call);
2550
2551 // Note: Requires called functions to be resolved first.
2552 // This is currently guaranteed as functions must be declared before
2553 // use.
2554 current_function_->transitive_calls.add(callee_func);
2555 for (auto* transitive_call : callee_func->transitive_calls) {
2556 current_function_->transitive_calls.add(transitive_call);
2557 }
2558
2559 // We inherit any referenced variables from the callee.
2560 for (auto* var : callee_func->referenced_module_vars) {
2561 set_referenced_from_function_if_needed(var, false);
2562 }
2563 }
2564
Sarah3d441d42021-07-20 18:14:02 +00002565 function_calls_.emplace(call,
2566 FunctionCallInfo{callee_func, current_statement_});
2567 SetExprInfo(call, callee_func->return_type, callee_func->return_type_name);
2568
2569 if (!ValidateFunctionCall(call, callee_func)) {
2570 return false;
2571 }
2572 return true;
2573}
2574
2575bool Resolver::ValidateFunctionCall(const ast::CallExpression* call,
2576 const FunctionInfo* callee_func) {
2577 auto* ident = call->func();
2578 auto name = builder_->Symbols().NameFor(ident->symbol());
2579
Antonio Maiorano14b34032021-06-09 20:17:59 +00002580 if (call->params().size() != callee_func->parameters.size()) {
2581 bool more = call->params().size() > callee_func->parameters.size();
Ben Claytonffd28e22021-06-24 11:27:36 +00002582 AddError("too " + (more ? std::string("many") : std::string("few")) +
2583 " arguments in call to '" + name + "', expected " +
2584 std::to_string(callee_func->parameters.size()) + ", got " +
2585 std::to_string(call->params().size()),
2586 call->source());
Antonio Maiorano14b34032021-06-09 20:17:59 +00002587 return false;
2588 }
2589
Antonio Maiorano14b34032021-06-09 20:17:59 +00002590 for (size_t i = 0; i < call->params().size(); ++i) {
2591 const VariableInfo* param = callee_func->parameters[i];
2592 const ast::Expression* arg_expr = call->params()[i];
2593 auto* arg_type = TypeOf(arg_expr)->UnwrapRef();
2594
2595 if (param->type != arg_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002596 AddError("type mismatch for argument " + std::to_string(i + 1) +
2597 " in call to '" + name + "', expected '" +
2598 param->type->FriendlyName(builder_->Symbols()) + "', got '" +
2599 arg_type->FriendlyName(builder_->Symbols()) + "'",
2600 arg_expr->source());
Antonio Maiorano14b34032021-06-09 20:17:59 +00002601 return false;
2602 }
Sarah3d441d42021-07-20 18:14:02 +00002603
2604 if (param->declaration->type()->Is<ast::Pointer>()) {
2605 auto is_valid = false;
2606 if (auto* ident_expr = arg_expr->As<ast::IdentifierExpression>()) {
2607 VariableInfo* var;
2608 if (!variable_stack_.get(ident_expr->symbol(), &var)) {
2609 TINT_ICE(Resolver, diagnostics_) << "failed to resolve identifier";
2610 return false;
2611 }
2612 if (var->kind == VariableKind::kParameter) {
2613 is_valid = true;
2614 }
2615 } else if (auto* unary = arg_expr->As<ast::UnaryOpExpression>()) {
2616 if (unary->op() == ast::UnaryOp::kAddressOf) {
2617 if (auto* ident_unary =
2618 unary->expr()->As<ast::IdentifierExpression>()) {
2619 VariableInfo* var;
2620 if (!variable_stack_.get(ident_unary->symbol(), &var)) {
2621 TINT_ICE(Resolver, diagnostics_)
2622 << "failed to resolve identifier";
2623 return false;
2624 }
2625 if (var->declaration->is_const()) {
2626 TINT_ICE(Resolver, diagnostics_)
2627 << "Resolver::FunctionCall() encountered an address-of "
2628 "expression of a constant identifier expression";
2629 return false;
2630 }
2631 is_valid = true;
2632 }
2633 }
2634 }
2635
2636 if (!is_valid) {
2637 AddError(
2638 "expected an address-of expression of a variable identifier "
2639 "expression or a function parameter",
2640 arg_expr->source());
2641 return false;
2642 }
2643 }
Antonio Maiorano14b34032021-06-09 20:17:59 +00002644 }
Antonio Maiorano14b34032021-06-09 20:17:59 +00002645 return true;
2646}
2647
Ben Clayton5f0ea112021-03-09 10:54:37 +00002648bool Resolver::Constructor(ast::ConstructorExpression* expr) {
Arman Uguray3549e2e2021-03-15 21:21:33 +00002649 if (auto* type_ctor = expr->As<ast::TypeConstructorExpression>()) {
2650 for (auto* value : type_ctor->values()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002651 Mark(value);
Ben Clayton5f0ea112021-03-09 10:54:37 +00002652 if (!Expression(value)) {
dan sinclair361e4572020-04-24 00:41:12 +00002653 return false;
2654 }
2655 }
Ben Clayton109b18f2021-04-28 13:50:43 +00002656
Ben Clayton0e66b402021-06-03 08:17:44 +00002657 auto* type = Type(type_ctor->type());
2658 if (!type) {
2659 return false;
2660 }
Arman Uguray3549e2e2021-03-15 21:21:33 +00002661
Ben Clayton71f619b2021-07-13 12:18:13 +00002662 auto type_name = type_ctor->type()->FriendlyName(builder_->Symbols());
Ben Clayton02ebf0d2021-05-05 09:09:41 +00002663
Arman Uguray3549e2e2021-03-15 21:21:33 +00002664 // Now that the argument types have been determined, make sure that they
2665 // obey the constructor type rules laid out in
2666 // https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr.
Sarah4b1c9de2021-06-16 17:42:13 +00002667 if (type->Is<sem::Pointer>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002668 AddError("cannot cast to a pointer", expr->source());
Sarah4b1c9de2021-06-16 17:42:13 +00002669 return false;
2670 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002671
2672 bool ok = true;
Ben Clayton02ebf0d2021-05-05 09:09:41 +00002673 if (auto* vec_type = type->As<sem::Vector>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00002674 ok = ValidateVectorConstructor(type_ctor, vec_type, type_name);
2675 } else if (auto* mat_type = type->As<sem::Matrix>()) {
2676 ok = ValidateMatrixConstructor(type_ctor, mat_type, type_name);
2677 } else if (type->is_scalar()) {
2678 ok = ValidateScalarConstructor(type_ctor, type, type_name);
2679 } else if (auto* arr_type = type->As<sem::Array>()) {
2680 ok = ValidateArrayConstructor(type_ctor, arr_type);
2681 } else if (auto* struct_type = type->As<sem::Struct>()) {
2682 ok = ValidateStructureConstructor(type_ctor, struct_type);
Arman Uguray3549e2e2021-03-15 21:21:33 +00002683 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002684 if (!ok) {
2685 return false;
Arman Uguray097c75a2021-03-18 15:43:14 +00002686 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002687 SetExprInfo(expr, type, type_name);
2688 return true;
2689 }
2690
2691 if (auto* scalar_ctor = expr->As<ast::ScalarConstructorExpression>()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002692 Mark(scalar_ctor->literal());
Ben Clayton0e66b402021-06-03 08:17:44 +00002693 auto* type = TypeOf(scalar_ctor->literal());
2694 if (!type) {
2695 return false;
2696 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002697 SetExprInfo(expr, type);
2698 return true;
Arman Uguray3549e2e2021-03-15 21:21:33 +00002699 }
Ben Clayton71f619b2021-07-13 12:18:13 +00002700
2701 TINT_ICE(Resolver, diagnostics_) << "unexpected constructor expression type";
2702 return false;
Arman Uguray3549e2e2021-03-15 21:21:33 +00002703}
2704
Sarahe2859112021-07-09 16:32:00 +00002705bool Resolver::ValidateStructureConstructor(
2706 const ast::TypeConstructorExpression* ctor,
2707 const sem::Struct* struct_type) {
2708 if (ctor->values().size() > 0) {
2709 if (ctor->values().size() != struct_type->Members().size()) {
2710 std::string fm = ctor->values().size() < struct_type->Members().size()
2711 ? "few"
2712 : "many";
2713 AddError("struct constructor has too " + fm + " inputs: expected " +
2714 std::to_string(struct_type->Members().size()) + ", found " +
2715 std::to_string(ctor->values().size()),
2716 ctor->source());
2717 return false;
2718 }
2719 for (auto* member : struct_type->Members()) {
2720 auto* value = ctor->values()[member->Index()];
2721 if (member->Type() != TypeOf(value)->UnwrapRef()) {
2722 AddError(
2723 "type in struct constructor does not match struct member type: "
2724 "expected '" +
2725 member->Type()->FriendlyName(builder_->Symbols()) +
2726 "', found '" + TypeNameOf(value) + "'",
2727 value->source());
2728 return false;
2729 }
2730 }
2731 }
2732 return true;
2733}
2734
Sarah5a4dc9a2021-06-11 15:51:26 +00002735bool Resolver::ValidateArrayConstructor(
2736 const ast::TypeConstructorExpression* ctor,
2737 const sem::Array* array_type) {
2738 auto& values = ctor->values();
2739 auto* elem_type = array_type->ElemType();
2740 for (auto* value : values) {
2741 auto* value_type = TypeOf(value)->UnwrapRef();
2742 if (value_type != elem_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002743 AddError(
Sarah5a4dc9a2021-06-11 15:51:26 +00002744 "type in array constructor does not match array type: "
2745 "expected '" +
2746 elem_type->FriendlyName(builder_->Symbols()) + "', found '" +
2747 TypeNameOf(value) + "'",
2748 value->source());
2749 return false;
2750 }
2751 }
2752
2753 if (array_type->IsRuntimeSized()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002754 AddError("cannot init a runtime-sized array", ctor->source());
Sarah5a4dc9a2021-06-11 15:51:26 +00002755 return false;
2756 } else if (!values.empty() && (values.size() != array_type->Count())) {
2757 std::string fm = values.size() < array_type->Count() ? "few" : "many";
Ben Claytonffd28e22021-06-24 11:27:36 +00002758 AddError("array constructor has too " + fm + " elements: expected " +
2759 std::to_string(array_type->Count()) + ", found " +
2760 std::to_string(values.size()),
2761 ctor->source());
Sarah5a4dc9a2021-06-11 15:51:26 +00002762 return false;
2763 } else if (values.size() > array_type->Count()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002764 AddError("array constructor has too many elements: expected " +
2765 std::to_string(array_type->Count()) + ", found " +
2766 std::to_string(values.size()),
2767 ctor->source());
Sarah5a4dc9a2021-06-11 15:51:26 +00002768 return false;
2769 }
2770 return true;
2771}
2772
Ben Clayton109b18f2021-04-28 13:50:43 +00002773bool Resolver::ValidateVectorConstructor(
2774 const ast::TypeConstructorExpression* ctor,
Ben Clayton71f619b2021-07-13 12:18:13 +00002775 const sem::Vector* vec_type,
2776 const std::string& type_name) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00002777 auto& values = ctor->values();
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002778 auto* elem_type = vec_type->type();
Arman Uguray3549e2e2021-03-15 21:21:33 +00002779 size_t value_cardinality_sum = 0;
2780 for (auto* value : values) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002781 auto* value_type = TypeOf(value)->UnwrapRef();
Arman Uguray3549e2e2021-03-15 21:21:33 +00002782 if (value_type->is_scalar()) {
2783 if (elem_type != value_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002784 AddError(
Arman Uguray3549e2e2021-03-15 21:21:33 +00002785 "type in vector constructor does not match vector type: "
2786 "expected '" +
2787 elem_type->FriendlyName(builder_->Symbols()) + "', found '" +
Ben Clayton109b18f2021-04-28 13:50:43 +00002788 TypeNameOf(value) + "'",
Arman Uguray3549e2e2021-03-15 21:21:33 +00002789 value->source());
2790 return false;
2791 }
2792
2793 value_cardinality_sum++;
Antonio Maiorano3751fd22021-04-19 22:51:23 +00002794 } else if (auto* value_vec = value_type->As<sem::Vector>()) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002795 auto* value_elem_type = value_vec->type();
Arman Uguray3549e2e2021-03-15 21:21:33 +00002796 // A mismatch of vector type parameter T is only an error if multiple
2797 // arguments are present. A single argument constructor constitutes a
2798 // type conversion expression.
James Price1fa28ac2021-07-19 17:35:39 +00002799 if (elem_type != value_elem_type && values.size() > 1u) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002800 AddError(
Arman Uguray3549e2e2021-03-15 21:21:33 +00002801 "type in vector constructor does not match vector type: "
2802 "expected '" +
2803 elem_type->FriendlyName(builder_->Symbols()) + "', found '" +
2804 value_elem_type->FriendlyName(builder_->Symbols()) + "'",
2805 value->source());
2806 return false;
2807 }
2808
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00002809 value_cardinality_sum += value_vec->Width();
Arman Uguray3549e2e2021-03-15 21:21:33 +00002810 } else {
2811 // A vector constructor can only accept vectors and scalars.
Ben Claytonffd28e22021-06-24 11:27:36 +00002812 AddError("expected vector or scalar type in vector constructor; found: " +
2813 value_type->FriendlyName(builder_->Symbols()),
2814 value->source());
Arman Uguray3549e2e2021-03-15 21:21:33 +00002815 return false;
2816 }
2817 }
2818
Antonio Maioranob5508fd2021-06-10 13:23:31 +00002819 // A correct vector constructor must either be a zero-value expression,
2820 // a single-value initializer (splat) expression, or the number of components
2821 // of all constructor arguments must add up to the vector cardinality.
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00002822 if (value_cardinality_sum > 1 && value_cardinality_sum != vec_type->Width()) {
Arman Uguray3549e2e2021-03-15 21:21:33 +00002823 if (values.empty()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002824 TINT_ICE(Resolver, diagnostics_)
Arman Uguray3549e2e2021-03-15 21:21:33 +00002825 << "constructor arguments expected to be non-empty!";
2826 }
2827 const Source& values_start = values[0]->source();
2828 const Source& values_end = values[values.size() - 1]->source();
Ben Clayton71f619b2021-07-13 12:18:13 +00002829 AddError("attempted to construct '" + type_name + "' with " +
Ben Claytonffd28e22021-06-24 11:27:36 +00002830 std::to_string(value_cardinality_sum) + " component(s)",
2831 Source::Combine(values_start, values_end));
Arman Uguray3549e2e2021-03-15 21:21:33 +00002832 return false;
dan sinclairb7edc4c2020-04-07 12:46:30 +00002833 }
2834 return true;
2835}
2836
Ben Claytonffe79782021-07-05 20:21:35 +00002837bool Resolver::ValidateVector(const sem::Vector* ty, const Source& source) {
2838 if (!ty->type()->is_scalar()) {
2839 AddError("vector element type must be 'bool', 'f32', 'i32' or 'u32'",
2840 source);
2841 return false;
2842 }
2843 return true;
2844}
2845
2846bool Resolver::ValidateMatrix(const sem::Matrix* ty, const Source& source) {
2847 if (!ty->is_float_matrix()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002848 AddError("matrix element type must be 'f32'", source);
Sarah4d697512021-06-21 17:08:05 +00002849 return false;
2850 }
2851 return true;
Ben Claytonffe79782021-07-05 20:21:35 +00002852}
Sarah4d697512021-06-21 17:08:05 +00002853
Ben Clayton109b18f2021-04-28 13:50:43 +00002854bool Resolver::ValidateMatrixConstructor(
2855 const ast::TypeConstructorExpression* ctor,
Ben Clayton71f619b2021-07-13 12:18:13 +00002856 const sem::Matrix* matrix_type,
2857 const std::string& type_name) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00002858 auto& values = ctor->values();
Arman Uguray097c75a2021-03-18 15:43:14 +00002859 // Zero Value expression
2860 if (values.empty()) {
2861 return true;
2862 }
2863
Sarah4d697512021-06-21 17:08:05 +00002864 if (!ValidateMatrix(matrix_type, ctor->source())) {
2865 return false;
2866 }
2867
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002868 auto* elem_type = matrix_type->type();
Arman Uguray097c75a2021-03-18 15:43:14 +00002869 if (matrix_type->columns() != values.size()) {
2870 const Source& values_start = values[0]->source();
2871 const Source& values_end = values[values.size() - 1]->source();
Ben Claytonffd28e22021-06-24 11:27:36 +00002872 AddError("expected " + std::to_string(matrix_type->columns()) + " '" +
2873 VectorPretty(matrix_type->rows(), elem_type) +
Ben Clayton71f619b2021-07-13 12:18:13 +00002874 "' arguments in '" + type_name + "' constructor, found " +
2875 std::to_string(values.size()),
Ben Claytonffd28e22021-06-24 11:27:36 +00002876 Source::Combine(values_start, values_end));
Arman Uguray097c75a2021-03-18 15:43:14 +00002877 return false;
2878 }
2879
2880 for (auto* value : values) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002881 auto* value_type = TypeOf(value)->UnwrapRef();
Antonio Maiorano3751fd22021-04-19 22:51:23 +00002882 auto* value_vec = value_type->As<sem::Vector>();
Arman Uguray097c75a2021-03-18 15:43:14 +00002883
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00002884 if (!value_vec || value_vec->Width() != matrix_type->rows() ||
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002885 elem_type != value_vec->type()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002886 AddError("expected argument type '" +
2887 VectorPretty(matrix_type->rows(), elem_type) + "' in '" +
Ben Clayton71f619b2021-07-13 12:18:13 +00002888 type_name + "' constructor, found '" + TypeNameOf(value) +
2889 "'",
Ben Claytonffd28e22021-06-24 11:27:36 +00002890 value->source());
Arman Uguray097c75a2021-03-18 15:43:14 +00002891 return false;
2892 }
2893 }
2894
2895 return true;
2896}
2897
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002898bool Resolver::ValidateScalarConstructor(
2899 const ast::TypeConstructorExpression* ctor,
Ben Clayton71f619b2021-07-13 12:18:13 +00002900 const sem::Type* type,
2901 const std::string& type_name) {
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002902 if (ctor->values().size() == 0) {
2903 return true;
2904 }
2905 if (ctor->values().size() > 1) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002906 AddError("expected zero or one value in constructor, got " +
2907 std::to_string(ctor->values().size()),
2908 ctor->source());
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002909 return false;
2910 }
2911
2912 // Validate constructor
2913 auto* value = ctor->values()[0];
2914 auto* value_type = TypeOf(value)->UnwrapRef();
2915
2916 using Bool = sem::Bool;
2917 using I32 = sem::I32;
2918 using U32 = sem::U32;
2919 using F32 = sem::F32;
2920
James Price1fa28ac2021-07-19 17:35:39 +00002921 const bool is_valid = (type->Is<Bool>() && value_type->is_scalar()) ||
2922 (type->Is<I32>() && value_type->is_scalar()) ||
2923 (type->Is<U32>() && value_type->is_scalar()) ||
2924 (type->Is<F32>() && value_type->is_scalar());
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002925 if (!is_valid) {
Ben Clayton71f619b2021-07-13 12:18:13 +00002926 AddError("cannot construct '" + type_name + "' with a value of type '" +
2927 TypeNameOf(value) + "'",
Ben Claytonffd28e22021-06-24 11:27:36 +00002928 ctor->source());
Antonio Maioranoadbbd0b2021-06-18 15:32:21 +00002929
2930 return false;
2931 }
2932
2933 return true;
2934}
2935
Ben Clayton5f0ea112021-03-09 10:54:37 +00002936bool Resolver::Identifier(ast::IdentifierExpression* expr) {
dan sinclair795b6b52021-01-11 15:10:19 +00002937 auto symbol = expr->symbol();
Ben Claytonb17aea12021-02-03 17:51:09 +00002938 VariableInfo* var;
dan sinclair795b6b52021-01-11 15:10:19 +00002939 if (variable_stack_.get(symbol, &var)) {
Ben Clayton71f619b2021-07-13 12:18:13 +00002940 SetExprInfo(expr, var->type, var->type_name);
dan sinclair13d2a3b2020-06-22 20:52:24 +00002941
James Pricec9af5972021-02-16 21:15:01 +00002942 var->users.push_back(expr);
Enrico Galli3d449d22020-12-08 21:07:24 +00002943 set_referenced_from_function_if_needed(var, true);
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002944
James Pricea07d21a2021-03-22 17:25:56 +00002945 if (current_block_) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00002946 // If identifier is part of a loop continuing block, make sure it
2947 // doesn't refer to a variable that is bypassed by a continue statement
2948 // in the loop's body block.
Ben Clayton9a3ba022021-05-19 21:22:07 +00002949 if (auto* continuing_block =
2950 current_block_
2951 ->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
James Pricea07d21a2021-03-22 17:25:56 +00002952 auto* loop_block =
Ben Clayton9a3ba022021-05-19 21:22:07 +00002953 continuing_block->FindFirstParent<sem::LoopBlockStatement>();
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002954 if (loop_block->FirstContinue() != size_t(~0)) {
2955 auto& decls = loop_block->Decls();
James Pricea07d21a2021-03-22 17:25:56 +00002956 // If our identifier is in loop_block->decls, make sure its index is
2957 // less than first_continue
2958 auto iter = std::find_if(
2959 decls.begin(), decls.end(),
2960 [&symbol](auto* v) { return v->symbol() == symbol; });
2961 if (iter != decls.end()) {
2962 auto var_decl_index =
2963 static_cast<size_t>(std::distance(decls.begin(), iter));
Alastair F. Donaldsonac908292021-05-15 14:48:46 +00002964 if (var_decl_index >= loop_block->FirstContinue()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002965 AddError("continue statement bypasses declaration of '" +
2966 builder_->Symbols().NameFor(symbol) +
2967 "' in continuing block",
2968 expr->source());
James Pricea07d21a2021-03-22 17:25:56 +00002969 return false;
2970 }
Antonio Maioranofd31bbd2021-03-09 10:26:57 +00002971 }
2972 }
2973 }
2974 }
2975
dan sinclaircab0e732020-04-07 12:57:27 +00002976 return true;
2977 }
2978
Ben Claytonf6866a22021-01-11 22:02:42 +00002979 auto iter = symbol_to_function_.find(symbol);
dan sinclair4ac65682021-01-11 16:24:32 +00002980 if (iter != symbol_to_function_.end()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002981 AddError("missing '(' for function call", expr->source().End());
Ben Clayton33a8cdd2021-02-24 13:31:22 +00002982 return false;
dan sinclaircab0e732020-04-07 12:57:27 +00002983 }
2984
Ben Clayton1618f4b2021-02-03 21:02:25 +00002985 std::string name = builder_->Symbols().NameFor(symbol);
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00002986 if (sem::ParseIntrinsicType(name) != IntrinsicType::kNone) {
Ben Claytonffd28e22021-06-24 11:27:36 +00002987 AddError("missing '(' for intrinsic call", expr->source().End());
Ben Clayton33a8cdd2021-02-24 13:31:22 +00002988 return false;
dan sinclairff267ca2020-10-14 18:26:31 +00002989 }
Ben Clayton1618f4b2021-02-03 21:02:25 +00002990
Ben Clayton5a88ec82021-06-29 14:42:19 +00002991 AddError("identifier must be declared before use: " + name, expr->source());
Ben Clayton1618f4b2021-02-03 21:02:25 +00002992 return false;
dan sinclair8ee1d222020-04-07 16:41:33 +00002993}
2994
Ben Clayton5f0ea112021-03-09 10:54:37 +00002995bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00002996 Mark(expr->structure());
Ben Clayton5f0ea112021-03-09 10:54:37 +00002997 if (!Expression(expr->structure())) {
dan sinclair8ee1d222020-04-07 16:41:33 +00002998 return false;
2999 }
3000
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003001 auto* structure = TypeOf(expr->structure());
3002 auto* storage_type = structure->UnwrapRef();
dan sinclairb445a9b2020-04-24 00:40:45 +00003003
Antonio Maiorano3751fd22021-04-19 22:51:23 +00003004 sem::Type* ret = nullptr;
Ben Clayton6d612ad2021-02-24 14:15:02 +00003005 std::vector<uint32_t> swizzle;
Ben Claytonc1052a42021-02-03 23:55:56 +00003006
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003007 if (auto* str = storage_type->As<sem::Struct>()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00003008 Mark(expr->member());
dan sinclaireb737c22021-01-11 16:24:32 +00003009 auto symbol = expr->member()->symbol();
dan sinclair8ee1d222020-04-07 16:41:33 +00003010
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003011 const sem::StructMember* member = nullptr;
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003012 for (auto* m : str->Members()) {
Ben Clayton053559d2021-07-23 16:43:01 +00003013 if (m->Name() == symbol) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00003014 ret = m->Type();
Ben Claytone9c49842021-04-09 13:56:08 +00003015 member = m;
dan sinclair8eddb782020-04-23 22:26:52 +00003016 break;
dan sinclair8ee1d222020-04-07 16:41:33 +00003017 }
dan sinclair8ee1d222020-04-07 16:41:33 +00003018 }
3019
dan sinclair8eddb782020-04-23 22:26:52 +00003020 if (ret == nullptr) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003021 AddError(
Ben Clayton6b4924f2021-02-17 20:13:34 +00003022 "struct member " + builder_->Symbols().NameFor(symbol) + " not found",
3023 expr->source());
dan sinclair8eddb782020-04-23 22:26:52 +00003024 return false;
3025 }
dan sinclair7cac2452020-05-01 16:17:03 +00003026
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003027 // If we're extracting from a reference, we return a reference.
3028 if (auto* ref = structure->As<sem::Reference>()) {
Ben Clayton18588542021-06-04 22:17:37 +00003029 ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
3030 ref->Access());
dan sinclair7cac2452020-05-01 16:17:03 +00003031 }
Ben Claytone9c49842021-04-09 13:56:08 +00003032
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003033 builder_->Sem().Add(expr, builder_->create<sem::StructMemberAccess>(
Ben Claytone9c49842021-04-09 13:56:08 +00003034 expr, ret, current_statement_, member));
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003035 } else if (auto* vec = storage_type->As<sem::Vector>()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00003036 Mark(expr->member());
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003037 std::string s = builder_->Symbols().NameFor(expr->member()->symbol());
3038 auto size = s.size();
3039 swizzle.reserve(s.size());
dan sinclaireb737c22021-01-11 16:24:32 +00003040
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003041 for (auto c : s) {
Ben Clayton6d612ad2021-02-24 14:15:02 +00003042 switch (c) {
3043 case 'x':
3044 case 'r':
3045 swizzle.emplace_back(0);
3046 break;
3047 case 'y':
3048 case 'g':
3049 swizzle.emplace_back(1);
3050 break;
3051 case 'z':
3052 case 'b':
3053 swizzle.emplace_back(2);
3054 break;
3055 case 'w':
3056 case 'a':
3057 swizzle.emplace_back(3);
3058 break;
3059 default:
Ben Claytonffd28e22021-06-24 11:27:36 +00003060 AddError("invalid vector swizzle character",
3061 expr->member()->source().Begin() + swizzle.size());
Ben Clayton6d612ad2021-02-24 14:15:02 +00003062 return false;
3063 }
Antonio Maiorano39c05a92021-06-01 00:37:40 +00003064
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003065 if (swizzle.back() >= vec->Width()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003066 AddError("invalid vector swizzle member", expr->member()->source());
Antonio Maiorano39c05a92021-06-01 00:37:40 +00003067 return false;
3068 }
Ben Clayton6d612ad2021-02-24 14:15:02 +00003069 }
3070
3071 if (size < 1 || size > 4) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003072 AddError("invalid vector swizzle size", expr->member()->source());
Ben Clayton6d612ad2021-02-24 14:15:02 +00003073 return false;
3074 }
3075
Antonio Maioranofe2b4172021-03-01 20:01:39 +00003076 // All characters are valid, check if they're being mixed
3077 auto is_rgba = [](char c) {
3078 return c == 'r' || c == 'g' || c == 'b' || c == 'a';
3079 };
3080 auto is_xyzw = [](char c) {
3081 return c == 'x' || c == 'y' || c == 'z' || c == 'w';
3082 };
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003083 if (!std::all_of(s.begin(), s.end(), is_rgba) &&
3084 !std::all_of(s.begin(), s.end(), is_xyzw)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003085 AddError("invalid mixing of vector swizzle characters rgba with xyzw",
3086 expr->member()->source());
Antonio Maioranofe2b4172021-03-01 20:01:39 +00003087 return false;
3088 }
3089
dan sinclairaac58652020-04-21 13:05:34 +00003090 if (size == 1) {
3091 // A single element swizzle is just the type of the vector.
dan sinclair8eddb782020-04-23 22:26:52 +00003092 ret = vec->type();
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003093 // If we're extracting from a reference, we return a reference.
3094 if (auto* ref = structure->As<sem::Reference>()) {
Ben Clayton18588542021-06-04 22:17:37 +00003095 ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
3096 ref->Access());
dan sinclair7cac2452020-05-01 16:17:03 +00003097 }
dan sinclairaac58652020-04-21 13:05:34 +00003098 } else {
Ben Clayton6d612ad2021-02-24 14:15:02 +00003099 // The vector will have a number of components equal to the length of
Antonio Maioranod15391e2021-04-08 14:08:47 +00003100 // the swizzle.
Antonio Maiorano3751fd22021-04-19 22:51:23 +00003101 ret = builder_->create<sem::Vector>(vec->type(),
3102 static_cast<uint32_t>(size));
dan sinclairaac58652020-04-21 13:05:34 +00003103 }
Ben Claytone9c49842021-04-09 13:56:08 +00003104 builder_->Sem().Add(
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003105 expr, builder_->create<sem::Swizzle>(expr, ret, current_statement_,
3106 std::move(swizzle)));
dan sinclair8eddb782020-04-23 22:26:52 +00003107 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00003108 AddError("invalid use of member accessor on a non-vector/non-struct " +
3109 TypeNameOf(expr->structure()),
3110 expr->source());
dan sinclair8eddb782020-04-23 22:26:52 +00003111 return false;
dan sinclair8ee1d222020-04-07 16:41:33 +00003112 }
3113
Ben Clayton71f619b2021-07-13 12:18:13 +00003114 SetExprInfo(expr, ret);
dan sinclair8eddb782020-04-23 22:26:52 +00003115
3116 return true;
dan sinclaircab0e732020-04-07 12:57:27 +00003117}
3118
Antonio Maiorano0131ce22021-05-27 18:25:06 +00003119bool Resolver::Binary(ast::BinaryExpression* expr) {
3120 Mark(expr->lhs());
3121 Mark(expr->rhs());
3122
3123 if (!Expression(expr->lhs()) || !Expression(expr->rhs())) {
3124 return false;
3125 }
3126
Antonio Maiorano3751fd22021-04-19 22:51:23 +00003127 using Bool = sem::Bool;
3128 using F32 = sem::F32;
3129 using I32 = sem::I32;
3130 using U32 = sem::U32;
3131 using Matrix = sem::Matrix;
3132 using Vector = sem::Vector;
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003133
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003134 auto* lhs_type = const_cast<sem::Type*>(TypeOf(expr->lhs())->UnwrapRef());
3135 auto* rhs_type = const_cast<sem::Type*>(TypeOf(expr->rhs())->UnwrapRef());
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003136
3137 auto* lhs_vec = lhs_type->As<Vector>();
Antonio Maiorano25436862021-04-13 13:32:33 +00003138 auto* lhs_vec_elem_type = lhs_vec ? lhs_vec->type() : nullptr;
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003139 auto* rhs_vec = rhs_type->As<Vector>();
Antonio Maiorano25436862021-04-13 13:32:33 +00003140 auto* rhs_vec_elem_type = rhs_vec ? rhs_vec->type() : nullptr;
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003141
Antonio Maiorano61dabab2021-04-01 19:58:37 +00003142 const bool matching_vec_elem_types =
3143 lhs_vec_elem_type && rhs_vec_elem_type &&
3144 (lhs_vec_elem_type == rhs_vec_elem_type) &&
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003145 (lhs_vec->Width() == rhs_vec->Width());
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003146
Antonio Maiorano15c6ed02021-04-01 14:59:27 +00003147 const bool matching_types = matching_vec_elem_types || (lhs_type == rhs_type);
3148
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003149 // Binary logical expressions
3150 if (expr->IsLogicalAnd() || expr->IsLogicalOr()) {
3151 if (matching_types && lhs_type->Is<Bool>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003152 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003153 return true;
3154 }
3155 }
3156 if (expr->IsOr() || expr->IsAnd()) {
3157 if (matching_types && lhs_type->Is<Bool>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003158 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003159 return true;
3160 }
3161 if (matching_types && lhs_vec_elem_type && lhs_vec_elem_type->Is<Bool>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003162 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003163 return true;
3164 }
3165 }
3166
3167 // Arithmetic expressions
3168 if (expr->IsArithmetic()) {
3169 // Binary arithmetic expressions over scalars
Antonio Maiorano0131ce22021-05-27 18:25:06 +00003170 if (matching_types && lhs_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003171 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003172 return true;
3173 }
3174
3175 // Binary arithmetic expressions over vectors
3176 if (matching_types && lhs_vec_elem_type &&
Antonio Maiorano0131ce22021-05-27 18:25:06 +00003177 lhs_vec_elem_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003178 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003179 return true;
3180 }
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003181
3182 // Binary arithmetic expressions with mixed scalar and vector operands
3183 if (lhs_vec_elem_type && (lhs_vec_elem_type == rhs_type)) {
3184 if (expr->IsModulo()) {
3185 if (rhs_type->is_integer_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003186 SetExprInfo(expr, lhs_type);
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003187 return true;
3188 }
3189 } else if (rhs_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003190 SetExprInfo(expr, lhs_type);
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003191 return true;
3192 }
3193 }
3194 if (rhs_vec_elem_type && (rhs_vec_elem_type == lhs_type)) {
3195 if (expr->IsModulo()) {
3196 if (lhs_type->is_integer_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003197 SetExprInfo(expr, rhs_type);
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003198 return true;
3199 }
3200 } else if (lhs_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003201 SetExprInfo(expr, rhs_type);
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003202 return true;
3203 }
3204 }
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003205 }
3206
Antonio Maioranoeaed2b62021-05-27 21:07:56 +00003207 // Matrix arithmetic
Antonio Maioranoc91f8f22021-05-31 15:53:20 +00003208 auto* lhs_mat = lhs_type->As<Matrix>();
3209 auto* lhs_mat_elem_type = lhs_mat ? lhs_mat->type() : nullptr;
3210 auto* rhs_mat = rhs_type->As<Matrix>();
3211 auto* rhs_mat_elem_type = rhs_mat ? rhs_mat->type() : nullptr;
3212 // Addition and subtraction of float matrices
3213 if ((expr->IsAdd() || expr->IsSubtract()) && lhs_mat_elem_type &&
3214 lhs_mat_elem_type->Is<F32>() && rhs_mat_elem_type &&
3215 rhs_mat_elem_type->Is<F32>() &&
3216 (lhs_mat->columns() == rhs_mat->columns()) &&
3217 (lhs_mat->rows() == rhs_mat->rows())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003218 SetExprInfo(expr, rhs_type);
Antonio Maioranoc91f8f22021-05-31 15:53:20 +00003219 return true;
3220 }
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003221 if (expr->IsMultiply()) {
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003222 // Multiplication of a matrix and a scalar
3223 if (lhs_type->Is<F32>() && rhs_mat_elem_type &&
3224 rhs_mat_elem_type->Is<F32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003225 SetExprInfo(expr, rhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003226 return true;
3227 }
3228 if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() &&
3229 rhs_type->Is<F32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003230 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003231 return true;
3232 }
3233
3234 // Vector times matrix
3235 if (lhs_vec_elem_type && lhs_vec_elem_type->Is<F32>() &&
Antonio Maiorano61dabab2021-04-01 19:58:37 +00003236 rhs_mat_elem_type && rhs_mat_elem_type->Is<F32>() &&
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003237 (lhs_vec->Width() == rhs_mat->rows())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003238 SetExprInfo(expr, builder_->create<sem::Vector>(lhs_vec->type(),
3239 rhs_mat->columns()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003240 return true;
3241 }
3242
3243 // Matrix times vector
3244 if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() &&
Antonio Maiorano61dabab2021-04-01 19:58:37 +00003245 rhs_vec_elem_type && rhs_vec_elem_type->Is<F32>() &&
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003246 (lhs_mat->columns() == rhs_vec->Width())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003247 SetExprInfo(expr, builder_->create<sem::Vector>(rhs_vec->type(),
3248 lhs_mat->rows()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003249 return true;
3250 }
3251
3252 // Matrix times matrix
3253 if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() &&
Antonio Maiorano61dabab2021-04-01 19:58:37 +00003254 rhs_mat_elem_type && rhs_mat_elem_type->Is<F32>() &&
3255 (lhs_mat->columns() == rhs_mat->rows())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003256 SetExprInfo(expr, builder_->create<sem::Matrix>(
3257 builder_->create<sem::Vector>(lhs_mat_elem_type,
3258 lhs_mat->rows()),
3259 rhs_mat->columns()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003260 return true;
3261 }
3262 }
3263
3264 // Comparison expressions
3265 if (expr->IsComparison()) {
3266 if (matching_types) {
3267 // Special case for bools: only == and !=
3268 if (lhs_type->Is<Bool>() && (expr->IsEqual() || expr->IsNotEqual())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003269 SetExprInfo(expr, builder_->create<sem::Bool>());
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003270 return true;
3271 }
3272
3273 // For the rest, we can compare i32, u32, and f32
3274 if (lhs_type->IsAnyOf<I32, U32, F32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003275 SetExprInfo(expr, builder_->create<sem::Bool>());
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003276 return true;
3277 }
3278 }
3279
3280 // Same for vectors
3281 if (matching_vec_elem_types) {
3282 if (lhs_vec_elem_type->Is<Bool>() &&
3283 (expr->IsEqual() || expr->IsNotEqual())) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003284 SetExprInfo(expr, builder_->create<sem::Vector>(
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003285 builder_->create<sem::Bool>(), lhs_vec->Width()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003286 return true;
3287 }
3288
Antonio Maiorano0131ce22021-05-27 18:25:06 +00003289 if (lhs_vec_elem_type->is_numeric_scalar()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003290 SetExprInfo(expr, builder_->create<sem::Vector>(
Ben Claytonf5ed2ba2021-07-22 18:31:34 +00003291 builder_->create<sem::Bool>(), lhs_vec->Width()));
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003292 return true;
3293 }
3294 }
3295 }
3296
3297 // Binary bitwise operations
3298 if (expr->IsBitwise()) {
Antonio Maiorano0895c232021-06-01 17:42:41 +00003299 if (matching_types && lhs_type->is_integer_scalar_or_vector()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003300 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003301 return true;
3302 }
3303 }
3304
3305 // Bit shift expressions
3306 if (expr->IsBitshift()) {
3307 // Type validation rules are the same for left or right shift, despite
3308 // differences in computation rules (i.e. right shift can be arithmetic or
3309 // logical depending on lhs type).
3310
3311 if (lhs_type->IsAnyOf<I32, U32>() && rhs_type->Is<U32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003312 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003313 return true;
3314 }
3315
3316 if (lhs_vec_elem_type && lhs_vec_elem_type->IsAnyOf<I32, U32>() &&
3317 rhs_vec_elem_type && rhs_vec_elem_type->Is<U32>()) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003318 SetExprInfo(expr, lhs_type);
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003319 return true;
3320 }
3321 }
3322
Ben Claytonffd28e22021-06-24 11:27:36 +00003323 AddError("Binary expression operand types are invalid for this operation: " +
3324 lhs_type->FriendlyName(builder_->Symbols()) + " " +
3325 FriendlyName(expr->op()) + " " +
3326 rhs_type->FriendlyName(builder_->Symbols()),
3327 expr->source());
Antonio Maioranobe0fc4e2021-03-16 13:26:03 +00003328 return false;
3329}
3330
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003331bool Resolver::UnaryOp(ast::UnaryOpExpression* unary) {
3332 Mark(unary->expr());
Ben Clayton6fcefe42021-04-19 19:16:12 +00003333
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003334 // Resolve the inner expression
3335 if (!Expression(unary->expr())) {
dan sinclair327ed1b2020-04-07 19:27:21 +00003336 return false;
3337 }
Ben Clayton33352542021-01-29 16:43:41 +00003338
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003339 auto* expr_type = TypeOf(unary->expr());
3340 if (!expr_type) {
3341 return false;
3342 }
3343
3344 std::string type_name;
3345 const sem::Type* type = nullptr;
3346
3347 switch (unary->op()) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003348 case ast::UnaryOp::kNot:
3349 // Result type matches the deref'd inner type.
3350 type_name = TypeNameOf(unary->expr());
3351 type = expr_type->UnwrapRef();
Saraha5715e32021-06-28 14:09:33 +00003352 if (!type->Is<sem::Bool>() && !type->is_bool_vector()) {
3353 AddError("cannot logical negate expression of type '" +
3354 TypeNameOf(unary->expr()),
3355 unary->expr()->source());
3356 return false;
3357 }
3358 break;
3359
3360 case ast::UnaryOp::kComplement:
3361 // Result type matches the deref'd inner type.
3362 type_name = TypeNameOf(unary->expr());
3363 type = expr_type->UnwrapRef();
3364 if (!type->is_integer_scalar_or_vector()) {
3365 AddError("cannot bitwise complement expression of type '" +
3366 TypeNameOf(unary->expr()),
3367 unary->expr()->source());
3368 return false;
3369 }
3370 break;
3371
3372 case ast::UnaryOp::kNegation:
3373 // Result type matches the deref'd inner type.
3374 type_name = TypeNameOf(unary->expr());
3375 type = expr_type->UnwrapRef();
3376 if (!(type->IsAnyOf<sem::F32, sem::I32>() ||
3377 type->is_signed_integer_vector() || type->is_float_vector())) {
3378 AddError(
3379 "cannot negate expression of type '" + TypeNameOf(unary->expr()),
3380 unary->expr()->source());
3381 return false;
3382 }
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003383 break;
3384
3385 case ast::UnaryOp::kAddressOf:
3386 if (auto* ref = expr_type->As<sem::Reference>()) {
Sarahedecbb12021-07-28 03:57:22 +00003387 if (ref->StoreType()->UnwrapRef()->is_handle()) {
3388 AddError(
3389 "cannot take the address of expression in handle storage class",
3390 unary->expr()->source());
3391 return false;
3392 }
Ben Clayton18588542021-06-04 22:17:37 +00003393 type = builder_->create<sem::Pointer>(
3394 ref->StoreType(), ref->StorageClass(), ref->Access());
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003395 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00003396 AddError("cannot take the address of expression",
3397 unary->expr()->source());
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003398 return false;
3399 }
3400 break;
3401
3402 case ast::UnaryOp::kIndirection:
3403 if (auto* ptr = expr_type->As<sem::Pointer>()) {
Ben Clayton18588542021-06-04 22:17:37 +00003404 type = builder_->create<sem::Reference>(
3405 ptr->StoreType(), ptr->StorageClass(), ptr->Access());
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003406 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00003407 AddError("cannot dereference expression of type '" +
3408 TypeNameOf(unary->expr()) + "'",
3409 unary->expr()->source());
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003410 return false;
3411 }
3412 break;
3413 }
3414
Ben Clayton71f619b2021-07-13 12:18:13 +00003415 SetExprInfo(unary, type);
dan sinclair327ed1b2020-04-07 19:27:21 +00003416 return true;
dan sinclair0e257622020-04-07 19:27:11 +00003417}
3418
Ben Clayton5f0ea112021-03-09 10:54:37 +00003419bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
Antonio Maiorano9ef17472021-03-26 12:47:58 +00003420 ast::Variable* var = stmt->variable();
Ben Clayton6fcefe42021-04-19 19:16:12 +00003421 Mark(var);
3422
Sarahc0353662021-06-29 21:30:37 +00003423 if (!ValidateNoDuplicateDefinition(var->symbol(), var->source())) {
Antonio Maiorano09356cc2021-04-06 14:07:07 +00003424 return false;
3425 }
3426
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003427 auto* info = Variable(var, VariableKind::kLocal);
Ben Clayton5df76612021-05-12 10:41:21 +00003428 if (!info) {
3429 return false;
Ben Claytona88090b2021-03-17 22:47:33 +00003430 }
3431
Ben Clayton6fcefe42021-04-19 19:16:12 +00003432 for (auto* deco : var->decorations()) {
3433 // TODO(bclayton): Validate decorations
3434 Mark(deco);
3435 }
3436
Ben Claytona88090b2021-03-17 22:47:33 +00003437 variable_stack_.set(var->symbol(), info);
Ben Clayton6e459fe2021-07-14 09:44:41 +00003438 if (current_block_) { // Not all statements are inside a block
3439 current_block_->AddDecl(var);
3440 }
Ben Claytona88090b2021-03-17 22:47:33 +00003441
Ben Claytonfcda15e2021-05-10 18:01:51 +00003442 if (!ValidateVariable(info)) {
Antonio Maiorano09356cc2021-04-06 14:07:07 +00003443 return false;
3444 }
3445
Ben Claytona88090b2021-03-17 22:47:33 +00003446 if (!var->is_const()) {
James Price7a47fa82021-05-26 15:41:02 +00003447 if (info->storage_class != ast::StorageClass::kFunction &&
Saraha8f58ef2021-06-30 19:22:30 +00003448 IsValidationEnabled(var->decorations(),
3449 ast::DisabledValidation::kIgnoreStorageClass)) {
Ben Claytona88090b2021-03-17 22:47:33 +00003450 if (info->storage_class != ast::StorageClass::kNone) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003451 AddError("function variable has a non-function storage class",
3452 stmt->source());
Ben Claytona88090b2021-03-17 22:47:33 +00003453 return false;
3454 }
3455 info->storage_class = ast::StorageClass::kFunction;
3456 }
3457 }
3458
Antonio Maiorano9ef17472021-03-26 12:47:58 +00003459 if (!ApplyStorageClassUsageToType(info->storage_class, info->type,
Ben Clayton722b5a22021-03-18 20:46:24 +00003460 var->source())) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003461 AddNote("while instantiating variable " +
3462 builder_->Symbols().NameFor(var->symbol()),
3463 var->source());
Ben Claytona88090b2021-03-17 22:47:33 +00003464 return false;
Antonio Maiorano6ce2edf2021-02-26 18:25:56 +00003465 }
3466
3467 return true;
3468}
3469
Ben Clayton8758f102021-06-09 14:32:14 +00003470sem::Type* Resolver::TypeDecl(const ast::TypeDecl* named_type) {
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003471 sem::Type* result = nullptr;
3472 if (auto* alias = named_type->As<ast::Alias>()) {
3473 result = Type(alias->type());
3474 } else if (auto* str = named_type->As<ast::Struct>()) {
3475 result = Structure(str);
3476 } else {
Ben Claytonffd28e22021-06-24 11:27:36 +00003477 TINT_UNREACHABLE(Resolver, diagnostics_) << "Unhandled TypeDecl";
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003478 }
3479
3480 if (!result) {
3481 return nullptr;
3482 }
3483
3484 named_type_info_.emplace(named_type->name(),
Ben Clayton8758f102021-06-09 14:32:14 +00003485 TypeDeclInfo{named_type, result});
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003486
Ben Clayton8758f102021-06-09 14:32:14 +00003487 if (!ValidateTypeDecl(named_type)) {
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003488 return nullptr;
3489 }
3490
3491 builder_->Sem().Add(named_type, result);
3492 return result;
3493}
3494
Ben Clayton8758f102021-06-09 14:32:14 +00003495bool Resolver::ValidateTypeDecl(const ast::TypeDecl* named_type) const {
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003496 auto iter = named_type_info_.find(named_type->name());
3497 if (iter == named_type_info_.end()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003498 TINT_ICE(Resolver, diagnostics_)
3499 << "ValidateTypeDecl called() before TypeDecl()";
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003500 }
3501 if (iter->second.ast != named_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003502 AddError("type with the name '" +
3503 builder_->Symbols().NameFor(named_type->name()) +
3504 "' was already declared",
3505 named_type->source());
3506 AddNote("first declared here", iter->second.ast->source());
Antonio Maioranoc5f5d362021-05-20 08:44:57 +00003507 return false;
3508 }
3509 return true;
3510}
3511
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003512sem::Type* Resolver::TypeOf(const ast::Expression* expr) {
Ben Claytonf97b9c92021-02-16 18:45:45 +00003513 auto it = expr_info_.find(expr);
3514 if (it != expr_info_.end()) {
Ben Clayton19d32052021-05-20 15:10:48 +00003515 return const_cast<sem::Type*>(it->second.type);
Ben Clayton7b7d6982021-02-09 17:38:05 +00003516 }
3517 return nullptr;
3518}
3519
Ben Clayton109b18f2021-04-28 13:50:43 +00003520std::string Resolver::TypeNameOf(const ast::Expression* expr) {
3521 auto it = expr_info_.find(expr);
3522 if (it != expr_info_.end()) {
3523 return it->second.type_name;
3524 }
3525 return "";
3526}
3527
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003528sem::Type* Resolver::TypeOf(const ast::Literal* lit) {
Ben Clayton109b18f2021-04-28 13:50:43 +00003529 if (lit->Is<ast::SintLiteral>()) {
3530 return builder_->create<sem::I32>();
3531 }
3532 if (lit->Is<ast::UintLiteral>()) {
3533 return builder_->create<sem::U32>();
3534 }
3535 if (lit->Is<ast::FloatLiteral>()) {
3536 return builder_->create<sem::F32>();
3537 }
3538 if (lit->Is<ast::BoolLiteral>()) {
3539 return builder_->create<sem::Bool>();
3540 }
Ben Claytonffd28e22021-06-24 11:27:36 +00003541 TINT_UNREACHABLE(Resolver, diagnostics_)
Ben Clayton109b18f2021-04-28 13:50:43 +00003542 << "Unhandled literal type: " << lit->TypeInfo().name;
3543 return nullptr;
3544}
3545
Ben Clayton71f619b2021-07-13 12:18:13 +00003546void Resolver::SetExprInfo(const ast::Expression* expr,
3547 const sem::Type* type,
3548 std::string type_name) {
Ben Clayton90f43cf2021-03-31 20:43:26 +00003549 if (expr_info_.count(expr)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003550 TINT_ICE(Resolver, diagnostics_)
Ben Clayton71f619b2021-07-13 12:18:13 +00003551 << "SetExprInfo() called twice for the same expression";
Ben Clayton90f43cf2021-03-31 20:43:26 +00003552 }
Ben Clayton71f619b2021-07-13 12:18:13 +00003553 if (type_name.empty()) {
3554 type_name = type->FriendlyName(builder_->Symbols());
3555 }
3556 auto constant_value = EvaluateConstantValue(expr, type);
3557 expr_info_.emplace(
3558 expr, ExpressionInfo{type, std::move(type_name), current_statement_,
3559 std::move(constant_value)});
Ben Clayton33352542021-01-29 16:43:41 +00003560}
3561
Ben Clayton71786c92021-06-03 16:07:34 +00003562bool Resolver::ValidatePipelineStages() {
Sarah95485312021-06-24 08:56:16 +00003563 auto check_workgroup_storage = [&](FunctionInfo* func,
3564 FunctionInfo* entry_point) {
3565 auto stage = entry_point->declaration->pipeline_stage();
3566 if (stage != ast::PipelineStage::kCompute) {
3567 for (auto* var : func->local_referenced_module_vars) {
3568 if (var->storage_class == ast::StorageClass::kWorkgroup) {
3569 std::stringstream stage_name;
3570 stage_name << stage;
3571 for (auto* user : var->users) {
3572 auto it = expr_info_.find(user->As<ast::Expression>());
3573 if (it != expr_info_.end()) {
3574 if (func->declaration->symbol() ==
3575 it->second.statement->Function()->symbol()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003576 AddError("workgroup memory cannot be used by " +
3577 stage_name.str() + " pipeline stage",
3578 user->source());
Sarah95485312021-06-24 08:56:16 +00003579 break;
3580 }
3581 }
3582 }
Ben Claytonffd28e22021-06-24 11:27:36 +00003583 AddNote("variable is declared here", var->declaration->source());
Sarah95485312021-06-24 08:56:16 +00003584 if (func != entry_point) {
3585 TraverseCallChain(entry_point, func, [&](FunctionInfo* f) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003586 AddNote(
Sarah95485312021-06-24 08:56:16 +00003587 "called by function '" +
3588 builder_->Symbols().NameFor(f->declaration->symbol()) +
3589 "'",
3590 f->declaration->source());
3591 });
Ben Claytonffd28e22021-06-24 11:27:36 +00003592 AddNote("called by entry point '" +
3593 builder_->Symbols().NameFor(
3594 entry_point->declaration->symbol()) +
3595 "'",
3596 entry_point->declaration->source());
Sarah95485312021-06-24 08:56:16 +00003597 }
3598 return false;
3599 }
3600 }
3601 }
3602 return true;
3603 };
3604
3605 for (auto* entry_point : entry_points_) {
3606 if (!check_workgroup_storage(entry_point, entry_point)) {
3607 return false;
3608 }
3609 for (auto* func : entry_point->transitive_calls) {
3610 if (!check_workgroup_storage(func, entry_point)) {
3611 return false;
3612 }
3613 }
3614 }
3615
Ben Clayton71786c92021-06-03 16:07:34 +00003616 auto check_intrinsic_calls = [&](FunctionInfo* func,
3617 FunctionInfo* entry_point) {
3618 auto stage = entry_point->declaration->pipeline_stage();
3619 for (auto& call : func->intrinsic_calls) {
3620 if (!call.intrinsic->SupportedStages().Contains(stage)) {
3621 std::stringstream err;
3622 err << "built-in cannot be used by " << stage << " pipeline stage";
Ben Claytonffd28e22021-06-24 11:27:36 +00003623 AddError(err.str(), call.call->source());
Ben Clayton71786c92021-06-03 16:07:34 +00003624 if (func != entry_point) {
3625 TraverseCallChain(entry_point, func, [&](FunctionInfo* f) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003626 AddNote("called by function '" +
3627 builder_->Symbols().NameFor(f->declaration->symbol()) +
3628 "'",
3629 f->declaration->source());
Ben Clayton71786c92021-06-03 16:07:34 +00003630 });
Ben Claytonffd28e22021-06-24 11:27:36 +00003631 AddNote("called by entry point '" +
3632 builder_->Symbols().NameFor(
3633 entry_point->declaration->symbol()) +
3634 "'",
3635 entry_point->declaration->source());
Ben Clayton71786c92021-06-03 16:07:34 +00003636 }
3637 return false;
3638 }
3639 }
3640 return true;
3641 };
3642
3643 for (auto* entry_point : entry_points_) {
3644 if (!check_intrinsic_calls(entry_point, entry_point)) {
3645 return false;
3646 }
3647 for (auto* func : entry_point->transitive_calls) {
3648 if (!check_intrinsic_calls(func, entry_point)) {
3649 return false;
3650 }
3651 }
3652 }
3653 return true;
3654}
3655
3656template <typename CALLBACK>
3657void Resolver::TraverseCallChain(FunctionInfo* from,
3658 FunctionInfo* to,
3659 CALLBACK&& callback) const {
3660 for (auto* f : from->transitive_calls) {
3661 if (f == to) {
3662 callback(f);
3663 return;
3664 }
3665 if (f->transitive_calls.contains(to)) {
3666 TraverseCallChain(f, to, callback);
3667 callback(f);
3668 return;
3669 }
3670 }
Ben Claytonffd28e22021-06-24 11:27:36 +00003671 TINT_ICE(Resolver, diagnostics_)
Ben Clayton71786c92021-06-03 16:07:34 +00003672 << "TraverseCallChain() 'from' does not transitively call 'to'";
3673}
3674
Ben Clayton5f0ea112021-03-09 10:54:37 +00003675void Resolver::CreateSemanticNodes() const {
Ben Claytonb17aea12021-02-03 17:51:09 +00003676 auto& sem = builder_->Sem();
3677
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003678 // Collate all the 'ancestor_entry_points' - this is a map of function
3679 // symbol to all the entry points that transitively call the function.
Ben Clayton5a132582021-03-03 19:54:44 +00003680 std::unordered_map<Symbol, std::vector<Symbol>> ancestor_entry_points;
Ben Clayton71786c92021-06-03 16:07:34 +00003681 for (auto* entry_point : entry_points_) {
3682 for (auto* call : entry_point->transitive_calls) {
Ben Clayton5a132582021-03-03 19:54:44 +00003683 auto& vec = ancestor_entry_points[call->declaration->symbol()];
Ben Clayton71786c92021-06-03 16:07:34 +00003684 vec.emplace_back(entry_point->declaration->symbol());
Ben Clayton5a132582021-03-03 19:54:44 +00003685 }
3686 }
3687
James Pricef2f3bfc2021-05-13 20:32:32 +00003688 // The next pipeline constant ID to try to allocate.
3689 uint16_t next_constant_id = 0;
3690
Ben Clayton7b7d6982021-02-09 17:38:05 +00003691 // Create semantic nodes for all ast::Variables
Ben Clayton4ffcf062021-07-22 13:24:59 +00003692 std::unordered_map<const tint::ast::Variable*, sem::Parameter*> sem_params;
Ben Claytonb17aea12021-02-03 17:51:09 +00003693 for (auto it : variable_to_info_) {
3694 auto* var = it.first;
3695 auto* info = it.second;
James Pricef2f3bfc2021-05-13 20:32:32 +00003696
3697 sem::Variable* sem_var = nullptr;
3698
3699 if (auto* override_deco =
3700 ast::GetDecoration<ast::OverrideDecoration>(var->decorations())) {
3701 // Create a pipeline overridable constant.
3702 uint16_t constant_id;
3703 if (override_deco->HasValue()) {
Antonio Maioranodc4e6c12021-05-14 17:51:13 +00003704 constant_id = static_cast<uint16_t>(override_deco->value());
James Pricef2f3bfc2021-05-13 20:32:32 +00003705 } else {
3706 // No ID was specified, so allocate the next available ID.
3707 constant_id = next_constant_id;
3708 while (constant_ids_.count(constant_id)) {
3709 if (constant_id == UINT16_MAX) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003710 TINT_ICE(Resolver, builder_->Diagnostics())
James Pricef2f3bfc2021-05-13 20:32:32 +00003711 << "no more pipeline constant IDs available";
3712 return;
3713 }
3714 constant_id++;
3715 }
3716 next_constant_id = constant_id + 1;
3717 }
3718
James Pricee55e2102021-06-18 09:27:13 +00003719 sem_var =
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003720 builder_->create<sem::GlobalVariable>(var, info->type, constant_id);
3721 } else {
3722 switch (info->kind) {
3723 case VariableKind::kGlobal:
3724 sem_var = builder_->create<sem::GlobalVariable>(
3725 var, info->type, info->storage_class, info->access,
3726 info->binding_point);
3727 break;
3728 case VariableKind::kLocal:
3729 sem_var = builder_->create<sem::LocalVariable>(
3730 var, info->type, info->storage_class, info->access);
3731 break;
Ben Clayton4ffcf062021-07-22 13:24:59 +00003732 case VariableKind::kParameter: {
3733 auto* param = builder_->create<sem::Parameter>(
3734 var, info->index, info->type, info->storage_class, info->access);
3735 sem_var = param;
3736 sem_params.emplace(var, param);
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003737 break;
Ben Clayton4ffcf062021-07-22 13:24:59 +00003738 }
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003739 }
James Pricef2f3bfc2021-05-13 20:32:32 +00003740 }
3741
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003742 std::vector<const sem::VariableUser*> users;
James Pricec9af5972021-02-16 21:15:01 +00003743 for (auto* user : info->users) {
3744 // Create semantic node for the identifier expression if necessary
3745 auto* sem_expr = sem.Get(user);
3746 if (sem_expr == nullptr) {
Ben Clayton71f619b2021-07-13 12:18:13 +00003747 auto& expr_info = expr_info_.at(user);
3748 auto* type = expr_info.type;
3749 auto* stmt = expr_info.statement;
3750 auto* sem_user = builder_->create<sem::VariableUser>(
3751 user, type, stmt, sem_var, expr_info.constant_value);
Ben Clayton86c2cbf2021-04-07 08:09:01 +00003752 sem_var->AddUser(sem_user);
3753 sem.Add(user, sem_user);
3754 } else {
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003755 auto* sem_user = sem_expr->As<sem::VariableUser>();
Ben Clayton86c2cbf2021-04-07 08:09:01 +00003756 if (!sem_user) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003757 TINT_ICE(Resolver, diagnostics_) << "expected sem::VariableUser, got "
3758 << sem_expr->TypeInfo().name;
Ben Clayton86c2cbf2021-04-07 08:09:01 +00003759 }
3760 sem_var->AddUser(sem_user);
James Pricec9af5972021-02-16 21:15:01 +00003761 }
James Pricec9af5972021-02-16 21:15:01 +00003762 }
Ben Clayton86c2cbf2021-04-07 08:09:01 +00003763 sem.Add(var, sem_var);
Ben Claytonb17aea12021-02-03 17:51:09 +00003764 }
3765
3766 auto remap_vars = [&sem](const std::vector<VariableInfo*>& in) {
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003767 std::vector<const sem::Variable*> out;
Ben Claytonb17aea12021-02-03 17:51:09 +00003768 out.reserve(in.size());
3769 for (auto* info : in) {
3770 out.emplace_back(sem.Get(info->declaration));
3771 }
3772 return out;
3773 };
3774
Ben Clayton7b7d6982021-02-09 17:38:05 +00003775 // Create semantic nodes for all ast::Functions
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003776 std::unordered_map<FunctionInfo*, sem::Function*> func_info_to_sem_func;
Ben Clayton87c78dd2021-02-03 16:43:20 +00003777 for (auto it : function_to_info_) {
3778 auto* func = it.first;
3779 auto* info = it.second;
Ben Clayton5a132582021-03-03 19:54:44 +00003780
Ben Clayton4ffcf062021-07-22 13:24:59 +00003781 std::vector<sem::Parameter*> parameters;
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003782 parameters.reserve(info->parameters.size());
3783 for (auto* p : info->parameters) {
Ben Clayton4ffcf062021-07-22 13:24:59 +00003784 parameters.emplace_back(sem_params.at(p->declaration));
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003785 }
3786
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003787 auto* sem_func = builder_->create<sem::Function>(
Ben Clayton3068dcb2021-04-30 19:24:29 +00003788 info->declaration, const_cast<sem::Type*>(info->return_type),
Ben Clayton0f2d95d2021-07-22 13:24:59 +00003789 parameters, remap_vars(info->referenced_module_vars),
James Price4ffd3e22021-03-17 14:24:04 +00003790 remap_vars(info->local_referenced_module_vars), info->return_statements,
James Pricebcefe462021-05-22 12:48:24 +00003791 info->callsites, ancestor_entry_points[func->symbol()],
3792 info->workgroup_size);
Ben Clayton316f9f62021-02-08 22:31:44 +00003793 func_info_to_sem_func.emplace(info, sem_func);
3794 sem.Add(func, sem_func);
3795 }
3796
Ben Clayton7b7d6982021-02-09 17:38:05 +00003797 // Create semantic nodes for all ast::CallExpressions
Ben Clayton316f9f62021-02-08 22:31:44 +00003798 for (auto it : function_calls_) {
3799 auto* call = it.first;
Ben Claytonf97b9c92021-02-16 18:45:45 +00003800 auto info = it.second;
3801 auto* sem_func = func_info_to_sem_func.at(info.function);
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00003802 sem.Add(call, builder_->create<sem::Call>(call, sem_func, info.statement));
Ben Clayton7b7d6982021-02-09 17:38:05 +00003803 }
3804
3805 // Create semantic nodes for all remaining expression types
Ben Claytonf97b9c92021-02-16 18:45:45 +00003806 for (auto it : expr_info_) {
Ben Clayton7b7d6982021-02-09 17:38:05 +00003807 auto* expr = it.first;
Ben Claytonf97b9c92021-02-16 18:45:45 +00003808 auto& info = it.second;
Ben Clayton7b7d6982021-02-09 17:38:05 +00003809 if (sem.Get(expr)) {
3810 // Expression has already been assigned a semantic node
3811 continue;
3812 }
Ben Clayton71f619b2021-07-13 12:18:13 +00003813 sem.Add(expr, builder_->create<sem::Expression>(
3814 const_cast<ast::Expression*>(expr), info.type,
3815 info.statement, info.constant_value));
Ben Clayton87c78dd2021-02-03 16:43:20 +00003816 }
3817}
3818
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003819sem::Array* Resolver::Array(const ast::Array* arr) {
3820 auto source = arr->source();
Ben Claytond614dd52021-03-15 10:43:11 +00003821
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003822 auto* el_ty = Type(arr->type());
3823 if (!el_ty) {
Ben Claytond614dd52021-03-15 10:43:11 +00003824 return nullptr;
3825 }
3826
Ken Rockotac9db202021-07-19 20:30:09 +00003827 if (!IsPlain(el_ty)) { // Check must come before GetDefaultAlignAndSize()
Ben Claytonffd28e22021-06-24 11:27:36 +00003828 AddError(el_ty->FriendlyName(builder_->Symbols()) +
3829 " cannot be used as an element type of an array",
3830 source);
Ben Claytonefb741f2021-06-03 08:24:55 +00003831 return nullptr;
3832 }
3833
Ben Claytonfced3502021-07-22 18:56:54 +00003834 uint32_t el_align = el_ty->Align();
3835 uint32_t el_size = el_ty->Size();
Ben Claytond614dd52021-03-15 10:43:11 +00003836
Ben Clayton241c16d2021-06-09 18:53:57 +00003837 if (!ValidateNoDuplicateDecorations(arr->decorations())) {
3838 return nullptr;
3839 }
3840
Ben Claytond614dd52021-03-15 10:43:11 +00003841 // Look for explicit stride via [[stride(n)]] decoration
Ben Clayton6fcefe42021-04-19 19:16:12 +00003842 uint32_t explicit_stride = 0;
Ben Claytond614dd52021-03-15 10:43:11 +00003843 for (auto* deco : arr->decorations()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00003844 Mark(deco);
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003845 if (auto* sd = deco->As<ast::StrideDecoration>()) {
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003846 explicit_stride = sd->stride();
3847 if (!ValidateArrayStrideDecoration(sd, el_size, el_align, source)) {
Antonio Maioranofc03a462021-04-16 02:36:44 +00003848 return nullptr;
3849 }
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003850 continue;
Ben Claytond614dd52021-03-15 10:43:11 +00003851 }
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003852
Ben Claytonffd28e22021-06-24 11:27:36 +00003853 AddError("decoration is not valid for array types", deco->source());
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003854 return nullptr;
Ben Clayton6fcefe42021-04-19 19:16:12 +00003855 }
Ben Claytond614dd52021-03-15 10:43:11 +00003856
3857 // Calculate implicit stride
Antonio Maioranofc03a462021-04-16 02:36:44 +00003858 auto implicit_stride = utils::RoundUp(el_align, el_size);
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003859
3860 auto stride = explicit_stride ? explicit_stride : implicit_stride;
3861
3862 // WebGPU requires runtime arrays have at least one element, but the AST
3863 // records an element count of 0 for it.
3864 auto size = std::max<uint32_t>(arr->size(), 1) * stride;
3865 auto* sem = builder_->create<sem::Array>(el_ty, arr->size(), el_align, size,
Ben Clayton31936f32021-06-16 09:50:11 +00003866 stride, implicit_stride);
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003867
3868 if (!ValidateArray(sem, source)) {
3869 return nullptr;
3870 }
3871
3872 return sem;
Ben Claytond614dd52021-03-15 10:43:11 +00003873}
3874
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003875bool Resolver::ValidateArray(const sem::Array* arr, const Source& source) {
3876 auto* el_ty = arr->ElemType();
Ben Clayton8db81882021-04-21 16:45:02 +00003877
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003878 if (auto* el_str = el_ty->As<sem::Struct>()) {
3879 if (el_str->IsBlockDecorated()) {
Ben Clayton8db81882021-04-21 16:45:02 +00003880 // https://gpuweb.github.io/gpuweb/wgsl/#attributes
3881 // A structure type with the block attribute must not be:
3882 // * the element type of an array type
3883 // * the member type in another structure
Ben Claytonffd28e22021-06-24 11:27:36 +00003884 AddError(
Ben Clayton8db81882021-04-21 16:45:02 +00003885 "A structure type with a [[block]] decoration cannot be used as an "
3886 "element of an array",
3887 source);
3888 return false;
3889 }
3890 }
3891 return true;
3892}
3893
3894bool Resolver::ValidateArrayStrideDecoration(const ast::StrideDecoration* deco,
3895 uint32_t el_size,
3896 uint32_t el_align,
3897 const Source& source) {
3898 auto stride = deco->stride();
3899 bool is_valid_stride =
3900 (stride >= el_size) && (stride >= el_align) && (stride % el_align == 0);
3901 if (!is_valid_stride) {
3902 // https://gpuweb.github.io/gpuweb/wgsl/#array-layout-rules
3903 // Arrays decorated with the stride attribute must have a stride that is
3904 // at least the size of the element type, and be a multiple of the
3905 // element type's alignment value.
Ben Claytonffd28e22021-06-24 11:27:36 +00003906 AddError(
Ben Clayton8db81882021-04-21 16:45:02 +00003907 "arrays decorated with the stride attribute must have a stride "
3908 "that is at least the size of the element type, and be a multiple "
3909 "of the element type's alignment value.",
3910 source);
3911 return false;
3912 }
3913 return true;
3914}
3915
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003916bool Resolver::ValidateStructure(const sem::Struct* str) {
James Price37cabbb2021-07-01 08:13:41 +00003917 if (str->Members().empty()) {
3918 AddError("structures must have at least one member",
3919 str->Declaration()->source());
3920 return false;
3921 }
3922
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003923 for (auto* member : str->Members()) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00003924 if (auto* r = member->Type()->As<sem::Array>()) {
Ben Clayton4cd5eea2021-05-07 20:58:34 +00003925 if (r->IsRuntimeSized()) {
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003926 if (member != str->Members().back()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003927 AddError(
Antonio Maiorano9970ec62021-03-18 17:59:54 +00003928 "runtime arrays may only appear as the last member of a struct",
Ben Clayton02ebf0d2021-05-05 09:09:41 +00003929 member->Declaration()->source());
Antonio Maiorano9970ec62021-03-18 17:59:54 +00003930 return false;
3931 }
Ben Claytonba6ab5e2021-05-07 14:49:34 +00003932 if (!str->IsBlockDecorated()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00003933 AddError(
3934 "a struct containing a runtime-sized array "
3935 "requires the [[block]] attribute: '" +
3936 builder_->Symbols().NameFor(str->Declaration()->name()) + "'",
3937 member->Declaration()->source());
Antonio Maiorano9970ec62021-03-18 17:59:54 +00003938 return false;
3939 }
Antonio Maiorano9970ec62021-03-18 17:59:54 +00003940 }
3941 }
3942
Saraha4696682021-07-21 12:16:35 +00003943 auto has_position = false;
3944 ast::InvariantDecoration* invariant_attribute = nullptr;
Ben Clayton02ebf0d2021-05-05 09:09:41 +00003945 for (auto* deco : member->Declaration()->decorations()) {
Ben Clayton97668c82021-07-27 08:17:29 +00003946 if (!deco->IsAnyOf<ast::BuiltinDecoration, //
3947 ast::InternalDecoration, //
3948 ast::InterpolateDecoration, //
3949 ast::InvariantDecoration, //
3950 ast::LocationDecoration, //
3951 ast::StructMemberOffsetDecoration, //
3952 ast::StructMemberSizeDecoration, //
3953 ast::StructMemberAlignDecoration>()) {
3954 if (deco->Is<ast::StrideDecoration>() &&
3955 IsValidationDisabled(
3956 member->Declaration()->decorations(),
3957 ast::DisabledValidation::kIgnoreStrideDecoration)) {
3958 continue;
3959 }
Ben Claytonffd28e22021-06-24 11:27:36 +00003960 AddError("decoration is not valid for structure members",
3961 deco->source());
Antonio Maiorano9970ec62021-03-18 17:59:54 +00003962 return false;
3963 }
Saraha4696682021-07-21 12:16:35 +00003964 if (auto* invariant = deco->As<ast::InvariantDecoration>()) {
3965 invariant_attribute = invariant;
3966 }
Sarahc58738a2021-06-09 16:01:29 +00003967 if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
Sarah465c5aa2021-07-23 13:23:20 +00003968 if (!ValidateBuiltinDecoration(builtin, member->Type(),
3969 /* is_input */ false,
3970 /* is_struct_member */ true)) {
Sarah443c41d2021-06-18 19:58:27 +00003971 return false;
Sarahc58738a2021-06-09 16:01:29 +00003972 }
Saraha4696682021-07-21 12:16:35 +00003973 if (builtin->value() == ast::Builtin::kPosition) {
3974 has_position = true;
3975 }
James Price989a8e42021-06-28 23:04:43 +00003976 } else if (auto* interpolate = deco->As<ast::InterpolateDecoration>()) {
3977 if (!ValidateInterpolateDecoration(interpolate, member->Type())) {
3978 return false;
3979 }
Sarahc58738a2021-06-09 16:01:29 +00003980 }
Antonio Maiorano9970ec62021-03-18 17:59:54 +00003981 }
Antonio Maiorano8b2be2d2021-06-18 19:57:57 +00003982
Saraha4696682021-07-21 12:16:35 +00003983 if (invariant_attribute && !has_position) {
3984 AddError("invariant attribute must only be applied to a position builtin",
3985 invariant_attribute->source());
3986 return false;
3987 }
3988
Antonio Maiorano8b2be2d2021-06-18 19:57:57 +00003989 if (auto* member_struct_type = member->Type()->As<sem::Struct>()) {
3990 if (auto* member_struct_type_block_decoration =
3991 ast::GetDecoration<ast::StructBlockDecoration>(
3992 member_struct_type->Declaration()->decorations())) {
Ben Claytonffd28e22021-06-24 11:27:36 +00003993 AddError("structs must not contain [[block]] decorated struct members",
3994 member->Declaration()->source());
3995 AddNote("see member's struct decoration here",
3996 member_struct_type_block_decoration->source());
Antonio Maiorano8b2be2d2021-06-18 19:57:57 +00003997 return false;
3998 }
3999 }
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004000 }
4001
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004002 for (auto* deco : str->Declaration()->decorations()) {
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004003 if (!(deco->Is<ast::StructBlockDecoration>())) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004004 AddError("decoration is not valid for struct declarations",
4005 deco->source());
Antonio Maiorano9970ec62021-03-18 17:59:54 +00004006 return false;
4007 }
4008 }
4009
4010 return true;
4011}
4012
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004013sem::Struct* Resolver::Structure(const ast::Struct* str) {
Ben Clayton241c16d2021-06-09 18:53:57 +00004014 if (!ValidateNoDuplicateDecorations(str->decorations())) {
4015 return nullptr;
4016 }
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004017 for (auto* deco : str->decorations()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00004018 Mark(deco);
4019 }
4020
Antonio Maiorano5cd71b82021-04-16 19:07:51 +00004021 sem::StructMemberList sem_members;
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004022 sem_members.reserve(str->members().size());
Ben Claytond614dd52021-03-15 10:43:11 +00004023
4024 // Calculate the effective size and alignment of each field, and the overall
4025 // size of the structure.
4026 // For size, use the size attribute if provided, otherwise use the default
4027 // size for the type.
4028 // For alignment, use the alignment attribute if provided, otherwise use the
4029 // default alignment for the member type.
4030 // Diagnostic errors are raised if a basic rule is violated.
4031 // Validation of storage-class rules requires analysing the actual variable
4032 // usage of the structure, and so is performed as part of the variable
4033 // validation.
Ben Claytond614dd52021-03-15 10:43:11 +00004034 uint32_t struct_size = 0;
4035 uint32_t struct_align = 1;
Sarah0bbe24d2021-07-19 17:38:20 +00004036 std::unordered_map<Symbol, ast::StructMember*> member_map;
Ben Claytond614dd52021-03-15 10:43:11 +00004037
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004038 for (auto* member : str->members()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00004039 Mark(member);
Sarah0bbe24d2021-07-19 17:38:20 +00004040 auto result = member_map.emplace(member->symbol(), member);
4041 if (!result.second) {
4042 AddError("redefinition of '" +
4043 builder_->Symbols().NameFor(member->symbol()) + "'",
4044 member->source());
4045 AddNote("previous definition is here", result.first->second->source());
4046 return nullptr;
4047 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00004048
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004049 // Resolve member type
4050 auto* type = Type(member->type());
4051 if (!type) {
4052 return nullptr;
4053 }
Ben Clayton2ac55fe2021-04-28 14:13:13 +00004054
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004055 // Validate member type
James Price3b267172021-06-09 09:12:57 +00004056 if (!IsPlain(type)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004057 AddError(type->FriendlyName(builder_->Symbols()) +
4058 " cannot be used as the type of a structure member",
4059 member->source());
Ben Claytond614dd52021-03-15 10:43:11 +00004060 return nullptr;
4061 }
4062
4063 uint32_t offset = struct_size;
Ben Claytonfced3502021-07-22 18:56:54 +00004064 uint32_t align = type->Align();
4065 uint32_t size = type->Size();
Ben Claytond614dd52021-03-15 10:43:11 +00004066
Ben Clayton241c16d2021-06-09 18:53:57 +00004067 if (!ValidateNoDuplicateDecorations(member->decorations())) {
4068 return nullptr;
4069 }
4070
Ben Clayton2f9ced02021-03-15 20:34:22 +00004071 bool has_offset_deco = false;
4072 bool has_align_deco = false;
4073 bool has_size_deco = false;
Ben Claytond614dd52021-03-15 10:43:11 +00004074 for (auto* deco : member->decorations()) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00004075 Mark(deco);
Ben Claytond614dd52021-03-15 10:43:11 +00004076 if (auto* o = deco->As<ast::StructMemberOffsetDecoration>()) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004077 // Offset decorations are not part of the WGSL spec, but are emitted
4078 // by the SPIR-V reader.
Ben Claytond614dd52021-03-15 10:43:11 +00004079 if (o->offset() < struct_size) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004080 AddError("offsets must be in ascending order", o->source());
Ben Claytond614dd52021-03-15 10:43:11 +00004081 return nullptr;
4082 }
4083 offset = o->offset();
4084 align = 1;
Ben Clayton2f9ced02021-03-15 20:34:22 +00004085 has_offset_deco = true;
Ben Claytond614dd52021-03-15 10:43:11 +00004086 } else if (auto* a = deco->As<ast::StructMemberAlignDecoration>()) {
Ben Claytona7520522021-03-15 13:37:41 +00004087 if (a->align() <= 0 || !utils::IsPowerOfTwo(a->align())) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004088 AddError("align value must be a positive, power-of-two integer",
4089 a->source());
Ben Claytond614dd52021-03-15 10:43:11 +00004090 return nullptr;
4091 }
4092 align = a->align();
Ben Clayton2f9ced02021-03-15 20:34:22 +00004093 has_align_deco = true;
Ben Claytond614dd52021-03-15 10:43:11 +00004094 } else if (auto* s = deco->As<ast::StructMemberSizeDecoration>()) {
4095 if (s->size() < size) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004096 AddError("size must be at least as big as the type's size (" +
4097 std::to_string(size) + ")",
4098 s->source());
Ben Claytond614dd52021-03-15 10:43:11 +00004099 return nullptr;
4100 }
4101 size = s->size();
Ben Clayton2f9ced02021-03-15 20:34:22 +00004102 has_size_deco = true;
Ben Claytond614dd52021-03-15 10:43:11 +00004103 }
4104 }
4105
Ben Clayton2f9ced02021-03-15 20:34:22 +00004106 if (has_offset_deco && (has_align_deco || has_size_deco)) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004107 AddError(
Ben Clayton2f9ced02021-03-15 20:34:22 +00004108 "offset decorations cannot be used with align or size decorations",
4109 member->source());
4110 return nullptr;
4111 }
4112
Ben Claytona7520522021-03-15 13:37:41 +00004113 offset = utils::RoundUp(align, offset);
Ben Claytond614dd52021-03-15 10:43:11 +00004114
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004115 auto* sem_member = builder_->create<sem::StructMember>(
Ben Clayton053559d2021-07-23 16:43:01 +00004116 member, member->symbol(), const_cast<sem::Type*>(type),
Ben Clayton2e1a2842021-05-07 21:05:54 +00004117 static_cast<uint32_t>(sem_members.size()), offset, align, size);
Ben Claytond614dd52021-03-15 10:43:11 +00004118 builder_->Sem().Add(member, sem_member);
4119 sem_members.emplace_back(sem_member);
4120
4121 struct_size = offset + size;
4122 struct_align = std::max(struct_align, align);
4123 }
4124
Ben Claytonad973432021-03-17 21:54:13 +00004125 auto size_no_padding = struct_size;
Ben Claytona7520522021-03-15 13:37:41 +00004126 struct_size = utils::RoundUp(struct_align, struct_size);
Ben Claytond614dd52021-03-15 10:43:11 +00004127
Ben Clayton053559d2021-07-23 16:43:01 +00004128 auto* out =
4129 builder_->create<sem::Struct>(str, str->name(), sem_members, struct_align,
4130 struct_size, size_no_padding);
Ben Clayton313e6182021-06-17 19:56:14 +00004131
4132 // Keep track of atomic members for validation after all usages have been
4133 // determined.
4134 for (size_t i = 0; i < sem_members.size(); i++) {
4135 if (sem_members[i]->Type()->Is<sem::Atomic>()) {
4136 atomic_members_.emplace_back(StructMember{out, i});
4137 }
4138 }
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004139
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004140 if (!ValidateStructure(out)) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004141 return nullptr;
4142 }
4143
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004144 return out;
Ben Claytond614dd52021-03-15 10:43:11 +00004145}
4146
Antonio Maiorano2e974352021-03-22 23:20:17 +00004147bool Resolver::ValidateReturn(const ast::ReturnStatement* ret) {
Ben Clayton3068dcb2021-04-30 19:24:29 +00004148 auto* func_type = current_function_->return_type;
Antonio Maiorano2e974352021-03-22 23:20:17 +00004149
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004150 auto* ret_type = ret->has_value() ? TypeOf(ret->value())->UnwrapRef()
Ben Claytoncc98b4f2021-05-20 14:31:48 +00004151 : builder_->create<sem::Void>();
Antonio Maiorano2e974352021-03-22 23:20:17 +00004152
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004153 if (func_type->UnwrapRef() != ret_type) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004154 AddError(
4155 "return statement type must match its function "
4156 "return type, returned '" +
4157 ret_type->FriendlyName(builder_->Symbols()) + "', expected '" +
4158 current_function_->return_type_name + "'",
4159 ret->source());
Antonio Maiorano2e974352021-03-22 23:20:17 +00004160 return false;
4161 }
4162
Ben Claytoncd7eb4f2021-07-17 18:09:26 +00004163 auto* sem = builder_->Sem().Get(ret);
4164 if (auto* continuing =
4165 sem->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
4166 AddError("continuing blocks must not contain a return statement",
4167 ret->source());
4168 if (continuing != sem->Parent()) {
4169 AddNote("see continuing block here", continuing->Declaration()->source());
4170 }
4171 return false;
4172 }
4173
Antonio Maiorano2e974352021-03-22 23:20:17 +00004174 return true;
4175}
4176
4177bool Resolver::Return(ast::ReturnStatement* ret) {
4178 current_function_->return_statements.push_back(ret);
4179
Ben Clayton6fcefe42021-04-19 19:16:12 +00004180 if (auto* value = ret->value()) {
4181 Mark(value);
James Price7e221962021-06-15 15:00:57 +00004182 if (!Expression(value)) {
4183 return false;
4184 }
Ben Clayton6fcefe42021-04-19 19:16:12 +00004185 }
4186
James Price7e221962021-06-15 15:00:57 +00004187 // Validate after processing the return value expression so that its type is
4188 // available for validation.
4189 return ValidateReturn(ret);
Antonio Maiorano2e974352021-03-22 23:20:17 +00004190}
4191
Antonio Maioranocea744d2021-03-25 12:55:27 +00004192bool Resolver::ValidateSwitch(const ast::SwitchStatement* s) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004193 auto* cond_type = TypeOf(s->condition())->UnwrapRef();
Antonio Maioranocea744d2021-03-25 12:55:27 +00004194 if (!cond_type->is_integer_scalar()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004195 AddError(
4196 "switch statement selector expression must be of a "
4197 "scalar integer type",
4198 s->condition()->source());
Antonio Maioranocea744d2021-03-25 12:55:27 +00004199 return false;
4200 }
4201
4202 bool has_default = false;
4203 std::unordered_set<uint32_t> selector_set;
4204
4205 for (auto* case_stmt : s->body()) {
4206 if (case_stmt->IsDefault()) {
4207 if (has_default) {
4208 // More than one default clause
Ben Clayton5a88ec82021-06-29 14:42:19 +00004209 AddError("switch statement must have exactly one default clause",
Ben Claytonffd28e22021-06-24 11:27:36 +00004210 case_stmt->source());
Antonio Maioranocea744d2021-03-25 12:55:27 +00004211 return false;
4212 }
4213 has_default = true;
4214 }
4215
4216 for (auto* selector : case_stmt->selectors()) {
Ben Clayton109b18f2021-04-28 13:50:43 +00004217 if (cond_type != TypeOf(selector)) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004218 AddError(
4219 "the case selector values must have the same "
4220 "type as the selector expression.",
4221 case_stmt->source());
Antonio Maioranocea744d2021-03-25 12:55:27 +00004222 return false;
4223 }
4224
4225 auto v = selector->value_as_u32();
4226 if (selector_set.find(v) != selector_set.end()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004227 AddError(
4228 "a literal value must not appear more than once in "
4229 "the case selectors for a switch statement: '" +
4230 builder_->str(selector) + "'",
4231 case_stmt->source());
Antonio Maioranocea744d2021-03-25 12:55:27 +00004232 return false;
4233 }
4234 selector_set.emplace(v);
4235 }
4236 }
4237
4238 if (!has_default) {
4239 // No default clause
Ben Claytonffd28e22021-06-24 11:27:36 +00004240 AddError("switch statement must have a default clause", s->source());
Antonio Maioranocea744d2021-03-25 12:55:27 +00004241 return false;
4242 }
4243
4244 if (!s->body().empty()) {
4245 auto* last_clause = s->body().back()->As<ast::CaseStatement>();
4246 auto* last_stmt = last_clause->body()->last();
4247 if (last_stmt && last_stmt->Is<ast::FallthroughStatement>()) {
Ben Clayton5a88ec82021-06-29 14:42:19 +00004248 AddError(
4249 "a fallthrough statement must not appear as "
4250 "the last statement in last clause of a switch",
4251 last_stmt->source());
Antonio Maioranocea744d2021-03-25 12:55:27 +00004252 return false;
4253 }
4254 }
4255
4256 return true;
4257}
4258
Ben Clayton6e459fe2021-07-14 09:44:41 +00004259bool Resolver::SwitchStatement(ast::SwitchStatement* stmt) {
4260 auto* sem =
4261 builder_->create<sem::SwitchStatement>(stmt, current_compound_statement_);
4262 builder_->Sem().Add(stmt, sem);
4263 return Scope(sem, [&] {
4264 Mark(stmt->condition());
4265 if (!Expression(stmt->condition())) {
Antonio Maioranocea744d2021-03-25 12:55:27 +00004266 return false;
4267 }
Ben Clayton6e459fe2021-07-14 09:44:41 +00004268 for (auto* case_stmt : stmt->body()) {
4269 Mark(case_stmt);
4270 if (!CaseStatement(case_stmt)) {
4271 return false;
4272 }
4273 }
4274 if (!ValidateSwitch(stmt)) {
4275 return false;
4276 }
4277 return true;
4278 });
Antonio Maioranocea744d2021-03-25 12:55:27 +00004279}
4280
Antonio Maioranoe09989a2021-03-31 13:26:43 +00004281bool Resolver::Assignment(ast::AssignmentStatement* a) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00004282 Mark(a->lhs());
4283 Mark(a->rhs());
4284
Antonio Maioranoe09989a2021-03-31 13:26:43 +00004285 if (!Expression(a->lhs()) || !Expression(a->rhs())) {
4286 return false;
4287 }
4288 return ValidateAssignment(a);
4289}
4290
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004291bool Resolver::ValidateAssignment(const ast::AssignmentStatement* a) {
4292 // https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
4293 auto const* lhs_type = TypeOf(a->lhs());
4294 auto const* rhs_type = TypeOf(a->rhs());
4295
Sarahcb0309e2021-06-28 20:44:31 +00004296 if (auto* ident = a->lhs()->As<ast::IdentifierExpression>()) {
4297 VariableInfo* var;
4298 if (variable_stack_.get(ident->symbol(), &var)) {
4299 if (var->kind == VariableKind::kParameter) {
4300 AddError("cannot assign to function parameter", a->lhs()->source());
4301 AddNote("'" + builder_->Symbols().NameFor(ident->symbol()) +
4302 "' is declared here:",
4303 var->declaration->source());
4304 return false;
4305 }
4306 if (var->declaration->is_const()) {
4307 AddError("cannot assign to const", a->lhs()->source());
4308 AddNote("'" + builder_->Symbols().NameFor(ident->symbol()) +
4309 "' is declared here:",
4310 var->declaration->source());
4311 return false;
4312 }
4313 }
4314 }
4315
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004316 auto* lhs_ref = lhs_type->As<sem::Reference>();
4317 if (!lhs_ref) {
4318 // LHS is not a reference, so it has no storage.
Ben Claytonffd28e22021-06-24 11:27:36 +00004319 AddError("cannot assign to value of type '" + TypeNameOf(a->lhs()) + "'",
4320 a->lhs()->source());
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004321 return false;
4322 }
4323
Antonio Maioranobe607c02021-05-18 15:26:40 +00004324 auto* storage_type = lhs_ref->StoreType();
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004325 auto* value_type = rhs_type->UnwrapRef(); // Implicit load of RHS
4326
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004327 // Value type has to match storage type
4328 if (storage_type != value_type) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004329 AddError("cannot assign '" + TypeNameOf(a->rhs()) + "' to '" +
4330 TypeNameOf(a->lhs()) + "'",
4331 a->source());
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004332 return false;
4333 }
Sarahebaa4b42021-06-15 22:39:19 +00004334 if (lhs_ref->Access() == ast::Access::kRead) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004335 AddError(
Sarahebaa4b42021-06-15 22:39:19 +00004336 "cannot store into a read-only type '" + TypeNameOf(a->lhs()) + "'",
4337 a->source());
4338 return false;
4339 }
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004340 return true;
4341}
4342
Sarahc0353662021-06-29 21:30:37 +00004343bool Resolver::ValidateNoDuplicateDefinition(Symbol sym,
4344 const Source& source,
4345 bool check_global_scope_only) {
4346 if (check_global_scope_only) {
4347 bool is_global = false;
4348 VariableInfo* var;
4349 if (variable_stack_.get(sym, &var, &is_global)) {
4350 if (is_global) {
4351 AddError("redefinition of '" + builder_->Symbols().NameFor(sym) + "'",
4352 source);
4353 AddNote("previous definition is here", var->declaration->source());
4354 return false;
4355 }
4356 }
4357 auto it = symbol_to_function_.find(sym);
4358 if (it != symbol_to_function_.end()) {
4359 AddError("redefinition of '" + builder_->Symbols().NameFor(sym) + "'",
4360 source);
4361 AddNote("previous definition is here", it->second->declaration->source());
4362 return false;
4363 }
4364 } else {
4365 VariableInfo* var;
4366 if (variable_stack_.get(sym, &var)) {
4367 AddError("redefinition of '" + builder_->Symbols().NameFor(sym) + "'",
4368 source);
4369 AddNote("previous definition is here", var->declaration->source());
4370 return false;
4371 }
4372 }
4373 return true;
4374}
4375
Ben Clayton241c16d2021-06-09 18:53:57 +00004376bool Resolver::ValidateNoDuplicateDecorations(
4377 const ast::DecorationList& decorations) {
4378 std::unordered_map<const TypeInfo*, Source> seen;
4379 for (auto* d : decorations) {
4380 auto res = seen.emplace(&d->TypeInfo(), d->source());
James Price4daac0e2021-06-15 16:33:57 +00004381 if (!res.second && !d->Is<ast::InternalDecoration>()) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004382 AddError("duplicate " + d->name() + " decoration", d->source());
4383 AddNote("first decoration declared here", res.first->second);
Ben Clayton241c16d2021-06-09 18:53:57 +00004384 return false;
4385 }
4386 }
4387 return true;
4388}
4389
Ben Claytona88090b2021-03-17 22:47:33 +00004390bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004391 sem::Type* ty,
Antonio Maiorano2e0bd4a2021-04-16 01:15:43 +00004392 const Source& usage) {
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004393 ty = const_cast<sem::Type*>(ty->UnwrapRef());
Ben Claytona88090b2021-03-17 22:47:33 +00004394
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004395 if (auto* str = ty->As<sem::Struct>()) {
4396 if (str->StorageClassUsage().count(sc)) {
Ben Claytona88090b2021-03-17 22:47:33 +00004397 return true; // Already applied
4398 }
Ben Claytonba6ab5e2021-05-07 14:49:34 +00004399
4400 str->AddUsage(sc);
4401
4402 for (auto* member : str->Members()) {
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004403 if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
Ben Claytona88090b2021-03-17 22:47:33 +00004404 std::stringstream err;
Ben Clayton722b5a22021-03-18 20:46:24 +00004405 err << "while analysing structure member "
4406 << str->FriendlyName(builder_->Symbols()) << "."
Ben Clayton02ebf0d2021-05-05 09:09:41 +00004407 << builder_->Symbols().NameFor(member->Declaration()->symbol());
Ben Claytonffd28e22021-06-24 11:27:36 +00004408 AddNote(err.str(), member->Declaration()->source());
Ben Claytona88090b2021-03-17 22:47:33 +00004409 return false;
4410 }
4411 }
Ben Clayton722b5a22021-03-18 20:46:24 +00004412 return true;
Ben Claytona88090b2021-03-17 22:47:33 +00004413 }
4414
Ben Clayton4cd5eea2021-05-07 20:58:34 +00004415 if (auto* arr = ty->As<sem::Array>()) {
4416 return ApplyStorageClassUsageToType(
4417 sc, const_cast<sem::Type*>(arr->ElemType()), usage);
Ben Clayton722b5a22021-03-18 20:46:24 +00004418 }
4419
Ben Clayton25eef8d2021-03-18 21:03:24 +00004420 if (ast::IsHostShareable(sc) && !IsHostShareable(ty)) {
Ben Clayton722b5a22021-03-18 20:46:24 +00004421 std::stringstream err;
4422 err << "Type '" << ty->FriendlyName(builder_->Symbols())
4423 << "' cannot be used in storage class '" << sc
Ben Clayton25eef8d2021-03-18 21:03:24 +00004424 << "' as it is non-host-shareable";
Ben Claytonffd28e22021-06-24 11:27:36 +00004425 AddError(err.str(), usage);
Ben Clayton722b5a22021-03-18 20:46:24 +00004426 return false;
Ben Claytona88090b2021-03-17 22:47:33 +00004427 }
4428
4429 return true;
4430}
4431
Ben Clayton9430cb42021-03-09 15:06:37 +00004432template <typename F>
Ben Clayton6e459fe2021-07-14 09:44:41 +00004433bool Resolver::Scope(sem::CompoundStatement* stmt, F&& callback) {
4434 auto* prev_current_statement = current_statement_;
4435 auto* prev_current_compound_statement = current_compound_statement_;
4436 auto* prev_current_block = current_block_;
4437 current_statement_ = stmt;
4438 current_compound_statement_ = stmt;
4439 current_block_ = stmt->As<sem::BlockStatement>();
Antonio Maiorano4682e3f2021-03-22 17:38:45 +00004440 variable_stack_.push_scope();
Ben Clayton6e459fe2021-07-14 09:44:41 +00004441
4442 TINT_DEFER({
4443 TINT_DEFER(variable_stack_.pop_scope());
4444 current_block_ = prev_current_block;
4445 current_compound_statement_ = prev_current_compound_statement;
4446 current_statement_ = prev_current_statement;
4447 });
4448
Ben Clayton1b03f0a2021-07-08 21:23:33 +00004449 return callback();
Ben Clayton9430cb42021-03-09 15:06:37 +00004450}
4451
Ben Clayton4cd5eea2021-05-07 20:58:34 +00004452std::string Resolver::VectorPretty(uint32_t size,
4453 const sem::Type* element_type) {
Antonio Maiorano3751fd22021-04-19 22:51:23 +00004454 sem::Vector vec_type(element_type, size);
Arman Uguray097c75a2021-03-18 15:43:14 +00004455 return vec_type.FriendlyName(builder_->Symbols());
4456}
4457
Ben Clayton12ed13d2021-04-28 12:38:13 +00004458void Resolver::Mark(const ast::Node* node) {
Ben Clayton6fcefe42021-04-19 19:16:12 +00004459 if (node == nullptr) {
Ben Claytonffd28e22021-06-24 11:27:36 +00004460 TINT_ICE(Resolver, diagnostics_) << "Resolver::Mark() called with nullptr";
Ben Clayton6fcefe42021-04-19 19:16:12 +00004461 }
4462 if (marked_.emplace(node).second) {
4463 return;
4464 }
Ben Claytonffd28e22021-06-24 11:27:36 +00004465 TINT_ICE(Resolver, diagnostics_)
Ben Clayton6fcefe42021-04-19 19:16:12 +00004466 << "AST node '" << node->TypeInfo().name
4467 << "' was encountered twice in the same AST of a Program\n"
Ben Claytonf0756e32021-04-29 20:57:55 +00004468 << "At: " << node->source() << "\n"
4469 << "Content: " << builder_->str(node) << "\n"
4470 << "Pointer: " << node;
Ben Clayton6fcefe42021-04-19 19:16:12 +00004471}
4472
Ben Claytonffd28e22021-06-24 11:27:36 +00004473void Resolver::AddError(const std::string& msg, const Source& source) const {
4474 diagnostics_.add_error(diag::System::Resolver, msg, source);
4475}
4476
4477void Resolver::AddWarning(const std::string& msg, const Source& source) const {
4478 diagnostics_.add_warning(diag::System::Resolver, msg, source);
4479}
4480
4481void Resolver::AddNote(const std::string& msg, const Source& source) const {
4482 diagnostics_.add_note(diag::System::Resolver, msg, source);
4483}
4484
Ben Clayton12ed13d2021-04-28 12:38:13 +00004485Resolver::VariableInfo::VariableInfo(const ast::Variable* decl,
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004486 sem::Type* ty,
Antonio Maioranodc4e6c12021-05-14 17:51:13 +00004487 const std::string& tn,
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004488 ast::StorageClass sc,
Ryan Harrison3832b8e2021-06-09 20:45:09 +00004489 ast::Access ac,
Ben Clayton4ffcf062021-07-22 13:24:59 +00004490 VariableKind k,
4491 uint32_t idx)
Antonio Maiorano9ef17472021-03-26 12:47:58 +00004492 : declaration(decl),
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004493 type(ty),
Ben Clayton109b18f2021-04-28 13:50:43 +00004494 type_name(tn),
Ben Clayton9b54a2e2021-05-18 10:28:48 +00004495 storage_class(sc),
Ryan Harrison3832b8e2021-06-09 20:45:09 +00004496 access(ac),
Ben Clayton4ffcf062021-07-22 13:24:59 +00004497 kind(k),
4498 index(idx) {}
Ben Claytonb17aea12021-02-03 17:51:09 +00004499
Ben Clayton5f0ea112021-03-09 10:54:37 +00004500Resolver::VariableInfo::~VariableInfo() = default;
Ben Claytonb17aea12021-02-03 17:51:09 +00004501
Ben Clayton5f0ea112021-03-09 10:54:37 +00004502Resolver::FunctionInfo::FunctionInfo(ast::Function* decl) : declaration(decl) {}
Ben Clayton5f0ea112021-03-09 10:54:37 +00004503Resolver::FunctionInfo::~FunctionInfo() = default;
Ben Clayton87c78dd2021-02-03 16:43:20 +00004504
Ben Claytonc7dcbae2021-03-09 15:08:48 +00004505} // namespace resolver
Dan Sinclair6e581892020-03-02 15:47:43 -05004506} // namespace tint