[ir] Add framework to dump IR to text

This CL adds the framework and `tint` option to write the IR to stdout
as text for debug purposes.

Bug: tint:1718
Change-Id: I05bd83635800fbfe3b65d968a84b30931ec1bdb6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/110171
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/cmd/main.cc b/src/tint/cmd/main.cc
index d3f9161..30dba76 100644
--- a/src/tint/cmd/main.cc
+++ b/src/tint/cmd/main.cc
@@ -110,6 +110,7 @@
     std::optional<tint::sem::BindingPoint> hlsl_root_constant_binding_point;
 
 #if TINT_BUILD_IR
+    bool dump_ir = false;
     bool dump_ir_graph = false;
 #endif  // TINT_BUILD_IR
 };
@@ -475,6 +476,8 @@
             }
             opts->dxc_path = args[i];
 #if TINT_BUILD_IR
+        } else if (arg == "--dump-ir") {
+            opts->dump_ir = true;
         } else if (arg == "--dump-ir-graph") {
             opts->dump_ir_graph = true;
 #endif  // TINT_BUILD_IR
@@ -1205,6 +1208,7 @@
         std::string usage = tint::utils::ReplaceAll(kUsage, "${transforms}", transform_names());
 #if TINT_BUILD_IR
         usage +=
+            "  --dump-ir                 -- Writes the IR to stdout\n"
             "  --dump-ir-graph           -- Writes the IR graph to 'tint.dot' as a dot graph\n";
 #endif  // TINT_BUILD_IR
 
@@ -1327,14 +1331,19 @@
     }
 
 #if TINT_BUILD_IR
-    if (options.dump_ir_graph) {
+    if (options.dump_ir || options.dump_ir_graph) {
         auto result = tint::ir::Module::FromProgram(program.get());
         if (!result) {
             std::cerr << "Failed to build IR from program: " << result.Failure() << std::endl;
         } else {
             auto mod = result.Move();
-            auto graph = tint::ir::Debug::AsDotGraph(&mod);
-            WriteFile("tint.dot", "w", graph);
+            if (options.dump_ir) {
+                std::cout << tint::ir::Debug::AsString(&mod) << std::endl;
+            }
+            if (options.dump_ir_graph) {
+                auto graph = tint::ir::Debug::AsDotGraph(&mod);
+                WriteFile("tint.dot", "w", graph);
+            }
         }
     }
 #endif  // TINT_BUILD_IR
diff --git a/src/tint/ir/debug.cc b/src/tint/ir/debug.cc
index be83111..755d9de 100644
--- a/src/tint/ir/debug.cc
+++ b/src/tint/ir/debug.cc
@@ -156,4 +156,11 @@
     return out.str();
 }
 
+// static
+std::string Debug::AsString(const Module*) {
+    std::stringstream out;
+    out << "IR" << std::endl;
+    return out.str();
+}
+
 }  // namespace tint::ir
diff --git a/src/tint/ir/debug.h b/src/tint/ir/debug.h
index bd0570b..2363776 100644
--- a/src/tint/ir/debug.h
+++ b/src/tint/ir/debug.h
@@ -28,6 +28,11 @@
     /// @param mod the module to emit
     /// @returns the dot graph for the given module
     static std::string AsDotGraph(const Module* mod);
+
+    /// Returns the module as a string
+    /// @param mod the module to emit
+    /// @returns the string representation of the module
+    static std::string AsString(const Module* mod);
 };
 
 }  // namespace tint::ir