[msl] Add printer support for u64

Emit it as `ulong`, and use the `u` suffix for constants.

Bug: 394291739
Change-Id: I82c591e4734cbaf8898fedffc6d9dfb54a4b1ecf
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/224600
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/lang/msl/writer/BUILD.bazel b/src/tint/lang/msl/writer/BUILD.bazel
index c36364d..d848197 100644
--- a/src/tint/lang/msl/writer/BUILD.bazel
+++ b/src/tint/lang/msl/writer/BUILD.bazel
@@ -122,6 +122,7 @@
       "//src/tint/lang/msl/validate",
       "//src/tint/lang/msl/writer",
       "//src/tint/lang/msl/writer/common",
+      "//src/tint/lang/msl/writer/printer",
     ],
     "//conditions:default": [],
   }),
diff --git a/src/tint/lang/msl/writer/BUILD.cmake b/src/tint/lang/msl/writer/BUILD.cmake
index 71f367ea..f986cbf 100644
--- a/src/tint/lang/msl/writer/BUILD.cmake
+++ b/src/tint/lang/msl/writer/BUILD.cmake
@@ -142,6 +142,7 @@
     tint_lang_msl_validate
     tint_lang_msl_writer
     tint_lang_msl_writer_common
+    tint_lang_msl_writer_printer
   )
 endif(TINT_BUILD_MSL_WRITER)
 
diff --git a/src/tint/lang/msl/writer/BUILD.gn b/src/tint/lang/msl/writer/BUILD.gn
index f003138..9028589 100644
--- a/src/tint/lang/msl/writer/BUILD.gn
+++ b/src/tint/lang/msl/writer/BUILD.gn
@@ -128,6 +128,7 @@
           "${tint_src_dir}/lang/msl/validate",
           "${tint_src_dir}/lang/msl/writer",
           "${tint_src_dir}/lang/msl/writer/common",
+          "${tint_src_dir}/lang/msl/writer/printer",
         ]
       }
     }
diff --git a/src/tint/lang/msl/writer/constant_test.cc b/src/tint/lang/msl/writer/constant_test.cc
index 61b0aa5..6f5c5cf 100644
--- a/src/tint/lang/msl/writer/constant_test.cc
+++ b/src/tint/lang/msl/writer/constant_test.cc
@@ -101,6 +101,23 @@
 )");
 }
 
+TEST_F(MslWriterTest, Constant_u64) {
+    auto* c = b.Constant(u64(UINT64_MAX));
+    auto* func = b.Function("foo", ty.void_());
+    b.Append(func->Block(), [&] {
+        b.Let("a", c);
+        b.Return(func);
+    });
+
+    // Use `Print()` as u64 types are only support after certain transforms have run.
+    ASSERT_TRUE(Print()) << err_ << output_.msl;
+    EXPECT_EQ(output_.msl, MetalHeader() + R"(
+void foo() {
+  ulong const a = 18446744073709551615ul;
+}
+)");
+}
+
 TEST_F(MslWriterTest, Constant_F32) {
     auto* c = b.Constant(f32((1 << 30) - 4));
     auto* func = b.Function("foo", ty.void_());
diff --git a/src/tint/lang/msl/writer/helper_test.h b/src/tint/lang/msl/writer/helper_test.h
index 7fe349b..38fc1f4 100644
--- a/src/tint/lang/msl/writer/helper_test.h
+++ b/src/tint/lang/msl/writer/helper_test.h
@@ -35,6 +35,7 @@
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/validator.h"
 #include "src/tint/lang/msl/validate/validate.h"
+#include "src/tint/lang/msl/writer/printer/printer.h"
 #include "src/tint/lang/msl/writer/writer.h"
 
 namespace tint::msl::writer {
@@ -90,6 +91,28 @@
         }
         output_ = result.Get();
 
+        return Validate(msl_version);
+    }
+
+    /// Run the printer on the MSL IR module and validate the result.
+    /// @param options the writer options
+    /// @returns true if generation and validation succeeded
+    bool Print(Options options = {},
+               [[maybe_unused]] validate::MslVersion msl_version = validate::MslVersion::kMsl_2_3) {
+        auto result = writer::Print(mod, options);
+        if (result != Success) {
+            err_ = result.Failure().reason.Str();
+            return false;
+        }
+        output_ = result.Get();
+
+        return Validate(msl_version);
+    }
+
+    /// Validate the output.
+    /// @param msl_version the MSL version to validate against
+    /// @returns true if validation succeeded
+    bool Validate([[maybe_unused]] validate::MslVersion msl_version) {
 #if TINT_BUILD_IS_MAC
         auto msl_validation = validate::ValidateUsingMetal(output_.msl, msl_version);
         if (msl_validation.failed) {
@@ -97,7 +120,6 @@
             return false;
         }
 #endif
-
         return true;
     }
 
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index 4243268..1c57ba0 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -85,6 +85,7 @@
 #include "src/tint/lang/core/type/storage_texture.h"
 #include "src/tint/lang/core/type/texture.h"
 #include "src/tint/lang/core/type/u32.h"
+#include "src/tint/lang/core/type/u64.h"
 #include "src/tint/lang/core/type/u8.h"
 #include "src/tint/lang/core/type/vector.h"
 #include "src/tint/lang/core/type/void.h"
@@ -127,6 +128,7 @@
             ir_, "msl.Printer",
             core::ir::Capabilities{
                 core::ir::Capability::kAllow8BitIntegers,
+                core::ir::Capability::kAllow64BitIntegers,
                 core::ir::Capability::kAllowPointersAndHandlesInStructures,
                 core::ir::Capability::kAllowPrivateVarsInFunctions,
             });
@@ -1290,6 +1292,7 @@
             [&](const core::type::F16*) { out << "half"; },   //
             [&](const core::type::I32*) { out << "int"; },    //
             [&](const core::type::U32*) { out << "uint"; },   //
+            [&](const core::type::U64*) { out << "ulong"; },  //
             [&](const core::type::I8*) { out << "char"; },    //
             [&](const core::type::U8*) { out << "uchar"; },   //
             [&](const core::type::Array* arr) { EmitArrayType(out, arr); },
@@ -1692,6 +1695,7 @@
             [&](const core::type::Bool*) { out << (c->ValueAs<bool>() ? "true" : "false"); },
             [&](const core::type::I32*) { PrintI32(out, c->ValueAs<i32>()); },
             [&](const core::type::U32*) { out << c->ValueAs<u32>() << "u"; },
+            [&](const core::type::U64*) { out << c->ValueAs<u64>() << "ul"; },
             [&](const core::type::F32*) { PrintF32(out, c->ValueAs<f32>()); },
             [&](const core::type::F16*) { PrintF16(out, c->ValueAs<f16>()); },
             [&](const core::type::Vector* v) {
@@ -1755,6 +1759,7 @@
             [&](const core::type::F32*) { out << "0.0f"; },                           //
             [&](const core::type::I32*) { out << "0"; },                              //
             [&](const core::type::U32*) { out << "0u"; },                             //
+            [&](const core::type::U64*) { out << "0u"; },                             //
             [&](const core::type::Vector* vec) { EmitZeroValue(out, vec->Type()); },  //
             [&](const core::type::Matrix* mat) {
                 EmitType(out, mat);
diff --git a/src/tint/lang/msl/writer/type_test.cc b/src/tint/lang/msl/writer/type_test.cc
index 3fee85d..725cfed 100644
--- a/src/tint/lang/msl/writer/type_test.cc
+++ b/src/tint/lang/msl/writer/type_test.cc
@@ -209,6 +209,22 @@
 )");
 }
 
+TEST_F(MslWriterTest, EmitType_U64) {
+    auto* func = b.Function("foo", ty.void_());
+    b.Append(func->Block(), [&] {
+        b.Var("a", ty.ptr(core::AddressSpace::kFunction, ty.u64()));
+        b.Return(func);
+    });
+
+    // Use `Print()` as u64 types are only support after certain transforms have run.
+    ASSERT_TRUE(Print()) << err_ << output_.msl;
+    EXPECT_EQ(output_.msl, MetalHeader() + R"(
+void foo() {
+  ulong a = 0u;
+}
+)");
+}
+
 TEST_F(MslWriterTest, EmitType_Atomic_U32) {
     auto* func = b.Function("foo", ty.void_());
     auto* param = b.FunctionParam("a", ty.ptr(core::AddressSpace::kWorkgroup, ty.atomic<u32>()));