|  | // Copyright 2021 The Tint Authors. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include "src/transform/fold_constants.h" | 
|  |  | 
|  | #include <unordered_map> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "src/program_builder.h" | 
|  | #include "src/sem/call.h" | 
|  | #include "src/sem/expression.h" | 
|  | #include "src/sem/type_constructor.h" | 
|  | #include "src/sem/type_conversion.h" | 
|  |  | 
|  | TINT_INSTANTIATE_TYPEINFO(tint::transform::FoldConstants); | 
|  |  | 
|  | namespace tint { | 
|  | namespace transform { | 
|  |  | 
|  | FoldConstants::FoldConstants() = default; | 
|  |  | 
|  | FoldConstants::~FoldConstants() = default; | 
|  |  | 
|  | void FoldConstants::Run(CloneContext& ctx, const DataMap&, DataMap&) const { | 
|  | ctx.ReplaceAll([&](const ast::Expression* expr) -> const ast::Expression* { | 
|  | auto* call = ctx.src->Sem().Get<sem::Call>(expr); | 
|  | if (!call) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | auto value = call->ConstantValue(); | 
|  | if (!value.IsValid()) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | auto* ty = call->Type(); | 
|  |  | 
|  | if (!call->Target()->IsAnyOf<sem::TypeConversion, sem::TypeConstructor>()) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // If original ctor expression had no init values, don't replace the | 
|  | // expression | 
|  | if (call->Arguments().empty()) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | if (auto* vec = ty->As<sem::Vector>()) { | 
|  | uint32_t vec_size = static_cast<uint32_t>(vec->Width()); | 
|  |  | 
|  | // We'd like to construct the new vector with the same number of | 
|  | // constructor args that the original node had, but after folding | 
|  | // constants, cases like the following are problematic: | 
|  | // | 
|  | // vec3<f32> = vec3<f32>(vec2<f32>, 1.0) // vec_size=3, ctor_size=2 | 
|  | // | 
|  | // In this case, creating a vec3 with 2 args is invalid, so we should | 
|  | // create it with 3. So what we do is construct with vec_size args, | 
|  | // except if the original vector was single-value initialized, in | 
|  | // which case, we only construct with one arg again. | 
|  | uint32_t ctor_size = (call->Arguments().size() == 1) ? 1 : vec_size; | 
|  |  | 
|  | ast::ExpressionList ctors; | 
|  | for (uint32_t i = 0; i < ctor_size; ++i) { | 
|  | value.WithScalarAt( | 
|  | i, [&](auto&& s) { ctors.emplace_back(ctx.dst->Expr(s)); }); | 
|  | } | 
|  |  | 
|  | auto* el_ty = CreateASTTypeFor(ctx, vec->type()); | 
|  | return ctx.dst->vec(el_ty, vec_size, ctors); | 
|  | } | 
|  |  | 
|  | if (ty->is_scalar()) { | 
|  | return value.WithScalarAt(0, | 
|  | [&](auto&& s) -> const ast::LiteralExpression* { | 
|  | return ctx.dst->Expr(s); | 
|  | }); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | }); | 
|  |  | 
|  | ctx.Clone(); | 
|  | } | 
|  |  | 
|  | }  // namespace transform | 
|  | }  // namespace tint |