blob: 6b4887a59ddd3cb3a45d1e2c2fe7b2091057caf7 [file] [log] [blame]
Ben Clayton4b9e7f92021-02-16 23:21:51 +00001// Copyright 2021 The Tint Authors.
Ben Clayton2101c352021-02-10 21:22:03 +00002//
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 Price2f04dc92021-04-01 22:07:37 +000019#include "src/ast/stage_decoration.h"
Ben Clayton4b9e7f92021-02-16 23:21:51 +000020#include "src/ast/variable_decl_statement.h"
Ben Clayton2101c352021-02-10 21:22:03 +000021#include "src/program_builder.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000022#include "src/sem/expression.h"
23#include "src/sem/statement.h"
24#include "src/sem/variable.h"
Ben Claytone2c775f2021-04-09 13:20:28 +000025#include "src/transform/calculate_array_length.h"
James Pricef8f31a42021-04-09 13:50:38 +000026#include "src/transform/canonicalize_entry_point_io.h"
Ben Claytone2c775f2021-04-09 13:20:28 +000027#include "src/transform/decompose_storage_access.h"
28#include "src/transform/manager.h"
Ben Clayton2101c352021-02-10 21:22:03 +000029
30namespace tint {
31namespace transform {
32
33Hlsl::Hlsl() = default;
34Hlsl::~Hlsl() = default;
35
Ben Clayton856a3682021-04-16 08:35:24 +000036Output Hlsl::Run(const Program* in, const DataMap& data) {
Ben Claytone2c775f2021-04-09 13:20:28 +000037 Manager manager;
James Pricef8f31a42021-04-09 13:50:38 +000038 manager.Add<CanonicalizeEntryPointIO>();
Ben Claytone2c775f2021-04-09 13:20:28 +000039 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 Clayton933d44a2021-04-07 17:29:31 +000048 PromoteInitializersToConstVar(ctx);
James Price2f04dc92021-04-01 22:07:37 +000049 AddEmptyEntryPoint(ctx);
Ben Clayton4b9e7f92021-02-16 23:21:51 +000050 ctx.Clone();
Ben Claytone2c775f2021-04-09 13:20:28 +000051 return Output{Program(std::move(builder))};
Ben Clayton2101c352021-02-10 21:22:03 +000052}
53
Ben Clayton933d44a2021-04-07 17:29:31 +000054void 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 Clayton4b9e7f92021-02-16 23:21:51 +000057
Ben Clayton933d44a2021-04-07 17:29:31 +000058 // Note: Correct handling of nested expressions is guaranteed due to the
Ben Clayton4b9e7f92021-02-16 23:21:51 +000059 // depth-first traversal of the ast::Node::Clone() methods:
60 //
Ben Clayton933d44a2021-04-07 17:29:31 +000061 // The inner-most initializers are traversed first, and they are hoisted
Ben Clayton4b9e7f92021-02-16 23:21:51 +000062 // to const variables declared just above the statement of use. The outer
Ben Clayton933d44a2021-04-07 17:29:31 +000063 // 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 Clayton4b9e7f92021-02-16 23:21:51 +000066 //
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 Clayton6b4924f2021-02-17 20:13:34 +000073 auto* src_sem_expr = ctx.src->Sem().Get(src_init);
74 if (!src_sem_expr) {
Ben Clayton3a9a55e2021-02-18 16:33:38 +000075 TINT_ICE(ctx.dst->Diagnostics())
76 << "ast::TypeConstructorExpression has no semantic expression node";
Ben Clayton6b4924f2021-02-17 20:13:34 +000077 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 Clayton933d44a2021-04-07 17:29:31 +000091 // 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 Clayton4b9e7f92021-02-16 23:21:51 +000094 continue;
95 }
Ben Clayton6b4924f2021-02-17 20:13:34 +000096 }
Ben Clayton4b9e7f92021-02-16 23:21:51 +000097
Ben Clayton933d44a2021-04-07 17:29:31 +000098 auto* src_ty = src_sem_expr->Type();
Antonio Maiorano3751fd22021-04-19 22:51:23 +000099 if (src_ty->IsAnyOf<sem::ArrayType, sem::StructType>()) {
Ben Clayton6b4924f2021-02-17 20:13:34 +0000100 // Create a new symbol for the constant
James Price65ae64d2021-04-29 12:59:14 +0000101 auto dst_symbol = ctx.dst->Sym();
Ben Clayton933d44a2021-04-07 17:29:31 +0000102 // Clone the type
103 auto* dst_ty = ctx.Clone(src_ty);
104 // Clone the initializer
Ben Clayton6b4924f2021-02-17 20:13:34 +0000105 auto* dst_init = ctx.Clone(src_init);
Ben Clayton933d44a2021-04-07 17:29:31 +0000106 // Construct the constant that holds the hoisted initializer
107 auto* dst_var = ctx.dst->Const(dst_symbol, dst_ty, dst_init);
Ben Clayton6b4924f2021-02-17 20:13:34 +0000108 // Construct the variable declaration statement
Ben Clayton43073d82021-04-22 13:50:53 +0000109 auto* dst_var_decl = ctx.dst->Decl(dst_var);
Ben Clayton6b4924f2021-02-17 20:13:34 +0000110 // Construct the identifier for referencing the constant
111 auto* dst_ident = ctx.dst->Expr(dst_symbol);
Ben Clayton4b9e7f92021-02-16 23:21:51 +0000112
Ben Clayton6b4924f2021-02-17 20:13:34 +0000113 // Insert the constant before the usage
Ben Claytonb4275c82021-03-31 21:00:26 +0000114 ctx.InsertBefore(src_sem_stmt->Block()->statements(), src_stmt,
115 dst_var_decl);
Ben Clayton933d44a2021-04-07 17:29:31 +0000116 // Replace the inlined initializer with a reference to the constant
Ben Clayton6b4924f2021-02-17 20:13:34 +0000117 ctx.Replace(src_init, dst_ident);
Ben Clayton4b9e7f92021-02-16 23:21:51 +0000118 }
119 }
120 }
121}
122
James Price2f04dc92021-04-01 22:07:37 +0000123void Hlsl::AddEmptyEntryPoint(CloneContext& ctx) const {
124 for (auto* func : ctx.src->AST().Functions()) {
125 if (func->IsEntryPoint()) {
126 return;
127 }
128 }
Ben Clayton43073d82021-04-22 13:50:53 +0000129 ctx.dst->Func(ctx.dst->Symbols().New("tint_unused_entry_point"), {},
130 ctx.dst->ty.void_(), {},
131 {ctx.dst->Stage(ast::PipelineStage::kCompute)});
James Price2f04dc92021-04-01 22:07:37 +0000132}
133
Ben Clayton2101c352021-02-10 21:22:03 +0000134} // namespace transform
135} // namespace tint