Eliminate unreachable code in dehydrated modules.

At present this has no effect. There isn't any dead path in the built-in
code (as you would hope) and we don't do any sufficiently-interesting
transformations that might cause unreachable code to appear.

Change-Id: I6798ae21f8721cf9f6f61ecb1765c8d8df7a9d0d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/540039
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 29cce65..2211089 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -602,12 +602,13 @@
 
     std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module, base);
 
+    // Remove any unreachable code.
+    Transform::EliminateUnreachableCode(module, usage.get());
+
     while (Transform::EliminateDeadLocalVariables(*fContext, module, usage.get())) {
         // Removing dead variables may cause more variables to become unreferenced. Try again.
     }
 
-    // TODO: run EliminateUnreachableCode pass
-
     // Note that we intentionally don't attempt to eliminate unreferenced global variables or
     // functions here, since those can be referenced by the finished program even if they're
     // unreferenced now. We also don't run the inliner to avoid growing the program; that is done in
diff --git a/src/sksl/transform/BUILD.bazel b/src/sksl/transform/BUILD.bazel
index ef08690..9d1944f 100644
--- a/src/sksl/transform/BUILD.bazel
+++ b/src/sksl/transform/BUILD.bazel
@@ -92,9 +92,11 @@
     deps = [
         ":SkSLProgramWriter_hdr",
         ":SkSLTransform_hdr",
+        "//include/core:SkSpan_hdr",
         "//include/private:SkSLProgramElement_hdr",
         "//include/private:SkSLStatement_hdr",
         "//include/private:SkTArray_hdr",
+        "//src/sksl:SkSLCompiler_hdr",
         "//src/sksl/ir:SkSLFunctionDefinition_hdr",
         "//src/sksl/ir:SkSLIfStatement_hdr",
         "//src/sksl/ir:SkSLNop_hdr",
diff --git a/src/sksl/transform/SkSLEliminateUnreachableCode.cpp b/src/sksl/transform/SkSLEliminateUnreachableCode.cpp
index 9c9ecc7..2e44912 100644
--- a/src/sksl/transform/SkSLEliminateUnreachableCode.cpp
+++ b/src/sksl/transform/SkSLEliminateUnreachableCode.cpp
@@ -5,9 +5,11 @@
  * found in the LICENSE file.
  */
 
+#include "include/core/SkSpan.h"
 #include "include/private/SkSLProgramElement.h"
 #include "include/private/SkSLStatement.h"
 #include "include/private/SkTArray.h"
+#include "src/sksl/SkSLCompiler.h"
 #include "src/sksl/ir/SkSLFunctionDefinition.h"
 #include "src/sksl/ir/SkSLIfStatement.h"
 #include "src/sksl/ir/SkSLNop.h"
@@ -16,17 +18,16 @@
 #include "src/sksl/transform/SkSLTransform.h"
 
 #include <memory>
-#include <vector>
 
 namespace SkSL {
 
 class Expression;
 
-void Transform::EliminateUnreachableCode(Program& program, ProgramUsage* usage) {
+static void eliminate_unreachable_code(SkSpan<std::unique_ptr<ProgramElement>> elements,
+                                       ProgramUsage* usage) {
     class UnreachableCodeEliminator : public ProgramWriter {
     public:
-        UnreachableCodeEliminator(ProgramUsage* usage)
-                : fUsage(usage) {
+        UnreachableCodeEliminator(ProgramUsage* usage) : fUsage(usage) {
             fFoundFunctionExit.push_back(false);
             fFoundLoopExit.push_back(false);
         }
@@ -41,9 +42,7 @@
                 // If we already found an exit in this section, anything beyond it is dead code.
                 if (!stmt->is<Nop>()) {
                     // Eliminate the dead statement by substituting a Nop.
-                    if (fUsage) {
-                        fUsage->remove(stmt.get());
-                    }
+                    fUsage->remove(stmt.get());
                     stmt = Nop::Make();
                 }
                 return false;
@@ -138,7 +137,7 @@
         using INHERITED = ProgramWriter;
     };
 
-    for (std::unique_ptr<ProgramElement>& pe : program.fOwnedElements) {
+    for (std::unique_ptr<ProgramElement>& pe : elements) {
         if (pe->is<FunctionDefinition>()) {
             UnreachableCodeEliminator visitor{usage};
             visitor.visitStatementPtr(pe->as<FunctionDefinition>().body());
@@ -146,4 +145,12 @@
     }
 }
 
+void Transform::EliminateUnreachableCode(LoadedModule& module, ProgramUsage* usage) {
+    return eliminate_unreachable_code(SkMakeSpan(module.fElements), usage);
+}
+
+void Transform::EliminateUnreachableCode(Program& program, ProgramUsage* usage) {
+    return eliminate_unreachable_code(SkMakeSpan(program.fOwnedElements), usage);
+}
+
 }  // namespace SkSL
diff --git a/src/sksl/transform/SkSLTransform.h b/src/sksl/transform/SkSLTransform.h
index 99fad7c..2bc317d 100644
--- a/src/sksl/transform/SkSLTransform.h
+++ b/src/sksl/transform/SkSLTransform.h
@@ -35,7 +35,8 @@
  * Eliminates statements in a block which cannot be reached; for example, a statement
  * immediately after a `return` or `continue` can safely be eliminated.
  */
-void EliminateUnreachableCode(Program& program, ProgramUsage* usage = nullptr);
+void EliminateUnreachableCode(LoadedModule& module, ProgramUsage* usage);
+void EliminateUnreachableCode(Program& program, ProgramUsage* usage);
 
 /**
  * Eliminates functions in a program which are never called. Returns true if any changes were made.