2 * Copyright 2021 Google LLC
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "include/sksl/SkSLErrorReporter.h"
9 #include "src/sksl/SkSLAnalysis.h"
10 #include "src/sksl/SkSLConstantFolder.h"
11 #include "src/sksl/SkSLProgramSettings.h"
12 #include "src/sksl/ir/SkSLBinaryExpression.h"
13 #include "src/sksl/ir/SkSLIndexExpression.h"
14 #include "src/sksl/ir/SkSLLiteral.h"
15 #include "src/sksl/ir/SkSLSetting.h"
16 #include "src/sksl/ir/SkSLSwizzle.h"
17 #include "src/sksl/ir/SkSLTernaryExpression.h"
18 #include "src/sksl/ir/SkSLType.h"
19 #include "src/sksl/ir/SkSLVariableReference.h"
23 static bool is_low_precision_matrix_vector_multiply(const Expression& left,
25 const Expression& right,
26 const Type& resultType) {
27 return !resultType.highPrecision() &&
28 op.kind() == Operator::Kind::STAR &&
29 left.type().isMatrix() &&
30 right.type().isVector() &&
31 left.type().rows() == right.type().columns() &&
32 Analysis::IsTrivialExpression(left) &&
33 Analysis::IsTrivialExpression(right);
36 static std::unique_ptr<Expression> rewrite_matrix_vector_multiply(const Context& context,
38 const Expression& left,
40 const Expression& right,
41 const Type& resultType) {
42 // Rewrite m33 * v3 as (m[0] * v[0] + m[1] * v[1] + m[2] * v[2])
43 std::unique_ptr<Expression> sum;
44 for (int n = 0; n < left.type().rows(); ++n) {
45 // Get mat[N] with an index expression.
46 std::unique_ptr<Expression> matN = IndexExpression::Make(
47 context, pos, left.clone(), Literal::MakeInt(context, left.fPosition, n));
48 // Get vec[N] with a swizzle expression.
49 std::unique_ptr<Expression> vecN = Swizzle::Make(context,
50 left.fPosition.rangeThrough(right.fPosition), right.clone(),
51 ComponentArray{(SkSL::SwizzleComponent::Type)n});
52 // Multiply them together.
53 const Type* matNType = &matN->type();
54 std::unique_ptr<Expression> product =
55 BinaryExpression::Make(context, pos, std::move(matN), op, std::move(vecN),
57 // Sum all the components together.
59 sum = std::move(product);
61 sum = BinaryExpression::Make(context,
64 Operator(Operator::Kind::PLUS),
73 std::unique_ptr<Expression> BinaryExpression::Convert(const Context& context,
75 std::unique_ptr<Expression> left,
77 std::unique_ptr<Expression> right) {
78 if (!left || !right) {
81 const Type* rawLeftType = (left->isIntLiteral() && right->type().isInteger())
84 const Type* rawRightType = (right->isIntLiteral() && left->type().isInteger())
88 bool isAssignment = op.isAssignment();
90 !Analysis::UpdateVariableRefKind(left.get(),
91 op.kind() != Operator::Kind::EQ
92 ? VariableReference::RefKind::kReadWrite
93 : VariableReference::RefKind::kWrite,
99 const Type* rightType;
100 const Type* resultType;
101 if (!op.determineBinaryType(context, *rawLeftType, *rawRightType,
102 &leftType, &rightType, &resultType)) {
103 context.fErrors->error(pos, "type mismatch: '" + std::string(op.tightOperatorName()) +
104 "' cannot operate on '" + left->type().displayName() + "', '" +
105 right->type().displayName() + "'");
109 if (isAssignment && leftType->componentType().isOpaque()) {
110 context.fErrors->error(pos, "assignments to opaque type '" + left->type().displayName() +
111 "' are not permitted");
114 if (context.fConfig->strictES2Mode()) {
115 if (!op.isAllowedInStrictES2Mode()) {
116 context.fErrors->error(pos, "operator '" + std::string(op.tightOperatorName()) +
120 if (leftType->isOrContainsArray()) {
121 // Most operators are already rejected on arrays, but GLSL ES 1.0 is very explicit that
122 // the *only* operator allowed on arrays is subscripting (and the rules against
123 // assignment, comparison, and even sequence apply to structs containing arrays as well)
124 context.fErrors->error(pos, "operator '" + std::string(op.tightOperatorName()) +
125 "' can not operate on arrays (or structs containing arrays)");
130 left = leftType->coerceExpression(std::move(left), context);
131 right = rightType->coerceExpression(std::move(right), context);
132 if (!left || !right) {
136 return BinaryExpression::Make(context, pos, std::move(left), op, std::move(right), resultType);
139 std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
141 std::unique_ptr<Expression> left,
143 std::unique_ptr<Expression> right) {
144 // Determine the result type of the binary expression.
145 const Type* leftType;
146 const Type* rightType;
147 const Type* resultType;
148 SkAssertResult(op.determineBinaryType(context, left->type(), right->type(),
149 &leftType, &rightType, &resultType));
151 return BinaryExpression::Make(context, pos, std::move(left), op, std::move(right), resultType);
154 std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
156 std::unique_ptr<Expression> left,
158 std::unique_ptr<Expression> right,
159 const Type* resultType) {
160 // We should have detected non-ES2 compliant behavior in Convert.
161 SkASSERT(!context.fConfig->strictES2Mode() || op.isAllowedInStrictES2Mode());
162 SkASSERT(!context.fConfig->strictES2Mode() || !left->type().isOrContainsArray());
164 // We should have detected non-assignable assignment expressions in Convert.
165 SkASSERT(!op.isAssignment() || Analysis::IsAssignable(*left));
166 SkASSERT(!op.isAssignment() || !left->type().componentType().isOpaque());
168 // For simple assignments, detect and report out-of-range literal values.
169 if (op.kind() == Operator::Kind::EQ) {
170 left->type().checkForOutOfRangeLiteral(context, *right);
173 // Perform constant-folding on the expression.
174 if (std::unique_ptr<Expression> result = ConstantFolder::Simplify(context, pos, *left,
175 op, *right, *resultType)) {
179 if (context.fConfig->fSettings.fOptimize) {
180 // When sk_Caps.rewriteMatrixVectorMultiply is set, we rewrite medium-precision
181 // matrix * vector multiplication as:
182 // (sk_Caps.rewriteMatrixVectorMultiply ? (mat[0]*vec[0] + ... + mat[N]*vec[N])
184 if (is_low_precision_matrix_vector_multiply(*left, op, *right, *resultType)) {
185 // Look up `sk_Caps.rewriteMatrixVectorMultiply`.
186 auto caps = Setting::Convert(context, pos, "rewriteMatrixVectorMultiply");
188 bool capsBitIsTrue = caps->isBoolLiteral() && caps->as<Literal>().boolValue();
189 if (capsBitIsTrue || !caps->isBoolLiteral()) {
190 // Rewrite the multiplication as a sum of vector-scalar products.
191 std::unique_ptr<Expression> rewrite =
192 rewrite_matrix_vector_multiply(context, pos, *left, op, *right,
195 // If we know the caps bit is true, return the rewritten expression directly.
200 // Return a ternary expression:
201 // sk_Caps.rewriteMatrixVectorMultiply ? (rewrite) : (mat * vec)
202 return TernaryExpression::Make(
207 std::make_unique<BinaryExpression>(pos, std::move(left), op,
208 std::move(right), resultType));
213 return std::make_unique<BinaryExpression>(pos, std::move(left), op,
214 std::move(right), resultType);
217 bool BinaryExpression::CheckRef(const Expression& expr) {
218 switch (expr.kind()) {
219 case Expression::Kind::kFieldAccess:
220 return CheckRef(*expr.as<FieldAccess>().base());
222 case Expression::Kind::kIndex:
223 return CheckRef(*expr.as<IndexExpression>().base());
225 case Expression::Kind::kSwizzle:
226 return CheckRef(*expr.as<Swizzle>().base());
228 case Expression::Kind::kTernary: {
229 const TernaryExpression& t = expr.as<TernaryExpression>();
230 return CheckRef(*t.ifTrue()) && CheckRef(*t.ifFalse());
232 case Expression::Kind::kVariableReference: {
233 const VariableReference& ref = expr.as<VariableReference>();
234 return ref.refKind() == VariableRefKind::kWrite ||
235 ref.refKind() == VariableRefKind::kReadWrite;
242 std::unique_ptr<Expression> BinaryExpression::clone(Position pos) const {
243 return std::make_unique<BinaryExpression>(pos,
244 this->left()->clone(),
246 this->right()->clone(),
250 std::string BinaryExpression::description() const {
251 return "(" + this->left()->description() +
252 this->getOperator().operatorName() +
253 this->right()->description() + ")";