• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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 "src/sksl/SkSLConstantFolder.h"
9 #include "src/sksl/ir/SkSLIndexExpression.h"
10 #include "src/sksl/ir/SkSLSwizzle.h"
11 
12 namespace SkSL {
13 
IndexType(const Context & context,const Type & type)14 const Type& IndexExpression::IndexType(const Context& context, const Type& type) {
15     if (type.isMatrix()) {
16         if (type.componentType() == *context.fTypes.fFloat) {
17             switch (type.rows()) {
18                 case 2: return *context.fTypes.fFloat2;
19                 case 3: return *context.fTypes.fFloat3;
20                 case 4: return *context.fTypes.fFloat4;
21                 default: SkASSERT(false);
22             }
23         } else if (type.componentType() == *context.fTypes.fHalf) {
24             switch (type.rows()) {
25                 case 2: return *context.fTypes.fHalf2;
26                 case 3: return *context.fTypes.fHalf3;
27                 case 4: return *context.fTypes.fHalf4;
28                 default: SkASSERT(false);
29             }
30         }
31     }
32     return type.componentType();
33 }
34 
Convert(const Context & context,std::unique_ptr<Expression> base,std::unique_ptr<Expression> index)35 std::unique_ptr<Expression> IndexExpression::Convert(const Context& context,
36                                                      std::unique_ptr<Expression> base,
37                                                      std::unique_ptr<Expression> index) {
38     // Convert an index expression with an expression inside of it: `arr[a * 3]`.
39     const Type& baseType = base->type();
40     if (!baseType.isArray() && !baseType.isMatrix() && !baseType.isVector()) {
41         context.fErrors.error(base->fOffset,
42                               "expected array, but found '" + baseType.displayName() + "'");
43         return nullptr;
44     }
45     if (!index->type().isInteger()) {
46         index = context.fTypes.fInt->coerceExpression(std::move(index), context);
47         if (!index) {
48             return nullptr;
49         }
50     }
51     // Perform compile-time bounds checking on constant-expression indices.
52     const Expression* indexExpr = ConstantFolder::GetConstantValueForVariable(*index);
53     if (indexExpr->is<IntLiteral>()) {
54         SKSL_INT indexValue = indexExpr->as<IntLiteral>().value();
55         const int upperBound = (baseType.isArray() && baseType.columns() == Type::kUnsizedArray)
56                                        ? INT_MAX
57                                        : baseType.columns();
58         if (indexValue < 0 || indexValue >= upperBound) {
59             context.fErrors.error(base->fOffset, "index " + to_string(indexValue) + " out of range "
60                                                  "for '" + baseType.displayName() + "'");
61             return nullptr;
62         }
63     }
64     return IndexExpression::Make(context, std::move(base), std::move(index));
65 }
66 
Make(const Context & context,std::unique_ptr<Expression> base,std::unique_ptr<Expression> index)67 std::unique_ptr<Expression> IndexExpression::Make(const Context& context,
68                                                   std::unique_ptr<Expression> base,
69                                                   std::unique_ptr<Expression> index) {
70     const Type& baseType = base->type();
71     SkASSERT(baseType.isArray() || baseType.isMatrix() || baseType.isVector());
72     SkASSERT(index->type().isInteger());
73 
74     if (context.fConfig->fSettings.fOptimize) {
75         // Constant array indexes on vectors can be converted to swizzles: `v[2]` --> `v.z`.
76         // Swizzling is harmless and can unlock further simplifications for some base types.
77         const Expression* indexExpr = ConstantFolder::GetConstantValueForVariable(*index);
78         if (indexExpr->is<IntLiteral>() && baseType.isVector()) {
79             SKSL_INT indexValue = indexExpr->as<IntLiteral>().value();
80             return Swizzle::Make(context, std::move(base), ComponentArray{(int8_t)indexValue});
81         }
82     }
83 
84     return std::make_unique<IndexExpression>(context, std::move(base), std::move(index));
85 }
86 
87 }  // namespace SkSL
88