1 // Copyright 2020 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/clone_context.h"
16
17 #include <string>
18
19 #include "src/program_builder.h"
20 #include "src/utils/map.h"
21
22 TINT_INSTANTIATE_TYPEINFO(tint::Cloneable);
23
24 namespace tint {
25
26 CloneContext::ListTransforms::ListTransforms() = default;
27 CloneContext::ListTransforms::~ListTransforms() = default;
28
CloneContext(ProgramBuilder * to,Program const * from,bool auto_clone_symbols)29 CloneContext::CloneContext(ProgramBuilder* to,
30 Program const* from,
31 bool auto_clone_symbols)
32 : dst(to), src(from) {
33 if (auto_clone_symbols) {
34 // Almost all transforms will want to clone all symbols before doing any
35 // work, to avoid any newly created symbols clashing with existing symbols
36 // in the source program and causing them to be renamed.
37 from->Symbols().Foreach([&](Symbol s, const std::string&) { Clone(s); });
38 }
39 }
40
CloneContext(ProgramBuilder * builder)41 CloneContext::CloneContext(ProgramBuilder* builder)
42 : CloneContext(builder, nullptr, false) {}
43
44 CloneContext::~CloneContext() = default;
45
Clone(Symbol s)46 Symbol CloneContext::Clone(Symbol s) {
47 if (!src) {
48 return s; // In-place clone
49 }
50 return utils::GetOrCreate(cloned_symbols_, s, [&]() -> Symbol {
51 if (symbol_transform_) {
52 return symbol_transform_(s);
53 }
54 return dst->Symbols().New(src->Symbols().NameFor(s));
55 });
56 }
57
Clone()58 void CloneContext::Clone() {
59 dst->AST().Copy(this, &src->AST());
60 dst->SetTransformApplied(src->TransformsApplied());
61 }
62
Clone(const ast::FunctionList & v)63 ast::FunctionList CloneContext::Clone(const ast::FunctionList& v) {
64 ast::FunctionList out;
65 out.reserve(v.size());
66 for (const ast::Function* el : v) {
67 out.Add(Clone(el));
68 }
69 return out;
70 }
71
CloneCloneable(const Cloneable * object)72 const tint::Cloneable* CloneContext::CloneCloneable(const Cloneable* object) {
73 // If the input is nullptr, there's nothing to clone - just return nullptr.
74 if (object == nullptr) {
75 return nullptr;
76 }
77
78 // Was Replace() called for this object?
79 auto it = replacements_.find(object);
80 if (it != replacements_.end()) {
81 return it->second();
82 }
83
84 // Attempt to clone using the registered replacer functions.
85 auto& typeinfo = object->TypeInfo();
86 for (auto& transform : transforms_) {
87 if (typeinfo.Is(*transform.typeinfo)) {
88 if (auto* transformed = transform.function(object)) {
89 return transformed;
90 }
91 break;
92 }
93 }
94
95 // No transform for this type, or the transform returned nullptr.
96 // Clone with T::Clone().
97 return object->Clone(this);
98 }
99
CheckedCastFailure(const Cloneable * got,const TypeInfo & expected)100 void CloneContext::CheckedCastFailure(const Cloneable* got,
101 const TypeInfo& expected) {
102 TINT_ICE(Clone, Diagnostics())
103 << "Cloned object was not of the expected type\n"
104 << "got: " << got->TypeInfo().name << "\n"
105 << "expected: " << expected.name;
106 }
107
Diagnostics() const108 diag::List& CloneContext::Diagnostics() const {
109 return dst->Diagnostics();
110 }
111
112 CloneContext::CloneableTransform::CloneableTransform() = default;
113 CloneContext::CloneableTransform::CloneableTransform(
114 const CloneableTransform&) = default;
115 CloneContext::CloneableTransform::~CloneableTransform() = default;
116
117 } // namespace tint
118