blob: 6d1fe9e49542055d1e3d7c4ed9c921a9bbb23de6 [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"
11#include "src/sksl/ir/SkSLType.h"
12
13namespace SkSL {
14
John Stiles23521a82021-03-02 17:02:51 -050015std::unique_ptr<Expression> BinaryExpression::Convert(const Context& context,
16 std::unique_ptr<Expression> left,
17 Operator op,
18 std::unique_ptr<Expression> right) {
John Stilese2aec432021-03-01 09:27:48 -050019 if (!left || !right) {
20 return nullptr;
21 }
John Stiles23521a82021-03-02 17:02:51 -050022 const int offset = left->fOffset;
John Stilese2aec432021-03-01 09:27:48 -050023
24 const Type* rawLeftType;
25 if (left->is<IntLiteral>() && right->type().isInteger()) {
26 rawLeftType = &right->type();
27 } else {
28 rawLeftType = &left->type();
29 }
30
31 const Type* rawRightType;
32 if (right->is<IntLiteral>() && left->type().isInteger()) {
33 rawRightType = &left->type();
34 } else {
35 rawRightType = &right->type();
36 }
37
John Stilese2aec432021-03-01 09:27:48 -050038 bool isAssignment = op.isAssignment();
39 if (isAssignment &&
40 !Analysis::MakeAssignmentExpr(left.get(),
41 op.kind() != Token::Kind::TK_EQ
42 ? VariableReference::RefKind::kReadWrite
43 : VariableReference::RefKind::kWrite,
44 &context.fErrors)) {
45 return nullptr;
46 }
47
48 const Type* leftType;
49 const Type* rightType;
50 const Type* resultType;
51 if (!op.determineBinaryType(context, *rawLeftType, *rawRightType,
52 &leftType, &rightType, &resultType)) {
53 context.fErrors.error(offset, String("type mismatch: '") + op.operatorName() +
54 "' cannot operate on '" + left->type().displayName() +
55 "', '" + right->type().displayName() + "'");
56 return nullptr;
57 }
John Stiles23521a82021-03-02 17:02:51 -050058
John Stilese2aec432021-03-01 09:27:48 -050059 if (isAssignment && leftType->componentType().isOpaque()) {
60 context.fErrors.error(offset, "assignments to opaque type '" + left->type().displayName() +
61 "' are not permitted");
John Stilese2aec432021-03-01 09:27:48 -050062 return nullptr;
63 }
John Stiles23521a82021-03-02 17:02:51 -050064 if (context.fConfig->strictES2Mode()) {
65 if (!op.isAllowedInStrictES2Mode()) {
66 context.fErrors.error(offset, String("operator '") + op.operatorName() +
67 "' is not allowed");
68 return nullptr;
69 }
70 if (leftType->isOrContainsArray()) {
71 // Most operators are already rejected on arrays, but GLSL ES 1.0 is very explicit that
72 // the *only* operator allowed on arrays is subscripting (and the rules against
73 // assignment, comparison, and even sequence apply to structs containing arrays as well)
74 context.fErrors.error(offset, String("operator '") + op.operatorName() + "' can not "
75 "operate on arrays (or structs containing arrays)");
76 return nullptr;
77 }
78 }
John Stilese2aec432021-03-01 09:27:48 -050079
80 left = leftType->coerceExpression(std::move(left), context);
81 right = rightType->coerceExpression(std::move(right), context);
82 if (!left || !right) {
83 return nullptr;
84 }
85
John Stiles23521a82021-03-02 17:02:51 -050086 return BinaryExpression::Make(context, std::move(left), op, std::move(right), resultType);
87}
88
89std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
90 std::unique_ptr<Expression> left,
91 Operator op,
92 std::unique_ptr<Expression> right) {
93 // Determine the result type of the binary expression.
94 const Type* leftType;
95 const Type* rightType;
96 const Type* resultType;
97 SkAssertResult(op.determineBinaryType(context, left->type(), right->type(),
98 &leftType, &rightType, &resultType));
99
100 return BinaryExpression::Make(context, std::move(left), op, std::move(right), resultType);
101}
102
103std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
104 std::unique_ptr<Expression> left,
105 Operator op,
106 std::unique_ptr<Expression> right,
107 const Type* resultType) {
108 // We should have detected non-ES2 compliant behavior in Convert.
109 SkASSERT(!context.fConfig->strictES2Mode() || op.isAllowedInStrictES2Mode());
110 SkASSERT(!context.fConfig->strictES2Mode() || !left->type().isOrContainsArray());
111
112 // We should have detected non-assignable assignment expressions in Convert.
113 SkASSERT(!op.isAssignment() || Analysis::IsAssignable(*left));
114 SkASSERT(!op.isAssignment() || !left->type().componentType().isOpaque());
115
116 // If we can detect division-by-zero, we should synthesize an error, but our caller is still
117 // expecting to receive a binary expression back; don't return nullptr.
118 const int offset = left->fOffset;
John Stilese2aec432021-03-01 09:27:48 -0500119 if (!ConstantFolder::ErrorOnDivideByZero(context, offset, op, *right)) {
John Stiles23521a82021-03-02 17:02:51 -0500120 std::unique_ptr<Expression> result =
121 ConstantFolder::Simplify(context, offset, *left, op, *right);
122 if (result) {
123 return result;
124 }
John Stilese2aec432021-03-01 09:27:48 -0500125 }
John Stiles23521a82021-03-02 17:02:51 -0500126
127 return std::make_unique<BinaryExpression>(offset, std::move(left), op, std::move(right),
128 resultType);
John Stilese2aec432021-03-01 09:27:48 -0500129}
130
131bool BinaryExpression::CheckRef(const Expression& expr) {
132 switch (expr.kind()) {
133 case Expression::Kind::kFieldAccess:
134 return CheckRef(*expr.as<FieldAccess>().base());
135
136 case Expression::Kind::kIndex:
137 return CheckRef(*expr.as<IndexExpression>().base());
138
139 case Expression::Kind::kSwizzle:
140 return CheckRef(*expr.as<Swizzle>().base());
141
142 case Expression::Kind::kTernary: {
143 const TernaryExpression& t = expr.as<TernaryExpression>();
144 return CheckRef(*t.ifTrue()) && CheckRef(*t.ifFalse());
145 }
146 case Expression::Kind::kVariableReference: {
147 const VariableReference& ref = expr.as<VariableReference>();
148 return ref.refKind() == VariableRefKind::kWrite ||
149 ref.refKind() == VariableRefKind::kReadWrite;
150 }
151 default:
152 return false;
153 }
154}
155
156std::unique_ptr<Expression> BinaryExpression::clone() const {
157 return std::make_unique<BinaryExpression>(fOffset,
158 this->left()->clone(),
159 this->getOperator(),
160 this->right()->clone(),
161 &this->type());
162}
163
164String BinaryExpression::description() const {
165 return "(" + this->left()->description() +
166 " " + this->getOperator().operatorName() +
167 " " + this->right()->description() + ")";
168}
169
170} // namespace SkSL