transform/Renamer: Pass through swizzles and intrinsics

These must not be mangled.

Bug: tint:273
Change-Id: I05b02bf785c9d6ab587996bfed284e89912cd0cb
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/43941
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/transform/renamer.cc b/src/transform/renamer.cc
index 3527f4d..b9b7404 100644
--- a/src/transform/renamer.cc
+++ b/src/transform/renamer.cc
@@ -15,9 +15,14 @@
 #include "src/transform/renamer.h"
 
 #include <memory>
+#include <unordered_set>
 #include <utility>
 
+#include "src/ast/member_accessor_expression.h"
 #include "src/program_builder.h"
+#include "src/semantic/call.h"
+#include "src/semantic/intrinsic.h"
+#include "src/semantic/member_accessor_expression.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::Renamer::Data);
 
@@ -40,16 +45,57 @@
   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 str_out = "_tint_" + std::to_string(sym.value());
+        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();
diff --git a/src/transform/renamer_test.cc b/src/transform/renamer_test.cc
index 63d68c3..2b3b039 100644
--- a/src/transform/renamer_test.cc
+++ b/src/transform/renamer_test.cc
@@ -80,6 +80,74 @@
   EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
 }
 
+TEST_F(RenamerTest, PreserveSwizzles) {
+  auto* src = R"(
+[[stage(vertex)]]
+fn entry() -> void {
+  var v : vec4<f32>;
+  var rgba : f32;
+  var xyzw : f32;
+  return v.zyxw + v.rgab;
+}
+)";
+
+  auto* expect = R"(
+[[stage(vertex)]]
+fn _tint_1() -> void {
+  var _tint_2 : vec4<f32>;
+  var _tint_3 : f32;
+  var _tint_4 : f32;
+  return (_tint_2.zyxw + _tint_2.rgab);
+}
+)";
+
+  auto got = Transform<Renamer>(src);
+
+  EXPECT_EQ(expect, str(got));
+
+  auto* data = got.data.Get<Renamer::Data>();
+
+  ASSERT_NE(data, nullptr);
+  Renamer::Data::Remappings expected_remappings = {
+      {"entry", "_tint_1"},
+      {"v", "_tint_2"},
+      {"rgba", "_tint_3"},
+      {"xyzw", "_tint_4"},
+  };
+  EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
+}
+
+TEST_F(RenamerTest, PreserveIntrinsics) {
+  auto* src = R"(
+[[stage(vertex)]]
+fn entry() -> void {
+  var blah : vec4<f32>;
+  return abs(blah);
+}
+)";
+
+  auto* expect = R"(
+[[stage(vertex)]]
+fn _tint_1() -> void {
+  var _tint_2 : vec4<f32>;
+  return abs(_tint_2);
+}
+)";
+
+  auto got = Transform<Renamer>(src);
+
+  EXPECT_EQ(expect, str(got));
+
+  auto* data = got.data.Get<Renamer::Data>();
+
+  ASSERT_NE(data, nullptr);
+  Renamer::Data::Remappings expected_remappings = {
+      {"entry", "_tint_1"},
+      {"blah", "_tint_2"},
+  };
+  EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint