blob: 1024ca44f989c90232179ea556ee9ece843ead40 [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/SkSLBoolLiteral.h"
12#include "src/sksl/ir/SkSLIndexExpression.h"
13#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 Stiles23521a82021-03-02 17:02:51 -050020std::unique_ptr<Expression> BinaryExpression::Convert(const Context& context,
21 std::unique_ptr<Expression> left,
22 Operator op,
23 std::unique_ptr<Expression> right) {
John Stilese2aec432021-03-01 09:27:48 -050024 if (!left || !right) {
25 return nullptr;
26 }
John Stiles23521a82021-03-02 17:02:51 -050027 const int offset = left->fOffset;
John Stilese2aec432021-03-01 09:27:48 -050028
29 const Type* rawLeftType;
30 if (left->is<IntLiteral>() && right->type().isInteger()) {
31 rawLeftType = &right->type();
32 } else {
33 rawLeftType = &left->type();
34 }
35
36 const Type* rawRightType;
37 if (right->is<IntLiteral>() && left->type().isInteger()) {
38 rawRightType = &left->type();
39 } else {
40 rawRightType = &right->type();
41 }
42
John Stilese2aec432021-03-01 09:27:48 -050043 bool isAssignment = op.isAssignment();
44 if (isAssignment &&
45 !Analysis::MakeAssignmentExpr(left.get(),
46 op.kind() != Token::Kind::TK_EQ
47 ? VariableReference::RefKind::kReadWrite
48 : VariableReference::RefKind::kWrite,
49 &context.fErrors)) {
50 return nullptr;
51 }
52
53 const Type* leftType;
54 const Type* rightType;
55 const Type* resultType;
56 if (!op.determineBinaryType(context, *rawLeftType, *rawRightType,
57 &leftType, &rightType, &resultType)) {
58 context.fErrors.error(offset, String("type mismatch: '") + op.operatorName() +
59 "' cannot operate on '" + left->type().displayName() +
60 "', '" + right->type().displayName() + "'");
61 return nullptr;
62 }
John Stiles23521a82021-03-02 17:02:51 -050063
John Stilese2aec432021-03-01 09:27:48 -050064 if (isAssignment && leftType->componentType().isOpaque()) {
65 context.fErrors.error(offset, "assignments to opaque type '" + left->type().displayName() +
66 "' are not permitted");
John Stilese2aec432021-03-01 09:27:48 -050067 return nullptr;
68 }
John Stiles23521a82021-03-02 17:02:51 -050069 if (context.fConfig->strictES2Mode()) {
70 if (!op.isAllowedInStrictES2Mode()) {
71 context.fErrors.error(offset, String("operator '") + op.operatorName() +
72 "' is not allowed");
73 return nullptr;
74 }
75 if (leftType->isOrContainsArray()) {
76 // Most operators are already rejected on arrays, but GLSL ES 1.0 is very explicit that
77 // the *only* operator allowed on arrays is subscripting (and the rules against
78 // assignment, comparison, and even sequence apply to structs containing arrays as well)
79 context.fErrors.error(offset, String("operator '") + op.operatorName() + "' can not "
80 "operate on arrays (or structs containing arrays)");
81 return nullptr;
82 }
83 }
John Stilese2aec432021-03-01 09:27:48 -050084
85 left = leftType->coerceExpression(std::move(left), context);
86 right = rightType->coerceExpression(std::move(right), context);
87 if (!left || !right) {
88 return nullptr;
89 }
90
John Stiles23521a82021-03-02 17:02:51 -050091 return BinaryExpression::Make(context, std::move(left), op, std::move(right), resultType);
92}
93
94std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
95 std::unique_ptr<Expression> left,
96 Operator op,
97 std::unique_ptr<Expression> right) {
98 // Determine the result type of the binary expression.
99 const Type* leftType;
100 const Type* rightType;
101 const Type* resultType;
102 SkAssertResult(op.determineBinaryType(context, left->type(), right->type(),
103 &leftType, &rightType, &resultType));
104
105 return BinaryExpression::Make(context, std::move(left), op, std::move(right), resultType);
106}
107
108std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
109 std::unique_ptr<Expression> left,
110 Operator op,
111 std::unique_ptr<Expression> right,
112 const Type* resultType) {
113 // We should have detected non-ES2 compliant behavior in Convert.
114 SkASSERT(!context.fConfig->strictES2Mode() || op.isAllowedInStrictES2Mode());
115 SkASSERT(!context.fConfig->strictES2Mode() || !left->type().isOrContainsArray());
116
117 // We should have detected non-assignable assignment expressions in Convert.
118 SkASSERT(!op.isAssignment() || Analysis::IsAssignable(*left));
119 SkASSERT(!op.isAssignment() || !left->type().componentType().isOpaque());
120
121 // If we can detect division-by-zero, we should synthesize an error, but our caller is still
122 // expecting to receive a binary expression back; don't return nullptr.
123 const int offset = left->fOffset;
John Stilese2aec432021-03-01 09:27:48 -0500124 if (!ConstantFolder::ErrorOnDivideByZero(context, offset, op, *right)) {
John Stiles8f440b42021-03-05 16:48:56 -0500125 std::unique_ptr<Expression> result = ConstantFolder::Simplify(context, offset, *left,
126 op, *right, *resultType);
John Stiles23521a82021-03-02 17:02:51 -0500127 if (result) {
128 return result;
129 }
John Stilese2aec432021-03-01 09:27:48 -0500130 }
John Stiles23521a82021-03-02 17:02:51 -0500131
John Stiles9e13fe82021-03-23 18:45:25 -0400132 // When sk_Caps.rewriteMatrixVectorMultiply is set, we rewrite medium-precision matrix * vector
133 // multiplication as:
134 // (sk_Caps.rewriteMatrixVectorMultiply ? (mat[0]*vec[0] + ... + mat[N]*vec[N]) : mat * vec)
135 if (context.fConfig->fSettings.fOptimize &&
136 !resultType->highPrecision() &&
137 op.kind() == Token::Kind::TK_STAR &&
138 left->type().isMatrix() && right->type().isVector() &&
139 left->type().rows() == right->type().columns() &&
140 Analysis::IsTrivialExpression(*left) && Analysis::IsTrivialExpression(*right)) {
141 // Look up `sk_Caps.rewriteMatrixVectorMultiply`.
142 auto caps = Setting::Convert(context, left->fOffset, "rewriteMatrixVectorMultiply");
143
144 // If the caps bit returns a constant "false," avoid making all this additional IR.
145 std::unique_ptr<Expression> sum;
146 bool rewriteMatrixVectorMultiplyIsTrue = caps->is<BoolLiteral>() &&
147 caps->as<BoolLiteral>().value();
148 if (rewriteMatrixVectorMultiplyIsTrue || !caps->is<BoolLiteral>()) {
149 // Rewrite m33 * v3 as (m[0] * v[0] + m[1] * v[1] + m[2] * v[2])
150 for (int n = 0; n < left->type().rows(); ++n) {
151 // Get mat[N] with an index expression.
152 std::unique_ptr<Expression> matN = IndexExpression::Make(
153 context, left->clone(), IntLiteral::Make(context, /*offset=*/-1, n));
154 // Get vec[N] with a swizzle expression.
155 std::unique_ptr<Expression> vecN = Swizzle::Make(
156 context, right->clone(), ComponentArray{(SkSL::SwizzleComponent::Type)n});
157 // Multiply them together.
158 const Type* matNType = &matN->type();
159 std::unique_ptr<Expression> product = BinaryExpression::Make(
160 context, std::move(matN), op, std::move(vecN), matNType);
161 // Sum all the components together.
162 if (!sum) {
163 sum = std::move(product);
164 } else {
165 sum = BinaryExpression::Make(context, std::move(sum),
166 Operator(Token::Kind::TK_PLUS),
167 std::move(product), matNType);
168 }
169 }
170
171 // If we know the caps bit is true, return the sum-of-products expression directly.
172 if (rewriteMatrixVectorMultiplyIsTrue) {
173 return sum;
174 }
175
176 // Generate a ternary expression:
177 // sk_Caps.rewriteMatrixVectorMultiply ? (sum of products) : (mat * vec)
178 return TernaryExpression::Make(
179 context,
180 std::move(caps),
181 std::move(sum),
182 std::make_unique<BinaryExpression>(offset, std::move(left), op,
183 std::move(right), resultType));
184 }
185 }
186
187 return std::make_unique<BinaryExpression>(offset, std::move(left), op,
188 std::move(right), resultType);
John Stilese2aec432021-03-01 09:27:48 -0500189}
190
191bool BinaryExpression::CheckRef(const Expression& expr) {
192 switch (expr.kind()) {
193 case Expression::Kind::kFieldAccess:
194 return CheckRef(*expr.as<FieldAccess>().base());
195
196 case Expression::Kind::kIndex:
197 return CheckRef(*expr.as<IndexExpression>().base());
198
199 case Expression::Kind::kSwizzle:
200 return CheckRef(*expr.as<Swizzle>().base());
201
202 case Expression::Kind::kTernary: {
203 const TernaryExpression& t = expr.as<TernaryExpression>();
204 return CheckRef(*t.ifTrue()) && CheckRef(*t.ifFalse());
205 }
206 case Expression::Kind::kVariableReference: {
207 const VariableReference& ref = expr.as<VariableReference>();
208 return ref.refKind() == VariableRefKind::kWrite ||
209 ref.refKind() == VariableRefKind::kReadWrite;
210 }
211 default:
212 return false;
213 }
214}
215
216std::unique_ptr<Expression> BinaryExpression::clone() const {
217 return std::make_unique<BinaryExpression>(fOffset,
218 this->left()->clone(),
219 this->getOperator(),
220 this->right()->clone(),
221 &this->type());
222}
223
224String BinaryExpression::description() const {
225 return "(" + this->left()->description() +
226 " " + this->getOperator().operatorName() +
227 " " + this->right()->description() + ")";
228}
229
230} // namespace SkSL