Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 1 | // Copyright 2021 The Tint Authors. |
Ben Clayton | 2101c35 | 2021-02-10 21:22:03 +0000 | [diff] [blame] | 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/hlsl.h" |
| 16 | |
| 17 | #include <utility> |
| 18 | |
James Price | 2f04dc9 | 2021-04-01 22:07:37 +0000 | [diff] [blame] | 19 | #include "src/ast/stage_decoration.h" |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 20 | #include "src/ast/variable_decl_statement.h" |
Ben Clayton | 2101c35 | 2021-02-10 21:22:03 +0000 | [diff] [blame] | 21 | #include "src/program_builder.h" |
Antonio Maiorano | 5cd71b8 | 2021-04-16 19:07:51 +0000 | [diff] [blame] | 22 | #include "src/sem/expression.h" |
| 23 | #include "src/sem/statement.h" |
| 24 | #include "src/sem/variable.h" |
Ben Clayton | e2c775f | 2021-04-09 13:20:28 +0000 | [diff] [blame] | 25 | #include "src/transform/calculate_array_length.h" |
James Price | f8f31a4 | 2021-04-09 13:50:38 +0000 | [diff] [blame] | 26 | #include "src/transform/canonicalize_entry_point_io.h" |
Ben Clayton | e2c775f | 2021-04-09 13:20:28 +0000 | [diff] [blame] | 27 | #include "src/transform/decompose_storage_access.h" |
| 28 | #include "src/transform/manager.h" |
Ben Clayton | 2101c35 | 2021-02-10 21:22:03 +0000 | [diff] [blame] | 29 | |
| 30 | namespace tint { |
| 31 | namespace transform { |
| 32 | |
| 33 | Hlsl::Hlsl() = default; |
| 34 | Hlsl::~Hlsl() = default; |
| 35 | |
Ben Clayton | 856a368 | 2021-04-16 08:35:24 +0000 | [diff] [blame] | 36 | Output Hlsl::Run(const Program* in, const DataMap& data) { |
Ben Clayton | e2c775f | 2021-04-09 13:20:28 +0000 | [diff] [blame] | 37 | Manager manager; |
James Price | f8f31a4 | 2021-04-09 13:50:38 +0000 | [diff] [blame] | 38 | manager.Add<CanonicalizeEntryPointIO>(); |
Ben Clayton | e2c775f | 2021-04-09 13:20:28 +0000 | [diff] [blame] | 39 | manager.Add<DecomposeStorageAccess>(); |
| 40 | manager.Add<CalculateArrayLength>(); |
| 41 | auto out = manager.Run(in, data); |
| 42 | if (!out.program.IsValid()) { |
| 43 | return out; |
| 44 | } |
| 45 | |
| 46 | ProgramBuilder builder; |
| 47 | CloneContext ctx(&builder, &out.program); |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 48 | PromoteInitializersToConstVar(ctx); |
James Price | 2f04dc9 | 2021-04-01 22:07:37 +0000 | [diff] [blame] | 49 | AddEmptyEntryPoint(ctx); |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 50 | ctx.Clone(); |
Ben Clayton | e2c775f | 2021-04-09 13:20:28 +0000 | [diff] [blame] | 51 | return Output{Program(std::move(builder))}; |
Ben Clayton | 2101c35 | 2021-02-10 21:22:03 +0000 | [diff] [blame] | 52 | } |
| 53 | |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 54 | void Hlsl::PromoteInitializersToConstVar(CloneContext& ctx) const { |
| 55 | // Scan the AST nodes for array and structure initializers which |
| 56 | // need to be promoted to their own constant declaration. |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 57 | |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 58 | // Note: Correct handling of nested expressions is guaranteed due to the |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 59 | // depth-first traversal of the ast::Node::Clone() methods: |
| 60 | // |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 61 | // The inner-most initializers are traversed first, and they are hoisted |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 62 | // to const variables declared just above the statement of use. The outer |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 63 | // initializer will then be hoisted, inserting themselves between the |
| 64 | // inner declaration and the statement of use. This pattern applies correctly |
| 65 | // to any nested depth. |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 66 | // |
| 67 | // Depth-first traversal of the AST is guaranteed because AST nodes are fully |
| 68 | // immutable and require their children to be constructed first so their |
| 69 | // pointer can be passed to the parent's constructor. |
| 70 | |
| 71 | for (auto* src_node : ctx.src->ASTNodes().Objects()) { |
| 72 | if (auto* src_init = src_node->As<ast::TypeConstructorExpression>()) { |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 73 | auto* src_sem_expr = ctx.src->Sem().Get(src_init); |
| 74 | if (!src_sem_expr) { |
Ben Clayton | 3a9a55e | 2021-02-18 16:33:38 +0000 | [diff] [blame] | 75 | TINT_ICE(ctx.dst->Diagnostics()) |
| 76 | << "ast::TypeConstructorExpression has no semantic expression node"; |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 77 | continue; |
| 78 | } |
| 79 | auto* src_sem_stmt = src_sem_expr->Stmt(); |
| 80 | if (!src_sem_stmt) { |
| 81 | // Expression is outside of a statement. This usually means the |
| 82 | // expression is part of a global (module-scope) constant declaration. |
| 83 | // These must be constexpr, and so cannot contain the type of |
| 84 | // expressions that must be sanitized. |
| 85 | continue; |
| 86 | } |
| 87 | auto* src_stmt = src_sem_stmt->Declaration(); |
| 88 | |
| 89 | if (auto* src_var_decl = src_stmt->As<ast::VariableDeclStatement>()) { |
| 90 | if (src_var_decl->variable()->constructor() == src_init) { |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 91 | // This statement is just a variable declaration with the initializer |
| 92 | // as the constructor value. This is what we're attempting to |
| 93 | // transform to, and so ignore. |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 94 | continue; |
| 95 | } |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 96 | } |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 97 | |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 98 | auto* src_ty = src_sem_expr->Type(); |
Antonio Maiorano | 3751fd2 | 2021-04-19 22:51:23 +0000 | [diff] [blame] | 99 | if (src_ty->IsAnyOf<sem::ArrayType, sem::StructType>()) { |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 100 | // Create a new symbol for the constant |
James Price | 65ae64d | 2021-04-29 12:59:14 +0000 | [diff] [blame^] | 101 | auto dst_symbol = ctx.dst->Sym(); |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 102 | // Clone the type |
| 103 | auto* dst_ty = ctx.Clone(src_ty); |
| 104 | // Clone the initializer |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 105 | auto* dst_init = ctx.Clone(src_init); |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 106 | // Construct the constant that holds the hoisted initializer |
| 107 | auto* dst_var = ctx.dst->Const(dst_symbol, dst_ty, dst_init); |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 108 | // Construct the variable declaration statement |
Ben Clayton | 43073d8 | 2021-04-22 13:50:53 +0000 | [diff] [blame] | 109 | auto* dst_var_decl = ctx.dst->Decl(dst_var); |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 110 | // Construct the identifier for referencing the constant |
| 111 | auto* dst_ident = ctx.dst->Expr(dst_symbol); |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 112 | |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 113 | // Insert the constant before the usage |
Ben Clayton | b4275c8 | 2021-03-31 21:00:26 +0000 | [diff] [blame] | 114 | ctx.InsertBefore(src_sem_stmt->Block()->statements(), src_stmt, |
| 115 | dst_var_decl); |
Ben Clayton | 933d44a | 2021-04-07 17:29:31 +0000 | [diff] [blame] | 116 | // Replace the inlined initializer with a reference to the constant |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 117 | ctx.Replace(src_init, dst_ident); |
Ben Clayton | 4b9e7f9 | 2021-02-16 23:21:51 +0000 | [diff] [blame] | 118 | } |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | |
James Price | 2f04dc9 | 2021-04-01 22:07:37 +0000 | [diff] [blame] | 123 | void Hlsl::AddEmptyEntryPoint(CloneContext& ctx) const { |
| 124 | for (auto* func : ctx.src->AST().Functions()) { |
| 125 | if (func->IsEntryPoint()) { |
| 126 | return; |
| 127 | } |
| 128 | } |
Ben Clayton | 43073d8 | 2021-04-22 13:50:53 +0000 | [diff] [blame] | 129 | ctx.dst->Func(ctx.dst->Symbols().New("tint_unused_entry_point"), {}, |
| 130 | ctx.dst->ty.void_(), {}, |
| 131 | {ctx.dst->Stage(ast::PipelineStage::kCompute)}); |
James Price | 2f04dc9 | 2021-04-01 22:07:37 +0000 | [diff] [blame] | 132 | } |
| 133 | |
Ben Clayton | 2101c35 | 2021-02-10 21:22:03 +0000 | [diff] [blame] | 134 | } // namespace transform |
| 135 | } // namespace tint |