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 "dex/dex_file-inl.h"
22 #include "optimizing/data_type.h"
23 #include "optimizing/nodes.h"
24
25 namespace art HIDDEN {
26
27 // This visitor tries to simplify instructions that can be evaluated
28 // as constants.
29 class HConstantFoldingVisitor final : public HGraphDelegateVisitor {
30 public:
HConstantFoldingVisitor(HGraph * graph,OptimizingCompilerStats * stats,bool use_all_optimizations)31 HConstantFoldingVisitor(HGraph* graph, OptimizingCompilerStats* stats, bool use_all_optimizations)
32 : HGraphDelegateVisitor(graph, stats), use_all_optimizations_(use_all_optimizations) {}
33
34 private:
35 void VisitBasicBlock(HBasicBlock* block) override;
36
37 void VisitUnaryOperation(HUnaryOperation* inst) override;
38 void VisitBinaryOperation(HBinaryOperation* inst) override;
39
40 void VisitArrayLength(HArrayLength* inst) override;
41 void VisitDivZeroCheck(HDivZeroCheck* inst) override;
42 void VisitIf(HIf* inst) override;
43 void VisitTypeConversion(HTypeConversion* inst) override;
44
45 void PropagateValue(HBasicBlock* starting_block, HInstruction* variable, HConstant* constant);
46
47 // Use all optimizations without restrictions.
48 bool use_all_optimizations_;
49
50 DISALLOW_COPY_AND_ASSIGN(HConstantFoldingVisitor);
51 };
52
53 // This visitor tries to simplify operations with an absorbing input,
54 // yielding a constant. For example `input * 0` is replaced by a
55 // null constant.
56 class InstructionWithAbsorbingInputSimplifier : public HGraphVisitor {
57 public:
InstructionWithAbsorbingInputSimplifier(HGraph * graph)58 explicit InstructionWithAbsorbingInputSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
59
60 private:
61 void VisitShift(HBinaryOperation* shift);
62
63 void VisitEqual(HEqual* instruction) override;
64 void VisitNotEqual(HNotEqual* instruction) override;
65
66 void VisitAbove(HAbove* instruction) override;
67 void VisitAboveOrEqual(HAboveOrEqual* instruction) override;
68 void VisitBelow(HBelow* instruction) override;
69 void VisitBelowOrEqual(HBelowOrEqual* instruction) override;
70
71 void VisitGreaterThan(HGreaterThan* instruction) override;
72 void VisitGreaterThanOrEqual(HGreaterThanOrEqual* instruction) override;
73 void VisitLessThan(HLessThan* instruction) override;
74 void VisitLessThanOrEqual(HLessThanOrEqual* instruction) override;
75
76 void VisitAnd(HAnd* instruction) override;
77 void VisitCompare(HCompare* instruction) override;
78 void VisitMul(HMul* instruction) override;
79 void VisitOr(HOr* instruction) override;
80 void VisitRem(HRem* instruction) override;
81 void VisitShl(HShl* instruction) override;
82 void VisitShr(HShr* instruction) override;
83 void VisitSub(HSub* instruction) override;
84 void VisitUShr(HUShr* instruction) override;
85 void VisitXor(HXor* instruction) override;
86 };
87
88
Run()89 bool HConstantFolding::Run() {
90 HConstantFoldingVisitor visitor(graph_, stats_, use_all_optimizations_);
91 // Process basic blocks in reverse post-order in the dominator tree,
92 // so that an instruction turned into a constant, used as input of
93 // another instruction, may possibly be used to turn that second
94 // instruction into a constant as well.
95 visitor.VisitReversePostOrder();
96 return true;
97 }
98
99
VisitBasicBlock(HBasicBlock * block)100 void HConstantFoldingVisitor::VisitBasicBlock(HBasicBlock* block) {
101 // Traverse this block's instructions (phis don't need to be
102 // processed) in (forward) order and replace the ones that can be
103 // statically evaluated by a compile-time counterpart.
104 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
105 it.Current()->Accept(this);
106 }
107 }
108
VisitUnaryOperation(HUnaryOperation * inst)109 void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) {
110 // Constant folding: replace `op(a)' with a constant at compile
111 // time if `a' is a constant.
112 HConstant* constant = inst->TryStaticEvaluation();
113 if (constant != nullptr) {
114 inst->ReplaceWith(constant);
115 inst->GetBlock()->RemoveInstruction(inst);
116 }
117 }
118
VisitBinaryOperation(HBinaryOperation * inst)119 void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
120 // Constant folding: replace `op(a, b)' with a constant at
121 // compile time if `a' and `b' are both constants.
122 HConstant* constant = inst->TryStaticEvaluation();
123 if (constant != nullptr) {
124 inst->ReplaceWith(constant);
125 inst->GetBlock()->RemoveInstruction(inst);
126 } else {
127 InstructionWithAbsorbingInputSimplifier simplifier(GetGraph());
128 inst->Accept(&simplifier);
129 }
130 }
131
VisitDivZeroCheck(HDivZeroCheck * inst)132 void HConstantFoldingVisitor::VisitDivZeroCheck(HDivZeroCheck* inst) {
133 // We can safely remove the check if the input is a non-null constant.
134 HInstruction* check_input = inst->InputAt(0);
135 if (check_input->IsConstant() && !check_input->AsConstant()->IsArithmeticZero()) {
136 inst->ReplaceWith(check_input);
137 inst->GetBlock()->RemoveInstruction(inst);
138 }
139 }
140
PropagateValue(HBasicBlock * starting_block,HInstruction * variable,HConstant * constant)141 void HConstantFoldingVisitor::PropagateValue(HBasicBlock* starting_block,
142 HInstruction* variable,
143 HConstant* constant) {
144 const bool recording_stats = stats_ != nullptr;
145 size_t uses_before = 0;
146 size_t uses_after = 0;
147 if (recording_stats) {
148 uses_before = variable->GetUses().SizeSlow();
149 }
150
151 if (variable->GetUses().HasExactlyOneElement()) {
152 // Nothing to do, since we only have the `if (variable)` use or the `condition` use.
153 return;
154 }
155
156 variable->ReplaceUsesDominatedBy(
157 starting_block->GetFirstInstruction(), constant, /* strictly_dominated= */ false);
158
159 if (recording_stats) {
160 uses_after = variable->GetUses().SizeSlow();
161 DCHECK_GE(uses_after, 1u) << "we must at least have the use in the if clause.";
162 DCHECK_GE(uses_before, uses_after);
163 MaybeRecordStat(stats_, MethodCompilationStat::kPropagatedIfValue, uses_before - uses_after);
164 }
165 }
166
VisitIf(HIf * inst)167 void HConstantFoldingVisitor::VisitIf(HIf* inst) {
168 // This optimization can take a lot of compile time since we have a lot of If instructions in
169 // graphs.
170 if (!use_all_optimizations_) {
171 return;
172 }
173
174 // Consistency check: the true and false successors do not dominate each other.
175 DCHECK(!inst->IfTrueSuccessor()->Dominates(inst->IfFalseSuccessor()) &&
176 !inst->IfFalseSuccessor()->Dominates(inst->IfTrueSuccessor()));
177
178 HInstruction* if_input = inst->InputAt(0);
179
180 // Already a constant.
181 if (if_input->IsConstant()) {
182 return;
183 }
184
185 // if (variable) {
186 // SSA `variable` guaranteed to be true
187 // } else {
188 // and here false
189 // }
190 PropagateValue(inst->IfTrueSuccessor(), if_input, GetGraph()->GetIntConstant(1));
191 PropagateValue(inst->IfFalseSuccessor(), if_input, GetGraph()->GetIntConstant(0));
192
193 // If the input is a condition, we can propagate the information of the condition itself.
194 if (!if_input->IsCondition()) {
195 return;
196 }
197 HCondition* condition = if_input->AsCondition();
198
199 // We want either `==` or `!=`, since we cannot make assumptions for other conditions e.g. `>`
200 if (!condition->IsEqual() && !condition->IsNotEqual()) {
201 return;
202 }
203
204 HInstruction* left = condition->GetLeft();
205 HInstruction* right = condition->GetRight();
206
207 // We want one of them to be a constant and not the other.
208 if (left->IsConstant() == right->IsConstant()) {
209 return;
210 }
211
212 // At this point we have something like:
213 // if (variable == constant) {
214 // SSA `variable` guaranteed to be equal to constant here
215 // } else {
216 // No guarantees can be made here (usually, see boolean case below).
217 // }
218 // Similarly with variable != constant, except that we can make guarantees in the else case.
219
220 HConstant* constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
221 HInstruction* variable = left->IsConstant() ? right : left;
222
223 // Don't deal with floats/doubles since they bring a lot of edge cases e.g.
224 // if (f == 0.0f) {
225 // // f is not really guaranteed to be 0.0f. It could be -0.0f, for example
226 // }
227 if (DataType::IsFloatingPointType(variable->GetType())) {
228 return;
229 }
230 DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
231
232 // Sometimes we have an HCompare flowing into an Equals/NonEquals, which can act as a proxy. For
233 // example: `Equals(Compare(var, constant), 0)`. This is common for long, float, and double.
234 if (variable->IsCompare()) {
235 // We only care about equality comparisons so we skip if it is a less or greater comparison.
236 if (!constant->IsArithmeticZero()) {
237 return;
238 }
239
240 // Update left and right to be the ones from the HCompare.
241 left = variable->AsCompare()->GetLeft();
242 right = variable->AsCompare()->GetRight();
243
244 // Re-check that one of them to be a constant and not the other.
245 if (left->IsConstant() == right->IsConstant()) {
246 return;
247 }
248
249 constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
250 variable = left->IsConstant() ? right : left;
251
252 // Re-check floating point values.
253 if (DataType::IsFloatingPointType(variable->GetType())) {
254 return;
255 }
256 DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
257 }
258
259 // From this block forward we want to replace the SSA value. We use `starting_block` and not the
260 // `if` block as we want to update one of the branches but not the other.
261 HBasicBlock* starting_block =
262 condition->IsEqual() ? inst->IfTrueSuccessor() : inst->IfFalseSuccessor();
263
264 PropagateValue(starting_block, variable, constant);
265
266 // Special case for booleans since they have only two values so we know what to propagate in the
267 // other branch. However, sometimes our boolean values are not compared to 0 or 1. In those cases
268 // we cannot make an assumption for the `else` branch.
269 if (variable->GetType() == DataType::Type::kBool &&
270 constant->IsIntConstant() &&
271 (constant->AsIntConstant()->IsTrue() || constant->AsIntConstant()->IsFalse())) {
272 HBasicBlock* other_starting_block =
273 condition->IsEqual() ? inst->IfFalseSuccessor() : inst->IfTrueSuccessor();
274 DCHECK_NE(other_starting_block, starting_block);
275
276 HConstant* other_constant = constant->AsIntConstant()->IsTrue() ?
277 GetGraph()->GetIntConstant(0) :
278 GetGraph()->GetIntConstant(1);
279 DCHECK_NE(other_constant, constant);
280 PropagateValue(other_starting_block, variable, other_constant);
281 }
282 }
283
VisitArrayLength(HArrayLength * inst)284 void HConstantFoldingVisitor::VisitArrayLength(HArrayLength* inst) {
285 HInstruction* input = inst->InputAt(0);
286 if (input->IsLoadString()) {
287 DCHECK(inst->IsStringLength());
288 HLoadString* load_string = input->AsLoadString();
289 const DexFile& dex_file = load_string->GetDexFile();
290 const dex::StringId& string_id = dex_file.GetStringId(load_string->GetStringIndex());
291 inst->ReplaceWith(GetGraph()->GetIntConstant(dex_file.GetStringLength(string_id)));
292 }
293 }
294
VisitTypeConversion(HTypeConversion * inst)295 void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
296 // Constant folding: replace `TypeConversion(a)' with a constant at
297 // compile time if `a' is a constant.
298 HConstant* constant = inst->TryStaticEvaluation();
299 if (constant != nullptr) {
300 inst->ReplaceWith(constant);
301 inst->GetBlock()->RemoveInstruction(inst);
302 }
303 }
304
VisitShift(HBinaryOperation * instruction)305 void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
306 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
307 HInstruction* left = instruction->GetLeft();
308 if (left->IsConstant() && left->AsConstant()->IsArithmeticZero()) {
309 // Replace code looking like
310 // SHL dst, 0, shift_amount
311 // with
312 // CONSTANT 0
313 instruction->ReplaceWith(left);
314 instruction->GetBlock()->RemoveInstruction(instruction);
315 }
316 }
317
VisitEqual(HEqual * instruction)318 void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
319 if (instruction->GetLeft() == instruction->GetRight() &&
320 !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
321 // Replace code looking like
322 // EQUAL lhs, lhs
323 // CONSTANT true
324 // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
325 // opposite value.
326 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
327 instruction->GetBlock()->RemoveInstruction(instruction);
328 } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
329 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
330 // Replace code looking like
331 // EQUAL lhs, null
332 // where lhs cannot be null with
333 // CONSTANT false
334 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
335 instruction->GetBlock()->RemoveInstruction(instruction);
336 }
337 }
338
VisitNotEqual(HNotEqual * instruction)339 void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
340 if (instruction->GetLeft() == instruction->GetRight() &&
341 !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
342 // Replace code looking like
343 // NOT_EQUAL lhs, lhs
344 // CONSTANT false
345 // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
346 // opposite value.
347 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
348 instruction->GetBlock()->RemoveInstruction(instruction);
349 } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
350 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
351 // Replace code looking like
352 // NOT_EQUAL lhs, null
353 // where lhs cannot be null with
354 // CONSTANT true
355 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
356 instruction->GetBlock()->RemoveInstruction(instruction);
357 }
358 }
359
VisitAbove(HAbove * instruction)360 void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
361 if (instruction->GetLeft() == instruction->GetRight()) {
362 // Replace code looking like
363 // ABOVE lhs, lhs
364 // CONSTANT false
365 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
366 instruction->GetBlock()->RemoveInstruction(instruction);
367 } else if (instruction->GetLeft()->IsConstant() &&
368 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
369 // Replace code looking like
370 // ABOVE dst, 0, src // unsigned 0 > src is always false
371 // with
372 // CONSTANT false
373 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
374 instruction->GetBlock()->RemoveInstruction(instruction);
375 }
376 }
377
VisitAboveOrEqual(HAboveOrEqual * instruction)378 void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
379 if (instruction->GetLeft() == instruction->GetRight()) {
380 // Replace code looking like
381 // ABOVE_OR_EQUAL lhs, lhs
382 // CONSTANT true
383 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
384 instruction->GetBlock()->RemoveInstruction(instruction);
385 } else if (instruction->GetRight()->IsConstant() &&
386 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
387 // Replace code looking like
388 // ABOVE_OR_EQUAL dst, src, 0 // unsigned src >= 0 is always true
389 // with
390 // CONSTANT true
391 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
392 instruction->GetBlock()->RemoveInstruction(instruction);
393 }
394 }
395
VisitBelow(HBelow * instruction)396 void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
397 if (instruction->GetLeft() == instruction->GetRight()) {
398 // Replace code looking like
399 // BELOW lhs, lhs
400 // CONSTANT false
401 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
402 instruction->GetBlock()->RemoveInstruction(instruction);
403 } else if (instruction->GetRight()->IsConstant() &&
404 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
405 // Replace code looking like
406 // BELOW dst, src, 0 // unsigned src < 0 is always false
407 // with
408 // CONSTANT false
409 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
410 instruction->GetBlock()->RemoveInstruction(instruction);
411 }
412 }
413
VisitBelowOrEqual(HBelowOrEqual * instruction)414 void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
415 if (instruction->GetLeft() == instruction->GetRight()) {
416 // Replace code looking like
417 // BELOW_OR_EQUAL lhs, lhs
418 // CONSTANT true
419 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
420 instruction->GetBlock()->RemoveInstruction(instruction);
421 } else if (instruction->GetLeft()->IsConstant() &&
422 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
423 // Replace code looking like
424 // BELOW_OR_EQUAL dst, 0, src // unsigned 0 <= src is always true
425 // with
426 // CONSTANT true
427 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
428 instruction->GetBlock()->RemoveInstruction(instruction);
429 }
430 }
431
VisitGreaterThan(HGreaterThan * instruction)432 void InstructionWithAbsorbingInputSimplifier::VisitGreaterThan(HGreaterThan* instruction) {
433 if (instruction->GetLeft() == instruction->GetRight() &&
434 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
435 instruction->IsLtBias())) {
436 // Replace code looking like
437 // GREATER_THAN lhs, lhs
438 // CONSTANT false
439 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
440 instruction->GetBlock()->RemoveInstruction(instruction);
441 }
442 }
443
VisitGreaterThanOrEqual(HGreaterThanOrEqual * instruction)444 void InstructionWithAbsorbingInputSimplifier::VisitGreaterThanOrEqual(
445 HGreaterThanOrEqual* instruction) {
446 if (instruction->GetLeft() == instruction->GetRight() &&
447 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
448 instruction->IsGtBias())) {
449 // Replace code looking like
450 // GREATER_THAN_OR_EQUAL lhs, lhs
451 // CONSTANT true
452 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
453 instruction->GetBlock()->RemoveInstruction(instruction);
454 }
455 }
456
VisitLessThan(HLessThan * instruction)457 void InstructionWithAbsorbingInputSimplifier::VisitLessThan(HLessThan* instruction) {
458 if (instruction->GetLeft() == instruction->GetRight() &&
459 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
460 instruction->IsGtBias())) {
461 // Replace code looking like
462 // LESS_THAN lhs, lhs
463 // CONSTANT false
464 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
465 instruction->GetBlock()->RemoveInstruction(instruction);
466 }
467 }
468
VisitLessThanOrEqual(HLessThanOrEqual * instruction)469 void InstructionWithAbsorbingInputSimplifier::VisitLessThanOrEqual(HLessThanOrEqual* instruction) {
470 if (instruction->GetLeft() == instruction->GetRight() &&
471 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
472 instruction->IsLtBias())) {
473 // Replace code looking like
474 // LESS_THAN_OR_EQUAL lhs, lhs
475 // CONSTANT true
476 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
477 instruction->GetBlock()->RemoveInstruction(instruction);
478 }
479 }
480
VisitAnd(HAnd * instruction)481 void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
482 DataType::Type type = instruction->GetType();
483 HConstant* input_cst = instruction->GetConstantRight();
484 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
485 // Replace code looking like
486 // AND dst, src, 0
487 // with
488 // CONSTANT 0
489 instruction->ReplaceWith(input_cst);
490 instruction->GetBlock()->RemoveInstruction(instruction);
491 }
492
493 HInstruction* left = instruction->GetLeft();
494 HInstruction* right = instruction->GetRight();
495
496 if (left->IsNot() ^ right->IsNot()) {
497 // Replace code looking like
498 // NOT notsrc, src
499 // AND dst, notsrc, src
500 // with
501 // CONSTANT 0
502 HInstruction* hnot = (left->IsNot() ? left : right);
503 HInstruction* hother = (left->IsNot() ? right : left);
504 HInstruction* src = hnot->AsNot()->GetInput();
505
506 if (src == hother) {
507 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
508 instruction->GetBlock()->RemoveInstruction(instruction);
509 }
510 }
511 }
512
VisitCompare(HCompare * instruction)513 void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
514 HConstant* input_cst = instruction->GetConstantRight();
515 if (input_cst != nullptr) {
516 HInstruction* input_value = instruction->GetLeastConstantLeft();
517 if (DataType::IsFloatingPointType(input_value->GetType()) &&
518 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
519 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
520 // Replace code looking like
521 // CMP{G,L}-{FLOAT,DOUBLE} dst, src, NaN
522 // with
523 // CONSTANT +1 (gt bias)
524 // or
525 // CONSTANT -1 (lt bias)
526 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kInt32,
527 (instruction->IsGtBias() ? 1 : -1)));
528 instruction->GetBlock()->RemoveInstruction(instruction);
529 }
530 }
531 }
532
VisitMul(HMul * instruction)533 void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
534 HConstant* input_cst = instruction->GetConstantRight();
535 DataType::Type type = instruction->GetType();
536 if (DataType::IsIntOrLongType(type) &&
537 (input_cst != nullptr) && input_cst->IsArithmeticZero()) {
538 // Replace code looking like
539 // MUL dst, src, 0
540 // with
541 // CONSTANT 0
542 // Integral multiplication by zero always yields zero, but floating-point
543 // multiplication by zero does not always do. For example `Infinity * 0.0`
544 // should yield a NaN.
545 instruction->ReplaceWith(input_cst);
546 instruction->GetBlock()->RemoveInstruction(instruction);
547 }
548 }
549
VisitOr(HOr * instruction)550 void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
551 HConstant* input_cst = instruction->GetConstantRight();
552
553 if (input_cst == nullptr) {
554 return;
555 }
556
557 if (Int64FromConstant(input_cst) == -1) {
558 // Replace code looking like
559 // OR dst, src, 0xFFF...FF
560 // with
561 // CONSTANT 0xFFF...FF
562 instruction->ReplaceWith(input_cst);
563 instruction->GetBlock()->RemoveInstruction(instruction);
564 }
565 }
566
VisitRem(HRem * instruction)567 void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
568 DataType::Type type = instruction->GetType();
569
570 if (!DataType::IsIntegralType(type)) {
571 return;
572 }
573
574 HBasicBlock* block = instruction->GetBlock();
575
576 if (instruction->GetLeft()->IsConstant() &&
577 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
578 // Replace code looking like
579 // REM dst, 0, src
580 // with
581 // CONSTANT 0
582 instruction->ReplaceWith(instruction->GetLeft());
583 block->RemoveInstruction(instruction);
584 }
585
586 HConstant* cst_right = instruction->GetRight()->AsConstant();
587 if (((cst_right != nullptr) &&
588 (cst_right->IsOne() || cst_right->IsMinusOne())) ||
589 (instruction->GetLeft() == instruction->GetRight())) {
590 // Replace code looking like
591 // REM dst, src, 1
592 // or
593 // REM dst, src, -1
594 // or
595 // REM dst, src, src
596 // with
597 // CONSTANT 0
598 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
599 block->RemoveInstruction(instruction);
600 }
601 }
602
VisitShl(HShl * instruction)603 void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
604 VisitShift(instruction);
605 }
606
VisitShr(HShr * instruction)607 void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
608 VisitShift(instruction);
609 }
610
VisitSub(HSub * instruction)611 void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
612 DataType::Type type = instruction->GetType();
613
614 if (!DataType::IsIntegralType(type)) {
615 return;
616 }
617
618 HBasicBlock* block = instruction->GetBlock();
619
620 // We assume that GVN has run before, so we only perform a pointer
621 // comparison. If for some reason the values are equal but the pointers are
622 // different, we are still correct and only miss an optimization
623 // opportunity.
624 if (instruction->GetLeft() == instruction->GetRight()) {
625 // Replace code looking like
626 // SUB dst, src, src
627 // with
628 // CONSTANT 0
629 // Note that we cannot optimize `x - x` to `0` for floating-point. It does
630 // not work when `x` is an infinity.
631 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
632 block->RemoveInstruction(instruction);
633 }
634 }
635
VisitUShr(HUShr * instruction)636 void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
637 VisitShift(instruction);
638 }
639
VisitXor(HXor * instruction)640 void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
641 if (instruction->GetLeft() == instruction->GetRight()) {
642 // Replace code looking like
643 // XOR dst, src, src
644 // with
645 // CONSTANT 0
646 DataType::Type type = instruction->GetType();
647 HBasicBlock* block = instruction->GetBlock();
648 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
649 block->RemoveInstruction(instruction);
650 }
651 }
652
653 } // namespace art
654