Allow multiple expressions on the same statement to be inlined.

This will allow the inliner to successfully do more work in a single
pass.

Change-Id: I26e8831737c10bdf9a35eebd94ea8b74f6487077
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/386916
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/src/sksl/SkSLInliner.cpp b/src/sksl/SkSLInliner.cpp
index 48a80b8..459f17d 100644
--- a/src/sksl/SkSLInliner.cpp
+++ b/src/sksl/SkSLInliner.cpp
@@ -928,7 +928,7 @@
                 this->addInlineCandidate(expr);
                 break;
             }
-            case Expression::Kind::kIndex:{
+            case Expression::Kind::kIndex: {
                 IndexExpression& indexExpr = (*expr)->as<IndexExpression>();
                 this->visitExpression(&indexExpr.base());
                 this->visitExpression(&indexExpr.index());
@@ -1076,18 +1076,14 @@
     this->buildCandidateList(elements, symbols, usage, &candidateList);
 
     // Inline the candidates where we've determined that it's safe to do so.
-    std::unordered_set<const std::unique_ptr<Statement>*> enclosingStmtSet;
+    using StatementRemappingTable = std::unordered_map<std::unique_ptr<Statement>*,
+                                                       std::unique_ptr<Statement>*>;
+    StatementRemappingTable statementRemappingTable;
+
     bool madeChanges = false;
     for (const InlineCandidate& candidate : candidateList.fCandidates) {
         FunctionCall& funcCall = (*candidate.fCandidateExpr)->as<FunctionCall>();
 
-        // Inlining two expressions using the same enclosing statement in the same inlining pass
-        // does not work properly. If this happens, skip it; we'll get it in the next pass.
-        auto [unusedIter, inserted] = enclosingStmtSet.insert(candidate.fEnclosingStmt);
-        if (!inserted) {
-            continue;
-        }
-
         // Convert the function call to its inlined equivalent.
         InlinedCall inlinedCall = this->inlineCall(&funcCall, candidate.fSymbols, *usage,
                                                    &candidate.fEnclosingFunction->declaration());
@@ -1103,6 +1099,16 @@
         // Add references within the inlined body
         usage->add(inlinedCall.fInlinedBody.get());
 
+        // Look up the enclosing statement; remap it if necessary.
+        std::unique_ptr<Statement>* enclosingStmt = candidate.fEnclosingStmt;
+        for (;;) {
+            auto iter = statementRemappingTable.find(enclosingStmt);
+            if (iter == statementRemappingTable.end()) {
+                break;
+            }
+            enclosingStmt = iter->second;
+        }
+
         // Move the enclosing statement to the end of the unscoped Block containing the inlined
         // function, then replace the enclosing statement with that Block.
         // Before:
@@ -1111,14 +1117,18 @@
         // After:
         //     fInlinedBody = null
         //     fEnclosingStmt = Block{ stmt1, stmt2, stmt3, stmt4 }
-        inlinedCall.fInlinedBody->children().push_back(std::move(*candidate.fEnclosingStmt));
-        *candidate.fEnclosingStmt = std::move(inlinedCall.fInlinedBody);
+        inlinedCall.fInlinedBody->children().push_back(std::move(*enclosingStmt));
+        *enclosingStmt = std::move(inlinedCall.fInlinedBody);
 
         // Replace the candidate function call with our replacement expression.
         usage->replace(candidate.fCandidateExpr->get(), inlinedCall.fReplacementExpr.get());
         *candidate.fCandidateExpr = std::move(inlinedCall.fReplacementExpr);
         madeChanges = true;
 
+        // If anything else pointed at our enclosing statement, it's now pointing at a Block
+        // containing many other statements as well. Maintain a fix-up table to account for this.
+        statementRemappingTable[enclosingStmt] = &(*enclosingStmt)->as<Block>().children().back();
+
         // Stop inlining if we've reached our hard cap on new statements.
         if (fInlinedStatementCounter >= kInlinedStatementLimit) {
             break;
diff --git a/tests/sksl/inliner/InlinerCanBeDisabledStandaloneSettings.glsl b/tests/sksl/inliner/InlinerCanBeDisabledStandaloneSettings.glsl
index 692492d..8482a00 100644
--- a/tests/sksl/inliner/InlinerCanBeDisabledStandaloneSettings.glsl
+++ b/tests/sksl/inliner/InlinerCanBeDisabledStandaloneSettings.glsl
@@ -47,8 +47,8 @@
     return vec4((((_blend_set_color_luminance(_blend_set_color_saturation(sda, dsa), alpha, dsa) + dst.xyz) - dsa) + src.xyz) - sda, (src.w + dst.w) - alpha);
 }
 void main() {
-    float _0_c = color.x * color.y + color.z;
-    sk_FragColor = vec4(_0_c);
+    float _1_c = color.x * color.y + color.z;
+    sk_FragColor = vec4(_1_c);
     sk_FragColor *= 1.25;
     sk_FragColor *= color.xxyy * color.w;
     sk_FragColor *= color.zzww * color.y;
diff --git a/tests/sksl/inliner/InlinerManglesNames.glsl b/tests/sksl/inliner/InlinerManglesNames.glsl
index 54b8662..8a82c7d 100644
--- a/tests/sksl/inliner/InlinerManglesNames.glsl
+++ b/tests/sksl/inliner/InlinerManglesNames.glsl
@@ -2,11 +2,11 @@
 out vec4 sk_FragColor;
 uniform vec4 color;
 vec4 main() {
-    float _0_c = color.x * color.y + color.z;
-    float a = _0_c;
-    float _1_c = color.y * color.z + color.w;
-    float b = _1_c;
-    float _2_c = color.z * color.w + color.x;
-    float c = _2_c;
+    float _1_c = color.x * color.y + color.z;
+    float a = _1_c;
+    float _2_c = color.y * color.z + color.w;
+    float b = _2_c;
+    float _3_c = color.z * color.w + color.x;
+    float c = _3_c;
     return vec4(a, b, c * c, a * (b * c));
 }