blob: e79287fb33f1ed0e5097bc4539aaccd25b175d9e [file] [log] [blame]
John Stilese2aec432021-03-01 09:27:48 -05001/*
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/SkSLAnalysis.h"
9#include "src/sksl/SkSLConstantFolder.h"
10#include "src/sksl/ir/SkSLBinaryExpression.h"
John Stiles9e13fe82021-03-23 18:45:25 -040011#include "src/sksl/ir/SkSLIndexExpression.h"
John Stiles7591d4b2021-09-13 13:32:06 -040012#include "src/sksl/ir/SkSLLiteral.h"
John Stiles9e13fe82021-03-23 18:45:25 -040013#include "src/sksl/ir/SkSLSetting.h"
14#include "src/sksl/ir/SkSLSwizzle.h"
15#include "src/sksl/ir/SkSLTernaryExpression.h"
John Stilese2aec432021-03-01 09:27:48 -050016#include "src/sksl/ir/SkSLType.h"
17
18namespace SkSL {
19
John Stiles70cd5982021-03-25 11:09:53 -040020static bool is_low_precision_matrix_vector_multiply(const Expression& left,
21 const Operator& op,
22 const Expression& right,
23 const Type& resultType) {
24 return !resultType.highPrecision() &&
25 op.kind() == Token::Kind::TK_STAR &&
26 left.type().isMatrix() &&
27 right.type().isVector() &&
28 left.type().rows() == right.type().columns() &&
29 Analysis::IsTrivialExpression(left) &&
30 Analysis::IsTrivialExpression(right);
31}
32
33static std::unique_ptr<Expression> rewrite_matrix_vector_multiply(const Context& context,
34 const Expression& left,
35 const Operator& op,
36 const Expression& right,
37 const Type& resultType) {
38 // Rewrite m33 * v3 as (m[0] * v[0] + m[1] * v[1] + m[2] * v[2])
39 std::unique_ptr<Expression> sum;
40 for (int n = 0; n < left.type().rows(); ++n) {
41 // Get mat[N] with an index expression.
42 std::unique_ptr<Expression> matN = IndexExpression::Make(
Ethan Nicholas89cfde12021-09-27 11:20:34 -040043 context, left.clone(), Literal::MakeInt(context, left.fLine, n));
John Stiles70cd5982021-03-25 11:09:53 -040044 // Get vec[N] with a swizzle expression.
45 std::unique_ptr<Expression> vecN = Swizzle::Make(
46 context, right.clone(), ComponentArray{(SkSL::SwizzleComponent::Type)n});
47 // Multiply them together.
48 const Type* matNType = &matN->type();
49 std::unique_ptr<Expression> product =
50 BinaryExpression::Make(context, std::move(matN), op, std::move(vecN), matNType);
51 // Sum all the components together.
52 if (!sum) {
53 sum = std::move(product);
54 } else {
55 sum = BinaryExpression::Make(context,
56 std::move(sum),
57 Operator(Token::Kind::TK_PLUS),
58 std::move(product),
59 matNType);
60 }
61 }
62
63 return sum;
64}
65
John Stiles23521a82021-03-02 17:02:51 -050066std::unique_ptr<Expression> BinaryExpression::Convert(const Context& context,
67 std::unique_ptr<Expression> left,
68 Operator op,
69 std::unique_ptr<Expression> right) {
John Stilese2aec432021-03-01 09:27:48 -050070 if (!left || !right) {
71 return nullptr;
72 }
Ethan Nicholas89cfde12021-09-27 11:20:34 -040073 const int line = left->fLine;
John Stilese2aec432021-03-01 09:27:48 -050074
John Stiles7591d4b2021-09-13 13:32:06 -040075 const Type* rawLeftType = (left->isIntLiteral() && right->type().isInteger())
76 ? &right->type()
77 : &left->type();
78 const Type* rawRightType = (right->isIntLiteral() && left->type().isInteger())
79 ? &left->type()
80 : &right->type();
John Stilese2aec432021-03-01 09:27:48 -050081
John Stilese2aec432021-03-01 09:27:48 -050082 bool isAssignment = op.isAssignment();
83 if (isAssignment &&
John Stilesbb8cf582021-08-26 23:34:59 -040084 !Analysis::UpdateVariableRefKind(left.get(),
85 op.kind() != Token::Kind::TK_EQ
86 ? VariableReference::RefKind::kReadWrite
87 : VariableReference::RefKind::kWrite,
88 context.fErrors)) {
John Stilese2aec432021-03-01 09:27:48 -050089 return nullptr;
90 }
91
92 const Type* leftType;
93 const Type* rightType;
94 const Type* resultType;
95 if (!op.determineBinaryType(context, *rawLeftType, *rawRightType,
96 &leftType, &rightType, &resultType)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -040097 context.fErrors->error(line, String("type mismatch: '") + op.operatorName() +
98 "' cannot operate on '" + left->type().displayName() +
99 "', '" + right->type().displayName() + "'");
John Stilese2aec432021-03-01 09:27:48 -0500100 return nullptr;
101 }
John Stiles23521a82021-03-02 17:02:51 -0500102
John Stilese2aec432021-03-01 09:27:48 -0500103 if (isAssignment && leftType->componentType().isOpaque()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400104 context.fErrors->error(line, "assignments to opaque type '" + left->type().displayName() +
105 "' are not permitted");
John Stilese2aec432021-03-01 09:27:48 -0500106 return nullptr;
107 }
John Stiles23521a82021-03-02 17:02:51 -0500108 if (context.fConfig->strictES2Mode()) {
109 if (!op.isAllowedInStrictES2Mode()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400110 context.fErrors->error(line, String("operator '") + op.operatorName() +
111 "' is not allowed");
John Stiles23521a82021-03-02 17:02:51 -0500112 return nullptr;
113 }
114 if (leftType->isOrContainsArray()) {
115 // Most operators are already rejected on arrays, but GLSL ES 1.0 is very explicit that
116 // the *only* operator allowed on arrays is subscripting (and the rules against
117 // assignment, comparison, and even sequence apply to structs containing arrays as well)
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400118 context.fErrors->error(line, String("operator '") + op.operatorName() + "' can not "
119 "operate on arrays (or structs containing arrays)");
John Stiles23521a82021-03-02 17:02:51 -0500120 return nullptr;
121 }
122 }
John Stilese2aec432021-03-01 09:27:48 -0500123
124 left = leftType->coerceExpression(std::move(left), context);
125 right = rightType->coerceExpression(std::move(right), context);
126 if (!left || !right) {
127 return nullptr;
128 }
129
John Stiles23521a82021-03-02 17:02:51 -0500130 return BinaryExpression::Make(context, std::move(left), op, std::move(right), resultType);
131}
132
133std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
134 std::unique_ptr<Expression> left,
135 Operator op,
136 std::unique_ptr<Expression> right) {
137 // Determine the result type of the binary expression.
138 const Type* leftType;
139 const Type* rightType;
140 const Type* resultType;
141 SkAssertResult(op.determineBinaryType(context, left->type(), right->type(),
142 &leftType, &rightType, &resultType));
143
144 return BinaryExpression::Make(context, std::move(left), op, std::move(right), resultType);
145}
146
147std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
148 std::unique_ptr<Expression> left,
149 Operator op,
150 std::unique_ptr<Expression> right,
151 const Type* resultType) {
152 // We should have detected non-ES2 compliant behavior in Convert.
153 SkASSERT(!context.fConfig->strictES2Mode() || op.isAllowedInStrictES2Mode());
154 SkASSERT(!context.fConfig->strictES2Mode() || !left->type().isOrContainsArray());
155
156 // We should have detected non-assignable assignment expressions in Convert.
157 SkASSERT(!op.isAssignment() || Analysis::IsAssignable(*left));
158 SkASSERT(!op.isAssignment() || !left->type().componentType().isOpaque());
159
John Stilesb0d93cc2021-06-01 11:07:53 -0400160 // For simple assignments, detect and report out-of-range literal values.
161 if (op.kind() == Token::Kind::TK_EQ) {
162 left->type().checkForOutOfRangeLiteral(context, *right);
163 }
164
John Stiles652e8632021-04-11 09:25:59 -0400165 // Perform constant-folding on the expression.
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400166 const int line = left->fLine;
167 if (std::unique_ptr<Expression> result = ConstantFolder::Simplify(context, line, *left,
John Stiles652e8632021-04-11 09:25:59 -0400168 op, *right, *resultType)) {
169 return result;
John Stilese2aec432021-03-01 09:27:48 -0500170 }
John Stiles23521a82021-03-02 17:02:51 -0500171
John Stiles70cd5982021-03-25 11:09:53 -0400172 if (context.fConfig->fSettings.fOptimize) {
173 // When sk_Caps.rewriteMatrixVectorMultiply is set, we rewrite medium-precision
174 // matrix * vector multiplication as:
175 // (sk_Caps.rewriteMatrixVectorMultiply ? (mat[0]*vec[0] + ... + mat[N]*vec[N])
176 // : mat * vec)
177 if (is_low_precision_matrix_vector_multiply(*left, op, *right, *resultType)) {
178 // Look up `sk_Caps.rewriteMatrixVectorMultiply`.
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400179 auto caps = Setting::Convert(context, line, "rewriteMatrixVectorMultiply");
John Stiles9e13fe82021-03-23 18:45:25 -0400180
John Stiles7591d4b2021-09-13 13:32:06 -0400181 bool capsBitIsTrue = caps->isBoolLiteral() && caps->as<Literal>().boolValue();
182 if (capsBitIsTrue || !caps->isBoolLiteral()) {
John Stiles70cd5982021-03-25 11:09:53 -0400183 // Rewrite the multiplication as a sum of vector-scalar products.
184 std::unique_ptr<Expression> rewrite =
185 rewrite_matrix_vector_multiply(context, *left, op, *right, *resultType);
186
187 // If we know the caps bit is true, return the rewritten expression directly.
188 if (capsBitIsTrue) {
189 return rewrite;
John Stiles9e13fe82021-03-23 18:45:25 -0400190 }
John Stiles9e13fe82021-03-23 18:45:25 -0400191
John Stiles70cd5982021-03-25 11:09:53 -0400192 // Return a ternary expression:
193 // sk_Caps.rewriteMatrixVectorMultiply ? (rewrite) : (mat * vec)
194 return TernaryExpression::Make(
195 context,
196 std::move(caps),
197 std::move(rewrite),
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400198 std::make_unique<BinaryExpression>(line, std::move(left), op,
John Stiles70cd5982021-03-25 11:09:53 -0400199 std::move(right), resultType));
John Stiles9e13fe82021-03-23 18:45:25 -0400200 }
John Stiles9e13fe82021-03-23 18:45:25 -0400201 }
202 }
203
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400204 return std::make_unique<BinaryExpression>(line, std::move(left), op,
John Stiles9e13fe82021-03-23 18:45:25 -0400205 std::move(right), resultType);
John Stilese2aec432021-03-01 09:27:48 -0500206}
207
208bool BinaryExpression::CheckRef(const Expression& expr) {
209 switch (expr.kind()) {
210 case Expression::Kind::kFieldAccess:
211 return CheckRef(*expr.as<FieldAccess>().base());
212
213 case Expression::Kind::kIndex:
214 return CheckRef(*expr.as<IndexExpression>().base());
215
216 case Expression::Kind::kSwizzle:
217 return CheckRef(*expr.as<Swizzle>().base());
218
219 case Expression::Kind::kTernary: {
220 const TernaryExpression& t = expr.as<TernaryExpression>();
221 return CheckRef(*t.ifTrue()) && CheckRef(*t.ifFalse());
222 }
223 case Expression::Kind::kVariableReference: {
224 const VariableReference& ref = expr.as<VariableReference>();
225 return ref.refKind() == VariableRefKind::kWrite ||
226 ref.refKind() == VariableRefKind::kReadWrite;
227 }
228 default:
229 return false;
230 }
231}
232
233std::unique_ptr<Expression> BinaryExpression::clone() const {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400234 return std::make_unique<BinaryExpression>(fLine,
John Stilese2aec432021-03-01 09:27:48 -0500235 this->left()->clone(),
236 this->getOperator(),
237 this->right()->clone(),
238 &this->type());
239}
240
241String BinaryExpression::description() const {
242 return "(" + this->left()->description() +
243 " " + this->getOperator().operatorName() +
244 " " + this->right()->description() + ")";
245}
246
247} // namespace SkSL