Reland "Add support for do-while loops in PipelineStage."

This is a reland of 9c7e04cd6f372c100e7a46d86a8841dff0d368fa

The DeadReturnES3 test isn't enabled yet due to crashes in Radeon, but
the PipelineStage fixes need to be landed now.

Original change's description:
> Add support for do-while loops in PipelineStage.
>
> This allows us to run tests which use do-while loops (like
> DeadReturnES3) within dm.
>
> Change-Id: If8ecb6b3fcd23d79451a43edf8e1ee8a182de984
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/410459
> Commit-Queue: John Stiles <johnstiles@google.com>
> Auto-Submit: John Stiles <johnstiles@google.com>
> Reviewed-by: Brian Osman <brianosman@google.com>

Change-Id: I73715f09defd950156cc252be9a52a36620d6d5b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/410936
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp
index e555c4f..0f1fe1c 100644
--- a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp
@@ -14,6 +14,7 @@
 #include "src/sksl/SkSLStringStream.h"
 #include "src/sksl/ir/SkSLBinaryExpression.h"
 #include "src/sksl/ir/SkSLConstructor.h"
+#include "src/sksl/ir/SkSLDoStatement.h"
 #include "src/sksl/ir/SkSLExpressionStatement.h"
 #include "src/sksl/ir/SkSLFieldAccess.h"
 #include "src/sksl/ir/SkSLForStatement.h"
@@ -88,6 +89,7 @@
     void writeStatement(const Statement& s);
     void writeBlock(const Block& b);
     void writeIfStatement(const IfStatement& stmt);
+    void writeDoStatement(const DoStatement& d);
     void writeForStatement(const ForStatement& f);
     void writeReturnStatement(const ReturnStatement& r);
 
@@ -591,6 +593,9 @@
             this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel);
             this->write(";");
             break;
+        case Statement::Kind::kDo:
+            this->writeDoStatement(s.as<DoStatement>());
+            break;
         case Statement::Kind::kFor:
             this->writeForStatement(s.as<ForStatement>());
             break;
@@ -604,7 +609,6 @@
             this->writeVarDeclaration(s.as<VarDeclaration>());
             break;
         case Statement::Kind::kDiscard:
-        case Statement::Kind::kDo:
         case Statement::Kind::kSwitch:
             SkDEBUGFAIL("Unsupported control flow");
             break;
@@ -636,7 +640,25 @@
     }
 }
 
+void PipelineStageCodeGenerator::writeDoStatement(const DoStatement& d) {
+    this->write("do ");
+    this->writeStatement(*d.statement());
+    this->write(" while (");
+    this->writeExpression(*d.test(), Precedence::kTopLevel);
+    this->write(");");
+    return;
+}
+
 void PipelineStageCodeGenerator::writeForStatement(const ForStatement& f) {
+    // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
+    if (!f.initializer() && f.test() && !f.next()) {
+        this->write("while (");
+        this->writeExpression(*f.test(), Precedence::kTopLevel);
+        this->write(") ");
+        this->writeStatement(*f.statement());
+        return;
+    }
+
     this->write("for (");
     if (f.initializer() && !f.initializer()->isEmpty()) {
         this->writeStatement(*f.initializer());
diff --git a/tests/SkSLTest.cpp b/tests/SkSLTest.cpp
index 8023cac..c0285b1 100644
--- a/tests/SkSLTest.cpp
+++ b/tests/SkSLTest.cpp
@@ -232,6 +232,8 @@
 SKSL_TEST(SkSLConstVariableComparison,         "shared/ConstVariableComparison.sksl")
 SKSL_TEST(SkSLDeadIfStatement,                 "shared/DeadIfStatement.sksl")
 SKSL_TEST(SkSLDeadReturn,                      "shared/DeadReturn.sksl")
+// TODO(skia:12012): some Radeons crash when compiling this code; disable them
+//SKSL_TEST_ES3(SkSLDeadReturnES3,               "shared/DeadReturnES3.sksl")
 SKSL_TEST(SkSLDeadStripFunctions,              "shared/DeadStripFunctions.sksl")
 SKSL_TEST(SkSLDependentInitializers,           "shared/DependentInitializers.sksl")
 SKSL_TEST_ES3(SkSLDoWhileControlFlow,          "shared/DoWhileControlFlow.sksl")