blob: 2100f6b17b7654cc42bb7413b6c729712686c032 [file] [log] [blame]
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001// Copyright 2021 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
15#include "src/tint/resolver/dependency_graph.h"
16
17#include <string>
Ryan Harrisondbc13af2022-02-21 15:19:07 +000018#include <utility>
19#include <vector>
20
Ben Clayton72876c12022-06-29 10:58:41 +000021#include "src/tint/ast/alias.h"
Ben Clayton72876c12022-06-29 10:58:41 +000022#include "src/tint/ast/assignment_statement.h"
Ben Clayton72876c12022-06-29 10:58:41 +000023#include "src/tint/ast/block_statement.h"
dan sinclairb8b0c212022-10-20 22:45:50 +000024#include "src/tint/ast/break_if_statement.h"
Ben Clayton72876c12022-06-29 10:58:41 +000025#include "src/tint/ast/break_statement.h"
26#include "src/tint/ast/call_statement.h"
27#include "src/tint/ast/compound_assignment_statement.h"
Ben Clayton0ddddb02023-02-09 15:35:27 +000028#include "src/tint/ast/const.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000029#include "src/tint/ast/continue_statement.h"
James Price098e3d82023-01-24 21:01:36 +000030#include "src/tint/ast/diagnostic_attribute.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000031#include "src/tint/ast/discard_statement.h"
Ben Clayton72876c12022-06-29 10:58:41 +000032#include "src/tint/ast/for_loop_statement.h"
Ben Clayton72876c12022-06-29 10:58:41 +000033#include "src/tint/ast/id_attribute.h"
Ben Clayton999db742023-02-02 15:16:28 +000034#include "src/tint/ast/identifier.h"
Ben Clayton72876c12022-06-29 10:58:41 +000035#include "src/tint/ast/if_statement.h"
36#include "src/tint/ast/increment_decrement_statement.h"
37#include "src/tint/ast/internal_attribute.h"
38#include "src/tint/ast/interpolate_attribute.h"
39#include "src/tint/ast/invariant_attribute.h"
40#include "src/tint/ast/location_attribute.h"
41#include "src/tint/ast/loop_statement.h"
Ben Clayton0ddddb02023-02-09 15:35:27 +000042#include "src/tint/ast/override.h"
Ben Clayton72876c12022-06-29 10:58:41 +000043#include "src/tint/ast/return_statement.h"
Ben Clayton72876c12022-06-29 10:58:41 +000044#include "src/tint/ast/stage_attribute.h"
Ben Clayton72876c12022-06-29 10:58:41 +000045#include "src/tint/ast/stride_attribute.h"
46#include "src/tint/ast/struct.h"
47#include "src/tint/ast/struct_member_align_attribute.h"
48#include "src/tint/ast/struct_member_offset_attribute.h"
49#include "src/tint/ast/struct_member_size_attribute.h"
50#include "src/tint/ast/switch_statement.h"
Ben Clayton2cdf1342023-02-03 13:24:18 +000051#include "src/tint/ast/templated_identifier.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000052#include "src/tint/ast/traverse_expressions.h"
Ben Clayton0ddddb02023-02-09 15:35:27 +000053#include "src/tint/ast/var.h"
Ben Clayton72876c12022-06-29 10:58:41 +000054#include "src/tint/ast/variable_decl_statement.h"
Ben Clayton72876c12022-06-29 10:58:41 +000055#include "src/tint/ast/while_statement.h"
56#include "src/tint/ast/workgroup_attribute.h"
dan sinclairef30aa42023-02-19 04:28:04 +000057#include "src/tint/builtin/builtin.h"
Ben Clayton4d3ff972023-02-21 17:33:54 +000058#include "src/tint/builtin/builtin_value.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000059#include "src/tint/scope_stack.h"
60#include "src/tint/sem/builtin.h"
Ben Clayton72876c12022-06-29 10:58:41 +000061#include "src/tint/symbol_table.h"
62#include "src/tint/utils/block_allocator.h"
Ben Clayton884f9522023-01-12 22:52:57 +000063#include "src/tint/utils/compiler_macros.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000064#include "src/tint/utils/defer.h"
65#include "src/tint/utils/map.h"
66#include "src/tint/utils/scoped_assignment.h"
67#include "src/tint/utils/unique_vector.h"
68
69#define TINT_DUMP_DEPENDENCY_GRAPH 0
70
dan sinclaird2093792022-04-07 17:45:45 +000071namespace tint::resolver {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000072namespace {
73
74// Forward declaration
75struct Global;
76
77/// Dependency describes how one global depends on another global
78struct DependencyInfo {
dan sinclair41e4d9a2022-05-01 14:40:55 +000079 /// The source of the symbol that forms the dependency
80 Source source;
81 /// A string describing how the dependency is referenced. e.g. 'calls'
82 const char* action = nullptr;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000083};
84
85/// DependencyEdge describes the two Globals used to define a dependency
86/// relationship.
87struct DependencyEdge {
dan sinclair41e4d9a2022-05-01 14:40:55 +000088 /// The Global that depends on #to
89 const Global* from;
90 /// The Global that is depended on by #from
91 const Global* to;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000092};
93
94/// DependencyEdgeCmp implements the contracts of std::equal_to<DependencyEdge>
95/// and std::hash<DependencyEdge>.
96struct DependencyEdgeCmp {
dan sinclair41e4d9a2022-05-01 14:40:55 +000097 /// Equality operator
98 bool operator()(const DependencyEdge& lhs, const DependencyEdge& rhs) const {
99 return lhs.from == rhs.from && lhs.to == rhs.to;
100 }
101 /// Hashing operator
102 inline std::size_t operator()(const DependencyEdge& d) const {
103 return utils::Hash(d.from, d.to);
104 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000105};
106
107/// A map of DependencyEdge to DependencyInfo
dan sinclair41e4d9a2022-05-01 14:40:55 +0000108using DependencyEdges =
Ben Clayton94181522022-11-09 20:55:33 +0000109 utils::Hashmap<DependencyEdge, DependencyInfo, 64, DependencyEdgeCmp, DependencyEdgeCmp>;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000110
111/// Global describes a module-scope variable, type or function.
112struct Global {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000113 explicit Global(const ast::Node* n) : node(n) {}
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000114
dan sinclair41e4d9a2022-05-01 14:40:55 +0000115 /// The declaration ast::Node
116 const ast::Node* node;
117 /// A list of dependencies that this global depends on
Ben Clayton94181522022-11-09 20:55:33 +0000118 utils::Vector<Global*, 8> deps;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000119};
120
121/// A map of global name to Global
Ben Clayton94181522022-11-09 20:55:33 +0000122using GlobalMap = utils::Hashmap<Symbol, Global*, 16>;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000123
124/// Raises an ICE that a global ast::Node type was not handled by this system.
125void UnhandledNode(diag::List& diagnostics, const ast::Node* node) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000126 TINT_ICE(Resolver, diagnostics) << "unhandled node type: " << node->TypeInfo().name;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000127}
128
129/// Raises an error diagnostic with the given message and source.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000130void AddError(diag::List& diagnostics, const std::string& msg, const Source& source) {
131 diagnostics.add_error(diag::System::Resolver, msg, source);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000132}
133
134/// Raises a note diagnostic with the given message and source.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000135void AddNote(diag::List& diagnostics, const std::string& msg, const Source& source) {
136 diagnostics.add_note(diag::System::Resolver, msg, source);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000137}
138
139/// DependencyScanner is used to traverse a module to build the list of
140/// global-to-global dependencies.
141class DependencyScanner {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000142 public:
143 /// Constructor
144 /// @param syms the program symbol table
145 /// @param globals_by_name map of global symbol to Global pointer
146 /// @param diagnostics diagnostic messages, appended with any errors found
147 /// @param graph the dependency graph to populate with resolved symbols
148 /// @param edges the map of globals-to-global dependency edges, which will
149 /// be populated by calls to Scan()
150 DependencyScanner(const SymbolTable& syms,
151 const GlobalMap& globals_by_name,
152 diag::List& diagnostics,
153 DependencyGraph& graph,
154 DependencyEdges& edges)
155 : symbols_(syms),
156 globals_(globals_by_name),
157 diagnostics_(diagnostics),
158 graph_(graph),
159 dependency_edges_(edges) {
160 // Register all the globals at global-scope
161 for (auto it : globals_by_name) {
Ben Clayton94181522022-11-09 20:55:33 +0000162 scope_stack_.Set(it.key, it.value->node);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000163 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000164 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000165
dan sinclair41e4d9a2022-05-01 14:40:55 +0000166 /// Walks the global declarations, resolving symbols, and determining the
167 /// dependencies of each global.
168 void Scan(Global* global) {
169 TINT_SCOPED_ASSIGNMENT(current_global_, global);
170 Switch(
171 global->node,
172 [&](const ast::Struct* str) {
Ben Claytonb75252b2023-02-09 10:34:14 +0000173 Declare(str->name->symbol, str);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000174 for (auto* member : str->members) {
dan sinclaircb41b8f2022-09-26 15:54:55 +0000175 TraverseAttributes(member->attributes);
Ben Clayton971318f2023-02-14 13:52:43 +0000176 TraverseTypeExpression(member->type);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000177 }
178 },
179 [&](const ast::Alias* alias) {
Ben Claytonb75252b2023-02-09 10:34:14 +0000180 Declare(alias->name->symbol, alias);
Ben Clayton971318f2023-02-14 13:52:43 +0000181 TraverseTypeExpression(alias->type);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000182 },
183 [&](const ast::Function* func) {
Ben Claytonce31d182023-02-09 10:34:14 +0000184 Declare(func->name->symbol, func);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000185 TraverseFunction(func);
186 },
Ben Clayton79781f22023-02-18 17:13:18 +0000187 [&](const ast::Variable* v) {
188 Declare(v->name->symbol, v);
189 TraverseVariable(v);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000190 },
James Price98dc5a82023-02-04 12:20:55 +0000191 [&](const ast::DiagnosticDirective*) {
192 // Diagnostic directives do not affect the dependency graph.
James Price098e3d82023-01-24 21:01:36 +0000193 },
dan sinclair41e4d9a2022-05-01 14:40:55 +0000194 [&](const ast::Enable*) {
James Price098e3d82023-01-24 21:01:36 +0000195 // Enable directives do not affect the dependency graph.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000196 },
Ben Clayton971318f2023-02-14 13:52:43 +0000197 [&](const ast::ConstAssert* assertion) {
198 TraverseValueExpression(assertion->condition);
199 },
dan sinclair41e4d9a2022-05-01 14:40:55 +0000200 [&](Default) { UnhandledNode(diagnostics_, global->node); });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000201 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000202
dan sinclair41e4d9a2022-05-01 14:40:55 +0000203 private:
Ben Clayton79781f22023-02-18 17:13:18 +0000204 /// Traverses the variable, performing symbol resolution.
205 void TraverseVariable(const ast::Variable* v) {
206 if (auto* var = v->As<ast::Var>()) {
207 TraverseAddressSpaceExpression(var->declared_address_space);
208 TraverseAccessExpression(var->declared_access);
209 }
210 TraverseTypeExpression(v->type);
211 TraverseAttributes(v->attributes);
212 TraverseValueExpression(v->initializer);
213 }
214
215 /// Traverses the function, performing symbol resolution and determining global dependencies.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000216 void TraverseFunction(const ast::Function* func) {
Ben Claytonca98b1b2022-11-07 13:15:21 +0000217 TraverseAttributes(func->attributes);
218 TraverseAttributes(func->return_type_attributes);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000219 // Perform symbol resolution on all the parameter types before registering
220 // the parameters themselves. This allows the case of declaring a parameter
221 // with the same identifier as its type.
222 for (auto* param : func->params) {
Ben Claytonca98b1b2022-11-07 13:15:21 +0000223 TraverseAttributes(param->attributes);
Ben Clayton971318f2023-02-14 13:52:43 +0000224 TraverseTypeExpression(param->type);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000225 }
226 // Resolve the return type
Ben Clayton971318f2023-02-14 13:52:43 +0000227 TraverseTypeExpression(func->return_type);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000228
dan sinclair41e4d9a2022-05-01 14:40:55 +0000229 // Push the scope stack for the parameters and function body.
230 scope_stack_.Push();
231 TINT_DEFER(scope_stack_.Pop());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000232
dan sinclair41e4d9a2022-05-01 14:40:55 +0000233 for (auto* param : func->params) {
Ben Clayton651d9e22023-02-09 10:34:14 +0000234 if (auto* shadows = scope_stack_.Get(param->name->symbol)) {
Ben Clayton94181522022-11-09 20:55:33 +0000235 graph_.shadows.Add(param, shadows);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000236 }
Ben Clayton651d9e22023-02-09 10:34:14 +0000237 Declare(param->name->symbol, param);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000238 }
239 if (func->body) {
240 TraverseStatements(func->body->statements);
241 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000242 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000243
dan sinclair41e4d9a2022-05-01 14:40:55 +0000244 /// Traverses the statements, performing symbol resolution and determining
245 /// global dependencies.
Ben Clayton783b1692022-08-02 17:03:35 +0000246 void TraverseStatements(utils::VectorRef<const ast::Statement*> stmts) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000247 for (auto* s : stmts) {
248 TraverseStatement(s);
249 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000250 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000251
252 /// Traverses the statement, performing symbol resolution and determining
253 /// global dependencies.
254 void TraverseStatement(const ast::Statement* stmt) {
255 if (!stmt) {
256 return;
257 }
258 Switch(
259 stmt, //
260 [&](const ast::AssignmentStatement* a) {
Ben Clayton971318f2023-02-14 13:52:43 +0000261 TraverseValueExpression(a->lhs);
262 TraverseValueExpression(a->rhs);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000263 },
264 [&](const ast::BlockStatement* b) {
265 scope_stack_.Push();
266 TINT_DEFER(scope_stack_.Pop());
267 TraverseStatements(b->statements);
268 },
Ben Clayton971318f2023-02-14 13:52:43 +0000269 [&](const ast::BreakIfStatement* b) { TraverseValueExpression(b->condition); },
270 [&](const ast::CallStatement* r) { TraverseValueExpression(r->expr); },
dan sinclair41e4d9a2022-05-01 14:40:55 +0000271 [&](const ast::CompoundAssignmentStatement* a) {
Ben Clayton971318f2023-02-14 13:52:43 +0000272 TraverseValueExpression(a->lhs);
273 TraverseValueExpression(a->rhs);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000274 },
275 [&](const ast::ForLoopStatement* l) {
276 scope_stack_.Push();
277 TINT_DEFER(scope_stack_.Pop());
278 TraverseStatement(l->initializer);
Ben Clayton971318f2023-02-14 13:52:43 +0000279 TraverseValueExpression(l->condition);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000280 TraverseStatement(l->continuing);
281 TraverseStatement(l->body);
282 },
Ben Clayton971318f2023-02-14 13:52:43 +0000283 [&](const ast::IncrementDecrementStatement* i) { TraverseValueExpression(i->lhs); },
dan sinclair41e4d9a2022-05-01 14:40:55 +0000284 [&](const ast::LoopStatement* l) {
285 scope_stack_.Push();
286 TINT_DEFER(scope_stack_.Pop());
287 TraverseStatements(l->body->statements);
288 TraverseStatement(l->continuing);
289 },
290 [&](const ast::IfStatement* i) {
Ben Clayton971318f2023-02-14 13:52:43 +0000291 TraverseValueExpression(i->condition);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000292 TraverseStatement(i->body);
293 if (i->else_statement) {
294 TraverseStatement(i->else_statement);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000295 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000296 },
Ben Clayton971318f2023-02-14 13:52:43 +0000297 [&](const ast::ReturnStatement* r) { TraverseValueExpression(r->value); },
dan sinclair41e4d9a2022-05-01 14:40:55 +0000298 [&](const ast::SwitchStatement* s) {
Ben Clayton971318f2023-02-14 13:52:43 +0000299 TraverseValueExpression(s->condition);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000300 for (auto* c : s->body) {
301 for (auto* sel : c->selectors) {
Ben Clayton971318f2023-02-14 13:52:43 +0000302 TraverseValueExpression(sel->expr);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000303 }
304 TraverseStatement(c->body);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000305 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000306 },
307 [&](const ast::VariableDeclStatement* v) {
Ben Clayton651d9e22023-02-09 10:34:14 +0000308 if (auto* shadows = scope_stack_.Get(v->variable->name->symbol)) {
Ben Clayton94181522022-11-09 20:55:33 +0000309 graph_.shadows.Add(v->variable, shadows);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000310 }
Ben Clayton79781f22023-02-18 17:13:18 +0000311 TraverseVariable(v->variable);
Ben Clayton651d9e22023-02-09 10:34:14 +0000312 Declare(v->variable->name->symbol, v->variable);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000313 },
dan sinclair49d1a2d2022-06-16 12:01:27 +0000314 [&](const ast::WhileStatement* w) {
315 scope_stack_.Push();
316 TINT_DEFER(scope_stack_.Pop());
Ben Clayton971318f2023-02-14 13:52:43 +0000317 TraverseValueExpression(w->condition);
dan sinclair49d1a2d2022-06-16 12:01:27 +0000318 TraverseStatement(w->body);
319 },
Ben Clayton971318f2023-02-14 13:52:43 +0000320 [&](const ast::ConstAssert* assertion) {
321 TraverseValueExpression(assertion->condition);
322 },
dan sinclair41e4d9a2022-05-01 14:40:55 +0000323 [&](Default) {
Ben Clayton884f9522023-01-12 22:52:57 +0000324 if (TINT_UNLIKELY((!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement,
325 ast::DiscardStatement>()))) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000326 UnhandledNode(diagnostics_, stmt);
327 }
328 });
329 }
330
331 /// Adds the symbol definition to the current scope, raising an error if two
332 /// symbols collide within the same scope.
333 void Declare(Symbol symbol, const ast::Node* node) {
334 auto* old = scope_stack_.Set(symbol, node);
335 if (old != nullptr && node != old) {
336 auto name = symbols_.NameFor(symbol);
337 AddError(diagnostics_, "redeclaration of '" + name + "'", node->source);
338 AddNote(diagnostics_, "'" + name + "' previously declared here", old->source);
339 }
340 }
341
Ben Clayton971318f2023-02-14 13:52:43 +0000342 /// Traverses the expression @p root_expr for the intended use as a value, performing symbol
343 /// resolution and determining global dependencies.
344 void TraverseValueExpression(const ast::Expression* root) {
345 TraverseExpression(root, "identifier", "references");
346 }
347
348 /// Traverses the expression @p root_expr for the intended use as a type, performing symbol
349 /// resolution and determining global dependencies.
350 void TraverseTypeExpression(const ast::Expression* root) {
351 TraverseExpression(root, "type", "references");
352 }
353
Ben Clayton79781f22023-02-18 17:13:18 +0000354 /// Traverses the expression @p root_expr for the intended use as an address space, performing
355 /// symbol resolution and determining global dependencies.
356 void TraverseAddressSpaceExpression(const ast::Expression* root) {
357 TraverseExpression(root, "address space", "references");
358 }
359
360 /// Traverses the expression @p root_expr for the intended use as an access, performing symbol
361 /// resolution and determining global dependencies.
362 void TraverseAccessExpression(const ast::Expression* root) {
363 TraverseExpression(root, "access", "references");
364 }
365
Ben Clayton971318f2023-02-14 13:52:43 +0000366 /// Traverses the expression @p root_expr for the intended use as a call target, performing
367 /// symbol resolution and determining global dependencies.
368 void TraverseCallableExpression(const ast::Expression* root) {
369 TraverseExpression(root, "function", "calls");
370 }
371
372 /// Traverses the expression @p root_expr, performing symbol resolution and determining global
373 /// dependencies.
374 void TraverseExpression(const ast::Expression* root_expr,
375 const char* root_use,
376 const char* root_action) {
377 if (!root_expr) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000378 return;
379 }
Ben Clayton971318f2023-02-14 13:52:43 +0000380
381 struct Pending {
382 const ast::Expression* expr;
383 const char* use;
384 const char* action;
385 };
386 utils::Vector<Pending, 8> pending{{root_expr, root_use, root_action}};
Ben Clayton1131d312023-02-10 19:24:24 +0000387 while (!pending.IsEmpty()) {
Ben Clayton971318f2023-02-14 13:52:43 +0000388 auto next = pending.Pop();
389 ast::TraverseExpressions(next.expr, diagnostics_, [&](const ast::Expression* expr) {
Ben Clayton1131d312023-02-10 19:24:24 +0000390 Switch(
391 expr,
392 [&](const ast::IdentifierExpression* e) {
Ben Clayton971318f2023-02-14 13:52:43 +0000393 AddDependency(e->identifier, e->identifier->symbol, next.use, next.action);
Ben Clayton1131d312023-02-10 19:24:24 +0000394 if (auto* tmpl_ident = e->identifier->As<ast::TemplatedIdentifier>()) {
395 for (auto* arg : tmpl_ident->arguments) {
Ben Clayton971318f2023-02-14 13:52:43 +0000396 pending.Push({arg, "identifier", "references"});
Ben Clayton1131d312023-02-10 19:24:24 +0000397 }
398 }
399 },
400 [&](const ast::CallExpression* call) {
Ben Clayton971318f2023-02-14 13:52:43 +0000401 TraverseCallableExpression(call->target);
Ben Clayton1131d312023-02-10 19:24:24 +0000402 },
Ben Clayton971318f2023-02-14 13:52:43 +0000403 [&](const ast::BitcastExpression* cast) {
404 TraverseTypeExpression(cast->type);
405 });
Ben Clayton1131d312023-02-10 19:24:24 +0000406 return ast::TraverseAction::Descend;
407 });
408 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000409 }
410
dan sinclair41e4d9a2022-05-01 14:40:55 +0000411 /// Traverses the attribute list, performing symbol resolution and
412 /// determining global dependencies.
Ben Clayton783b1692022-08-02 17:03:35 +0000413 void TraverseAttributes(utils::VectorRef<const ast::Attribute*> attrs) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000414 for (auto* attr : attrs) {
415 TraverseAttribute(attr);
416 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000417 }
418
dan sinclair41e4d9a2022-05-01 14:40:55 +0000419 /// Traverses the attribute, performing symbol resolution and determining
420 /// global dependencies.
421 void TraverseAttribute(const ast::Attribute* attr) {
dan sinclair72ac53e2022-10-14 18:39:04 +0000422 bool handled = Switch(
423 attr,
424 [&](const ast::BindingAttribute* binding) {
Ben Clayton971318f2023-02-14 13:52:43 +0000425 TraverseValueExpression(binding->expr);
dan sinclair72ac53e2022-10-14 18:39:04 +0000426 return true;
427 },
Ben Clayton4d3ff972023-02-21 17:33:54 +0000428 [&](const ast::BuiltinAttribute* builtin) {
429 TraverseExpression(builtin->builtin, "builtin", "references");
430 return true;
431 },
dan sinclair72ac53e2022-10-14 18:39:04 +0000432 [&](const ast::GroupAttribute* group) {
Ben Clayton971318f2023-02-14 13:52:43 +0000433 TraverseValueExpression(group->expr);
dan sinclair72ac53e2022-10-14 18:39:04 +0000434 return true;
435 },
dan sinclair155165c2022-10-17 14:35:43 +0000436 [&](const ast::IdAttribute* id) {
Ben Clayton971318f2023-02-14 13:52:43 +0000437 TraverseValueExpression(id->expr);
dan sinclair155165c2022-10-17 14:35:43 +0000438 return true;
439 },
dan sinclair3fd42ae2022-10-17 15:21:48 +0000440 [&](const ast::LocationAttribute* loc) {
Ben Clayton971318f2023-02-14 13:52:43 +0000441 TraverseValueExpression(loc->expr);
dan sinclair3fd42ae2022-10-17 15:21:48 +0000442 return true;
443 },
dan sinclair72ac53e2022-10-14 18:39:04 +0000444 [&](const ast::StructMemberAlignAttribute* align) {
Ben Clayton971318f2023-02-14 13:52:43 +0000445 TraverseValueExpression(align->expr);
dan sinclair72ac53e2022-10-14 18:39:04 +0000446 return true;
447 },
448 [&](const ast::StructMemberSizeAttribute* size) {
Ben Clayton971318f2023-02-14 13:52:43 +0000449 TraverseValueExpression(size->expr);
dan sinclair72ac53e2022-10-14 18:39:04 +0000450 return true;
451 },
452 [&](const ast::WorkgroupAttribute* wg) {
Ben Clayton971318f2023-02-14 13:52:43 +0000453 TraverseValueExpression(wg->x);
454 TraverseValueExpression(wg->y);
455 TraverseValueExpression(wg->z);
dan sinclair72ac53e2022-10-14 18:39:04 +0000456 return true;
457 });
458 if (handled) {
dan sinclair308c55d2022-10-14 18:27:35 +0000459 return;
460 }
dan sinclaircb41b8f2022-09-26 15:54:55 +0000461
James Price098e3d82023-01-24 21:01:36 +0000462 if (attr->IsAnyOf<ast::BuiltinAttribute, ast::DiagnosticAttribute, ast::InternalAttribute,
463 ast::InterpolateAttribute, ast::InvariantAttribute, ast::StageAttribute,
464 ast::StrideAttribute, ast::StructMemberOffsetAttribute>()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000465 return;
466 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000467
dan sinclair41e4d9a2022-05-01 14:40:55 +0000468 UnhandledNode(diagnostics_, attr);
469 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000470
Ben Claytoncf0e9302023-02-08 15:18:43 +0000471 /// Adds the dependency from @p from to @p to, erroring if @p to cannot be resolved.
472 void AddDependency(const ast::Identifier* from,
473 Symbol to,
474 const char* use,
475 const char* action) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000476 auto* resolved = scope_stack_.Get(to);
477 if (!resolved) {
Ben Claytoncf0e9302023-02-08 15:18:43 +0000478 auto s = symbols_.NameFor(to);
479 if (auto builtin_fn = sem::ParseBuiltinType(s); builtin_fn != sem::BuiltinType::kNone) {
480 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(builtin_fn));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000481 return;
482 }
dan sinclairef30aa42023-02-19 04:28:04 +0000483 if (auto builtin_ty = builtin::ParseBuiltin(s);
484 builtin_ty != builtin::Builtin::kUndefined) {
Ben Claytoncf0e9302023-02-08 15:18:43 +0000485 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(builtin_ty));
486 return;
487 }
Ben Clayton4d3ff972023-02-21 17:33:54 +0000488 if (auto builtin_val = builtin::ParseBuiltinValue(s);
489 builtin_val != builtin::BuiltinValue::kUndefined) {
490 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(builtin_val));
491 return;
492 }
dan sinclair2a651632023-02-19 04:03:55 +0000493 if (auto addr = builtin::ParseAddressSpace(s);
494 addr != builtin::AddressSpace::kUndefined) {
Ben Clayton031e2f52023-02-09 15:35:27 +0000495 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(addr));
496 return;
497 }
dan sinclairba082fd2023-02-19 04:14:19 +0000498 if (auto fmt = builtin::ParseTexelFormat(s); fmt != builtin::TexelFormat::kUndefined) {
Ben Clayton031e2f52023-02-09 15:35:27 +0000499 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(fmt));
500 return;
501 }
dan sinclairb6cc4cb2023-02-19 04:01:29 +0000502 if (auto access = builtin::ParseAccess(s); access != builtin::Access::kUndefined) {
Ben Clayton031e2f52023-02-09 15:35:27 +0000503 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(access));
504 return;
505 }
Ben Claytoncf0e9302023-02-08 15:18:43 +0000506
507 UnknownSymbol(to, from->source, use);
508 return;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000509 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000510
Ben Clayton7c6e2292022-11-23 21:04:25 +0000511 if (auto global = globals_.Find(to); global && (*global)->node == resolved) {
Ben Clayton94181522022-11-09 20:55:33 +0000512 if (dependency_edges_.Add(DependencyEdge{current_global_, *global},
513 DependencyInfo{from->source, action})) {
514 current_global_->deps.Push(*global);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000515 }
516 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000517
Ben Claytoncf0e9302023-02-08 15:18:43 +0000518 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(resolved));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000519 }
520
Ben Clayton971318f2023-02-14 13:52:43 +0000521 /// Appends an error to the diagnostics that the given symbol cannot be resolved.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000522 void UnknownSymbol(Symbol name, Source source, const char* use) {
523 AddError(diagnostics_, "unknown " + std::string(use) + ": '" + symbols_.NameFor(name) + "'",
524 source);
525 }
526
Ben Clayton94181522022-11-09 20:55:33 +0000527 using VariableMap = utils::Hashmap<Symbol, const ast::Variable*, 32>;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000528 const SymbolTable& symbols_;
529 const GlobalMap& globals_;
530 diag::List& diagnostics_;
531 DependencyGraph& graph_;
532 DependencyEdges& dependency_edges_;
533
James Price2cf32b12022-05-11 13:50:33 +0000534 ScopeStack<Symbol, const ast::Node*> scope_stack_;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000535 Global* current_global_ = nullptr;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000536};
537
538/// The global dependency analysis system
539struct DependencyAnalysis {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000540 public:
541 /// Constructor
542 DependencyAnalysis(const SymbolTable& symbols, diag::List& diagnostics, DependencyGraph& graph)
543 : symbols_(symbols), diagnostics_(diagnostics), graph_(graph) {}
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000544
dan sinclair41e4d9a2022-05-01 14:40:55 +0000545 /// Performs global dependency analysis on the module, emitting any errors to
546 /// #diagnostics.
547 /// @returns true if analysis found no errors, otherwise false.
548 bool Run(const ast::Module& module) {
Ben Clayton7d04ced2022-08-03 08:43:15 +0000549 // Reserve container memory
Ben Claytoncf0e9302023-02-08 15:18:43 +0000550 graph_.resolved_identifiers.Reserve(module.GlobalDeclarations().Length());
Ben Claytondce63f52022-08-17 18:07:20 +0000551 sorted_.Reserve(module.GlobalDeclarations().Length());
Ben Clayton7d04ced2022-08-03 08:43:15 +0000552
dan sinclair41e4d9a2022-05-01 14:40:55 +0000553 // Collect all the named globals from the AST module
554 GatherGlobals(module);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000555
dan sinclair41e4d9a2022-05-01 14:40:55 +0000556 // Traverse the named globals to build the dependency graph
557 DetermineDependencies();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000558
dan sinclair41e4d9a2022-05-01 14:40:55 +0000559 // Sort the globals into dependency order
560 SortGlobals();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000561
dan sinclair41e4d9a2022-05-01 14:40:55 +0000562 // Dump the dependency graph if TINT_DUMP_DEPENDENCY_GRAPH is non-zero
563 DumpDependencyGraph();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000564
Ben Claytondce63f52022-08-17 18:07:20 +0000565 graph_.ordered_globals = sorted_.Release();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000566
dan sinclair41e4d9a2022-05-01 14:40:55 +0000567 return !diagnostics_.contains_errors();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000568 }
569
dan sinclair41e4d9a2022-05-01 14:40:55 +0000570 private:
571 /// @param node the ast::Node of the global declaration
572 /// @returns the symbol of the global declaration node
573 /// @note will raise an ICE if the node is not a type, function or variable
574 /// declaration
575 Symbol SymbolOf(const ast::Node* node) const {
576 return Switch(
577 node, //
Ben Claytonb75252b2023-02-09 10:34:14 +0000578 [&](const ast::TypeDecl* td) { return td->name->symbol; },
Ben Claytonce31d182023-02-09 10:34:14 +0000579 [&](const ast::Function* func) { return func->name->symbol; },
Ben Clayton651d9e22023-02-09 10:34:14 +0000580 [&](const ast::Variable* var) { return var->name->symbol; },
James Price98dc5a82023-02-04 12:20:55 +0000581 [&](const ast::DiagnosticDirective*) { return Symbol(); },
Ben Clayton02791e92022-08-02 23:28:28 +0000582 [&](const ast::Enable*) { return Symbol(); },
Ben Claytonc98d57d2023-01-24 14:59:43 +0000583 [&](const ast::ConstAssert*) { return Symbol(); },
dan sinclair41e4d9a2022-05-01 14:40:55 +0000584 [&](Default) {
585 UnhandledNode(diagnostics_, node);
586 return Symbol{};
587 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000588 }
589
dan sinclair41e4d9a2022-05-01 14:40:55 +0000590 /// @param node the ast::Node of the global declaration
591 /// @returns the name of the global declaration node
592 /// @note will raise an ICE if the node is not a type, function or variable
593 /// declaration
594 std::string NameOf(const ast::Node* node) const { return symbols_.NameFor(SymbolOf(node)); }
595
596 /// @param node the ast::Node of the global declaration
597 /// @returns a string representation of the global declaration kind
598 /// @note will raise an ICE if the node is not a type, function or variable
599 /// declaration
600 std::string KindOf(const ast::Node* node) {
601 return Switch(
Ben Claytonc98d57d2023-01-24 14:59:43 +0000602 node, //
603 [&](const ast::Struct*) { return "struct"; }, //
604 [&](const ast::Alias*) { return "alias"; }, //
605 [&](const ast::Function*) { return "function"; }, //
606 [&](const ast::Variable* v) { return v->Kind(); }, //
607 [&](const ast::ConstAssert*) { return "const_assert"; }, //
dan sinclair41e4d9a2022-05-01 14:40:55 +0000608 [&](Default) {
609 UnhandledNode(diagnostics_, node);
610 return "<error>";
611 });
612 }
613
614 /// Traverses `module`, collecting all the global declarations and populating
615 /// the #globals and #declaration_order fields.
616 void GatherGlobals(const ast::Module& module) {
617 for (auto* node : module.GlobalDeclarations()) {
618 auto* global = allocator_.Create(node);
Ben Clayton02791e92022-08-02 23:28:28 +0000619 if (auto symbol = SymbolOf(node); symbol.IsValid()) {
Ben Clayton94181522022-11-09 20:55:33 +0000620 globals_.Add(symbol, global);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000621 }
Ben Clayton94181522022-11-09 20:55:33 +0000622 declaration_order_.Push(global);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000623 }
624 }
625
626 /// Walks the global declarations, determining the dependencies of each global
627 /// and adding these to each global's Global::deps field.
628 void DetermineDependencies() {
629 DependencyScanner scanner(symbols_, globals_, diagnostics_, graph_, dependency_edges_);
630 for (auto* global : declaration_order_) {
631 scanner.Scan(global);
632 }
633 }
634
635 /// Performs a depth-first traversal of `root`'s dependencies, calling `enter`
636 /// as the function decends into each dependency and `exit` when bubbling back
637 /// up towards the root.
638 /// @param enter is a function with the signature: `bool(Global*)`. The
639 /// `enter` function returns true if TraverseDependencies() should traverse
640 /// the dependency, otherwise it will be skipped.
641 /// @param exit is a function with the signature: `void(Global*)`. The `exit`
642 /// function is only called if the corresponding `enter` call returned true.
643 template <typename ENTER, typename EXIT>
644 void TraverseDependencies(const Global* root, ENTER&& enter, EXIT&& exit) {
645 // Entry is a single entry in the traversal stack. Entry points to a
646 // dep_idx'th dependency of Entry::global.
647 struct Entry {
648 const Global* global; // The parent global
649 size_t dep_idx; // The dependency index in `global->deps`
650 };
651
652 if (!enter(root)) {
653 return;
654 }
655
Ben Clayton94181522022-11-09 20:55:33 +0000656 utils::Vector<Entry, 16> stack{Entry{root, 0}};
dan sinclair41e4d9a2022-05-01 14:40:55 +0000657 while (true) {
Ben Clayton94181522022-11-09 20:55:33 +0000658 auto& entry = stack.Back();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000659 // Have we exhausted the dependencies of entry.global?
Ben Clayton94181522022-11-09 20:55:33 +0000660 if (entry.dep_idx < entry.global->deps.Length()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000661 // No, there's more dependencies to traverse.
662 auto& dep = entry.global->deps[entry.dep_idx];
663 // Does the caller want to enter this dependency?
Ben Clayton94181522022-11-09 20:55:33 +0000664 if (enter(dep)) { // Yes.
665 stack.Push(Entry{dep, 0}); // Enter the dependency.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000666 } else {
667 entry.dep_idx++; // No. Skip this node.
668 }
669 } else {
670 // Yes. Time to back up.
671 // Exit this global, pop the stack, and if there's another parent node,
672 // increment its dependency index, and loop again.
673 exit(entry.global);
Ben Clayton94181522022-11-09 20:55:33 +0000674 stack.Pop();
675 if (stack.IsEmpty()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000676 return; // All done.
677 }
Ben Clayton94181522022-11-09 20:55:33 +0000678 stack.Back().dep_idx++;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000679 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000680 }
681 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000682
dan sinclair41e4d9a2022-05-01 14:40:55 +0000683 /// SortGlobals sorts the globals into dependency order, erroring if cyclic
684 /// dependencies are found. The sorted dependencies are assigned to #sorted.
685 void SortGlobals() {
686 if (diagnostics_.contains_errors()) {
687 return; // This code assumes there are no undeclared identifiers.
688 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000689
James Price098e3d82023-01-24 21:01:36 +0000690 // Make sure all directives go before any other global declarations.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000691 for (auto* global : declaration_order_) {
James Price98dc5a82023-02-04 12:20:55 +0000692 if (global->node->IsAnyOf<ast::DiagnosticDirective, ast::Enable>()) {
James Price098e3d82023-01-24 21:01:36 +0000693 sorted_.Add(global->node);
Zhaoming Jiang418e8732022-06-16 08:30:17 +0000694 }
695 }
696
697 for (auto* global : declaration_order_) {
James Price98dc5a82023-02-04 12:20:55 +0000698 if (global->node->IsAnyOf<ast::DiagnosticDirective, ast::Enable>()) {
James Price098e3d82023-01-24 21:01:36 +0000699 // Skip directives here, as they are already added.
Zhaoming Jiang418e8732022-06-16 08:30:17 +0000700 continue;
701 }
Ben Claytondce63f52022-08-17 18:07:20 +0000702 utils::UniqueVector<const Global*, 8> stack;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000703 TraverseDependencies(
704 global,
705 [&](const Global* g) { // Enter
Ben Claytondce63f52022-08-17 18:07:20 +0000706 if (!stack.Add(g)) {
707 CyclicDependencyFound(g, stack.Release());
dan sinclair41e4d9a2022-05-01 14:40:55 +0000708 return false;
709 }
Ben Claytondce63f52022-08-17 18:07:20 +0000710 if (sorted_.Contains(g->node)) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000711 // Visited this global already.
712 // stack was pushed, but exit() will not be called when we return
713 // false, so pop here.
Ben Claytondce63f52022-08-17 18:07:20 +0000714 stack.Pop();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000715 return false;
716 }
717 return true;
718 },
719 [&](const Global* g) { // Exit. Only called if Enter returned true.
Ben Claytondce63f52022-08-17 18:07:20 +0000720 sorted_.Add(g->node);
721 stack.Pop();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000722 });
723
Ben Claytondce63f52022-08-17 18:07:20 +0000724 sorted_.Add(global->node);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000725
Ben Clayton884f9522023-01-12 22:52:57 +0000726 if (TINT_UNLIKELY(!stack.IsEmpty())) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000727 // Each stack.push() must have a corresponding stack.pop_back().
728 TINT_ICE(Resolver, diagnostics_)
729 << "stack not empty after returning from TraverseDependencies()";
730 }
731 }
732 }
733
734 /// DepInfoFor() looks up the global dependency information for the dependency
735 /// of global `from` depending on `to`.
736 /// @note will raise an ICE if the edge is not found.
737 DependencyInfo DepInfoFor(const Global* from, const Global* to) const {
Ben Clayton884f9522023-01-12 22:52:57 +0000738 auto info = dependency_edges_.Find(DependencyEdge{from, to});
739 if (TINT_LIKELY(info)) {
Ben Clayton94181522022-11-09 20:55:33 +0000740 return *info;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000741 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000742 TINT_ICE(Resolver, diagnostics_)
dan sinclair41e4d9a2022-05-01 14:40:55 +0000743 << "failed to find dependency info for edge: '" << NameOf(from->node) << "' -> '"
744 << NameOf(to->node) << "'";
745 return {};
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000746 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000747
dan sinclair41e4d9a2022-05-01 14:40:55 +0000748 /// CyclicDependencyFound() emits an error diagnostic for a cyclic dependency.
749 /// @param root is the global that starts the cyclic dependency, which must be
750 /// found in `stack`.
751 /// @param stack is the global dependency stack that contains a loop.
Ben Claytondce63f52022-08-17 18:07:20 +0000752 void CyclicDependencyFound(const Global* root, utils::VectorRef<const Global*> stack) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000753 std::stringstream msg;
754 msg << "cyclic dependency found: ";
755 constexpr size_t kLoopNotStarted = ~0u;
756 size_t loop_start = kLoopNotStarted;
Ben Claytondce63f52022-08-17 18:07:20 +0000757 for (size_t i = 0; i < stack.Length(); i++) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000758 auto* e = stack[i];
759 if (loop_start == kLoopNotStarted && e == root) {
760 loop_start = i;
761 }
762 if (loop_start != kLoopNotStarted) {
763 msg << "'" << NameOf(e->node) << "' -> ";
764 }
765 }
766 msg << "'" << NameOf(root->node) << "'";
767 AddError(diagnostics_, msg.str(), root->node->source);
Ben Claytondce63f52022-08-17 18:07:20 +0000768 for (size_t i = loop_start; i < stack.Length(); i++) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000769 auto* from = stack[i];
Ben Claytondce63f52022-08-17 18:07:20 +0000770 auto* to = (i + 1 < stack.Length()) ? stack[i + 1] : stack[loop_start];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000771 auto info = DepInfoFor(from, to);
772 AddNote(diagnostics_,
773 KindOf(from->node) + " '" + NameOf(from->node) + "' " + info.action + " " +
774 KindOf(to->node) + " '" + NameOf(to->node) + "' here",
775 info.source);
776 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000777 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000778
dan sinclair41e4d9a2022-05-01 14:40:55 +0000779 void DumpDependencyGraph() {
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000780#if TINT_DUMP_DEPENDENCY_GRAPH == 0
dan sinclair41e4d9a2022-05-01 14:40:55 +0000781 if ((true)) {
782 return;
783 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000784#endif // TINT_DUMP_DEPENDENCY_GRAPH
dan sinclair41e4d9a2022-05-01 14:40:55 +0000785 printf("=========================\n");
786 printf("------ declaration ------ \n");
787 for (auto* global : declaration_order_) {
788 printf("%s\n", NameOf(global->node).c_str());
789 }
790 printf("------ dependencies ------ \n");
791 for (auto* node : sorted_) {
792 auto symbol = SymbolOf(node);
Ben Clayton94181522022-11-09 20:55:33 +0000793 auto* global = *globals_.Find(symbol);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000794 printf("%s depends on:\n", symbols_.NameFor(symbol).c_str());
795 for (auto* dep : global->deps) {
796 printf(" %s\n", NameOf(dep->node).c_str());
797 }
798 }
799 printf("=========================\n");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000800 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000801
dan sinclair41e4d9a2022-05-01 14:40:55 +0000802 /// Program symbols
803 const SymbolTable& symbols_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000804
dan sinclair41e4d9a2022-05-01 14:40:55 +0000805 /// Program diagnostics
806 diag::List& diagnostics_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000807
dan sinclair41e4d9a2022-05-01 14:40:55 +0000808 /// The resulting dependency graph
809 DependencyGraph& graph_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000810
dan sinclair41e4d9a2022-05-01 14:40:55 +0000811 /// Allocator of Globals
812 utils::BlockAllocator<Global> allocator_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000813
dan sinclair41e4d9a2022-05-01 14:40:55 +0000814 /// Global map, keyed by name. Populated by GatherGlobals().
815 GlobalMap globals_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000816
dan sinclair41e4d9a2022-05-01 14:40:55 +0000817 /// Map of DependencyEdge to DependencyInfo. Populated by
818 /// DetermineDependencies().
819 DependencyEdges dependency_edges_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000820
dan sinclair41e4d9a2022-05-01 14:40:55 +0000821 /// Globals in declaration order. Populated by GatherGlobals().
Ben Clayton94181522022-11-09 20:55:33 +0000822 utils::Vector<Global*, 64> declaration_order_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000823
dan sinclair41e4d9a2022-05-01 14:40:55 +0000824 /// Globals in sorted dependency order. Populated by SortGlobals().
Ben Claytondce63f52022-08-17 18:07:20 +0000825 utils::UniqueVector<const ast::Node*, 64> sorted_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000826};
827
828} // namespace
829
830DependencyGraph::DependencyGraph() = default;
831DependencyGraph::DependencyGraph(DependencyGraph&&) = default;
832DependencyGraph::~DependencyGraph() = default;
833
834bool DependencyGraph::Build(const ast::Module& module,
835 const SymbolTable& symbols,
836 diag::List& diagnostics,
837 DependencyGraph& output) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000838 DependencyAnalysis da{symbols, diagnostics, output};
839 return da.Run(module);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000840}
841
Ben Clayton0ddddb02023-02-09 15:35:27 +0000842std::string ResolvedIdentifier::String(const SymbolTable& symbols, diag::List& diagnostics) const {
843 if (!Resolved()) {
844 return "<unresolved symbol>";
Ben Claytoncf0e9302023-02-08 15:18:43 +0000845 }
Ben Clayton0ddddb02023-02-09 15:35:27 +0000846 if (auto* node = Node()) {
847 return Switch(
848 node,
849 [&](const ast::TypeDecl* n) { //
850 return "type '" + symbols.NameFor(n->name->symbol) + "'";
851 },
852 [&](const ast::Var* n) { //
853 return "var '" + symbols.NameFor(n->name->symbol) + "'";
854 },
855 [&](const ast::Const* n) { //
856 return "const '" + symbols.NameFor(n->name->symbol) + "'";
857 },
858 [&](const ast::Override* n) { //
859 return "override '" + symbols.NameFor(n->name->symbol) + "'";
860 },
861 [&](const ast::Function* n) { //
862 return "function '" + symbols.NameFor(n->name->symbol) + "'";
863 },
864 [&](Default) {
865 TINT_UNREACHABLE(Resolver, diagnostics)
866 << "unhandled ast::Node: " << node->TypeInfo().name;
867 return "<unknown>";
868 });
Ben Claytoncf0e9302023-02-08 15:18:43 +0000869 }
Ben Clayton0ddddb02023-02-09 15:35:27 +0000870 if (auto builtin_fn = BuiltinFunction(); builtin_fn != sem::BuiltinType::kNone) {
871 return "builtin function '" + utils::ToString(builtin_fn) + "'";
Ben Claytoncf0e9302023-02-08 15:18:43 +0000872 }
dan sinclairef30aa42023-02-19 04:28:04 +0000873 if (auto builtin_ty = BuiltinType(); builtin_ty != builtin::Builtin::kUndefined) {
Ben Clayton0ddddb02023-02-09 15:35:27 +0000874 return "builtin type '" + utils::ToString(builtin_ty) + "'";
Ben Claytoncf0e9302023-02-08 15:18:43 +0000875 }
Ben Clayton4d3ff972023-02-21 17:33:54 +0000876 if (auto builtin_val = BuiltinValue(); builtin_val != builtin::BuiltinValue::kUndefined) {
877 return "builtin value '" + utils::ToString(builtin_val) + "'";
878 }
dan sinclairb6cc4cb2023-02-19 04:01:29 +0000879 if (auto access = Access(); access != builtin::Access::kUndefined) {
Ben Clayton031e2f52023-02-09 15:35:27 +0000880 return "access '" + utils::ToString(access) + "'";
881 }
dan sinclair2a651632023-02-19 04:03:55 +0000882 if (auto addr = AddressSpace(); addr != builtin::AddressSpace::kUndefined) {
Ben Clayton031e2f52023-02-09 15:35:27 +0000883 return "address space '" + utils::ToString(addr) + "'";
884 }
dan sinclairba082fd2023-02-19 04:14:19 +0000885 if (auto fmt = TexelFormat(); fmt != builtin::TexelFormat::kUndefined) {
Ben Clayton031e2f52023-02-09 15:35:27 +0000886 return "texel format '" + utils::ToString(fmt) + "'";
887 }
Ben Clayton0ddddb02023-02-09 15:35:27 +0000888 TINT_UNREACHABLE(Resolver, diagnostics) << "unhandled ResolvedIdentifier";
889 return "<unknown>";
Ben Claytoncf0e9302023-02-08 15:18:43 +0000890}
891
dan sinclaird2093792022-04-07 17:45:45 +0000892} // namespace tint::resolver