1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "constant_folding.h"
18
19 #include <algorithm>
20
21 #include "base/bit_utils.h"
22 #include "base/casts.h"
23 #include "base/logging.h"
24 #include "dex/dex_file-inl.h"
25 #include "intrinsics_enum.h"
26 #include "optimizing/data_type.h"
27 #include "optimizing/nodes.h"
28
29 namespace art HIDDEN {
30
31 // This visitor tries to simplify instructions that can be evaluated
32 // as constants.
33 class HConstantFoldingVisitor final : public HGraphDelegateVisitor {
34 public:
HConstantFoldingVisitor(HGraph * graph,OptimizingCompilerStats * stats)35 explicit HConstantFoldingVisitor(HGraph* graph, OptimizingCompilerStats* stats)
36 : HGraphDelegateVisitor(graph, stats) {}
37
38 private:
39 void VisitBasicBlock(HBasicBlock* block) override;
40
41 void VisitUnaryOperation(HUnaryOperation* inst) override;
42 void VisitBinaryOperation(HBinaryOperation* inst) override;
43
44 // Tries to replace constants in binary operations like:
45 // * BinaryOp(Select(false_constant, true_constant, condition), other_constant), or
46 // * BinaryOp(other_constant, Select(false_constant, true_constant, condition))
47 // with consolidated constants. For example, Add(Select(10, 20, condition), 5) can be replaced
48 // with Select(15, 25, condition).
49 bool TryRemoveBinaryOperationViaSelect(HBinaryOperation* inst);
50
51 void VisitArrayLength(HArrayLength* inst) override;
52 void VisitDivZeroCheck(HDivZeroCheck* inst) override;
53 void VisitIf(HIf* inst) override;
54 void VisitInvoke(HInvoke* inst) override;
55 void VisitTypeConversion(HTypeConversion* inst) override;
56
57 void PropagateValue(HBasicBlock* starting_block, HInstruction* variable, HConstant* constant);
58
59 // Intrinsics foldings
60 void FoldReverseIntrinsic(HInvoke* invoke);
61 void FoldReverseBytesIntrinsic(HInvoke* invoke);
62 void FoldBitCountIntrinsic(HInvoke* invoke);
63 void FoldDivideUnsignedIntrinsic(HInvoke* invoke);
64 void FoldHighestOneBitIntrinsic(HInvoke* invoke);
65 void FoldLowestOneBitIntrinsic(HInvoke* invoke);
66 void FoldNumberOfLeadingZerosIntrinsic(HInvoke* invoke);
67 void FoldNumberOfTrailingZerosIntrinsic(HInvoke* invoke);
68
69 DISALLOW_COPY_AND_ASSIGN(HConstantFoldingVisitor);
70 };
71
72 // This visitor tries to simplify operations with an absorbing input,
73 // yielding a constant. For example `input * 0` is replaced by a
74 // null constant.
75 class InstructionWithAbsorbingInputSimplifier : public HGraphVisitor {
76 public:
InstructionWithAbsorbingInputSimplifier(HGraph * graph)77 explicit InstructionWithAbsorbingInputSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
78
79 private:
80 void VisitShift(HBinaryOperation* shift);
81
82 void VisitEqual(HEqual* instruction) override;
83 void VisitNotEqual(HNotEqual* instruction) override;
84
85 void VisitAbove(HAbove* instruction) override;
86 void VisitAboveOrEqual(HAboveOrEqual* instruction) override;
87 void VisitBelow(HBelow* instruction) override;
88 void VisitBelowOrEqual(HBelowOrEqual* instruction) override;
89
90 void VisitGreaterThan(HGreaterThan* instruction) override;
91 void VisitGreaterThanOrEqual(HGreaterThanOrEqual* instruction) override;
92 void VisitLessThan(HLessThan* instruction) override;
93 void VisitLessThanOrEqual(HLessThanOrEqual* instruction) override;
94
95 void VisitAnd(HAnd* instruction) override;
96 void VisitCompare(HCompare* instruction) override;
97 void VisitMul(HMul* instruction) override;
98 void VisitOr(HOr* instruction) override;
99 void VisitRem(HRem* instruction) override;
100 void VisitShl(HShl* instruction) override;
101 void VisitShr(HShr* instruction) override;
102 void VisitSub(HSub* instruction) override;
103 void VisitUShr(HUShr* instruction) override;
104 void VisitXor(HXor* instruction) override;
105 };
106
107
Run()108 bool HConstantFolding::Run() {
109 HConstantFoldingVisitor visitor(graph_, stats_);
110 // Process basic blocks in reverse post-order in the dominator tree,
111 // so that an instruction turned into a constant, used as input of
112 // another instruction, may possibly be used to turn that second
113 // instruction into a constant as well.
114 visitor.VisitReversePostOrder();
115 return true;
116 }
117
118
VisitBasicBlock(HBasicBlock * block)119 void HConstantFoldingVisitor::VisitBasicBlock(HBasicBlock* block) {
120 // Traverse this block's instructions (phis don't need to be processed) in (forward) order
121 // and replace the ones that can be statically evaluated by a compile-time counterpart.
122 VisitNonPhiInstructions(block);
123 }
124
VisitUnaryOperation(HUnaryOperation * inst)125 void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) {
126 // Constant folding: replace `op(a)' with a constant at compile
127 // time if `a' is a constant.
128 HConstant* constant = inst->TryStaticEvaluation();
129 if (constant != nullptr) {
130 inst->ReplaceWith(constant);
131 inst->GetBlock()->RemoveInstruction(inst);
132 } else if (inst->InputAt(0)->IsSelect() && inst->InputAt(0)->HasOnlyOneNonEnvironmentUse()) {
133 // Try to replace the select's inputs in Select+UnaryOperation cases. We can do this if both
134 // inputs to the select are constants, and this is the only use of the select.
135 HSelect* select = inst->InputAt(0)->AsSelect();
136 HConstant* false_constant = inst->TryStaticEvaluation(select->GetFalseValue());
137 if (false_constant == nullptr) {
138 return;
139 }
140 HConstant* true_constant = inst->TryStaticEvaluation(select->GetTrueValue());
141 if (true_constant == nullptr) {
142 return;
143 }
144 DCHECK_EQ(select->InputAt(0), select->GetFalseValue());
145 DCHECK_EQ(select->InputAt(1), select->GetTrueValue());
146 select->ReplaceInput(false_constant, 0);
147 select->ReplaceInput(true_constant, 1);
148 select->UpdateType();
149 inst->ReplaceWith(select);
150 inst->GetBlock()->RemoveInstruction(inst);
151 }
152 }
153
TryRemoveBinaryOperationViaSelect(HBinaryOperation * inst)154 bool HConstantFoldingVisitor::TryRemoveBinaryOperationViaSelect(HBinaryOperation* inst) {
155 if (inst->GetLeft()->IsSelect() == inst->GetRight()->IsSelect()) {
156 // If both of them are constants, VisitBinaryOperation already tried the static evaluation. If
157 // both of them are selects, then we can't simplify.
158 // TODO(solanes): Technically, if both of them are selects we could simplify iff both select's
159 // conditions are equal e.g. Add(Select(1, 2, cond), Select(3, 4, cond)) could be replaced with
160 // Select(4, 6, cond). This seems very unlikely to happen so we don't implement it.
161 return false;
162 }
163
164 const bool left_is_select = inst->GetLeft()->IsSelect();
165 HSelect* select = left_is_select ? inst->GetLeft()->AsSelect() : inst->GetRight()->AsSelect();
166 HInstruction* maybe_constant = left_is_select ? inst->GetRight() : inst->GetLeft();
167
168 if (select->HasOnlyOneNonEnvironmentUse()) {
169 // Try to replace the select's inputs in Select+BinaryOperation. We can do this if both
170 // inputs to the select are constants, and this is the only use of the select.
171 HConstant* false_constant =
172 inst->TryStaticEvaluation(left_is_select ? select->GetFalseValue() : maybe_constant,
173 left_is_select ? maybe_constant : select->GetFalseValue());
174 if (false_constant == nullptr) {
175 return false;
176 }
177 HConstant* true_constant =
178 inst->TryStaticEvaluation(left_is_select ? select->GetTrueValue() : maybe_constant,
179 left_is_select ? maybe_constant : select->GetTrueValue());
180 if (true_constant == nullptr) {
181 return false;
182 }
183 DCHECK_EQ(select->InputAt(0), select->GetFalseValue());
184 DCHECK_EQ(select->InputAt(1), select->GetTrueValue());
185 select->ReplaceInput(false_constant, 0);
186 select->ReplaceInput(true_constant, 1);
187 select->UpdateType();
188 inst->ReplaceWith(select);
189 inst->GetBlock()->RemoveInstruction(inst);
190 return true;
191 }
192 return false;
193 }
194
VisitBinaryOperation(HBinaryOperation * inst)195 void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
196 // Constant folding: replace `op(a, b)' with a constant at
197 // compile time if `a' and `b' are both constants.
198 HConstant* constant = inst->TryStaticEvaluation();
199 if (constant != nullptr) {
200 inst->ReplaceWith(constant);
201 inst->GetBlock()->RemoveInstruction(inst);
202 } else if (TryRemoveBinaryOperationViaSelect(inst)) {
203 // Already replaced inside TryRemoveBinaryOperationViaSelect.
204 } else {
205 InstructionWithAbsorbingInputSimplifier simplifier(GetGraph());
206 inst->Accept(&simplifier);
207 }
208 }
209
VisitDivZeroCheck(HDivZeroCheck * inst)210 void HConstantFoldingVisitor::VisitDivZeroCheck(HDivZeroCheck* inst) {
211 // We can safely remove the check if the input is a non-null constant.
212 HInstruction* check_input = inst->InputAt(0);
213 if (check_input->IsConstant() && !check_input->AsConstant()->IsArithmeticZero()) {
214 inst->ReplaceWith(check_input);
215 inst->GetBlock()->RemoveInstruction(inst);
216 }
217 }
218
PropagateValue(HBasicBlock * starting_block,HInstruction * variable,HConstant * constant)219 void HConstantFoldingVisitor::PropagateValue(HBasicBlock* starting_block,
220 HInstruction* variable,
221 HConstant* constant) {
222 const bool recording_stats = stats_ != nullptr;
223 size_t uses_before = 0;
224 size_t uses_after = 0;
225 if (recording_stats) {
226 uses_before = variable->GetUses().SizeSlow();
227 }
228
229 if (!variable->GetUses().HasExactlyOneElement()) {
230 variable->ReplaceUsesDominatedBy(
231 starting_block->GetFirstInstruction(), constant, /* strictly_dominated= */ false);
232 }
233
234 if (recording_stats) {
235 uses_after = variable->GetUses().SizeSlow();
236 DCHECK_GE(uses_after, 1u) << "we must at least have the use in the if clause.";
237 DCHECK_GE(uses_before, uses_after);
238 MaybeRecordStat(stats_, MethodCompilationStat::kPropagatedIfValue, uses_before - uses_after);
239 }
240 }
241
VisitIf(HIf * inst)242 void HConstantFoldingVisitor::VisitIf(HIf* inst) {
243 // Consistency check: the true and false successors do not dominate each other.
244 DCHECK(!inst->IfTrueSuccessor()->Dominates(inst->IfFalseSuccessor()) &&
245 !inst->IfFalseSuccessor()->Dominates(inst->IfTrueSuccessor()));
246
247 HInstruction* if_input = inst->InputAt(0);
248
249 // Already a constant.
250 if (if_input->IsConstant()) {
251 return;
252 }
253
254 // if (variable) {
255 // SSA `variable` guaranteed to be true
256 // } else {
257 // and here false
258 // }
259 PropagateValue(inst->IfTrueSuccessor(), if_input, GetGraph()->GetIntConstant(1));
260 PropagateValue(inst->IfFalseSuccessor(), if_input, GetGraph()->GetIntConstant(0));
261
262 // If the input is a condition, we can propagate the information of the condition itself.
263 if (!if_input->IsCondition()) {
264 return;
265 }
266 HCondition* condition = if_input->AsCondition();
267
268 // We want either `==` or `!=`, since we cannot make assumptions for other conditions e.g. `>`
269 if (!condition->IsEqual() && !condition->IsNotEqual()) {
270 return;
271 }
272
273 HInstruction* left = condition->GetLeft();
274 HInstruction* right = condition->GetRight();
275
276 // We want one of them to be a constant and not the other.
277 if (left->IsConstant() == right->IsConstant()) {
278 return;
279 }
280
281 // At this point we have something like:
282 // if (variable == constant) {
283 // SSA `variable` guaranteed to be equal to constant here
284 // } else {
285 // No guarantees can be made here (usually, see boolean case below).
286 // }
287 // Similarly with variable != constant, except that we can make guarantees in the else case.
288
289 HConstant* constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
290 HInstruction* variable = left->IsConstant() ? right : left;
291
292 // Don't deal with floats/doubles since they bring a lot of edge cases e.g.
293 // if (f == 0.0f) {
294 // // f is not really guaranteed to be 0.0f. It could be -0.0f, for example
295 // }
296 if (DataType::IsFloatingPointType(variable->GetType())) {
297 return;
298 }
299 DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
300
301 // Sometimes we have an HCompare flowing into an Equals/NonEquals, which can act as a proxy. For
302 // example: `Equals(Compare(var, constant), 0)`. This is common for long, float, and double.
303 if (variable->IsCompare()) {
304 // We only care about equality comparisons so we skip if it is a less or greater comparison.
305 if (!constant->IsArithmeticZero()) {
306 return;
307 }
308
309 // Update left and right to be the ones from the HCompare.
310 left = variable->AsCompare()->GetLeft();
311 right = variable->AsCompare()->GetRight();
312
313 // Re-check that one of them to be a constant and not the other.
314 if (left->IsConstant() == right->IsConstant()) {
315 return;
316 }
317
318 constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
319 variable = left->IsConstant() ? right : left;
320
321 // Re-check floating point values.
322 if (DataType::IsFloatingPointType(variable->GetType())) {
323 return;
324 }
325 DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
326 }
327
328 // From this block forward we want to replace the SSA value. We use `starting_block` and not the
329 // `if` block as we want to update one of the branches but not the other.
330 HBasicBlock* starting_block =
331 condition->IsEqual() ? inst->IfTrueSuccessor() : inst->IfFalseSuccessor();
332
333 PropagateValue(starting_block, variable, constant);
334
335 // Special case for booleans since they have only two values so we know what to propagate in the
336 // other branch. However, sometimes our boolean values are not compared to 0 or 1. In those cases
337 // we cannot make an assumption for the `else` branch.
338 if (variable->GetType() == DataType::Type::kBool &&
339 constant->IsIntConstant() &&
340 (constant->AsIntConstant()->IsTrue() || constant->AsIntConstant()->IsFalse())) {
341 HBasicBlock* other_starting_block =
342 condition->IsEqual() ? inst->IfFalseSuccessor() : inst->IfTrueSuccessor();
343 DCHECK_NE(other_starting_block, starting_block);
344
345 HConstant* other_constant = constant->AsIntConstant()->IsTrue() ?
346 GetGraph()->GetIntConstant(0) :
347 GetGraph()->GetIntConstant(1);
348 DCHECK_NE(other_constant, constant);
349 PropagateValue(other_starting_block, variable, other_constant);
350 }
351 }
352
VisitInvoke(HInvoke * inst)353 void HConstantFoldingVisitor::VisitInvoke(HInvoke* inst) {
354 switch (inst->GetIntrinsic()) {
355 case Intrinsics::kIntegerReverse:
356 case Intrinsics::kLongReverse:
357 FoldReverseIntrinsic(inst);
358 break;
359 case Intrinsics::kIntegerReverseBytes:
360 case Intrinsics::kLongReverseBytes:
361 case Intrinsics::kShortReverseBytes:
362 FoldReverseBytesIntrinsic(inst);
363 break;
364 case Intrinsics::kIntegerBitCount:
365 case Intrinsics::kLongBitCount:
366 FoldBitCountIntrinsic(inst);
367 break;
368 case Intrinsics::kIntegerDivideUnsigned:
369 case Intrinsics::kLongDivideUnsigned:
370 FoldDivideUnsignedIntrinsic(inst);
371 break;
372 case Intrinsics::kIntegerHighestOneBit:
373 case Intrinsics::kLongHighestOneBit:
374 FoldHighestOneBitIntrinsic(inst);
375 break;
376 case Intrinsics::kIntegerLowestOneBit:
377 case Intrinsics::kLongLowestOneBit:
378 FoldLowestOneBitIntrinsic(inst);
379 break;
380 case Intrinsics::kIntegerNumberOfLeadingZeros:
381 case Intrinsics::kLongNumberOfLeadingZeros:
382 FoldNumberOfLeadingZerosIntrinsic(inst);
383 break;
384 case Intrinsics::kIntegerNumberOfTrailingZeros:
385 case Intrinsics::kLongNumberOfTrailingZeros:
386 FoldNumberOfTrailingZerosIntrinsic(inst);
387 break;
388 default:
389 break;
390 }
391 }
392
FoldReverseIntrinsic(HInvoke * inst)393 void HConstantFoldingVisitor::FoldReverseIntrinsic(HInvoke* inst) {
394 DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerReverse ||
395 inst->GetIntrinsic() == Intrinsics::kLongReverse);
396
397 HInstruction* input = inst->InputAt(0);
398 if (!input->IsConstant()) {
399 return;
400 }
401
402 // Integer and Long intrinsics have different return types.
403 if (inst->GetIntrinsic() == Intrinsics::kIntegerReverse) {
404 DCHECK(input->IsIntConstant());
405 inst->ReplaceWith(
406 GetGraph()->GetIntConstant(ReverseBits32(input->AsIntConstant()->GetValue())));
407 } else {
408 DCHECK(input->IsLongConstant());
409 inst->ReplaceWith(
410 GetGraph()->GetLongConstant(ReverseBits64(input->AsLongConstant()->GetValue())));
411 }
412 inst->GetBlock()->RemoveInstruction(inst);
413 }
414
FoldReverseBytesIntrinsic(HInvoke * inst)415 void HConstantFoldingVisitor::FoldReverseBytesIntrinsic(HInvoke* inst) {
416 DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerReverseBytes ||
417 inst->GetIntrinsic() == Intrinsics::kLongReverseBytes ||
418 inst->GetIntrinsic() == Intrinsics::kShortReverseBytes);
419
420 HInstruction* input = inst->InputAt(0);
421 if (!input->IsConstant()) {
422 return;
423 }
424
425 // Integer, Long, and Short intrinsics have different return types.
426 if (inst->GetIntrinsic() == Intrinsics::kIntegerReverseBytes) {
427 DCHECK(input->IsIntConstant());
428 inst->ReplaceWith(GetGraph()->GetIntConstant(BSWAP(input->AsIntConstant()->GetValue())));
429 } else if (inst->GetIntrinsic() == Intrinsics::kLongReverseBytes) {
430 DCHECK(input->IsLongConstant());
431 inst->ReplaceWith(GetGraph()->GetLongConstant(BSWAP(input->AsLongConstant()->GetValue())));
432 } else {
433 DCHECK(input->IsIntConstant());
434 inst->ReplaceWith(GetGraph()->GetIntConstant(
435 BSWAP(dchecked_integral_cast<int16_t>(input->AsIntConstant()->GetValue()))));
436 }
437 inst->GetBlock()->RemoveInstruction(inst);
438 }
439
FoldBitCountIntrinsic(HInvoke * inst)440 void HConstantFoldingVisitor::FoldBitCountIntrinsic(HInvoke* inst) {
441 DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerBitCount ||
442 inst->GetIntrinsic() == Intrinsics::kLongBitCount);
443
444 HInstruction* input = inst->InputAt(0);
445 if (!input->IsConstant()) {
446 return;
447 }
448
449 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerBitCount, input->IsIntConstant());
450 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongBitCount, input->IsLongConstant());
451
452 // Note that both the Integer and Long intrinsics return an int as a result.
453 int result = inst->GetIntrinsic() == Intrinsics::kIntegerBitCount ?
454 POPCOUNT(input->AsIntConstant()->GetValue()) :
455 POPCOUNT(input->AsLongConstant()->GetValue());
456 inst->ReplaceWith(GetGraph()->GetIntConstant(result));
457 inst->GetBlock()->RemoveInstruction(inst);
458 }
459
FoldDivideUnsignedIntrinsic(HInvoke * inst)460 void HConstantFoldingVisitor::FoldDivideUnsignedIntrinsic(HInvoke* inst) {
461 DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerDivideUnsigned ||
462 inst->GetIntrinsic() == Intrinsics::kLongDivideUnsigned);
463
464 HInstruction* divisor = inst->InputAt(1);
465 if (!divisor->IsConstant()) {
466 return;
467 }
468 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerDivideUnsigned,
469 divisor->IsIntConstant());
470 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongDivideUnsigned,
471 divisor->IsLongConstant());
472 const bool is_int_intrinsic = inst->GetIntrinsic() == Intrinsics::kIntegerDivideUnsigned;
473 if ((is_int_intrinsic && divisor->AsIntConstant()->IsArithmeticZero()) ||
474 (!is_int_intrinsic && divisor->AsLongConstant()->IsArithmeticZero())) {
475 // We will be throwing, don't constant fold.
476 inst->SetAlwaysThrows(true);
477 GetGraph()->SetHasAlwaysThrowingInvokes(true);
478 return;
479 }
480
481 HInstruction* dividend = inst->InputAt(0);
482 if (!dividend->IsConstant()) {
483 return;
484 }
485 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerDivideUnsigned,
486 dividend->IsIntConstant());
487 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongDivideUnsigned,
488 dividend->IsLongConstant());
489
490 if (is_int_intrinsic) {
491 uint32_t dividend_val =
492 dchecked_integral_cast<uint32_t>(dividend->AsIntConstant()->GetValueAsUint64());
493 uint32_t divisor_val =
494 dchecked_integral_cast<uint32_t>(divisor->AsIntConstant()->GetValueAsUint64());
495 inst->ReplaceWith(GetGraph()->GetIntConstant(static_cast<int32_t>(dividend_val / divisor_val)));
496 } else {
497 uint64_t dividend_val = dividend->AsLongConstant()->GetValueAsUint64();
498 uint64_t divisor_val = divisor->AsLongConstant()->GetValueAsUint64();
499 inst->ReplaceWith(
500 GetGraph()->GetLongConstant(static_cast<int64_t>(dividend_val / divisor_val)));
501 }
502
503 inst->GetBlock()->RemoveInstruction(inst);
504 }
505
FoldHighestOneBitIntrinsic(HInvoke * inst)506 void HConstantFoldingVisitor::FoldHighestOneBitIntrinsic(HInvoke* inst) {
507 DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerHighestOneBit ||
508 inst->GetIntrinsic() == Intrinsics::kLongHighestOneBit);
509
510 HInstruction* input = inst->InputAt(0);
511 if (!input->IsConstant()) {
512 return;
513 }
514
515 // Integer and Long intrinsics have different return types.
516 if (inst->GetIntrinsic() == Intrinsics::kIntegerHighestOneBit) {
517 DCHECK(input->IsIntConstant());
518 inst->ReplaceWith(
519 GetGraph()->GetIntConstant(HighestOneBitValue(input->AsIntConstant()->GetValue())));
520 } else {
521 DCHECK(input->IsLongConstant());
522 inst->ReplaceWith(
523 GetGraph()->GetLongConstant(HighestOneBitValue(input->AsLongConstant()->GetValue())));
524 }
525 inst->GetBlock()->RemoveInstruction(inst);
526 }
527
FoldLowestOneBitIntrinsic(HInvoke * inst)528 void HConstantFoldingVisitor::FoldLowestOneBitIntrinsic(HInvoke* inst) {
529 DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerLowestOneBit ||
530 inst->GetIntrinsic() == Intrinsics::kLongLowestOneBit);
531
532 HInstruction* input = inst->InputAt(0);
533 if (!input->IsConstant()) {
534 return;
535 }
536
537 // Integer and Long intrinsics have different return types.
538 if (inst->GetIntrinsic() == Intrinsics::kIntegerLowestOneBit) {
539 DCHECK(input->IsIntConstant());
540 inst->ReplaceWith(
541 GetGraph()->GetIntConstant(LowestOneBitValue(input->AsIntConstant()->GetValue())));
542 } else {
543 DCHECK(input->IsLongConstant());
544 inst->ReplaceWith(
545 GetGraph()->GetLongConstant(LowestOneBitValue(input->AsLongConstant()->GetValue())));
546 }
547 inst->GetBlock()->RemoveInstruction(inst);
548 }
549
FoldNumberOfLeadingZerosIntrinsic(HInvoke * inst)550 void HConstantFoldingVisitor::FoldNumberOfLeadingZerosIntrinsic(HInvoke* inst) {
551 DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerNumberOfLeadingZeros ||
552 inst->GetIntrinsic() == Intrinsics::kLongNumberOfLeadingZeros);
553
554 HInstruction* input = inst->InputAt(0);
555 if (!input->IsConstant()) {
556 return;
557 }
558
559 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerNumberOfLeadingZeros,
560 input->IsIntConstant());
561 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongNumberOfLeadingZeros,
562 input->IsLongConstant());
563
564 // Note that both the Integer and Long intrinsics return an int as a result.
565 int result = input->IsIntConstant() ? JAVASTYLE_CLZ(input->AsIntConstant()->GetValue()) :
566 JAVASTYLE_CLZ(input->AsLongConstant()->GetValue());
567 inst->ReplaceWith(GetGraph()->GetIntConstant(result));
568 inst->GetBlock()->RemoveInstruction(inst);
569 }
570
FoldNumberOfTrailingZerosIntrinsic(HInvoke * inst)571 void HConstantFoldingVisitor::FoldNumberOfTrailingZerosIntrinsic(HInvoke* inst) {
572 DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerNumberOfTrailingZeros ||
573 inst->GetIntrinsic() == Intrinsics::kLongNumberOfTrailingZeros);
574
575 HInstruction* input = inst->InputAt(0);
576 if (!input->IsConstant()) {
577 return;
578 }
579
580 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerNumberOfTrailingZeros,
581 input->IsIntConstant());
582 DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongNumberOfTrailingZeros,
583 input->IsLongConstant());
584
585 // Note that both the Integer and Long intrinsics return an int as a result.
586 int result = input->IsIntConstant() ? JAVASTYLE_CTZ(input->AsIntConstant()->GetValue()) :
587 JAVASTYLE_CTZ(input->AsLongConstant()->GetValue());
588 inst->ReplaceWith(GetGraph()->GetIntConstant(result));
589 inst->GetBlock()->RemoveInstruction(inst);
590 }
591
VisitArrayLength(HArrayLength * inst)592 void HConstantFoldingVisitor::VisitArrayLength(HArrayLength* inst) {
593 HInstruction* input = inst->InputAt(0);
594 if (input->IsLoadString()) {
595 DCHECK(inst->IsStringLength());
596 HLoadString* load_string = input->AsLoadString();
597 const DexFile& dex_file = load_string->GetDexFile();
598 const dex::StringId& string_id = dex_file.GetStringId(load_string->GetStringIndex());
599 inst->ReplaceWith(GetGraph()->GetIntConstant(
600 dchecked_integral_cast<int32_t>(dex_file.GetStringUtf16Length(string_id))));
601 }
602 }
603
VisitTypeConversion(HTypeConversion * inst)604 void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
605 // Constant folding: replace `TypeConversion(a)' with a constant at
606 // compile time if `a' is a constant.
607 HConstant* constant = inst->TryStaticEvaluation();
608 if (constant != nullptr) {
609 inst->ReplaceWith(constant);
610 inst->GetBlock()->RemoveInstruction(inst);
611 } else if (inst->InputAt(0)->IsSelect() && inst->InputAt(0)->HasOnlyOneNonEnvironmentUse()) {
612 // Try to replace the select's inputs in Select+TypeConversion. We can do this if both
613 // inputs to the select are constants, and this is the only use of the select.
614 HSelect* select = inst->InputAt(0)->AsSelect();
615 HConstant* false_constant = inst->TryStaticEvaluation(select->GetFalseValue());
616 if (false_constant == nullptr) {
617 return;
618 }
619 HConstant* true_constant = inst->TryStaticEvaluation(select->GetTrueValue());
620 if (true_constant == nullptr) {
621 return;
622 }
623 DCHECK_EQ(select->InputAt(0), select->GetFalseValue());
624 DCHECK_EQ(select->InputAt(1), select->GetTrueValue());
625 select->ReplaceInput(false_constant, 0);
626 select->ReplaceInput(true_constant, 1);
627 select->UpdateType();
628 inst->ReplaceWith(select);
629 inst->GetBlock()->RemoveInstruction(inst);
630 }
631 }
632
VisitShift(HBinaryOperation * instruction)633 void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
634 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
635 HInstruction* left = instruction->GetLeft();
636 if (left->IsConstant() && left->AsConstant()->IsArithmeticZero()) {
637 // Replace code looking like
638 // SHL dst, 0, shift_amount
639 // with
640 // CONSTANT 0
641 instruction->ReplaceWith(left);
642 instruction->GetBlock()->RemoveInstruction(instruction);
643 }
644 }
645
VisitEqual(HEqual * instruction)646 void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
647 if (instruction->GetLeft() == instruction->GetRight() &&
648 !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
649 // Replace code looking like
650 // EQUAL lhs, lhs
651 // CONSTANT true
652 // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
653 // opposite value.
654 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
655 instruction->GetBlock()->RemoveInstruction(instruction);
656 } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
657 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
658 // Replace code looking like
659 // EQUAL lhs, null
660 // where lhs cannot be null with
661 // CONSTANT false
662 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
663 instruction->GetBlock()->RemoveInstruction(instruction);
664 }
665 }
666
VisitNotEqual(HNotEqual * instruction)667 void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
668 if (instruction->GetLeft() == instruction->GetRight() &&
669 !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
670 // Replace code looking like
671 // NOT_EQUAL lhs, lhs
672 // CONSTANT false
673 // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
674 // opposite value.
675 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
676 instruction->GetBlock()->RemoveInstruction(instruction);
677 } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
678 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
679 // Replace code looking like
680 // NOT_EQUAL lhs, null
681 // where lhs cannot be null with
682 // CONSTANT true
683 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
684 instruction->GetBlock()->RemoveInstruction(instruction);
685 }
686 }
687
VisitAbove(HAbove * instruction)688 void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
689 if (instruction->GetLeft() == instruction->GetRight()) {
690 // Replace code looking like
691 // ABOVE lhs, lhs
692 // CONSTANT false
693 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
694 instruction->GetBlock()->RemoveInstruction(instruction);
695 } else if (instruction->GetLeft()->IsConstant() &&
696 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
697 // Replace code looking like
698 // ABOVE dst, 0, src // unsigned 0 > src is always false
699 // with
700 // CONSTANT false
701 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
702 instruction->GetBlock()->RemoveInstruction(instruction);
703 }
704 }
705
VisitAboveOrEqual(HAboveOrEqual * instruction)706 void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
707 if (instruction->GetLeft() == instruction->GetRight()) {
708 // Replace code looking like
709 // ABOVE_OR_EQUAL lhs, lhs
710 // CONSTANT true
711 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
712 instruction->GetBlock()->RemoveInstruction(instruction);
713 } else if (instruction->GetRight()->IsConstant() &&
714 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
715 // Replace code looking like
716 // ABOVE_OR_EQUAL dst, src, 0 // unsigned src >= 0 is always true
717 // with
718 // CONSTANT true
719 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
720 instruction->GetBlock()->RemoveInstruction(instruction);
721 }
722 }
723
VisitBelow(HBelow * instruction)724 void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
725 if (instruction->GetLeft() == instruction->GetRight()) {
726 // Replace code looking like
727 // BELOW lhs, lhs
728 // CONSTANT false
729 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
730 instruction->GetBlock()->RemoveInstruction(instruction);
731 } else if (instruction->GetRight()->IsConstant() &&
732 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
733 // Replace code looking like
734 // BELOW dst, src, 0 // unsigned src < 0 is always false
735 // with
736 // CONSTANT false
737 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
738 instruction->GetBlock()->RemoveInstruction(instruction);
739 }
740 }
741
VisitBelowOrEqual(HBelowOrEqual * instruction)742 void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
743 if (instruction->GetLeft() == instruction->GetRight()) {
744 // Replace code looking like
745 // BELOW_OR_EQUAL lhs, lhs
746 // CONSTANT true
747 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
748 instruction->GetBlock()->RemoveInstruction(instruction);
749 } else if (instruction->GetLeft()->IsConstant() &&
750 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
751 // Replace code looking like
752 // BELOW_OR_EQUAL dst, 0, src // unsigned 0 <= src is always true
753 // with
754 // CONSTANT true
755 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
756 instruction->GetBlock()->RemoveInstruction(instruction);
757 }
758 }
759
VisitGreaterThan(HGreaterThan * instruction)760 void InstructionWithAbsorbingInputSimplifier::VisitGreaterThan(HGreaterThan* instruction) {
761 if (instruction->GetLeft() == instruction->GetRight() &&
762 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
763 instruction->IsLtBias())) {
764 // Replace code looking like
765 // GREATER_THAN lhs, lhs
766 // CONSTANT false
767 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
768 instruction->GetBlock()->RemoveInstruction(instruction);
769 }
770 }
771
VisitGreaterThanOrEqual(HGreaterThanOrEqual * instruction)772 void InstructionWithAbsorbingInputSimplifier::VisitGreaterThanOrEqual(
773 HGreaterThanOrEqual* instruction) {
774 if (instruction->GetLeft() == instruction->GetRight() &&
775 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
776 instruction->IsGtBias())) {
777 // Replace code looking like
778 // GREATER_THAN_OR_EQUAL lhs, lhs
779 // CONSTANT true
780 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
781 instruction->GetBlock()->RemoveInstruction(instruction);
782 }
783 }
784
VisitLessThan(HLessThan * instruction)785 void InstructionWithAbsorbingInputSimplifier::VisitLessThan(HLessThan* instruction) {
786 if (instruction->GetLeft() == instruction->GetRight() &&
787 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
788 instruction->IsGtBias())) {
789 // Replace code looking like
790 // LESS_THAN lhs, lhs
791 // CONSTANT false
792 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
793 instruction->GetBlock()->RemoveInstruction(instruction);
794 }
795 }
796
VisitLessThanOrEqual(HLessThanOrEqual * instruction)797 void InstructionWithAbsorbingInputSimplifier::VisitLessThanOrEqual(HLessThanOrEqual* instruction) {
798 if (instruction->GetLeft() == instruction->GetRight() &&
799 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
800 instruction->IsLtBias())) {
801 // Replace code looking like
802 // LESS_THAN_OR_EQUAL lhs, lhs
803 // CONSTANT true
804 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
805 instruction->GetBlock()->RemoveInstruction(instruction);
806 }
807 }
808
VisitAnd(HAnd * instruction)809 void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
810 DataType::Type type = instruction->GetType();
811 HConstant* input_cst = instruction->GetConstantRight();
812 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
813 // Replace code looking like
814 // AND dst, src, 0
815 // with
816 // CONSTANT 0
817 instruction->ReplaceWith(input_cst);
818 instruction->GetBlock()->RemoveInstruction(instruction);
819 }
820
821 HInstruction* left = instruction->GetLeft();
822 HInstruction* right = instruction->GetRight();
823
824 if (left->IsNot() ^ right->IsNot()) {
825 // Replace code looking like
826 // NOT notsrc, src
827 // AND dst, notsrc, src
828 // with
829 // CONSTANT 0
830 HInstruction* hnot = (left->IsNot() ? left : right);
831 HInstruction* hother = (left->IsNot() ? right : left);
832 HInstruction* src = hnot->AsNot()->GetInput();
833
834 if (src == hother) {
835 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
836 instruction->GetBlock()->RemoveInstruction(instruction);
837 }
838 }
839 }
840
VisitCompare(HCompare * instruction)841 void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
842 HConstant* input_cst = instruction->GetConstantRight();
843 if (input_cst != nullptr) {
844 HInstruction* input_value = instruction->GetLeastConstantLeft();
845 if (DataType::IsFloatingPointType(input_value->GetType()) &&
846 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
847 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
848 // Replace code looking like
849 // CMP{G,L}-{FLOAT,DOUBLE} dst, src, NaN
850 // with
851 // CONSTANT +1 (gt bias)
852 // or
853 // CONSTANT -1 (lt bias)
854 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kInt32,
855 (instruction->IsGtBias() ? 1 : -1)));
856 instruction->GetBlock()->RemoveInstruction(instruction);
857 }
858 }
859 }
860
VisitMul(HMul * instruction)861 void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
862 HConstant* input_cst = instruction->GetConstantRight();
863 DataType::Type type = instruction->GetType();
864 if (DataType::IsIntOrLongType(type) &&
865 (input_cst != nullptr) && input_cst->IsArithmeticZero()) {
866 // Replace code looking like
867 // MUL dst, src, 0
868 // with
869 // CONSTANT 0
870 // Integral multiplication by zero always yields zero, but floating-point
871 // multiplication by zero does not always do. For example `Infinity * 0.0`
872 // should yield a NaN.
873 instruction->ReplaceWith(input_cst);
874 instruction->GetBlock()->RemoveInstruction(instruction);
875 }
876 }
877
VisitOr(HOr * instruction)878 void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
879 HConstant* input_cst = instruction->GetConstantRight();
880 if (input_cst != nullptr && Int64FromConstant(input_cst) == -1) {
881 // Replace code looking like
882 // OR dst, src, 0xFFF...FF
883 // with
884 // CONSTANT 0xFFF...FF
885 instruction->ReplaceWith(input_cst);
886 instruction->GetBlock()->RemoveInstruction(instruction);
887 return;
888 }
889
890 HInstruction* left = instruction->GetLeft();
891 HInstruction* right = instruction->GetRight();
892 if (left->IsNot() ^ right->IsNot()) {
893 // Replace code looking like
894 // NOT notsrc, src
895 // OR dst, notsrc, src
896 // with
897 // CONSTANT 0xFFF...FF
898 HInstruction* hnot = (left->IsNot() ? left : right);
899 HInstruction* hother = (left->IsNot() ? right : left);
900 HInstruction* src = hnot->AsNot()->GetInput();
901
902 if (src == hother) {
903 DCHECK(instruction->GetType() == DataType::Type::kInt32 ||
904 instruction->GetType() == DataType::Type::kInt64);
905 instruction->ReplaceWith(GetGraph()->GetConstant(instruction->GetType(), -1));
906 instruction->GetBlock()->RemoveInstruction(instruction);
907 return;
908 }
909 }
910 }
911
VisitRem(HRem * instruction)912 void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
913 DataType::Type type = instruction->GetType();
914
915 if (!DataType::IsIntegralType(type)) {
916 return;
917 }
918
919 HBasicBlock* block = instruction->GetBlock();
920
921 if (instruction->GetLeft()->IsConstant() &&
922 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
923 // Replace code looking like
924 // REM dst, 0, src
925 // with
926 // CONSTANT 0
927 instruction->ReplaceWith(instruction->GetLeft());
928 block->RemoveInstruction(instruction);
929 }
930
931 HConstant* cst_right = instruction->GetRight()->AsConstantOrNull();
932 if (((cst_right != nullptr) &&
933 (cst_right->IsOne() || cst_right->IsMinusOne())) ||
934 (instruction->GetLeft() == instruction->GetRight())) {
935 // Replace code looking like
936 // REM dst, src, 1
937 // or
938 // REM dst, src, -1
939 // or
940 // REM dst, src, src
941 // with
942 // CONSTANT 0
943 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
944 block->RemoveInstruction(instruction);
945 }
946 }
947
VisitShl(HShl * instruction)948 void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
949 VisitShift(instruction);
950 }
951
VisitShr(HShr * instruction)952 void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
953 VisitShift(instruction);
954 }
955
VisitSub(HSub * instruction)956 void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
957 DataType::Type type = instruction->GetType();
958
959 if (!DataType::IsIntegralType(type)) {
960 return;
961 }
962
963 HBasicBlock* block = instruction->GetBlock();
964
965 // We assume that GVN has run before, so we only perform a pointer
966 // comparison. If for some reason the values are equal but the pointers are
967 // different, we are still correct and only miss an optimization
968 // opportunity.
969 if (instruction->GetLeft() == instruction->GetRight()) {
970 // Replace code looking like
971 // SUB dst, src, src
972 // with
973 // CONSTANT 0
974 // Note that we cannot optimize `x - x` to `0` for floating-point. It does
975 // not work when `x` is an infinity.
976 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
977 block->RemoveInstruction(instruction);
978 }
979 }
980
VisitUShr(HUShr * instruction)981 void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
982 VisitShift(instruction);
983 }
984
VisitXor(HXor * instruction)985 void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
986 if (instruction->GetLeft() == instruction->GetRight()) {
987 // Replace code looking like
988 // XOR dst, src, src
989 // with
990 // CONSTANT 0
991 DataType::Type type = instruction->GetType();
992 HBasicBlock* block = instruction->GetBlock();
993 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
994 block->RemoveInstruction(instruction);
995 return;
996 }
997
998 HInstruction* left = instruction->GetLeft();
999 HInstruction* right = instruction->GetRight();
1000 if (left->IsNot() ^ right->IsNot()) {
1001 // Replace code looking like
1002 // NOT notsrc, src
1003 // XOR dst, notsrc, src
1004 // with
1005 // CONSTANT 0xFFF...FF
1006 HInstruction* hnot = (left->IsNot() ? left : right);
1007 HInstruction* hother = (left->IsNot() ? right : left);
1008 HInstruction* src = hnot->AsNot()->GetInput();
1009
1010 if (src == hother) {
1011 DCHECK(instruction->GetType() == DataType::Type::kInt32 ||
1012 instruction->GetType() == DataType::Type::kInt64);
1013 instruction->ReplaceWith(GetGraph()->GetConstant(instruction->GetType(), -1));
1014 instruction->GetBlock()->RemoveInstruction(instruction);
1015 return;
1016 }
1017 }
1018 }
1019
1020 } // namespace art
1021