Revert "Revert "Revert "implemented mustImplementGSInvocationsWithLoop workaround in sksl"""

This reverts commit f66d28dfb25127ff073e2e9549c6985785a65afa.

Reason for revert: breaks chrome-roll?
https://chromium-review.googlesource.com/c/542000

Original change's description:
> Revert "Revert "implemented mustImplementGSInvocationsWithLoop workaround in sksl""
> 
> This reverts commit 8ea60736aaa92cf3cf24705fb356e9e09e85b1fd.
> 
> Bug: skia:
> Change-Id: If77035e03430b469c2682788610b33ae0aefbe1f
> Reviewed-on: https://skia-review.googlesource.com/20053
> Reviewed-by: Chris Dalton <csmartdalton@google.com>
> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>

TBR=csmartdalton@google.com,ethannicholas@google.com

Change-Id: Iedada4e4b9facb37b792a655947d76eb0f7b22e4
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/20361
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp b/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp
index ea8e73f..01f223f 100644
--- a/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp
@@ -42,6 +42,10 @@
                                       int numInvocations) {
     SkASSERT(!this->isConfigured());
     fNumInvocations = numInvocations;
+    if (this->getProgramBuilder()->shaderCaps()->mustImplementGSInvocationsWithLoop()) {
+        maxVertices *= numInvocations;
+        numInvocations = 1;
+    }
     this->addLayoutQualifier(input_type_name(inputType), kIn_InterfaceQualifier);
     this->addLayoutQualifier(SkStringPrintf("invocations = %i", numInvocations).c_str(),
                              kIn_InterfaceQualifier);
@@ -53,4 +57,17 @@
 void GrGLSLGeometryBuilder::onFinalize() {
     SkASSERT(this->isConfigured());
     fProgramBuilder->varyingHandler()->getGeomDecls(&this->inputs(), &this->outputs());
+    GrShaderVar sk_InvocationID("sk_InvocationID", kInt_GrSLType);
+    this->declareGlobal(sk_InvocationID);
+    SkASSERT(sk_InvocationID.getName() == SkString("sk_InvocationID"));
+    if (this->getProgramBuilder()->shaderCaps()->mustImplementGSInvocationsWithLoop()) {
+        SkString invokeFn;
+        this->emitFunction(kVoid_GrSLType, "invoke", 0, nullptr, this->code().c_str(), &invokeFn);
+        this->code().printf("for (sk_InvocationID = 0; sk_InvocationID < %i; ++sk_InvocationID) {"
+                                "%s();"
+                                "EndPrimitive();"
+                            "}", fNumInvocations, invokeFn.c_str());
+    } else {
+        this->codePrependf("sk_InvocationID = gl_InvocationID;");
+    }
 }
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 2d541a3..dd20b5c 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -7,9 +7,11 @@
 
 #include "SkSLCompiler.h"
 
+#include "ast/SkSLASTPrecision.h"
 #include "SkSLCFGGenerator.h"
 #include "SkSLGLSLCodeGenerator.h"
 #include "SkSLIRGenerator.h"
+#include "SkSLParser.h"
 #include "SkSLSPIRVCodeGenerator.h"
 #include "ir/SkSLExpression.h"
 #include "ir/SkSLExpressionStatement.h"
@@ -154,7 +156,7 @@
 
     Modifiers::Flag ignored1;
     std::vector<std::unique_ptr<ProgramElement>> ignored2;
-    fIRGenerator->convertProgram(String(SKSL_INCLUDE), *fTypes, &ignored1, &ignored2);
+    this->internalConvertProgram(String(SKSL_INCLUDE), &ignored1, &ignored2);
     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
     ASSERT(!fErrorCount);
 }
@@ -1057,6 +1059,69 @@
     }
 }
 
+void Compiler::internalConvertProgram(String text,
+                                      Modifiers::Flag* defaultPrecision,
+                                      std::vector<std::unique_ptr<ProgramElement>>* result) {
+    Parser parser(text, *fTypes, *this);
+    std::vector<std::unique_ptr<ASTDeclaration>> parsed = parser.file();
+    if (fErrorCount) {
+        return;
+    }
+    *defaultPrecision = Modifiers::kHighp_Flag;
+    for (size_t i = 0; i < parsed.size(); i++) {
+        ASTDeclaration& decl = *parsed[i];
+        switch (decl.fKind) {
+            case ASTDeclaration::kVar_Kind: {
+                std::unique_ptr<VarDeclarations> s = fIRGenerator->convertVarDeclarations(
+                                                                         (ASTVarDeclarations&) decl,
+                                                                         Variable::kGlobal_Storage);
+                if (s) {
+                    result->push_back(std::move(s));
+                }
+                break;
+            }
+            case ASTDeclaration::kFunction_Kind: {
+                std::unique_ptr<FunctionDefinition> f = fIRGenerator->convertFunction(
+                                                                               (ASTFunction&) decl);
+                if (!fErrorCount && f) {
+                    this->scanCFG(*f);
+                    result->push_back(std::move(f));
+                }
+                break;
+            }
+            case ASTDeclaration::kModifiers_Kind: {
+                std::unique_ptr<ModifiersDeclaration> f = fIRGenerator->convertModifiersDeclaration(
+                                                                   (ASTModifiersDeclaration&) decl);
+                if (f) {
+                    result->push_back(std::move(f));
+                }
+                break;
+            }
+            case ASTDeclaration::kInterfaceBlock_Kind: {
+                std::unique_ptr<InterfaceBlock> i = fIRGenerator->convertInterfaceBlock(
+                                                                         (ASTInterfaceBlock&) decl);
+                if (i) {
+                    result->push_back(std::move(i));
+                }
+                break;
+            }
+            case ASTDeclaration::kExtension_Kind: {
+                std::unique_ptr<Extension> e = fIRGenerator->convertExtension((ASTExtension&) decl);
+                if (e) {
+                    result->push_back(std::move(e));
+                }
+                break;
+            }
+            case ASTDeclaration::kPrecision_Kind: {
+                *defaultPrecision = ((ASTPrecision&) decl).fPrecision;
+                break;
+            }
+            default:
+                ABORT("unsupported declaration: %s\n", decl.description().c_str());
+        }
+    }
+}
+
 std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, String text,
                                                   const Program::Settings& settings) {
     fErrorText = "";
@@ -1066,25 +1131,18 @@
     Modifiers::Flag ignored;
     switch (kind) {
         case Program::kVertex_Kind:
-            fIRGenerator->convertProgram(String(SKSL_VERT_INCLUDE), *fTypes, &ignored, &elements);
+            this->internalConvertProgram(String(SKSL_VERT_INCLUDE), &ignored, &elements);
             break;
         case Program::kFragment_Kind:
-            fIRGenerator->convertProgram(String(SKSL_FRAG_INCLUDE), *fTypes, &ignored, &elements);
+            this->internalConvertProgram(String(SKSL_FRAG_INCLUDE), &ignored, &elements);
             break;
         case Program::kGeometry_Kind:
-            fIRGenerator->convertProgram(String(SKSL_GEOM_INCLUDE), *fTypes, &ignored, &elements);
+            this->internalConvertProgram(String(SKSL_GEOM_INCLUDE), &ignored, &elements);
             break;
     }
     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
     Modifiers::Flag defaultPrecision;
-    fIRGenerator->convertProgram(text, *fTypes, &defaultPrecision, &elements);
-    if (!fErrorCount) {
-        for (auto& element : elements) {
-            if (element->fKind == ProgramElement::kFunction_Kind) {
-                this->scanCFG((FunctionDefinition&) *element);
-            }
-        }
-    }
+    this->internalConvertProgram(text, &defaultPrecision, &elements);
     auto result = std::unique_ptr<Program>(new Program(kind, settings, defaultPrecision, &fContext,
                                                        std::move(elements),
                                                        fIRGenerator->fSymbolTable,
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index bc9a196..5e7bc9e 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -98,6 +98,10 @@
 
     void scanCFG(FunctionDefinition& f);
 
+    void internalConvertProgram(String text,
+                                Modifiers::Flag* defaultPrecision,
+                                std::vector<std::unique_ptr<ProgramElement>>* result);
+
     std::shared_ptr<SymbolTable> fTypes;
     IRGenerator* fIRGenerator;
     String fSkiaVertText; // FIXME store parsed version instead
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 11e7a56..f85ea10 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -11,13 +11,11 @@
 #include <unordered_set>
 
 #include "SkSLCompiler.h"
-#include "SkSLParser.h"
 #include "ast/SkSLASTBoolLiteral.h"
 #include "ast/SkSLASTFieldSuffix.h"
 #include "ast/SkSLASTFloatLiteral.h"
 #include "ast/SkSLASTIndexSuffix.h"
 #include "ast/SkSLASTIntLiteral.h"
-#include "ast/SkSLASTPrecision.h"
 #include "ir/SkSLBinaryExpression.h"
 #include "ir/SkSLBoolLiteral.h"
 #include "ir/SkSLBreakStatement.h"
@@ -145,7 +143,6 @@
         fill_caps(*settings->fCaps, &fCapsMap);
     }
     this->pushSymbolTable();
-    fInvocations = -1;
     fInputs.reset();
 }
 
@@ -281,24 +278,7 @@
 
 std::unique_ptr<ModifiersDeclaration> IRGenerator::convertModifiersDeclaration(
                                                                  const ASTModifiersDeclaration& m) {
-    Modifiers modifiers = m.fModifiers;
-    if (modifiers.fLayout.fInvocations != -1) {
-        fInvocations = modifiers.fLayout.fInvocations;
-        if (fSettings->fCaps && fSettings->fCaps->mustImplementGSInvocationsWithLoop()) {
-            modifiers.fLayout.fInvocations = -1;
-            Variable* invocationId = (Variable*) (*fSymbolTable)["sk_InvocationID"];
-            ASSERT(invocationId);
-            invocationId->fModifiers.fLayout.fBuiltin = -1;
-            if (modifiers.fLayout.description() == "") {
-                return nullptr;
-            }
-        }
-    }
-    if (modifiers.fLayout.fMaxVertices != -1 && fInvocations > 0 && fSettings->fCaps &&
-        fSettings->fCaps->mustImplementGSInvocationsWithLoop()) {
-        modifiers.fLayout.fMaxVertices *= fInvocations;
-    }
-    return std::unique_ptr<ModifiersDeclaration>(new ModifiersDeclaration(modifiers));
+    return std::unique_ptr<ModifiersDeclaration>(new ModifiersDeclaration(m.fModifiers));
 }
 
 std::unique_ptr<Statement> IRGenerator::convertIf(const ASTIfStatement& s) {
@@ -510,73 +490,16 @@
     return std::unique_ptr<Statement>(new DiscardStatement(d.fPosition));
 }
 
-std::unique_ptr<Block> IRGenerator::applyInvocationIDWorkaround(std::unique_ptr<Block> main,
-        std::vector<std::unique_ptr<ProgramElement>>* out) {
-    Layout invokeLayout;
-    Modifiers invokeModifiers(invokeLayout, Modifiers::kHasSideEffects_Flag);
-    FunctionDeclaration* invokeDecl = new FunctionDeclaration(Position(),
-                                                              invokeModifiers,
-                                                              "_invoke",
-                                                              std::vector<const Variable*>(),
-                                                              *fContext.fVoid_Type);
-    out->push_back(std::unique_ptr<ProgramElement>(new FunctionDefinition(Position(),
-                                                                          *invokeDecl,
-                                                                          std::move(main))));
-    fSymbolTable->add(invokeDecl->fName, std::unique_ptr<FunctionDeclaration>(invokeDecl));
-
-    std::vector<std::unique_ptr<VarDeclaration>> variables;
-    Variable* loopIdx = (Variable*) (*fSymbolTable)["sk_InvocationID"];
-    ASSERT(loopIdx);
-    std::unique_ptr<Expression> test(new BinaryExpression(Position(),
-                    std::unique_ptr<Expression>(new VariableReference(Position(), *loopIdx)),
-                    Token::LT,
-                    std::unique_ptr<IntLiteral>(new IntLiteral(fContext, Position(), fInvocations)),
-                    *fContext.fBool_Type));
-    std::unique_ptr<Expression> next(new PostfixExpression(
-                std::unique_ptr<Expression>(
-                                      new VariableReference(Position(),
-                                                            *loopIdx,
-                                                            VariableReference::kReadWrite_RefKind)),
-                Token::PLUSPLUS));
-    ASTIdentifier endPrimitiveID = ASTIdentifier(Position(), "EndPrimitive");
-    std::unique_ptr<Expression> endPrimitive = this->convertExpression(endPrimitiveID);
-    ASSERT(endPrimitive);
-
-    std::vector<std::unique_ptr<Statement>> loopBody;
-    std::vector<std::unique_ptr<Expression>> invokeArgs;
-    loopBody.push_back(std::unique_ptr<Statement>(new ExpressionStatement(
-                                                        this->call(Position(), *invokeDecl, { }))));
-    loopBody.push_back(std::unique_ptr<Statement>(new ExpressionStatement(
-                                            this->call(Position(), std::move(endPrimitive), { }))));
-    std::unique_ptr<Expression> assignment(new BinaryExpression(Position(),
-                    std::unique_ptr<Expression>(new VariableReference(Position(), *loopIdx)),
-                    Token::EQ,
-                    std::unique_ptr<IntLiteral>(new IntLiteral(fContext, Position(), 0)),
-                    *fContext.fInt_Type));
-    std::unique_ptr<Statement> initializer(new ExpressionStatement(std::move(assignment)));
-    std::unique_ptr<Statement> loop = std::unique_ptr<Statement>(
-                new ForStatement(Position(),
-                                 std::move(initializer),
-                                 std::move(test),
-                                 std::move(next),
-                                 std::unique_ptr<Block>(new Block(Position(), std::move(loopBody))),
-                                 fSymbolTable));
-    std::vector<std::unique_ptr<Statement>> children;
-    children.push_back(std::move(loop));
-    return std::unique_ptr<Block>(new Block(Position(), std::move(children)));
-}
-
-void IRGenerator::convertFunction(const ASTFunction& f,
-                                  std::vector<std::unique_ptr<ProgramElement>>* out) {
+std::unique_ptr<FunctionDefinition> IRGenerator::convertFunction(const ASTFunction& f) {
     const Type* returnType = this->convertType(*f.fReturnType);
     if (!returnType) {
-        return;
+        return nullptr;
     }
     std::vector<const Variable*> parameters;
     for (const auto& param : f.fParameters) {
         const Type* type = this->convertType(*param->fType);
         if (!type) {
-            return;
+            return nullptr;
         }
         for (int j = (int) param->fSizes.size() - 1; j >= 0; j--) {
             int size = param->fSizes[j];
@@ -607,7 +530,7 @@
                 break;
             default:
                 fErrors.error(f.fPosition, "symbol '" + f.fName + "' was already defined");
-                return;
+                return nullptr;
         }
         for (const auto& other : functions) {
             ASSERT(other->fName == f.fName);
@@ -626,7 +549,7 @@
                         fErrors.error(f.fPosition, "functions '" + newDecl.description() +
                                                    "' and '" + other->description() +
                                                    "' differ only in return type");
-                        return;
+                        return nullptr;
                     }
                     decl = other;
                     for (size_t i = 0; i < parameters.size(); i++) {
@@ -635,7 +558,7 @@
                                                        to_string((uint64_t) i + 1) +
                                                        " differ between declaration and "
                                                        "definition");
-                            return;
+                            return nullptr;
                         }
                     }
                     if (other->fDefined) {
@@ -666,23 +589,17 @@
         for (size_t i = 0; i < parameters.size(); i++) {
             fSymbolTable->addWithoutOwnership(parameters[i]->fName, decl->fParameters[i]);
         }
-        bool needInvocationIDWorkaround = fSettings->fCaps &&
-                                          fSettings->fCaps->mustImplementGSInvocationsWithLoop() &&
-                                          fInvocations != -1 && f.fName == "main";
         std::unique_ptr<Block> body = this->convertBlock(*f.fBody);
         fCurrentFunction = nullptr;
         if (!body) {
-            return;
-        }
-        if (needInvocationIDWorkaround) {
-            body = this->applyInvocationIDWorkaround(std::move(body), out);
+            return nullptr;
         }
         // conservatively assume all user-defined functions have side effects
         ((Modifiers&) decl->fModifiers).fFlags |= Modifiers::kHasSideEffects_Flag;
-
-        out->push_back(std::unique_ptr<FunctionDefinition>(
-                                      new FunctionDefinition(f.fPosition, *decl, std::move(body))));
+        return std::unique_ptr<FunctionDefinition>(new FunctionDefinition(f.fPosition, *decl,
+                                                                          std::move(body)));
     }
+    return nullptr;
 }
 
 std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTInterfaceBlock& intf) {
@@ -1871,64 +1788,4 @@
     }
 }
 
-void IRGenerator::convertProgram(String text,
-                                 SymbolTable& types,
-                                 Modifiers::Flag* defaultPrecision,
-                                 std::vector<std::unique_ptr<ProgramElement>>* out) {
-    Parser parser(text, types, fErrors);
-    std::vector<std::unique_ptr<ASTDeclaration>> parsed = parser.file();
-    if (fErrors.errorCount()) {
-        return;
-    }
-    *defaultPrecision = Modifiers::kHighp_Flag;
-    for (size_t i = 0; i < parsed.size(); i++) {
-        ASTDeclaration& decl = *parsed[i];
-        switch (decl.fKind) {
-            case ASTDeclaration::kVar_Kind: {
-                std::unique_ptr<VarDeclarations> s = this->convertVarDeclarations(
-                                                                         (ASTVarDeclarations&) decl,
-                                                                         Variable::kGlobal_Storage);
-                if (s) {
-                    out->push_back(std::move(s));
-                }
-                break;
-            }
-            case ASTDeclaration::kFunction_Kind: {
-                this->convertFunction((ASTFunction&) decl, out);
-                break;
-            }
-            case ASTDeclaration::kModifiers_Kind: {
-                std::unique_ptr<ModifiersDeclaration> f = this->convertModifiersDeclaration(
-                                                                   (ASTModifiersDeclaration&) decl);
-                if (f) {
-                    out->push_back(std::move(f));
-                }
-                break;
-            }
-            case ASTDeclaration::kInterfaceBlock_Kind: {
-                std::unique_ptr<InterfaceBlock> i = this->convertInterfaceBlock(
-                                                                         (ASTInterfaceBlock&) decl);
-                if (i) {
-                    out->push_back(std::move(i));
-                }
-                break;
-            }
-            case ASTDeclaration::kExtension_Kind: {
-                std::unique_ptr<Extension> e = this->convertExtension((ASTExtension&) decl);
-                if (e) {
-                    out->push_back(std::move(e));
-                }
-                break;
-            }
-            case ASTDeclaration::kPrecision_Kind: {
-                *defaultPrecision = ((ASTPrecision&) decl).fPrecision;
-                break;
-            }
-            default:
-                ABORT("unsupported declaration: %s\n", decl.description().c_str());
-        }
-    }
-}
-
-
 }
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index 29513d8..d4a6846 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -81,10 +81,13 @@
     IRGenerator(const Context* context, std::shared_ptr<SymbolTable> root,
                 ErrorReporter& errorReporter);
 
-    void convertProgram(String text,
-                        SymbolTable& types,
-                        Modifiers::Flag* defaultPrecision,
-                        std::vector<std::unique_ptr<ProgramElement>>* result);
+    std::unique_ptr<VarDeclarations> convertVarDeclarations(const ASTVarDeclarations& decl,
+                                                            Variable::Storage storage);
+    std::unique_ptr<FunctionDefinition> convertFunction(const ASTFunction& f);
+    std::unique_ptr<Statement> convertStatement(const ASTStatement& statement);
+    std::unique_ptr<Expression> convertExpression(const ASTExpression& expression);
+    std::unique_ptr<ModifiersDeclaration> convertModifiersDeclaration(
+                                                                  const ASTModifiersDeclaration& m);
 
     /**
      * If both operands are compile-time constants and can be folded, returns an expression
@@ -112,15 +115,6 @@
     void pushSymbolTable();
     void popSymbolTable();
 
-    std::unique_ptr<VarDeclarations> convertVarDeclarations(const ASTVarDeclarations& decl,
-                                                            Variable::Storage storage);
-    void convertFunction(const ASTFunction& f,
-                         std::vector<std::unique_ptr<ProgramElement>>* out);
-    std::unique_ptr<Statement> convertStatement(const ASTStatement& statement);
-    std::unique_ptr<Expression> convertExpression(const ASTExpression& expression);
-    std::unique_ptr<ModifiersDeclaration> convertModifiersDeclaration(
-                                                                  const ASTModifiersDeclaration& m);
-
     const Type* convertType(const ASTType& type);
     std::unique_ptr<Expression> call(Position position,
                                      const FunctionDeclaration& function,
@@ -169,9 +163,6 @@
     std::unique_ptr<Expression> convertTernaryExpression(const ASTTernaryExpression& expression);
     std::unique_ptr<Statement> convertVarDeclarationStatement(const ASTVarDeclarationStatement& s);
     std::unique_ptr<Statement> convertWhile(const ASTWhileStatement& w);
-    std::unique_ptr<Block> applyInvocationIDWorkaround(
-                                                 std::unique_ptr<Block> main,
-                                                 std::vector<std::unique_ptr<ProgramElement>>* out);
 
     void fixRectSampling(std::vector<std::unique_ptr<Expression>>& arguments);
     void checkValid(const Expression& expr);
@@ -184,7 +175,6 @@
     int fLoopLevel;
     int fSwitchLevel;
     ErrorReporter& fErrors;
-    int fInvocations;
 
     friend class AutoSymbolTable;
     friend class AutoLoopLevel;
diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h
index b56ae16..d1af9bb 100644
--- a/src/sksl/SkSLUtil.h
+++ b/src/sksl/SkSLUtil.h
@@ -150,10 +150,6 @@
     const char* versionDeclString() const {
         return "";
     }
-
-    bool mustImplementGSInvocationsWithLoop() const {
-        return false;
-    }
 };
 
 extern StandaloneShaderCaps standaloneCaps;
@@ -228,13 +224,6 @@
         return result;
     }
 
-    static sk_sp<GrShaderCaps> MustImplementGSInvocationsWithLoop() {
-        sk_sp<GrShaderCaps> result = sk_make_sp<GrShaderCaps>(GrContextOptions());
-        result->fVersionDeclString = "#version 400";
-        result->fMustImplementGSInvocationsWithLoop = true;
-        return result;
-    }
-
     static sk_sp<GrShaderCaps> VariousCaps() {
         sk_sp<GrShaderCaps> result = sk_make_sp<GrShaderCaps>(GrContextOptions());
         result->fVersionDeclString = "#version 400";
diff --git a/src/sksl/ir/SkSLVarDeclarationsStatement.h b/src/sksl/ir/SkSLVarDeclarationsStatement.h
index a6a95a9..ab67536 100644
--- a/src/sksl/ir/SkSLVarDeclarationsStatement.h
+++ b/src/sksl/ir/SkSLVarDeclarationsStatement.h
@@ -31,7 +31,7 @@
     }
 
     String description() const override {
-        return fDeclaration->description() + ";";
+        return fDeclaration->description();
     }
 
     std::shared_ptr<VarDeclarations> fDeclaration;
diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp
index a4a3c0e..2ea6c7e 100644
--- a/tests/SkSLGLSLTest.cpp
+++ b/tests/SkSLGLSLTest.cpp
@@ -1393,39 +1393,4 @@
          );
 }
 
-DEF_TEST(SkSLInvocations, r) {
-    test(r,
-         "layout(points) in;"
-         "layout(invocations = 2) in;"
-         "layout(line_strip, max_vertices = 2) out;"
-         "void test() {"
-         "gl_Position = sk_in[0].gl_Position + vec4(0.5, 0, 0, sk_InvocationID);"
-         "EmitVertex();"
-         "}"
-         "void main() {"
-         "gl_Position = sk_in[0].gl_Position + vec4(-0.5, 0, 0, sk_InvocationID);"
-         "EmitVertex();"
-         "}",
-         *SkSL::ShaderCapsFactory::MustImplementGSInvocationsWithLoop(),
-         "#version 400\n"
-         "int sk_InvocationID;\n"
-         "layout (points) in ;\n"
-         "layout (line_strip, max_vertices = 4) out ;\n"
-         "void test() {\n"
-         "    gl_Position = gl_in[0].gl_Position + vec4(0.5, 0.0, 0.0, float(sk_InvocationID));\n"
-         "    EmitVertex();\n"
-         "}\n"
-         "void _invoke() {\n"
-         "    gl_Position = gl_in[0].gl_Position + vec4(-0.5, 0.0, 0.0, float(sk_InvocationID));\n"
-         "    EmitVertex();\n"
-         "}\n"
-         "void main() {\n"
-         "    for (sk_InvocationID = 0;sk_InvocationID < 2; sk_InvocationID++) {\n"
-         "        _invoke();\n"
-         "        EndPrimitive();\n"
-         "    }\n"
-         "}\n",
-         SkSL::Program::kGeometry_Kind);
-}
-
 #endif