• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/fold_constants.h"
16 
17 #include <unordered_map>
18 #include <utility>
19 #include <vector>
20 
21 #include "src/program_builder.h"
22 #include "src/sem/call.h"
23 #include "src/sem/expression.h"
24 #include "src/sem/type_constructor.h"
25 #include "src/sem/type_conversion.h"
26 
27 TINT_INSTANTIATE_TYPEINFO(tint::transform::FoldConstants);
28 
29 namespace tint {
30 namespace transform {
31 
32 FoldConstants::FoldConstants() = default;
33 
34 FoldConstants::~FoldConstants() = default;
35 
Run(CloneContext & ctx,const DataMap &,DataMap &)36 void FoldConstants::Run(CloneContext& ctx, const DataMap&, DataMap&) {
37   ctx.ReplaceAll([&](const ast::Expression* expr) -> const ast::Expression* {
38     auto* call = ctx.src->Sem().Get<sem::Call>(expr);
39     if (!call) {
40       return nullptr;
41     }
42 
43     auto value = call->ConstantValue();
44     if (!value.IsValid()) {
45       return nullptr;
46     }
47 
48     auto* ty = call->Type();
49 
50     if (!call->Target()->IsAnyOf<sem::TypeConversion, sem::TypeConstructor>()) {
51       return nullptr;
52     }
53 
54     // If original ctor expression had no init values, don't replace the
55     // expression
56     if (call->Arguments().empty()) {
57       return nullptr;
58     }
59 
60     if (auto* vec = ty->As<sem::Vector>()) {
61       uint32_t vec_size = static_cast<uint32_t>(vec->Width());
62 
63       // We'd like to construct the new vector with the same number of
64       // constructor args that the original node had, but after folding
65       // constants, cases like the following are problematic:
66       //
67       // vec3<f32> = vec3<f32>(vec2<f32>, 1.0) // vec_size=3, ctor_size=2
68       //
69       // In this case, creating a vec3 with 2 args is invalid, so we should
70       // create it with 3. So what we do is construct with vec_size args,
71       // except if the original vector was single-value initialized, in
72       // which case, we only construct with one arg again.
73       uint32_t ctor_size = (call->Arguments().size() == 1) ? 1 : vec_size;
74 
75       ast::ExpressionList ctors;
76       for (uint32_t i = 0; i < ctor_size; ++i) {
77         value.WithScalarAt(
78             i, [&](auto&& s) { ctors.emplace_back(ctx.dst->Expr(s)); });
79       }
80 
81       auto* el_ty = CreateASTTypeFor(ctx, vec->type());
82       return ctx.dst->vec(el_ty, vec_size, ctors);
83     }
84 
85     if (ty->is_scalar()) {
86       return value.WithScalarAt(0,
87                                 [&](auto&& s) -> const ast::LiteralExpression* {
88                                   return ctx.dst->Expr(s);
89                                 });
90     }
91 
92     return nullptr;
93   });
94 
95   ctx.Clone();
96 }
97 
98 }  // namespace transform
99 }  // namespace tint
100