Flutter Engine
The Flutter Engine
Public Member Functions | Public Attributes | List of all members
SkSL::InlineCandidateAnalyzer Class Reference

Public Member Functions

void visit (const std::vector< std::unique_ptr< ProgramElement > > &elements, SymbolTable *symbols, InlineCandidateList *candidateList)
 
void visitProgramElement (ProgramElement *pe)
 
void visitStatement (std::unique_ptr< Statement > *stmt, bool isViableAsEnclosingStatement=true)
 
void visitExpression (std::unique_ptr< Expression > *expr)
 
void addInlineCandidate (std::unique_ptr< Expression > *candidate)
 

Public Attributes

InlineCandidateListfCandidateList
 
std::vector< SymbolTable * > fSymbolTableStack
 
std::vector< std::unique_ptr< Statement > * > fEnclosingStmtStack
 
FunctionDefinitionfEnclosingFunction = nullptr
 

Detailed Description

Definition at line 686 of file SkSLInliner.cpp.

Member Function Documentation

◆ addInlineCandidate()

void SkSL::InlineCandidateAnalyzer::addInlineCandidate ( std::unique_ptr< Expression > *  candidate)
inline

Definition at line 954 of file SkSLInliner.cpp.

954 {
955 fCandidateList->fCandidates.push_back(
956 InlineCandidate{fSymbolTableStack.back(),
957 find_parent_statement(fEnclosingStmtStack),
958 fEnclosingStmtStack.back(),
959 candidate,
961 }
InlineCandidateList * fCandidateList
std::vector< SymbolTable * > fSymbolTableStack
FunctionDefinition * fEnclosingFunction
std::vector< std::unique_ptr< Statement > * > fEnclosingStmtStack
std::vector< InlineCandidate > fCandidates

◆ visit()

void SkSL::InlineCandidateAnalyzer::visit ( const std::vector< std::unique_ptr< ProgramElement > > &  elements,
SymbolTable symbols,
InlineCandidateList candidateList 
)
inline

Definition at line 701 of file SkSLInliner.cpp.

703 {
704 fCandidateList = candidateList;
705 fSymbolTableStack.push_back(symbols);
706
707 for (const std::unique_ptr<ProgramElement>& pe : elements) {
708 this->visitProgramElement(pe.get());
709 }
710
711 fSymbolTableStack.pop_back();
712 fCandidateList = nullptr;
713 }
void visitProgramElement(ProgramElement *pe)

◆ visitExpression()

void SkSL::InlineCandidateAnalyzer::visitExpression ( std::unique_ptr< Expression > *  expr)
inline

Definition at line 854 of file SkSLInliner.cpp.

854 {
855 if (!*expr) {
856 return;
857 }
858
859 switch ((*expr)->kind()) {
860 case Expression::Kind::kFieldAccess:
861 case Expression::Kind::kFunctionReference:
863 case Expression::Kind::kMethodReference:
864 case Expression::Kind::kSetting:
865 case Expression::Kind::kTypeReference:
866 case Expression::Kind::kVariableReference:
867 // Nothing to scan here.
868 break;
869
870 case Expression::Kind::kBinary: {
871 BinaryExpression& binaryExpr = (*expr)->as<BinaryExpression>();
872 this->visitExpression(&binaryExpr.left());
873
874 // Logical-and and logical-or binary expressions do not inline the right side,
875 // because that would invalidate short-circuiting. That is, when evaluating
876 // expressions like these:
877 // (false && x()) // always false
878 // (true || y()) // always true
879 // It is illegal for side-effects from x() or y() to occur. The simplest way to
880 // enforce that rule is to avoid inlining the right side entirely. However, it is
881 // safe for other types of binary expression to inline both sides.
882 Operator op = binaryExpr.getOperator();
883 bool shortCircuitable = (op.kind() == Operator::Kind::LOGICALAND ||
884 op.kind() == Operator::Kind::LOGICALOR);
885 if (!shortCircuitable) {
886 this->visitExpression(&binaryExpr.right());
887 }
888 break;
889 }
890 case Expression::Kind::kChildCall: {
891 ChildCall& childCallExpr = (*expr)->as<ChildCall>();
892 for (std::unique_ptr<Expression>& arg : childCallExpr.arguments()) {
893 this->visitExpression(&arg);
894 }
895 break;
896 }
897 case Expression::Kind::kConstructorArray:
898 case Expression::Kind::kConstructorArrayCast:
899 case Expression::Kind::kConstructorCompound:
900 case Expression::Kind::kConstructorCompoundCast:
901 case Expression::Kind::kConstructorDiagonalMatrix:
902 case Expression::Kind::kConstructorMatrixResize:
903 case Expression::Kind::kConstructorScalarCast:
904 case Expression::Kind::kConstructorSplat:
905 case Expression::Kind::kConstructorStruct: {
906 AnyConstructor& constructorExpr = (*expr)->asAnyConstructor();
907 for (std::unique_ptr<Expression>& arg : constructorExpr.argumentSpan()) {
908 this->visitExpression(&arg);
909 }
910 break;
911 }
912 case Expression::Kind::kFunctionCall: {
913 FunctionCall& funcCallExpr = (*expr)->as<FunctionCall>();
914 for (std::unique_ptr<Expression>& arg : funcCallExpr.arguments()) {
915 this->visitExpression(&arg);
916 }
917 this->addInlineCandidate(expr);
918 break;
919 }
921 IndexExpression& indexExpr = (*expr)->as<IndexExpression>();
922 this->visitExpression(&indexExpr.base());
923 this->visitExpression(&indexExpr.index());
924 break;
925 }
926 case Expression::Kind::kPostfix: {
927 PostfixExpression& postfixExpr = (*expr)->as<PostfixExpression>();
928 this->visitExpression(&postfixExpr.operand());
929 break;
930 }
931 case Expression::Kind::kPrefix: {
932 PrefixExpression& prefixExpr = (*expr)->as<PrefixExpression>();
933 this->visitExpression(&prefixExpr.operand());
934 break;
935 }
936 case Expression::Kind::kSwizzle: {
937 Swizzle& swizzleExpr = (*expr)->as<Swizzle>();
938 this->visitExpression(&swizzleExpr.base());
939 break;
940 }
941 case Expression::Kind::kTernary: {
942 TernaryExpression& ternaryExpr = (*expr)->as<TernaryExpression>();
943 // The test expression is a candidate for inlining.
944 this->visitExpression(&ternaryExpr.test());
945 // The true- and false-expressions cannot be inlined, because we are only allowed to
946 // evaluate one side.
947 break;
948 }
949 default:
951 }
952 }
#define SkUNREACHABLE
Definition: SkAssert.h:135
void addInlineCandidate(std::unique_ptr< Expression > *candidate)
void visitExpression(std::unique_ptr< Expression > *expr)

◆ visitProgramElement()

void SkSL::InlineCandidateAnalyzer::visitProgramElement ( ProgramElement pe)
inline

Definition at line 715 of file SkSLInliner.cpp.

715 {
716 switch (pe->kind()) {
718 FunctionDefinition& funcDef = pe->as<FunctionDefinition>();
719
720 // If this function has parameter names that would shadow globally-scoped names, we
721 // don't scan it for inline candidates, because it's too late to mangle the names.
722 bool foundShadowingParameterName = false;
723 for (const Variable* param : funcDef.declaration().parameters()) {
724 if (fSymbolTableStack.front()->find(param->name())) {
725 foundShadowingParameterName = true;
726 break;
727 }
728 }
729
730 if (!foundShadowingParameterName) {
731 fEnclosingFunction = &funcDef;
732 this->visitStatement(&funcDef.body());
733 }
734 break;
735 }
736 default:
737 // The inliner can't operate outside of a function's scope.
738 break;
739 }
740 }
void visitStatement(std::unique_ptr< Statement > *stmt, bool isViableAsEnclosingStatement=true)

◆ visitStatement()

void SkSL::InlineCandidateAnalyzer::visitStatement ( std::unique_ptr< Statement > *  stmt,
bool  isViableAsEnclosingStatement = true 
)
inline

Definition at line 742 of file SkSLInliner.cpp.

743 {
744 if (!*stmt) {
745 return;
746 }
747
748 Analysis::SymbolTableStackBuilder scopedStackBuilder(stmt->get(), &fSymbolTableStack);
749 // If this statement contains symbols that would shadow globally-scoped names, we don't look
750 // for any inline candidates, because it's too late to mangle the names.
751 if (scopedStackBuilder.foundSymbolTable() &&
752 fSymbolTableStack.back()->wouldShadowSymbolsFrom(fSymbolTableStack.front())) {
753 return;
754 }
755
756 size_t oldEnclosingStmtStackSize = fEnclosingStmtStack.size();
757
758 if (isViableAsEnclosingStatement) {
759 fEnclosingStmtStack.push_back(stmt);
760 }
761
762 switch ((*stmt)->kind()) {
763 case Statement::Kind::kBreak:
767 break;
768
769 case Statement::Kind::kBlock: {
770 Block& block = (*stmt)->as<Block>();
771 for (std::unique_ptr<Statement>& blockStmt : block.children()) {
772 this->visitStatement(&blockStmt);
773 }
774 break;
775 }
776 case Statement::Kind::kDo: {
777 DoStatement& doStmt = (*stmt)->as<DoStatement>();
778 // The loop body is a candidate for inlining.
779 this->visitStatement(&doStmt.statement());
780 // The inliner isn't smart enough to inline the test-expression for a do-while
781 // loop at this time. There are two limitations:
782 // - We would need to insert the inlined-body block at the very end of the do-
783 // statement's inner fStatement. We don't support that today, but it's doable.
784 // - We cannot inline the test expression if the loop uses `continue` anywhere; that
785 // would skip over the inlined block that evaluates the test expression. There
786 // isn't a good fix for this--any workaround would be more complex than the cost
787 // of a function call. However, loops that don't use `continue` would still be
788 // viable candidates for inlining.
789 break;
790 }
791 case Statement::Kind::kExpression: {
792 ExpressionStatement& expr = (*stmt)->as<ExpressionStatement>();
793 this->visitExpression(&expr.expression());
794 break;
795 }
796 case Statement::Kind::kFor: {
797 ForStatement& forStmt = (*stmt)->as<ForStatement>();
798 // The initializer and loop body are candidates for inlining.
799 this->visitStatement(&forStmt.initializer(),
800 /*isViableAsEnclosingStatement=*/false);
801 this->visitStatement(&forStmt.statement());
802
803 // The inliner isn't smart enough to inline the test- or increment-expressions
804 // of a for loop loop at this time. There are a handful of limitations:
805 // - We would need to insert the test-expression block at the very beginning of the
806 // for-loop's inner fStatement, and the increment-expression block at the very
807 // end. We don't support that today, but it's doable.
808 // - The for-loop's built-in test-expression would need to be dropped entirely,
809 // and the loop would be halted via a break statement at the end of the inlined
810 // test-expression. This is again something we don't support today, but it could
811 // be implemented.
812 // - We cannot inline the increment-expression if the loop uses `continue` anywhere;
813 // that would skip over the inlined block that evaluates the increment expression.
814 // There isn't a good fix for this--any workaround would be more complex than the
815 // cost of a function call. However, loops that don't use `continue` would still
816 // be viable candidates for increment-expression inlining.
817 break;
818 }
819 case Statement::Kind::kIf: {
820 IfStatement& ifStmt = (*stmt)->as<IfStatement>();
821 this->visitExpression(&ifStmt.test());
822 this->visitStatement(&ifStmt.ifTrue());
823 this->visitStatement(&ifStmt.ifFalse());
824 break;
825 }
826 case Statement::Kind::kReturn: {
827 ReturnStatement& returnStmt = (*stmt)->as<ReturnStatement>();
828 this->visitExpression(&returnStmt.expression());
829 break;
830 }
831 case Statement::Kind::kSwitch: {
832 SwitchStatement& switchStmt = (*stmt)->as<SwitchStatement>();
833 this->visitExpression(&switchStmt.value());
834 for (const std::unique_ptr<Statement>& switchCase : switchStmt.cases()) {
835 // The switch-case's fValue cannot be a FunctionCall; skip it.
836 this->visitStatement(&switchCase->as<SwitchCase>().statement());
837 }
838 break;
839 }
840 case Statement::Kind::kVarDeclaration: {
841 VarDeclaration& varDeclStmt = (*stmt)->as<VarDeclaration>();
842 // Don't need to scan the declaration's sizes; those are always literals.
843 this->visitExpression(&varDeclStmt.value());
844 break;
845 }
846 default:
848 }
849
850 // Pop our symbol and enclosing-statement stacks.
851 fEnclosingStmtStack.resize(oldEnclosingStmtStackSize);
852 }

Member Data Documentation

◆ fCandidateList

InlineCandidateList* SkSL::InlineCandidateAnalyzer::fCandidateList

Definition at line 689 of file SkSLInliner.cpp.

◆ fEnclosingFunction

FunctionDefinition* SkSL::InlineCandidateAnalyzer::fEnclosingFunction = nullptr

Definition at line 699 of file SkSLInliner.cpp.

◆ fEnclosingStmtStack

std::vector<std::unique_ptr<Statement>*> SkSL::InlineCandidateAnalyzer::fEnclosingStmtStack

Definition at line 697 of file SkSLInliner.cpp.

◆ fSymbolTableStack

std::vector<SymbolTable*> SkSL::InlineCandidateAnalyzer::fSymbolTableStack

Definition at line 693 of file SkSLInliner.cpp.


The documentation for this class was generated from the following file: