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/ir/SkSLBinaryExpression.h"
9
10 #include "include/private/SkSLDefines.h"
11 #include "include/sksl/SkSLErrorReporter.h"
12 #include "src/sksl/SkSLAnalysis.h"
13 #include "src/sksl/SkSLConstantFolder.h"
14 #include "src/sksl/SkSLContext.h"
15 #include "src/sksl/SkSLProgramSettings.h"
16 #include "src/sksl/SkSLUtil.h"
17 #include "src/sksl/ir/SkSLFieldAccess.h"
18 #include "src/sksl/ir/SkSLIndexExpression.h"
19 #include "src/sksl/ir/SkSLLiteral.h"
20 #include "src/sksl/ir/SkSLSetting.h"
21 #include "src/sksl/ir/SkSLSwizzle.h"
22 #include "src/sksl/ir/SkSLTernaryExpression.h"
23 #include "src/sksl/ir/SkSLType.h"
24 #include "src/sksl/ir/SkSLVariableReference.h"
25
26 namespace SkSL {
27
is_low_precision_matrix_vector_multiply(const Expression & left,const Operator & op,const Expression & right,const Type & resultType)28 static bool is_low_precision_matrix_vector_multiply(const Expression& left,
29 const Operator& op,
30 const Expression& right,
31 const Type& resultType) {
32 return !resultType.highPrecision() &&
33 op.kind() == Operator::Kind::STAR &&
34 left.type().isMatrix() &&
35 right.type().isVector() &&
36 left.type().rows() == right.type().columns() &&
37 Analysis::IsTrivialExpression(left) &&
38 Analysis::IsTrivialExpression(right);
39 }
40
rewrite_matrix_vector_multiply(const Context & context,Position pos,const Expression & left,const Operator & op,const Expression & right,const Type & resultType)41 static std::unique_ptr<Expression> rewrite_matrix_vector_multiply(const Context& context,
42 Position pos,
43 const Expression& left,
44 const Operator& op,
45 const Expression& right,
46 const Type& resultType) {
47 // Rewrite m33 * v3 as (m[0] * v[0] + m[1] * v[1] + m[2] * v[2])
48 std::unique_ptr<Expression> sum;
49 for (int n = 0; n < left.type().rows(); ++n) {
50 // Get mat[N] with an index expression.
51 std::unique_ptr<Expression> matN = IndexExpression::Make(
52 context, pos, left.clone(), Literal::MakeInt(context, left.fPosition, n));
53 // Get vec[N] with a swizzle expression.
54 std::unique_ptr<Expression> vecN = Swizzle::Make(context,
55 left.fPosition.rangeThrough(right.fPosition), right.clone(),
56 ComponentArray{(SkSL::SwizzleComponent::Type)n});
57 // Multiply them together.
58 const Type* matNType = &matN->type();
59 std::unique_ptr<Expression> product =
60 BinaryExpression::Make(context, pos, std::move(matN), op, std::move(vecN),
61 matNType);
62 // Sum all the components together.
63 if (!sum) {
64 sum = std::move(product);
65 } else {
66 sum = BinaryExpression::Make(context,
67 pos,
68 std::move(sum),
69 Operator(Operator::Kind::PLUS),
70 std::move(product),
71 matNType);
72 }
73 }
74
75 return sum;
76 }
77
Convert(const Context & context,Position pos,std::unique_ptr<Expression> left,Operator op,std::unique_ptr<Expression> right)78 std::unique_ptr<Expression> BinaryExpression::Convert(const Context& context,
79 Position pos,
80 std::unique_ptr<Expression> left,
81 Operator op,
82 std::unique_ptr<Expression> right) {
83 if (!left || !right) {
84 return nullptr;
85 }
86 const Type* rawLeftType = (left->isIntLiteral() && right->type().isInteger())
87 ? &right->type()
88 : &left->type();
89 const Type* rawRightType = (right->isIntLiteral() && left->type().isInteger())
90 ? &left->type()
91 : &right->type();
92
93 bool isAssignment = op.isAssignment();
94 if (isAssignment &&
95 !Analysis::UpdateVariableRefKind(left.get(),
96 op.kind() != Operator::Kind::EQ
97 ? VariableReference::RefKind::kReadWrite
98 : VariableReference::RefKind::kWrite,
99 context.fErrors)) {
100 return nullptr;
101 }
102
103 const Type* leftType;
104 const Type* rightType;
105 const Type* resultType;
106 if (!op.determineBinaryType(context, *rawLeftType, *rawRightType,
107 &leftType, &rightType, &resultType)) {
108 context.fErrors->error(pos, "type mismatch: '" + std::string(op.tightOperatorName()) +
109 "' cannot operate on '" + left->type().displayName() + "', '" +
110 right->type().displayName() + "'");
111 return nullptr;
112 }
113
114 if (isAssignment && (leftType->componentType().isOpaque() || leftType->isOrContainsAtomic())) {
115 context.fErrors->error(pos, "assignments to opaque type '" + left->type().displayName() +
116 "' are not permitted");
117 return nullptr;
118 }
119 if (context.fConfig->strictES2Mode()) {
120 if (!op.isAllowedInStrictES2Mode()) {
121 context.fErrors->error(pos, "operator '" + std::string(op.tightOperatorName()) +
122 "' is not allowed");
123 return nullptr;
124 }
125 if (leftType->isOrContainsArray()) {
126 // Most operators are already rejected on arrays, but GLSL ES 1.0 is very explicit that
127 // the *only* operator allowed on arrays is subscripting (and the rules against
128 // assignment, comparison, and even sequence apply to structs containing arrays as well)
129 context.fErrors->error(pos, "operator '" + std::string(op.tightOperatorName()) +
130 "' can not operate on arrays (or structs containing arrays)");
131 return nullptr;
132 }
133 }
134
135 left = leftType->coerceExpression(std::move(left), context);
136 right = rightType->coerceExpression(std::move(right), context);
137 if (!left || !right) {
138 return nullptr;
139 }
140
141 return BinaryExpression::Make(context, pos, std::move(left), op, std::move(right), resultType);
142 }
143
Make(const Context & context,Position pos,std::unique_ptr<Expression> left,Operator op,std::unique_ptr<Expression> right)144 std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
145 Position pos,
146 std::unique_ptr<Expression> left,
147 Operator op,
148 std::unique_ptr<Expression> right) {
149 // Determine the result type of the binary expression.
150 const Type* leftType;
151 const Type* rightType;
152 const Type* resultType;
153 SkAssertResult(op.determineBinaryType(context, left->type(), right->type(),
154 &leftType, &rightType, &resultType));
155
156 return BinaryExpression::Make(context, pos, std::move(left), op, std::move(right), resultType);
157 }
158
Make(const Context & context,Position pos,std::unique_ptr<Expression> left,Operator op,std::unique_ptr<Expression> right,const Type * resultType)159 std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
160 Position pos,
161 std::unique_ptr<Expression> left,
162 Operator op,
163 std::unique_ptr<Expression> right,
164 const Type* resultType) {
165 // We should have detected non-ES2 compliant behavior in Convert.
166 SkASSERT(!context.fConfig->strictES2Mode() || op.isAllowedInStrictES2Mode());
167 SkASSERT(!context.fConfig->strictES2Mode() || !left->type().isOrContainsArray());
168
169 // We should have detected non-assignable assignment expressions in Convert.
170 SkASSERT(!op.isAssignment() || Analysis::IsAssignable(*left));
171 SkASSERT(!op.isAssignment() || !left->type().componentType().isOpaque());
172
173 // For simple assignments, detect and report out-of-range literal values.
174 if (op.kind() == Operator::Kind::EQ) {
175 left->type().checkForOutOfRangeLiteral(context, *right);
176 }
177
178 // Perform constant-folding on the expression.
179 if (std::unique_ptr<Expression> result = ConstantFolder::Simplify(context, pos, *left,
180 op, *right, *resultType)) {
181 return result;
182 }
183
184 if (context.fConfig->fSettings.fOptimize && !context.fConfig->fIsBuiltinCode) {
185 // When sk_Caps.rewriteMatrixVectorMultiply is set, we rewrite medium-precision
186 // matrix * vector multiplication as:
187 // (sk_Caps.rewriteMatrixVectorMultiply ? (mat[0]*vec[0] + ... + mat[N]*vec[N])
188 // : mat * vec)
189 if (is_low_precision_matrix_vector_multiply(*left, op, *right, *resultType)) {
190 // Look up `sk_Caps.rewriteMatrixVectorMultiply`.
191 auto caps = Setting::Make(context, pos, &ShaderCaps::fRewriteMatrixVectorMultiply);
192
193 // There are three possible outcomes from Setting::Convert:
194 // - If the ShaderCaps aren't known (fCaps in the Context is null), we will get back a
195 // Setting IRNode. In practice, this should happen when compiling a module.
196 // In this case, we generate a ternary expression which will be optimized away when
197 // the module code is actually incorporated into a program.
198 // - If `rewriteMatrixVectorMultiply` is true in our shader caps, we will get back a
199 // Literal set to true. When this happens, we always return the rewritten expression.
200 // - If `rewriteMatrixVectorMultiply` is false in our shader caps, we will get back a
201 // Literal set to false. When this happens, we return the expression as-is.
202 bool capsBitIsTrue = caps->isBoolLiteral() && caps->as<Literal>().boolValue();
203 if (capsBitIsTrue || !caps->isBoolLiteral()) {
204 // Rewrite the multiplication as a sum of vector-scalar products.
205 std::unique_ptr<Expression> rewrite =
206 rewrite_matrix_vector_multiply(context, pos, *left, op, *right,
207 *resultType);
208
209 // If we know the caps bit is true, return the rewritten expression directly.
210 if (capsBitIsTrue) {
211 return rewrite;
212 }
213
214 // Return a ternary expression:
215 // sk_Caps.rewriteMatrixVectorMultiply ? (rewrite) : (mat * vec)
216 return TernaryExpression::Make(
217 context,
218 pos,
219 std::move(caps),
220 std::move(rewrite),
221 std::make_unique<BinaryExpression>(pos, std::move(left), op,
222 std::move(right), resultType));
223 }
224 }
225 }
226
227 return std::make_unique<BinaryExpression>(pos, std::move(left), op,
228 std::move(right), resultType);
229 }
230
CheckRef(const Expression & expr)231 bool BinaryExpression::CheckRef(const Expression& expr) {
232 switch (expr.kind()) {
233 case Expression::Kind::kFieldAccess:
234 return CheckRef(*expr.as<FieldAccess>().base());
235
236 case Expression::Kind::kIndex:
237 return CheckRef(*expr.as<IndexExpression>().base());
238
239 case Expression::Kind::kSwizzle:
240 return CheckRef(*expr.as<Swizzle>().base());
241
242 case Expression::Kind::kTernary: {
243 const TernaryExpression& t = expr.as<TernaryExpression>();
244 return CheckRef(*t.ifTrue()) && CheckRef(*t.ifFalse());
245 }
246 case Expression::Kind::kVariableReference: {
247 const VariableReference& ref = expr.as<VariableReference>();
248 return ref.refKind() == VariableRefKind::kWrite ||
249 ref.refKind() == VariableRefKind::kReadWrite;
250 }
251 default:
252 return false;
253 }
254 }
255
clone(Position pos) const256 std::unique_ptr<Expression> BinaryExpression::clone(Position pos) const {
257 return std::make_unique<BinaryExpression>(pos,
258 this->left()->clone(),
259 this->getOperator(),
260 this->right()->clone(),
261 &this->type());
262 }
263
description(OperatorPrecedence parentPrecedence) const264 std::string BinaryExpression::description(OperatorPrecedence parentPrecedence) const {
265 OperatorPrecedence operatorPrecedence = this->getOperator().getBinaryPrecedence();
266 bool needsParens = (operatorPrecedence >= parentPrecedence);
267 return std::string(needsParens ? "(" : "") +
268 this->left()->description(operatorPrecedence) +
269 this->getOperator().operatorName() +
270 this->right()->description(operatorPrecedence) +
271 std::string(needsParens ? ")" : "");
272 }
273
isAssignmentIntoVariable()274 VariableReference* BinaryExpression::isAssignmentIntoVariable() {
275 if (this->getOperator().isAssignment()) {
276 Analysis::AssignmentInfo assignmentInfo;
277 if (Analysis::IsAssignable(*this->left(), &assignmentInfo, /*errors=*/nullptr)) {
278 return assignmentInfo.fAssignedVar;
279 }
280 }
281 return nullptr;
282 }
283
284 } // namespace SkSL
285