[hlsl] Emit empty functions in HLSL IR.

This CL adds the ability to emit a function with no parameters and a
`void` return type in the HLSL ir backend.

Bug: 42251304
Change-Id: I5a2210cc3573f105a2f2f98fee42c47a6eadcace
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/192783
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/hlsl/writer/printer/BUILD.bazel b/src/tint/lang/hlsl/writer/printer/BUILD.bazel
index a7821d3..aff3d1f 100644
--- a/src/tint/lang/hlsl/writer/printer/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/printer/BUILD.bazel
@@ -45,16 +45,23 @@
     "printer.h",
   ],
   deps = [
+    "//src/tint/api/common",
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
     "//src/tint/lang/core/ir",
+    "//src/tint/lang/core/type",
     "//src/tint/utils/containers",
     "//src/tint/utils/diagnostic",
     "//src/tint/utils/generator",
     "//src/tint/utils/ice",
+    "//src/tint/utils/id",
     "//src/tint/utils/macros",
     "//src/tint/utils/math",
     "//src/tint/utils/memory",
+    "//src/tint/utils/reflection",
     "//src/tint/utils/result",
     "//src/tint/utils/rtti",
+    "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
   ],
diff --git a/src/tint/lang/hlsl/writer/printer/BUILD.cmake b/src/tint/lang/hlsl/writer/printer/BUILD.cmake
index eb6147a..d2bf03b 100644
--- a/src/tint/lang/hlsl/writer/printer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/printer/BUILD.cmake
@@ -44,16 +44,23 @@
 )
 
 tint_target_add_dependencies(tint_lang_hlsl_writer_printer lib
+  tint_api_common
+  tint_lang_core
+  tint_lang_core_constant
   tint_lang_core_ir
+  tint_lang_core_type
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_generator
   tint_utils_ice
+  tint_utils_id
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
+  tint_utils_reflection
   tint_utils_result
   tint_utils_rtti
+  tint_utils_symbol
   tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/lang/hlsl/writer/printer/BUILD.gn b/src/tint/lang/hlsl/writer/printer/BUILD.gn
index c0af7bb..1c642e4 100644
--- a/src/tint/lang/hlsl/writer/printer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/printer/BUILD.gn
@@ -44,16 +44,23 @@
     "printer.h",
   ]
   deps = [
+    "${tint_src_dir}/api/common",
+    "${tint_src_dir}/lang/core",
+    "${tint_src_dir}/lang/core/constant",
     "${tint_src_dir}/lang/core/ir",
+    "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/utils/containers",
     "${tint_src_dir}/utils/diagnostic",
     "${tint_src_dir}/utils/generator",
     "${tint_src_dir}/utils/ice",
+    "${tint_src_dir}/utils/id",
     "${tint_src_dir}/utils/macros",
     "${tint_src_dir}/utils/math",
     "${tint_src_dir}/utils/memory",
+    "${tint_src_dir}/utils/reflection",
     "${tint_src_dir}/utils/result",
     "${tint_src_dir}/utils/rtti",
+    "${tint_src_dir}/utils/symbol",
     "${tint_src_dir}/utils/text",
     "${tint_src_dir}/utils/traits",
   ]
diff --git a/src/tint/lang/hlsl/writer/printer/printer.cc b/src/tint/lang/hlsl/writer/printer/printer.cc
index fb49dee..e5c4a35 100644
--- a/src/tint/lang/hlsl/writer/printer/printer.cc
+++ b/src/tint/lang/hlsl/writer/printer/printer.cc
@@ -29,7 +29,10 @@
 
 #include <utility>
 
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/return.h"
 #include "src/tint/lang/core/ir/validator.h"
+#include "src/tint/lang/core/type/void.h"
 #include "src/tint/utils/generator/text_generator.h"
 
 namespace tint::hlsl::writer {
@@ -49,8 +52,14 @@
             return std::move(valid.Failure());
         }
 
-        // TODO(dsinclair): Flush out HLSL printer
+        // TOOD(dsinclair): EmitRootBlock
 
+        // Emit functions.
+        for (auto* func : ir_.DependencyOrderedFunctions()) {
+            EmitFunction(func);
+        }
+
+        result_.hlsl = main_buffer_.String();
         return std::move(result_);
     }
 
@@ -59,6 +68,71 @@
     PrintResult result_;
 
     core::ir::Module& ir_;
+
+    /// A hashmap of value to name
+    Hashmap<const core::ir::Value*, std::string, 32> names_;
+
+    /// Emit the function
+    /// @param func the function to emit
+    void EmitFunction(const core::ir::Function* func) {
+        {
+            auto out = Line();
+            auto func_name = NameOf(func);
+
+            // TODO(dsinclair): Pipeline stage and workgroup information
+
+            EmitType(out, func->ReturnType());
+            out << " " << func_name << "(";
+
+            // TODO(dsinclair): Parameters
+
+            out << ") {";
+        }
+        {
+            const ScopedIndent si(current_buffer_);
+            EmitBlock(func->Block());
+        }
+
+        Line() << "}";
+    }
+
+    /// Emit a block
+    /// @param block the block to emit
+    void EmitBlock(const core::ir::Block* block) {
+        for (auto* inst : *block) {
+            TINT_ASSERT(inst->Is<core::ir::Return>());
+
+            // TODO(dsinclair): handle instructions
+            Line() << "return;";
+        }
+    }
+
+    /// Emit a type
+    /// @param out the stream to emit too
+    /// @param ty the type to emit
+    void EmitType(StringStream& out, const core::type::Type* ty) {
+        TINT_ASSERT(ty->Is<core::type::Void>());
+
+        // TODO(dsinclair): Emit types
+        out << "void";
+    }
+
+    /// @param value the value to get the name of
+    /// @returns the name of the given value, creating a new unique name if the value is unnamed in
+    /// the module.
+    std::string NameOf(const core::ir::Value* value) {
+        return names_.GetOrAdd(value, [&] {
+            auto sym = ir_.NameOf(value);
+            return sym.IsValid() ? sym.Name() : UniqueIdentifier("v");
+        });
+    }
+
+    /// @return a new, unique identifier with the given prefix.
+    /// @param prefix optional prefix to apply to the generated identifier. If empty
+    /// "tint_symbol" will be used.
+    std::string UniqueIdentifier(const std::string& prefix /* = "" */) {
+        return ir_.symbols.New(prefix).Name();
+    }
 };
 
 }  // namespace