1cb93a386Sopenharmony_ci// Copyright 2020 The Tint Authors.
2cb93a386Sopenharmony_ci//
3cb93a386Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4cb93a386Sopenharmony_ci// you may not use this file except in compliance with the License.
5cb93a386Sopenharmony_ci// You may obtain a copy of the License at
6cb93a386Sopenharmony_ci//
7cb93a386Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8cb93a386Sopenharmony_ci//
9cb93a386Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10cb93a386Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11cb93a386Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb93a386Sopenharmony_ci// See the License for the specific language governing permissions and
13cb93a386Sopenharmony_ci// limitations under the License.
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#include "src/clone_context.h"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci#include <string>
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ci#include "src/program_builder.h"
20cb93a386Sopenharmony_ci#include "src/utils/map.h"
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ciTINT_INSTANTIATE_TYPEINFO(tint::Cloneable);
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cinamespace tint {
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ciCloneContext::ListTransforms::ListTransforms() = default;
27cb93a386Sopenharmony_ciCloneContext::ListTransforms::~ListTransforms() = default;
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ciCloneContext::CloneContext(ProgramBuilder* to,
30cb93a386Sopenharmony_ci                           Program const* from,
31cb93a386Sopenharmony_ci                           bool auto_clone_symbols)
32cb93a386Sopenharmony_ci    : dst(to), src(from) {
33cb93a386Sopenharmony_ci  if (auto_clone_symbols) {
34cb93a386Sopenharmony_ci    // Almost all transforms will want to clone all symbols before doing any
35cb93a386Sopenharmony_ci    // work, to avoid any newly created symbols clashing with existing symbols
36cb93a386Sopenharmony_ci    // in the source program and causing them to be renamed.
37cb93a386Sopenharmony_ci    from->Symbols().Foreach([&](Symbol s, const std::string&) { Clone(s); });
38cb93a386Sopenharmony_ci  }
39cb93a386Sopenharmony_ci}
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ciCloneContext::CloneContext(ProgramBuilder* builder)
42cb93a386Sopenharmony_ci    : CloneContext(builder, nullptr, false) {}
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_ciCloneContext::~CloneContext() = default;
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ciSymbol CloneContext::Clone(Symbol s) {
47cb93a386Sopenharmony_ci  if (!src) {
48cb93a386Sopenharmony_ci    return s;  // In-place clone
49cb93a386Sopenharmony_ci  }
50cb93a386Sopenharmony_ci  return utils::GetOrCreate(cloned_symbols_, s, [&]() -> Symbol {
51cb93a386Sopenharmony_ci    if (symbol_transform_) {
52cb93a386Sopenharmony_ci      return symbol_transform_(s);
53cb93a386Sopenharmony_ci    }
54cb93a386Sopenharmony_ci    return dst->Symbols().New(src->Symbols().NameFor(s));
55cb93a386Sopenharmony_ci  });
56cb93a386Sopenharmony_ci}
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_civoid CloneContext::Clone() {
59cb93a386Sopenharmony_ci  dst->AST().Copy(this, &src->AST());
60cb93a386Sopenharmony_ci  dst->SetTransformApplied(src->TransformsApplied());
61cb93a386Sopenharmony_ci}
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ciast::FunctionList CloneContext::Clone(const ast::FunctionList& v) {
64cb93a386Sopenharmony_ci  ast::FunctionList out;
65cb93a386Sopenharmony_ci  out.reserve(v.size());
66cb93a386Sopenharmony_ci  for (const ast::Function* el : v) {
67cb93a386Sopenharmony_ci    out.Add(Clone(el));
68cb93a386Sopenharmony_ci  }
69cb93a386Sopenharmony_ci  return out;
70cb93a386Sopenharmony_ci}
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ciconst tint::Cloneable* CloneContext::CloneCloneable(const Cloneable* object) {
73cb93a386Sopenharmony_ci  // If the input is nullptr, there's nothing to clone - just return nullptr.
74cb93a386Sopenharmony_ci  if (object == nullptr) {
75cb93a386Sopenharmony_ci    return nullptr;
76cb93a386Sopenharmony_ci  }
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci  // Was Replace() called for this object?
79cb93a386Sopenharmony_ci  auto it = replacements_.find(object);
80cb93a386Sopenharmony_ci  if (it != replacements_.end()) {
81cb93a386Sopenharmony_ci    return it->second();
82cb93a386Sopenharmony_ci  }
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci  // Attempt to clone using the registered replacer functions.
85cb93a386Sopenharmony_ci  auto& typeinfo = object->TypeInfo();
86cb93a386Sopenharmony_ci  for (auto& transform : transforms_) {
87cb93a386Sopenharmony_ci    if (typeinfo.Is(*transform.typeinfo)) {
88cb93a386Sopenharmony_ci      if (auto* transformed = transform.function(object)) {
89cb93a386Sopenharmony_ci        return transformed;
90cb93a386Sopenharmony_ci      }
91cb93a386Sopenharmony_ci      break;
92cb93a386Sopenharmony_ci    }
93cb93a386Sopenharmony_ci  }
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci  // No transform for this type, or the transform returned nullptr.
96cb93a386Sopenharmony_ci  // Clone with T::Clone().
97cb93a386Sopenharmony_ci  return object->Clone(this);
98cb93a386Sopenharmony_ci}
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_civoid CloneContext::CheckedCastFailure(const Cloneable* got,
101cb93a386Sopenharmony_ci                                      const TypeInfo& expected) {
102cb93a386Sopenharmony_ci  TINT_ICE(Clone, Diagnostics())
103cb93a386Sopenharmony_ci      << "Cloned object was not of the expected type\n"
104cb93a386Sopenharmony_ci      << "got:      " << got->TypeInfo().name << "\n"
105cb93a386Sopenharmony_ci      << "expected: " << expected.name;
106cb93a386Sopenharmony_ci}
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_cidiag::List& CloneContext::Diagnostics() const {
109cb93a386Sopenharmony_ci  return dst->Diagnostics();
110cb93a386Sopenharmony_ci}
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ciCloneContext::CloneableTransform::CloneableTransform() = default;
113cb93a386Sopenharmony_ciCloneContext::CloneableTransform::CloneableTransform(
114cb93a386Sopenharmony_ci    const CloneableTransform&) = default;
115cb93a386Sopenharmony_ciCloneContext::CloneableTransform::~CloneableTransform() = default;
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci}  // namespace tint
118