xref: /aosp_15_r20/external/skia/src/sksl/analysis/SkSLIsTrivialExpression.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2022 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkSpan.h"
9 #include "include/core/SkTypes.h"
10 #include "src/sksl/SkSLAnalysis.h"
11 #include "src/sksl/SkSLOperator.h"
12 #include "src/sksl/ir/SkSLConstructor.h"
13 #include "src/sksl/ir/SkSLExpression.h"
14 #include "src/sksl/ir/SkSLFieldAccess.h"
15 #include "src/sksl/ir/SkSLIRNode.h"
16 #include "src/sksl/ir/SkSLIndexExpression.h"
17 #include "src/sksl/ir/SkSLPrefixExpression.h"
18 #include "src/sksl/ir/SkSLSwizzle.h"
19 #include "src/sksl/ir/SkSLType.h"
20 
21 #include <memory>
22 
23 namespace SkSL {
24 
IsTrivialExpression(const Expression & expr)25 bool Analysis::IsTrivialExpression(const Expression& expr) {
26     switch (expr.kind()) {
27         case Expression::Kind::kLiteral:
28         case Expression::Kind::kVariableReference:
29             return true;
30 
31         case Expression::Kind::kSwizzle:
32             // All swizzles are considered to be trivial.
33             return IsTrivialExpression(*expr.as<Swizzle>().base());
34 
35         case Expression::Kind::kPrefix: {
36             const PrefixExpression& prefix = expr.as<PrefixExpression>();
37             switch (prefix.getOperator().kind()) {
38                 case OperatorKind::PLUS:
39                 case OperatorKind::MINUS:
40                 case OperatorKind::LOGICALNOT:
41                 case OperatorKind::BITWISENOT:
42                     return IsTrivialExpression(*prefix.operand());
43 
44                 default:
45                     return false;
46             }
47         }
48         case Expression::Kind::kFieldAccess:
49             // Accessing a field is trivial.
50             return IsTrivialExpression(*expr.as<FieldAccess>().base());
51 
52         case Expression::Kind::kIndex: {
53             // Accessing a constant array index is trivial.
54             const IndexExpression& inner = expr.as<IndexExpression>();
55             return inner.index()->isIntLiteral() && IsTrivialExpression(*inner.base());
56         }
57         case Expression::Kind::kConstructorArray:
58         case Expression::Kind::kConstructorStruct:
59             // Only consider small arrays/structs of compile-time-constants to be trivial.
60             return expr.type().slotCount() <= 4 && IsCompileTimeConstant(expr);
61 
62         case Expression::Kind::kConstructorArrayCast:
63         case Expression::Kind::kConstructorMatrixResize:
64             // These operations require function calls in Metal, so they're never trivial.
65             return false;
66 
67         case Expression::Kind::kConstructorCompound:
68             // Only compile-time-constant compound constructors are considered to be trivial.
69             return IsCompileTimeConstant(expr);
70 
71         case Expression::Kind::kConstructorCompoundCast:
72         case Expression::Kind::kConstructorScalarCast:
73         case Expression::Kind::kConstructorSplat:
74         case Expression::Kind::kConstructorDiagonalMatrix: {
75             // Single-argument constructors are trivial when their inner expression is trivial.
76             SkASSERT(expr.asAnyConstructor().argumentSpan().size() == 1);
77             const Expression& inner = *expr.asAnyConstructor().argumentSpan().front();
78             return IsTrivialExpression(inner);
79         }
80         default:
81             return false;
82     }
83 }
84 
85 }  // namespace SkSL
86