• 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/resolver/resolver.h"
16 
17 #include "src/sem/constant.h"
18 #include "src/sem/type_constructor.h"
19 #include "src/utils/map.h"
20 
21 namespace tint {
22 namespace resolver {
23 namespace {
24 
25 using i32 = ProgramBuilder::i32;
26 using u32 = ProgramBuilder::u32;
27 using f32 = ProgramBuilder::f32;
28 
29 }  // namespace
30 
EvaluateConstantValue(const ast::Expression * expr,const sem::Type * type)31 sem::Constant Resolver::EvaluateConstantValue(const ast::Expression* expr,
32                                               const sem::Type* type) {
33   if (auto* e = expr->As<ast::LiteralExpression>()) {
34     return EvaluateConstantValue(e, type);
35   }
36   if (auto* e = expr->As<ast::CallExpression>()) {
37     return EvaluateConstantValue(e, type);
38   }
39   return {};
40 }
41 
EvaluateConstantValue(const ast::LiteralExpression * literal,const sem::Type * type)42 sem::Constant Resolver::EvaluateConstantValue(
43     const ast::LiteralExpression* literal,
44     const sem::Type* type) {
45   if (auto* lit = literal->As<ast::SintLiteralExpression>()) {
46     return {type, {lit->ValueAsI32()}};
47   }
48   if (auto* lit = literal->As<ast::UintLiteralExpression>()) {
49     return {type, {lit->ValueAsU32()}};
50   }
51   if (auto* lit = literal->As<ast::FloatLiteralExpression>()) {
52     return {type, {lit->value}};
53   }
54   if (auto* lit = literal->As<ast::BoolLiteralExpression>()) {
55     return {type, {lit->value}};
56   }
57   TINT_UNREACHABLE(Resolver, builder_->Diagnostics());
58   return {};
59 }
60 
EvaluateConstantValue(const ast::CallExpression * call,const sem::Type * type)61 sem::Constant Resolver::EvaluateConstantValue(const ast::CallExpression* call,
62                                               const sem::Type* type) {
63   auto* vec = type->As<sem::Vector>();
64 
65   // For now, only fold scalars and vectors
66   if (!type->is_scalar() && !vec) {
67     return {};
68   }
69 
70   auto* elem_type = vec ? vec->type() : type;
71   int result_size = vec ? static_cast<int>(vec->Width()) : 1;
72 
73   // For zero value init, return 0s
74   if (call->args.empty()) {
75     if (elem_type->Is<sem::I32>()) {
76       return sem::Constant(type, sem::Constant::Scalars(result_size, 0));
77     }
78     if (elem_type->Is<sem::U32>()) {
79       return sem::Constant(type, sem::Constant::Scalars(result_size, 0u));
80     }
81     if (elem_type->Is<sem::F32>()) {
82       return sem::Constant(type, sem::Constant::Scalars(result_size, 0.f));
83     }
84     if (elem_type->Is<sem::Bool>()) {
85       return sem::Constant(type, sem::Constant::Scalars(result_size, false));
86     }
87   }
88 
89   // Build value for type_ctor from each child value by casting to
90   // type_ctor's type.
91   sem::Constant::Scalars elems;
92   for (auto* expr : call->args) {
93     auto* arg = builder_->Sem().Get(expr);
94     if (!arg || !arg->ConstantValue()) {
95       return {};
96     }
97     auto cast = ConstantCast(arg->ConstantValue(), elem_type);
98     elems.insert(elems.end(), cast.Elements().begin(), cast.Elements().end());
99   }
100 
101   // Splat single-value initializers
102   if (elems.size() == 1) {
103     for (int i = 0; i < result_size - 1; ++i) {
104       elems.emplace_back(elems[0]);
105     }
106   }
107 
108   return sem::Constant(type, std::move(elems));
109 }
110 
ConstantCast(const sem::Constant & value,const sem::Type * target_elem_type)111 sem::Constant Resolver::ConstantCast(const sem::Constant& value,
112                                      const sem::Type* target_elem_type) {
113   if (value.ElementType() == target_elem_type) {
114     return value;
115   }
116 
117   sem::Constant::Scalars elems;
118   for (size_t i = 0; i < value.Elements().size(); ++i) {
119     if (target_elem_type->Is<sem::I32>()) {
120       elems.emplace_back(
121           value.WithScalarAt(i, [](auto&& s) { return static_cast<i32>(s); }));
122     } else if (target_elem_type->Is<sem::U32>()) {
123       elems.emplace_back(
124           value.WithScalarAt(i, [](auto&& s) { return static_cast<u32>(s); }));
125     } else if (target_elem_type->Is<sem::F32>()) {
126       elems.emplace_back(
127           value.WithScalarAt(i, [](auto&& s) { return static_cast<f32>(s); }));
128     } else if (target_elem_type->Is<sem::Bool>()) {
129       elems.emplace_back(
130           value.WithScalarAt(i, [](auto&& s) { return static_cast<bool>(s); }));
131     }
132   }
133 
134   auto* target_type =
135       value.Type()->Is<sem::Vector>()
136           ? builder_->create<sem::Vector>(target_elem_type,
137                                           static_cast<uint32_t>(elems.size()))
138           : target_elem_type;
139 
140   return sem::Constant(target_type, elems);
141 }
142 
143 }  // namespace resolver
144 }  // namespace tint
145