107 lines
3.3 KiB
C++
107 lines
3.3 KiB
C++
// 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/renamer.h"
|
|
|
|
#include <memory>
|
|
#include <unordered_set>
|
|
#include <utility>
|
|
|
|
#include "src/program_builder.h"
|
|
#include "src/semantic/call.h"
|
|
#include "src/semantic/member_accessor_expression.h"
|
|
|
|
TINT_INSTANTIATE_TYPEINFO(tint::transform::Renamer::Data);
|
|
|
|
namespace tint {
|
|
namespace transform {
|
|
|
|
Renamer::Data::Data(Remappings&& r) : remappings(std::move(r)) {}
|
|
|
|
Renamer::Data::Data(const Data&) = default;
|
|
|
|
Renamer::Data::~Data() = default;
|
|
|
|
Renamer::Renamer() : cfg_{} {}
|
|
|
|
Renamer::Renamer(const Config& config) : cfg_(config) {}
|
|
|
|
Renamer::~Renamer() = default;
|
|
|
|
Transform::Output Renamer::Run(const Program* in) {
|
|
ProgramBuilder out;
|
|
CloneContext ctx(&out, in);
|
|
|
|
// Swizzles and intrinsic calls need to keep their symbols preserved.
|
|
std::unordered_set<ast::IdentifierExpression*> preserve;
|
|
for (auto* node : in->ASTNodes().Objects()) {
|
|
if (auto* member = node->As<ast::MemberAccessorExpression>()) {
|
|
auto* sem = in->Sem().Get(member);
|
|
if (!sem) {
|
|
TINT_ICE(out.Diagnostics())
|
|
<< "MemberAccessorExpression has no semantic info";
|
|
continue;
|
|
}
|
|
if (sem->IsSwizzle()) {
|
|
preserve.emplace(member->member());
|
|
}
|
|
} else if (auto* call = node->As<ast::CallExpression>()) {
|
|
auto* sem = in->Sem().Get(call);
|
|
if (!sem) {
|
|
TINT_ICE(out.Diagnostics()) << "CallExpression has no semantic info";
|
|
continue;
|
|
}
|
|
if (sem->Target()->Is<semantic::Intrinsic>()) {
|
|
preserve.emplace(call->func()->As<ast::IdentifierExpression>());
|
|
}
|
|
}
|
|
}
|
|
|
|
Data::Remappings remappings;
|
|
|
|
switch (cfg_.method) {
|
|
case Method::kMonotonic:
|
|
ctx.ReplaceAll([&](Symbol sym) {
|
|
auto str_in = in->Symbols().NameFor(sym);
|
|
auto it = remappings.find(str_in);
|
|
if (it != remappings.end()) {
|
|
return out.Symbols().Get(it->second);
|
|
}
|
|
auto str_out = "_tint_" + std::to_string(remappings.size() + 1);
|
|
remappings.emplace(str_in, str_out);
|
|
return out.Symbols().Register(str_out);
|
|
});
|
|
|
|
ctx.ReplaceAll(
|
|
[&](ast::IdentifierExpression* ident) -> ast::IdentifierExpression* {
|
|
if (preserve.count(ident)) {
|
|
auto sym_in = ident->symbol();
|
|
auto str = in->Symbols().NameFor(sym_in);
|
|
auto sym_out = out.Symbols().Register(str);
|
|
return ctx.dst->create<ast::IdentifierExpression>(
|
|
ctx.Clone(ident->source()), sym_out);
|
|
}
|
|
return nullptr; // Clone ident. Uses the symbol remapping above.
|
|
});
|
|
break;
|
|
}
|
|
ctx.Clone();
|
|
|
|
return Output(Program(std::move(out)),
|
|
std::make_unique<Data>(std::move(remappings)));
|
|
}
|
|
|
|
} // namespace transform
|
|
} // namespace tint
|