tint: Add Bitcast helper

Use this for the BlockAllocator cast.

Bug: dawn:1406
Change-Id: Ic5d1acf7f8e74037fb51fc9d5d3b5141a15bd962
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/89021
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 287c40f..6826259 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -510,6 +510,7 @@
     "transform/wrap_arrays_in_structs.h",
     "transform/zero_init_workgroup_memory.cc",
     "transform/zero_init_workgroup_memory.h",
+    "utils/bitcast.h",
     "utils/block_allocator.h",
     "utils/crc32.h",
     "utils/debugger.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 1b86aff..9e606d2 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -440,6 +440,7 @@
   sem/vector.h
   sem/void.cc
   sem/void.h
+  utils/bitcast.h
   utils/block_allocator.h
   utils/crc32.h
   utils/enum_set.h
@@ -806,6 +807,7 @@
     text/unicode_test.cc
     traits_test.cc
     transform/transform_test.cc
+    utils/bitcast_test.cc
     utils/block_allocator_test.cc
     utils/crc32_test.cc
     utils/defer_test.cc
diff --git a/src/tint/utils/bitcast.h b/src/tint/utils/bitcast.h
new file mode 100644
index 0000000..4450336
--- /dev/null
+++ b/src/tint/utils/bitcast.h
@@ -0,0 +1,39 @@
+// Copyright 2022 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.
+
+#ifndef SRC_TINT_UTILS_BITCAST_H_
+#define SRC_TINT_UTILS_BITCAST_H_
+
+#include <cstring>
+
+namespace tint::utils {
+
+/// Bitcast performs a cast of `from` to the `TO` type using a memcpy.
+/// This unsafe cast avoids triggering Clang's Control Flow Integrity checks.
+/// See: crbug.com/dawn/1406
+/// See: https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking
+/// @param from the value to cast
+/// @tparam TO the value to cast to
+/// @returns the cast value
+template <typename TO, typename FROM>
+inline TO Bitcast(FROM&& from) {
+    static_assert(sizeof(FROM) == sizeof(TO));
+    TO to;
+    memcpy(&to, &from, sizeof(TO));
+    return to;
+}
+
+}  // namespace tint::utils
+
+#endif  // SRC_TINT_UTILS_BITCAST_H_
diff --git a/src/tint/utils/bitcast_test.cc b/src/tint/utils/bitcast_test.cc
new file mode 100644
index 0000000..2364899
--- /dev/null
+++ b/src/tint/utils/bitcast_test.cc
@@ -0,0 +1,37 @@
+// Copyright 2022 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/tint/utils/bitcast.h"
+
+#include <stdint.h>
+
+#include "gtest/gtest.h"
+
+namespace tint::utils {
+namespace {
+
+TEST(Bitcast, Integer) {
+    uint32_t a = 123;
+    int32_t b = Bitcast<int32_t>(a);
+    EXPECT_EQ(a, static_cast<uint32_t>(b));
+}
+
+TEST(Bitcast, Pointer) {
+    uint32_t a = 123;
+    void* b = Bitcast<void*>(&a);
+    EXPECT_EQ(&a, static_cast<uint32_t*>(b));
+}
+
+}  // namespace
+}  // namespace tint::utils
diff --git a/src/tint/utils/block_allocator.h b/src/tint/utils/block_allocator.h
index 84d3bc3..f413940 100644
--- a/src/tint/utils/block_allocator.h
+++ b/src/tint/utils/block_allocator.h
@@ -19,6 +19,7 @@
 #include <cstring>
 #include <utility>
 
+#include "src/tint/utils/bitcast.h"
 #include "src/tint/utils/math.h"
 
 namespace tint::utils {
@@ -231,14 +232,7 @@
         }
 
         auto* base = &block_.current->data[0];
-        auto* addr = static_cast<void*>(base + block_.current_offset);
-        // Use a memcpy to reinterpret 'void* addr' as 'TYPE* ptr'.
-        // This is done without using a static_cast, as Clang's Control Flow Integrity checks can
-        // trigger for this cast, as we're casting from uint8_t* to TYPE*.
-        // See: crbug.com/dawn/1406
-        // See: https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking
-        TYPE* ptr;
-        memcpy(&ptr, &addr, sizeof(addr));
+        auto* ptr = utils::Bitcast<TYPE*>(base + block_.current_offset);
         block_.current_offset += sizeof(TYPE);
         return ptr;
     }
diff --git a/test/tint/BUILD.gn b/test/tint/BUILD.gn
index 3b9379f..8111273 100644
--- a/test/tint/BUILD.gn
+++ b/test/tint/BUILD.gn
@@ -357,6 +357,7 @@
 
 tint_unittests_source_set("tint_unittests_utils_src") {
   sources = [
+    "../../src/tint/utils/bitcast_test.cc",
     "../../src/tint/utils/crc32_test.cc",
     "../../src/tint/utils/defer_test.cc",
     "../../src/tint/utils/enum_set_test.cc",