1 // 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/transform/promote_initializers_to_const_var.h"
16
17 #include <utility>
18
19 #include "src/program_builder.h"
20 #include "src/sem/block_statement.h"
21 #include "src/sem/call.h"
22 #include "src/sem/expression.h"
23 #include "src/sem/statement.h"
24 #include "src/sem/type_constructor.h"
25
26 TINT_INSTANTIATE_TYPEINFO(tint::transform::PromoteInitializersToConstVar);
27
28 namespace tint {
29 namespace transform {
30
31 PromoteInitializersToConstVar::PromoteInitializersToConstVar() = default;
32
33 PromoteInitializersToConstVar::~PromoteInitializersToConstVar() = default;
34
Run(CloneContext & ctx,const DataMap &,DataMap &)35 void PromoteInitializersToConstVar::Run(CloneContext& ctx,
36 const DataMap&,
37 DataMap&) {
38 // Scan the AST nodes for array and structure initializers which
39 // need to be promoted to their own constant declaration.
40
41 // Note: Correct handling of nested expressions is guaranteed due to the
42 // depth-first traversal of the ast::Node::Clone() methods:
43 //
44 // The inner-most initializers are traversed first, and they are hoisted
45 // to const variables declared just above the statement of use. The outer
46 // initializer will then be hoisted, inserting themselves between the
47 // inner declaration and the statement of use. This pattern applies correctly
48 // to any nested depth.
49 //
50 // Depth-first traversal of the AST is guaranteed because AST nodes are fully
51 // immutable and require their children to be constructed first so their
52 // pointer can be passed to the parent's constructor.
53
54 for (auto* src_node : ctx.src->ASTNodes().Objects()) {
55 if (auto* src_init = src_node->As<ast::CallExpression>()) {
56 auto* call = ctx.src->Sem().Get(src_init);
57 if (!call->Target()->Is<sem::TypeConstructor>()) {
58 continue;
59 }
60 auto* src_sem_stmt = call->Stmt();
61 if (!src_sem_stmt) {
62 // Expression is outside of a statement. This usually means the
63 // expression is part of a global (module-scope) constant declaration.
64 // These must be constexpr, and so cannot contain the type of
65 // expressions that must be sanitized.
66 continue;
67 }
68 auto* src_stmt = src_sem_stmt->Declaration();
69
70 if (auto* src_var_decl = src_stmt->As<ast::VariableDeclStatement>()) {
71 if (src_var_decl->variable->constructor == src_init) {
72 // This statement is just a variable declaration with the initializer
73 // as the constructor value. This is what we're attempting to
74 // transform to, and so ignore.
75 continue;
76 }
77 }
78
79 auto* src_ty = call->Type();
80 if (src_ty->IsAnyOf<sem::Array, sem::Struct>()) {
81 // Create a new symbol for the constant
82 auto dst_symbol = ctx.dst->Sym();
83 // Clone the type
84 auto* dst_ty = CreateASTTypeFor(ctx, call->Type());
85 // Clone the initializer
86 auto* dst_init = ctx.Clone(src_init);
87 // Construct the constant that holds the hoisted initializer
88 auto* dst_var = ctx.dst->Const(dst_symbol, dst_ty, dst_init);
89 // Construct the variable declaration statement
90 auto* dst_var_decl = ctx.dst->Decl(dst_var);
91 // Construct the identifier for referencing the constant
92 auto* dst_ident = ctx.dst->Expr(dst_symbol);
93
94 // Insert the constant before the usage
95 ctx.InsertBefore(src_sem_stmt->Block()->Declaration()->statements,
96 src_stmt, dst_var_decl);
97 // Replace the inlined initializer with a reference to the constant
98 ctx.Replace(src_init, dst_ident);
99 }
100 }
101 }
102
103 ctx.Clone();
104 }
105
106 } // namespace transform
107 } // namespace tint
108