1 /*
2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "condition.h"
17
18 #include "compiler/core/pandagen.h"
19 #include "compiler/core/ETSGen.h"
20 #include "ir/expressions/assignmentExpression.h"
21 #include "ir/expressions/binaryExpression.h"
22 #include "ir/expressions/callExpression.h"
23 #include "ir/expressions/unaryExpression.h"
24
25 namespace ark::es2panda::compiler {
CompileBinaryExpr(PandaGen * pg,const ir::BinaryExpression * binExpr,Label * falseLabel)26 bool Condition::CompileBinaryExpr(PandaGen *pg, const ir::BinaryExpression *binExpr, Label *falseLabel)
27 {
28 switch (binExpr->OperatorType()) {
29 case lexer::TokenType::PUNCTUATOR_EQUAL:
30 case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
31 case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
32 case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL:
33 case lexer::TokenType::PUNCTUATOR_LESS_THAN:
34 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
35 case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
36 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
37 // This is a special case
38 // These operators are expressed via cmp instructions and the following
39 // if-else branches. Condition also expressed via cmp instruction and
40 // the following if-else.
41 // the goal of this method is to merge these two sequences of instructions.
42 RegScope rs(pg);
43 VReg lhs = pg->AllocReg();
44
45 binExpr->Left()->Compile(pg);
46 pg->StoreAccumulator(binExpr, lhs);
47 binExpr->Right()->Compile(pg);
48 pg->Condition(binExpr, binExpr->OperatorType(), lhs, falseLabel);
49 return true;
50 }
51 case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
52 binExpr->Left()->Compile(pg);
53 pg->ToBoolean(binExpr);
54 pg->BranchIfFalse(binExpr, falseLabel);
55
56 binExpr->Right()->Compile(pg);
57 pg->ToBoolean(binExpr);
58 pg->BranchIfFalse(binExpr, falseLabel);
59 return true;
60 }
61 case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
62 auto *endLabel = pg->AllocLabel();
63
64 binExpr->Left()->Compile(pg);
65 pg->ToBoolean(binExpr);
66 pg->BranchIfTrue(binExpr, endLabel);
67
68 binExpr->Right()->Compile(pg);
69 pg->ToBoolean(binExpr);
70 pg->BranchIfFalse(binExpr, falseLabel);
71 pg->SetLabel(binExpr, endLabel);
72 return true;
73 }
74 default: {
75 break;
76 }
77 }
78 return false;
79 }
80
Compile(PandaGen * pg,const ir::Expression * expr,Label * falseLabel)81 void Condition::Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLabel)
82 {
83 if (expr->IsBinaryExpression()) {
84 if (CompileBinaryExpr(pg, expr->AsBinaryExpression(), falseLabel)) {
85 return;
86 }
87 } else if (expr->IsUnaryExpression() &&
88 expr->AsUnaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) {
89 expr->AsUnaryExpression()->Argument()->Compile(pg);
90
91 pg->Negate(expr);
92 pg->BranchIfFalse(expr, falseLabel);
93 return;
94 }
95
96 // General case including some binExpr i.E.(a+b)
97 expr->Compile(pg);
98 pg->ToBoolean(expr);
99 pg->BranchIfFalse(expr, falseLabel);
100 }
101
CompileBinaryExprForBigInt(ETSGen * etsg,const ir::BinaryExpression * expr,Label * falseLabel)102 bool Condition::CompileBinaryExprForBigInt(ETSGen *etsg, const ir::BinaryExpression *expr, Label *falseLabel)
103 {
104 if ((expr->Left()->TsType() == nullptr) || (expr->Right()->TsType() == nullptr)) {
105 return false;
106 }
107
108 if (!expr->Left()->TsType()->IsETSBigIntType()) {
109 return false;
110 }
111
112 if (!expr->Right()->TsType()->IsETSBigIntType()) {
113 return false;
114 }
115
116 std::string_view signature = compiler::Signatures::ANY;
117 switch (expr->OperatorType()) {
118 case lexer::TokenType::PUNCTUATOR_LESS_THAN:
119 signature = compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LESS_THAN;
120 break;
121 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
122 signature = compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LESS_THAN_EQUAL;
123 break;
124 case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
125 signature = compiler::Signatures::BUILTIN_BIGINT_OPERATOR_GREATER_THAN;
126 break;
127 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL:
128 signature = compiler::Signatures::BUILTIN_BIGINT_OPERATOR_GREATER_THAN_EQUAL;
129 break;
130 default:
131 // Other operations are handled in the CompileBinaryExpr function
132 return false;
133 }
134
135 auto ttctx = TargetTypeContext(etsg, expr->OperationType());
136 RegScope rs(etsg);
137 VReg lhs = etsg->AllocReg();
138 expr->Left()->Compile(etsg);
139 etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType());
140 expr->Right()->Compile(etsg);
141 etsg->ApplyConversion(expr->Right(), expr->OperationType());
142 compiler::VReg rhs = etsg->AllocReg();
143 etsg->StoreAccumulator(expr, rhs);
144 etsg->CallBigIntBinaryComparison(expr, lhs, rhs, signature);
145 etsg->BranchIfFalse(expr, falseLabel);
146
147 return true;
148 }
149
CompileInstanceofExpr(ETSGen * etsg,const ir::BinaryExpression * binExpr,Label * falseLabel)150 void Condition::CompileInstanceofExpr(ETSGen *etsg, const ir::BinaryExpression *binExpr, Label *falseLabel)
151 {
152 ES2PANDA_ASSERT(binExpr->OperatorType() == lexer::TokenType::KEYW_INSTANCEOF);
153 binExpr->Compile(etsg);
154 etsg->BranchIfFalse(binExpr, falseLabel);
155 }
156
CompileLogical(ETSGen * etsg,const ir::BinaryExpression * binExpr,Label * falseLabel)157 void Condition::CompileLogical(ETSGen *etsg, const ir::BinaryExpression *binExpr, Label *falseLabel)
158 {
159 ES2PANDA_ASSERT(binExpr->IsLogicalExtended());
160
161 // If the Result is given, we can optimize the process.
162 if (binExpr->Result() != nullptr) {
163 if (binExpr->Result() != binExpr->Left()) {
164 ES2PANDA_ASSERT(binExpr->Result() == binExpr->Right());
165 etsg->CompileAndCheck(binExpr->Left());
166 }
167 Compile(etsg, binExpr->Result(), falseLabel);
168 return;
169 }
170
171 compiler::RegScope rs(etsg);
172 auto *endLabel = etsg->AllocLabel();
173
174 if (binExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) {
175 Compile(etsg, binExpr->Left(), falseLabel);
176 } else {
177 ES2PANDA_ASSERT(binExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_OR);
178 etsg->CompileAndCheck(binExpr->Left());
179 etsg->BranchConditionalIfTrue(binExpr->Left(), endLabel);
180 }
181
182 Compile(etsg, binExpr->Right(), falseLabel);
183 etsg->SetLabel(binExpr, endLabel);
184 }
185
CompileBinaryExpr(ETSGen * etsg,const ir::BinaryExpression * binExpr,Label * falseLabel)186 bool Condition::CompileBinaryExpr(ETSGen *etsg, const ir::BinaryExpression *binExpr, Label *falseLabel)
187 {
188 if (CompileBinaryExprForBigInt(etsg, binExpr, falseLabel)) {
189 return true;
190 }
191
192 switch (binExpr->OperatorType()) {
193 case lexer::TokenType::PUNCTUATOR_EQUAL:
194 case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
195 case lexer::TokenType::PUNCTUATOR_LESS_THAN:
196 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
197 case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
198 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
199 auto ttctx = TargetTypeContext(etsg, binExpr->OperationType());
200
201 RegScope rs(etsg);
202 VReg lhs = etsg->AllocReg();
203
204 binExpr->CompileOperands(etsg, lhs);
205 etsg->Condition(binExpr, binExpr->OperatorType(), lhs, falseLabel);
206 return true;
207 }
208 case lexer::TokenType::PUNCTUATOR_LOGICAL_OR:
209 case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
210 CompileLogical(etsg, binExpr, falseLabel);
211 return true;
212 }
213 case lexer::TokenType::KEYW_INSTANCEOF: {
214 CompileInstanceofExpr(etsg, binExpr, falseLabel);
215 return true;
216 }
217 default: {
218 break;
219 }
220 }
221 return false;
222 }
223
Compile(ETSGen * etsg,const ir::Expression * expr,Label * falseLabel)224 void Condition::Compile(ETSGen *etsg, const ir::Expression *expr, Label *falseLabel)
225 {
226 if (expr->IsBinaryExpression()) {
227 if (CompileBinaryExpr(etsg, expr->AsBinaryExpression(), falseLabel)) {
228 return;
229 }
230 } else if (expr->IsUnaryExpression() &&
231 expr->AsUnaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) {
232 expr->AsUnaryExpression()->Argument()->Compile(etsg);
233 etsg->ApplyConversion(expr->AsUnaryExpression()->Argument(), etsg->Checker()->GlobalETSBooleanType());
234 etsg->ResolveConditionalResultIfTrue<false, false>(expr, falseLabel);
235 etsg->BranchIfTrue(expr, falseLabel);
236 return;
237 }
238 expr->Compile(etsg);
239 etsg->ApplyConversion(expr, etsg->Checker()->GlobalETSBooleanType());
240 etsg->ResolveConditionalResultIfFalse(expr, falseLabel);
241 etsg->BranchIfFalse(expr, falseLabel);
242 }
243 } // namespace ark::es2panda::compiler
244