Add Variable::fBuiltin, to track Variables owned by pre-includes

Similar to the same field on Enum and FunctionDeclaration, will be used
to facilitate cloning builtin variables into Programs that use them.

Bug: skia:10589
Change-Id: Ic63701c61ee4658a5ec72adb506cc96aa0b2836f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/321196
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
diff --git a/src/sksl/SkSLInliner.cpp b/src/sksl/SkSLInliner.cpp
index c178f46..85c9439 100644
--- a/src/sksl/SkSLInliner.cpp
+++ b/src/sksl/SkSLInliner.cpp
@@ -427,11 +427,12 @@
                                                     SymbolTable* symbolTableForStatement,
                                                     const Expression* resultExpr,
                                                     bool haveEarlyReturns,
-                                                    const Statement& statement) {
+                                                    const Statement& statement,
+                                                    bool isBuiltinCode) {
     auto stmt = [&](const std::unique_ptr<Statement>& s) -> std::unique_ptr<Statement> {
         if (s) {
             return this->inlineStatement(offset, varMap, symbolTableForStatement, resultExpr,
-                                         haveEarlyReturns, *s);
+                                         haveEarlyReturns, *s, isBuiltinCode);
         }
         return nullptr;
     };
@@ -548,6 +549,7 @@
                                                old->fModifiers,
                                                namePtr->c_str(),
                                                typePtr,
+                                               isBuiltinCode,
                                                old->fStorage,
                                                initialValue.get()));
             (*varMap)[old] = std::make_unique<VariableReference>(offset, clone);
@@ -575,7 +577,8 @@
 }
 
 Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
-                                         SymbolTable* symbolTableForCall) {
+                                         SymbolTable* symbolTableForCall,
+                                         const FunctionDeclaration* caller) {
     // Inlining is more complicated here than in a typical compiler, because we have to have a
     // high-level IR and can't just drop statements into the middle of an expression or even use
     // gotos.
@@ -632,7 +635,8 @@
 
         // Add our new variable to the symbol table.
         auto newVar = std::make_unique<Variable>(/*offset=*/-1, Modifiers(), nameFrag, type,
-                                                 Variable::kLocal_Storage, initialValue->get());
+                                                 caller->fBuiltin, Variable::kLocal_Storage,
+                                                 initialValue->get());
         const Variable* variableSymbol = symbolTableForCall->add(nameFrag, std::move(newVar));
 
         // Prepare the variable declaration (taking extra care with `out` params to not clobber any
@@ -694,8 +698,9 @@
     auto inlineBlock = std::make_unique<Block>(offset, std::vector<std::unique_ptr<Statement>>{});
     inlineBlock->children().reserve(body.children().size());
     for (const std::unique_ptr<Statement>& stmt : body.children()) {
-        inlineBlock->children().push_back(this->inlineStatement(
-                offset, &varMap, symbolTableForCall, resultExpr.get(), hasEarlyReturn, *stmt));
+        inlineBlock->children().push_back(this->inlineStatement(offset, &varMap, symbolTableForCall,
+                                                                resultExpr.get(), hasEarlyReturn,
+                                                                *stmt, caller->fBuiltin));
     }
     if (hasEarlyReturn) {
         // Since we output to backends that don't have a goto statement (which would normally be
@@ -780,6 +785,7 @@
         Statement* fParentStmt;                       // the parent Statement of the enclosing stmt
         std::unique_ptr<Statement>* fEnclosingStmt;   // the Statement containing the candidate
         std::unique_ptr<Expression>* fCandidateExpr;  // the candidate FunctionCall to be inlined
+        FunctionDefinition* fEnclosingFunction;       // the Function containing the candidate
     };
 
     // This is structured much like a ProgramVisitor, but does not actually use ProgramVisitor.
@@ -797,6 +803,8 @@
         // adding new instructions. Not all statements are suitable (e.g. a for-loop's initializer).
         // The inliner might replace a statement with a block containing the statement.
         std::vector<std::unique_ptr<Statement>*> fEnclosingStmtStack;
+        // The function that we're currently processing (i.e. inlining into).
+        FunctionDefinition* fEnclosingFunction = nullptr;
 
         void visit(Program& program) {
             fSymbolTableStack.push_back(program.fSymbols.get());
@@ -812,6 +820,7 @@
             switch (pe->kind()) {
                 case ProgramElement::Kind::kFunction: {
                     FunctionDefinition& funcDef = pe->as<FunctionDefinition>();
+                    fEnclosingFunction = &funcDef;
                     this->visitStatement(&funcDef.fBody);
                     break;
                 }
@@ -1065,7 +1074,8 @@
             fInlineCandidates.push_back(InlineCandidate{fSymbolTableStack.back(),
                                                         find_parent_statement(fEnclosingStmtStack),
                                                         fEnclosingStmtStack.back(),
-                                                        candidate});
+                                                        candidate,
+                                                        fEnclosingFunction});
         }
     };
 
@@ -1108,7 +1118,8 @@
         }
 
         // Convert the function call to its inlined equivalent.
-        InlinedCall inlinedCall = this->inlineCall(&funcCall, candidate.fSymbols);
+        InlinedCall inlinedCall = this->inlineCall(&funcCall, candidate.fSymbols,
+                                                   &candidate.fEnclosingFunction->fDeclaration);
         if (inlinedCall.fInlinedBody) {
             // Ensure that the inlined body has a scope if it needs one.
             this->ensureScopedBlocks(inlinedCall.fInlinedBody.get(), candidate.fParentStmt);