Fixing symbol DCE stripping executable sources on round-tripping. (#12429)

Also adding a test that checks this workflow produces the expected
outputs.
diff --git a/compiler/src/iree/compiler/Dialect/HAL/Transforms/DumpExecutableSources.cpp b/compiler/src/iree/compiler/Dialect/HAL/Transforms/DumpExecutableSources.cpp
index 163b4ec..e626ac2 100644
--- a/compiler/src/iree/compiler/Dialect/HAL/Transforms/DumpExecutableSources.cpp
+++ b/compiler/src/iree/compiler/Dialect/HAL/Transforms/DumpExecutableSources.cpp
@@ -59,6 +59,10 @@
     }
 
     for (auto executableOp : moduleOp.getOps<IREE::HAL::ExecutableOp>()) {
+      // Reset to public visibility so symbol DCE won't drop it on load.
+      auto originalVisibility = executableOp.getVisibility();
+      executableOp.setVisibility(SymbolTable::Visibility::Public);
+
       auto fileName =
           (moduleName + "_" + executableOp.getName() + ".mlir").str();
       if (path.empty() || path == "-") {
@@ -76,6 +80,9 @@
         dumpExecutableToStream(executableOp, filePath, file->os());
         file->keep();
       }
+
+      // Restore original visibility.
+      executableOp.setVisibility(originalVisibility);
     }
   }
 
diff --git a/compiler/src/iree/compiler/Dialect/HAL/Transforms/test/dump_executable_sources.mlir b/compiler/src/iree/compiler/Dialect/HAL/Transforms/test/dump_executable_sources.mlir
index 455295d..c1bae6e 100644
--- a/compiler/src/iree/compiler/Dialect/HAL/Transforms/test/dump_executable_sources.mlir
+++ b/compiler/src/iree/compiler/Dialect/HAL/Transforms/test/dump_executable_sources.mlir
@@ -17,7 +17,7 @@
 
 module attributes {hal.device.targets = [#device_target_cpu]}  {
 
-  // CHECK: hal.executable private @ex0
+  // CHECK: hal.executable public @ex0
   hal.executable private @ex0 {
     // We expect local outputs with attributes inlined:
     // CHECK-NEXT: hal.executable.variant {{.+}}, target = <"llvm-cpu"
diff --git a/tools/test/BUILD b/tools/test/BUILD
index 5d6dba7..8bd9fa6 100644
--- a/tools/test/BUILD
+++ b/tools/test/BUILD
@@ -20,6 +20,7 @@
         [
             "compile_to_phase.mlir",
             "executable_benchmarks.mlir",
+            "executable_sources.mlir",
             "iree-benchmark-module.mlir",
             "iree-run-mlir.mlir",
             "iree-run-module.mlir",
diff --git a/tools/test/CMakeLists.txt b/tools/test/CMakeLists.txt
index a30447c..64a3e22 100644
--- a/tools/test/CMakeLists.txt
+++ b/tools/test/CMakeLists.txt
@@ -16,6 +16,7 @@
   SRCS
     "compile_to_phase.mlir"
     "executable_benchmarks.mlir"
+    "executable_sources.mlir"
     "iree-benchmark-module.mlir"
     "iree-run-mlir.mlir"
     "iree-run-module-expected.mlir"
diff --git a/tools/test/executable_sources.mlir b/tools/test/executable_sources.mlir
new file mode 100644
index 0000000..92df2e9
--- /dev/null
+++ b/tools/test/executable_sources.mlir
@@ -0,0 +1,42 @@
+// RUN: iree-compile %s -o ignored.mlir \
+// RUN:     --iree-hal-target-backends=vmvx \
+// RUN:     --iree-hal-dump-executable-sources-to=- | \
+// RUN: iree-compile - -o /dev/null \
+// RUN:     --compile-mode=hal-executable \
+// RUN:     --mlir-print-ir-before=iree-hal-serialize-executables 2>&1 | \
+// RUN: FileCheck %s
+
+// This test relies on us piping stdout and that there's only a single
+// executable (otherwise we'd need to look at files and that's harder
+// cross-platform). Real automation of this requires xargs: compile and dump a
+// directory of .mlir sources by specifying a path to the dump flag instead
+// of `-` (indicating stdout) and then ls | xargs them to iree-compile or
+// iree-opt.
+//
+// Example of dumping per-dispatch executable sources and compiling each to
+// their platform binary form, dumping their MLIR prior to lowering into the
+// backend representation (SPIR-V/LLVM-IR/etc):
+//  iree-compile some_input.mlir -o ignored.mlir \
+//      --iree-hal-target-backends=vmvx \
+//      --iree-hal-dump-executable-sources-to=sources/ | \
+//  ls -1 sources/ | xargs -i sh -c "iree-compile sources/{} --compile-mode=hal-executable --mlir-print-ir-before=iree-hal-serialize-executables"
+//
+// NOTE: executable sources are not runnable: they only exist to allow for
+// iteration on executable translation. If you want to run them you need
+// corresponding host code to dispatch them and can use benchmarks instead.
+//
+// If modifying the sources and wanting to see the changes in a full program the
+// --iree-hal-substitute-executable-sources-from= flag can be used to substitute
+// one or more executables dumped with this command from a path or for
+// individual executables one or more `executable_name=file.mlir` pairs can be
+// repeated in `--iree-hal-substitute-executable-source=`.
+
+func.func @abs(%input : tensor<f32>) -> (tensor<f32>) {
+  %result = math.absf %input : tensor<f32>
+  return %result : tensor<f32>
+}
+
+// CHECK: IR Dump Before mlir::iree_compiler::IREE::HAL::SerializeExecutablesPass
+// CHECK: hal.executable public @abs_dispatch_0
+// CHECK:   hal.executable.variant public @vmvx_bytecode_fb
+// CHECK:     vm.func private @abs_dispatch_0_generic