blob: b8ae1f63698bfb55cef07c90b595e8d81db26c47 [file] [log] [blame]
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001/*
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 "instruction_simplifier.h"
18
Calin Juravleacf735c2015-02-12 15:25:22 +000019#include "mirror/class-inl.h"
20#include "scoped_thread_state_change.h"
21
Nicolas Geoffray3c049742014-09-24 18:10:46 +010022namespace art {
23
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000024class InstructionSimplifierVisitor : public HGraphVisitor {
25 public:
Calin Juravleacf735c2015-02-12 15:25:22 +000026 InstructionSimplifierVisitor(HGraph* graph, OptimizingCompilerStats* stats)
Alexandre Rames188d4312015-04-09 18:30:21 +010027 : HGraphVisitor(graph),
28 stats_(stats) {}
29
30 void Run();
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000031
32 private:
Alexandre Rames188d4312015-04-09 18:30:21 +010033 void RecordSimplification() {
34 simplification_occurred_ = true;
35 simplifications_at_current_position_++;
36 if (stats_) {
37 stats_->RecordStat(kInstructionSimplifications);
38 }
39 }
40
41 bool TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000042 void VisitShift(HBinaryOperation* shift);
43
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000044 void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
45 void VisitEqual(HEqual* equal) OVERRIDE;
David Brazdil0d13fee2015-04-17 14:52:19 +010046 void VisitNotEqual(HNotEqual* equal) OVERRIDE;
47 void VisitBooleanNot(HBooleanNot* bool_not) OVERRIDE;
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000048 void VisitArraySet(HArraySet* equal) OVERRIDE;
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +000049 void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
Calin Juravle10e244f2015-01-26 18:54:32 +000050 void VisitNullCheck(HNullCheck* instruction) OVERRIDE;
Mingyao Yang0304e182015-01-30 16:41:29 -080051 void VisitArrayLength(HArrayLength* instruction) OVERRIDE;
Calin Juravleacf735c2015-02-12 15:25:22 +000052 void VisitCheckCast(HCheckCast* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000053 void VisitAdd(HAdd* instruction) OVERRIDE;
54 void VisitAnd(HAnd* instruction) OVERRIDE;
55 void VisitDiv(HDiv* instruction) OVERRIDE;
56 void VisitMul(HMul* instruction) OVERRIDE;
Alexandre Rames188d4312015-04-09 18:30:21 +010057 void VisitNeg(HNeg* instruction) OVERRIDE;
58 void VisitNot(HNot* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000059 void VisitOr(HOr* instruction) OVERRIDE;
60 void VisitShl(HShl* instruction) OVERRIDE;
61 void VisitShr(HShr* instruction) OVERRIDE;
62 void VisitSub(HSub* instruction) OVERRIDE;
63 void VisitUShr(HUShr* instruction) OVERRIDE;
64 void VisitXor(HXor* instruction) OVERRIDE;
Calin Juravleacf735c2015-02-12 15:25:22 +000065
66 OptimizingCompilerStats* stats_;
Alexandre Rames188d4312015-04-09 18:30:21 +010067 bool simplification_occurred_ = false;
68 int simplifications_at_current_position_ = 0;
69 // We ensure we do not loop infinitely. The value is a finger in the air guess
70 // that should allow enough simplification.
71 static constexpr int kMaxSamePositionSimplifications = 10;
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000072};
73
Nicolas Geoffray3c049742014-09-24 18:10:46 +010074void InstructionSimplifier::Run() {
Calin Juravleacf735c2015-02-12 15:25:22 +000075 InstructionSimplifierVisitor visitor(graph_, stats_);
Alexandre Rames188d4312015-04-09 18:30:21 +010076 visitor.Run();
77}
78
79void InstructionSimplifierVisitor::Run() {
80 for (HReversePostOrderIterator it(*GetGraph()); !it.Done();) {
81 // The simplification of an instruction to another instruction may yield
82 // possibilities for other simplifications. So although we perform a reverse
83 // post order visit, we sometimes need to revisit an instruction index.
84 simplification_occurred_ = false;
85 VisitBasicBlock(it.Current());
86 if (simplification_occurred_ &&
87 (simplifications_at_current_position_ < kMaxSamePositionSimplifications)) {
88 // New simplifications may be applicable to the instruction at the
89 // current index, so don't advance the iterator.
90 continue;
91 }
92 if (simplifications_at_current_position_ >= kMaxSamePositionSimplifications) {
93 LOG(WARNING) << "Too many simplifications (" << simplifications_at_current_position_
94 << ") occurred at the current position.";
95 }
96 simplifications_at_current_position_ = 0;
97 it.Advance();
98 }
Nicolas Geoffray3c049742014-09-24 18:10:46 +010099}
100
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000101namespace {
102
103bool AreAllBitsSet(HConstant* constant) {
104 return Int64FromConstant(constant) == -1;
105}
106
107} // namespace
108
Alexandre Rames188d4312015-04-09 18:30:21 +0100109// Returns true if the code was simplified to use only one negation operation
110// after the binary operation instead of one on each of the inputs.
111bool InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop) {
112 DCHECK(binop->IsAdd() || binop->IsSub());
113 DCHECK(binop->GetLeft()->IsNeg() && binop->GetRight()->IsNeg());
114 HNeg* left_neg = binop->GetLeft()->AsNeg();
115 HNeg* right_neg = binop->GetRight()->AsNeg();
116 if (!left_neg->HasOnlyOneNonEnvironmentUse() ||
117 !right_neg->HasOnlyOneNonEnvironmentUse()) {
118 return false;
119 }
120 // Replace code looking like
121 // NEG tmp1, a
122 // NEG tmp2, b
123 // ADD dst, tmp1, tmp2
124 // with
125 // ADD tmp, a, b
126 // NEG dst, tmp
127 binop->ReplaceInput(left_neg->GetInput(), 0);
128 binop->ReplaceInput(right_neg->GetInput(), 1);
129 left_neg->GetBlock()->RemoveInstruction(left_neg);
130 right_neg->GetBlock()->RemoveInstruction(right_neg);
131 HNeg* neg = new (GetGraph()->GetArena()) HNeg(binop->GetType(), binop);
132 binop->GetBlock()->InsertInstructionBefore(neg, binop->GetNext());
133 binop->ReplaceWithExceptInReplacementAtIndex(neg, 0);
134 RecordSimplification();
135 return true;
136}
137
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000138void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
139 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
140 HConstant* input_cst = instruction->GetConstantRight();
141 HInstruction* input_other = instruction->GetLeastConstantLeft();
142
143 if ((input_cst != nullptr) && input_cst->IsZero()) {
144 // Replace code looking like
145 // SHL dst, src, 0
146 // with
147 // src
148 instruction->ReplaceWith(input_other);
149 instruction->GetBlock()->RemoveInstruction(instruction);
150 }
151}
152
Calin Juravle10e244f2015-01-26 18:54:32 +0000153void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) {
154 HInstruction* obj = null_check->InputAt(0);
155 if (!obj->CanBeNull()) {
156 null_check->ReplaceWith(obj);
157 null_check->GetBlock()->RemoveInstruction(null_check);
Calin Juravleacf735c2015-02-12 15:25:22 +0000158 if (stats_ != nullptr) {
159 stats_->RecordStat(MethodCompilationStat::kRemovedNullCheck);
160 }
161 }
162}
163
164void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
165 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
166 if (!load_class->IsResolved()) {
167 // If the class couldn't be resolve it's not safe to compare against it. It's
168 // default type would be Top which might be wider that the actual class type
169 // and thus producing wrong results.
170 return;
171 }
172 ReferenceTypeInfo obj_rti = check_cast->InputAt(0)->GetReferenceTypeInfo();
173 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
174 ScopedObjectAccess soa(Thread::Current());
175 if (class_rti.IsSupertypeOf(obj_rti)) {
176 check_cast->GetBlock()->RemoveInstruction(check_cast);
177 if (stats_ != nullptr) {
178 stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
179 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000180 }
181}
182
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000183void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100184 HBasicBlock* block = check->GetBlock();
185 // Currently always keep the suspend check at entry.
186 if (block->IsEntryBlock()) return;
187
188 // Currently always keep suspend checks at loop entry.
189 if (block->IsLoopHeader() && block->GetFirstInstruction() == check) {
190 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == check);
191 return;
192 }
193
194 // Remove the suspend check that was added at build time for the baseline
195 // compiler.
196 block->RemoveInstruction(check);
197}
198
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000199void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
David Brazdil0d13fee2015-04-17 14:52:19 +0100200 HInstruction* input_const = equal->GetConstantRight();
201 if (input_const != nullptr) {
202 HInstruction* input_value = equal->GetLeastConstantLeft();
203 if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) {
204 HBasicBlock* block = equal->GetBlock();
205 if (input_const->AsIntConstant()->IsOne()) {
206 // Replace (bool_value == true) with bool_value
207 equal->ReplaceWith(input_value);
208 block->RemoveInstruction(equal);
209 RecordSimplification();
210 } else {
211 // Replace (bool_value == false) with !bool_value
212 DCHECK(input_const->AsIntConstant()->IsZero());
213 block->ReplaceAndRemoveInstructionWith(
214 equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
215 RecordSimplification();
216 }
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100217 }
218 }
219}
220
David Brazdil0d13fee2015-04-17 14:52:19 +0100221void InstructionSimplifierVisitor::VisitNotEqual(HNotEqual* not_equal) {
222 HInstruction* input_const = not_equal->GetConstantRight();
223 if (input_const != nullptr) {
224 HInstruction* input_value = not_equal->GetLeastConstantLeft();
225 if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) {
226 HBasicBlock* block = not_equal->GetBlock();
227 if (input_const->AsIntConstant()->IsOne()) {
228 // Replace (bool_value != true) with !bool_value
229 block->ReplaceAndRemoveInstructionWith(
230 not_equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
231 RecordSimplification();
232 } else {
233 // Replace (bool_value != false) with bool_value
234 DCHECK(input_const->AsIntConstant()->IsZero());
235 not_equal->ReplaceWith(input_value);
236 block->RemoveInstruction(not_equal);
237 RecordSimplification();
238 }
239 }
240 }
241}
242
243void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) {
244 HInstruction* parent = bool_not->InputAt(0);
245 if (parent->IsBooleanNot()) {
246 HInstruction* value = parent->InputAt(0);
247 // Replace (!(!bool_value)) with bool_value
248 bool_not->ReplaceWith(value);
249 bool_not->GetBlock()->RemoveInstruction(bool_not);
250 // It is possible that `parent` is dead at this point but we leave
251 // its removal to DCE for simplicity.
252 RecordSimplification();
253 }
254}
255
Mingyao Yang0304e182015-01-30 16:41:29 -0800256void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) {
257 HInstruction* input = instruction->InputAt(0);
258 // If the array is a NewArray with constant size, replace the array length
259 // with the constant instruction. This helps the bounds check elimination phase.
260 if (input->IsNewArray()) {
261 input = input->InputAt(0);
262 if (input->IsIntConstant()) {
263 instruction->ReplaceWith(input);
264 }
265 }
266}
267
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000268void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +0000269 HInstruction* value = instruction->GetValue();
270 if (value->GetType() != Primitive::kPrimNot) return;
271
272 if (value->IsArrayGet()) {
273 if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
274 // If the code is just swapping elements in the array, no need for a type check.
275 instruction->ClearNeedsTypeCheck();
276 }
277 }
278}
279
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +0000280void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
281 if (instruction->GetResultType() == instruction->GetInputType()) {
282 // Remove the instruction if it's converting to the same type.
283 instruction->ReplaceWith(instruction->GetInput());
284 instruction->GetBlock()->RemoveInstruction(instruction);
285 }
286}
287
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000288void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
289 HConstant* input_cst = instruction->GetConstantRight();
290 HInstruction* input_other = instruction->GetLeastConstantLeft();
291 if ((input_cst != nullptr) && input_cst->IsZero()) {
292 // Replace code looking like
293 // ADD dst, src, 0
294 // with
295 // src
296 instruction->ReplaceWith(input_other);
297 instruction->GetBlock()->RemoveInstruction(instruction);
Alexandre Rames188d4312015-04-09 18:30:21 +0100298 return;
299 }
300
301 HInstruction* left = instruction->GetLeft();
302 HInstruction* right = instruction->GetRight();
303 bool left_is_neg = left->IsNeg();
304 bool right_is_neg = right->IsNeg();
305
306 if (left_is_neg && right_is_neg) {
307 if (TryMoveNegOnInputsAfterBinop(instruction)) {
308 return;
309 }
310 }
311
312 HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg();
313 if ((left_is_neg ^ right_is_neg) && neg->HasOnlyOneNonEnvironmentUse()) {
314 // Replace code looking like
315 // NEG tmp, b
316 // ADD dst, a, tmp
317 // with
318 // SUB dst, a, b
319 // We do not perform the optimization if the input negation has environment
320 // uses or multiple non-environment uses as it could lead to worse code. In
321 // particular, we do not want the live range of `b` to be extended if we are
322 // not sure the initial 'NEG' instruction can be removed.
323 HInstruction* other = left_is_neg ? right : left;
324 HSub* sub = new(GetGraph()->GetArena()) HSub(instruction->GetType(), other, neg->GetInput());
325 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub);
326 RecordSimplification();
327 neg->GetBlock()->RemoveInstruction(neg);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000328 }
329}
330
331void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
332 HConstant* input_cst = instruction->GetConstantRight();
333 HInstruction* input_other = instruction->GetLeastConstantLeft();
334
335 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
336 // Replace code looking like
337 // AND dst, src, 0xFFF...FF
338 // with
339 // src
340 instruction->ReplaceWith(input_other);
341 instruction->GetBlock()->RemoveInstruction(instruction);
342 return;
343 }
344
345 // We assume that GVN has run before, so we only perform a pointer comparison.
346 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100347 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000348 if (instruction->GetLeft() == instruction->GetRight()) {
349 // Replace code looking like
350 // AND dst, src, src
351 // with
352 // src
353 instruction->ReplaceWith(instruction->GetLeft());
354 instruction->GetBlock()->RemoveInstruction(instruction);
355 }
356}
357
358void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
359 HConstant* input_cst = instruction->GetConstantRight();
360 HInstruction* input_other = instruction->GetLeastConstantLeft();
361 Primitive::Type type = instruction->GetType();
362
363 if ((input_cst != nullptr) && input_cst->IsOne()) {
364 // Replace code looking like
365 // DIV dst, src, 1
366 // with
367 // src
368 instruction->ReplaceWith(input_other);
369 instruction->GetBlock()->RemoveInstruction(instruction);
370 return;
371 }
372
373 if ((input_cst != nullptr) && input_cst->IsMinusOne() &&
374 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
375 // Replace code looking like
376 // DIV dst, src, -1
377 // with
378 // NEG dst, src
379 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
380 instruction, (new (GetGraph()->GetArena()) HNeg(type, input_other)));
Alexandre Rames188d4312015-04-09 18:30:21 +0100381 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000382 }
383}
384
385void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
386 HConstant* input_cst = instruction->GetConstantRight();
387 HInstruction* input_other = instruction->GetLeastConstantLeft();
388 Primitive::Type type = instruction->GetType();
389 HBasicBlock* block = instruction->GetBlock();
390 ArenaAllocator* allocator = GetGraph()->GetArena();
391
392 if (input_cst == nullptr) {
393 return;
394 }
395
396 if (input_cst->IsOne()) {
397 // Replace code looking like
398 // MUL dst, src, 1
399 // with
400 // src
401 instruction->ReplaceWith(input_other);
402 instruction->GetBlock()->RemoveInstruction(instruction);
403 return;
404 }
405
406 if (input_cst->IsMinusOne() &&
407 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
408 // Replace code looking like
409 // MUL dst, src, -1
410 // with
411 // NEG dst, src
412 HNeg* neg = new (allocator) HNeg(type, input_other);
413 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100414 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000415 return;
416 }
417
418 if (Primitive::IsFloatingPointType(type) &&
419 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
420 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
421 // Replace code looking like
422 // FP_MUL dst, src, 2.0
423 // with
424 // FP_ADD dst, src, src
425 // The 'int' and 'long' cases are handled below.
426 block->ReplaceAndRemoveInstructionWith(instruction,
427 new (allocator) HAdd(type, input_other, input_other));
Alexandre Rames188d4312015-04-09 18:30:21 +0100428 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000429 return;
430 }
431
432 if (Primitive::IsIntOrLongType(type)) {
433 int64_t factor = Int64FromConstant(input_cst);
434 // We expect the `0` case to have been handled in the constant folding pass.
435 DCHECK_NE(factor, 0);
436 if (IsPowerOfTwo(factor)) {
437 // Replace code looking like
438 // MUL dst, src, pow_of_2
439 // with
440 // SHL dst, src, log2(pow_of_2)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000441 HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000442 HShl* shl = new(allocator) HShl(type, input_other, shift);
443 block->ReplaceAndRemoveInstructionWith(instruction, shl);
Alexandre Rames188d4312015-04-09 18:30:21 +0100444 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000445 }
446 }
447}
448
Alexandre Rames188d4312015-04-09 18:30:21 +0100449void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) {
450 HInstruction* input = instruction->GetInput();
451 if (input->IsNeg()) {
452 // Replace code looking like
453 // NEG tmp, src
454 // NEG dst, tmp
455 // with
456 // src
457 HNeg* previous_neg = input->AsNeg();
458 instruction->ReplaceWith(previous_neg->GetInput());
459 instruction->GetBlock()->RemoveInstruction(instruction);
460 // We perform the optimization even if the input negation has environment
461 // uses since it allows removing the current instruction. But we only delete
462 // the input negation only if it is does not have any uses left.
463 if (!previous_neg->HasUses()) {
464 previous_neg->GetBlock()->RemoveInstruction(previous_neg);
465 }
466 RecordSimplification();
467 return;
468 }
469
470 if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse()) {
471 // Replace code looking like
472 // SUB tmp, a, b
473 // NEG dst, tmp
474 // with
475 // SUB dst, b, a
476 // We do not perform the optimization if the input subtraction has
477 // environment uses or multiple non-environment uses as it could lead to
478 // worse code. In particular, we do not want the live ranges of `a` and `b`
479 // to be extended if we are not sure the initial 'SUB' instruction can be
480 // removed.
481 HSub* sub = input->AsSub();
482 HSub* new_sub =
483 new (GetGraph()->GetArena()) HSub(instruction->GetType(), sub->GetRight(), sub->GetLeft());
484 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub);
485 if (!sub->HasUses()) {
486 sub->GetBlock()->RemoveInstruction(sub);
487 }
488 RecordSimplification();
489 }
490}
491
492void InstructionSimplifierVisitor::VisitNot(HNot* instruction) {
493 HInstruction* input = instruction->GetInput();
494 if (input->IsNot()) {
495 // Replace code looking like
496 // NOT tmp, src
497 // NOT dst, tmp
498 // with
499 // src
500 // We perform the optimization even if the input negation has environment
501 // uses since it allows removing the current instruction. But we only delete
502 // the input negation only if it is does not have any uses left.
503 HNot* previous_not = input->AsNot();
504 instruction->ReplaceWith(previous_not->GetInput());
505 instruction->GetBlock()->RemoveInstruction(instruction);
506 if (!previous_not->HasUses()) {
507 previous_not->GetBlock()->RemoveInstruction(previous_not);
508 }
509 RecordSimplification();
510 }
511}
512
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000513void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
514 HConstant* input_cst = instruction->GetConstantRight();
515 HInstruction* input_other = instruction->GetLeastConstantLeft();
516
517 if ((input_cst != nullptr) && input_cst->IsZero()) {
518 // Replace code looking like
519 // OR dst, src, 0
520 // with
521 // src
522 instruction->ReplaceWith(input_other);
523 instruction->GetBlock()->RemoveInstruction(instruction);
524 return;
525 }
526
527 // We assume that GVN has run before, so we only perform a pointer comparison.
528 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100529 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000530 if (instruction->GetLeft() == instruction->GetRight()) {
531 // Replace code looking like
532 // OR dst, src, src
533 // with
534 // src
535 instruction->ReplaceWith(instruction->GetLeft());
536 instruction->GetBlock()->RemoveInstruction(instruction);
537 }
538}
539
540void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
541 VisitShift(instruction);
542}
543
544void InstructionSimplifierVisitor::VisitShr(HShr* instruction) {
545 VisitShift(instruction);
546}
547
548void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
549 HConstant* input_cst = instruction->GetConstantRight();
550 HInstruction* input_other = instruction->GetLeastConstantLeft();
551
552 if ((input_cst != nullptr) && input_cst->IsZero()) {
553 // Replace code looking like
554 // SUB dst, src, 0
555 // with
556 // src
557 instruction->ReplaceWith(input_other);
558 instruction->GetBlock()->RemoveInstruction(instruction);
559 return;
560 }
561
562 Primitive::Type type = instruction->GetType();
563 if (!Primitive::IsIntegralType(type)) {
564 return;
565 }
566
567 HBasicBlock* block = instruction->GetBlock();
568 ArenaAllocator* allocator = GetGraph()->GetArena();
569
Alexandre Rames188d4312015-04-09 18:30:21 +0100570 HInstruction* left = instruction->GetLeft();
571 HInstruction* right = instruction->GetRight();
572 if (left->IsConstant()) {
573 if (Int64FromConstant(left->AsConstant()) == 0) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000574 // Replace code looking like
575 // SUB dst, 0, src
576 // with
577 // NEG dst, src
Alexandre Rames188d4312015-04-09 18:30:21 +0100578 // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000579 // `x` is `0.0`, the former expression yields `0.0`, while the later
580 // yields `-0.0`.
Alexandre Rames188d4312015-04-09 18:30:21 +0100581 HNeg* neg = new (allocator) HNeg(type, right);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000582 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100583 RecordSimplification();
584 return;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000585 }
586 }
Alexandre Rames188d4312015-04-09 18:30:21 +0100587
588 if (left->IsNeg() && right->IsNeg()) {
589 if (TryMoveNegOnInputsAfterBinop(instruction)) {
590 return;
591 }
592 }
593
594 if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) {
595 // Replace code looking like
596 // NEG tmp, b
597 // SUB dst, a, tmp
598 // with
599 // ADD dst, a, b
600 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left, right->AsNeg()->GetInput());
601 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add);
602 RecordSimplification();
603 right->GetBlock()->RemoveInstruction(right);
604 return;
605 }
606
607 if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) {
608 // Replace code looking like
609 // NEG tmp, a
610 // SUB dst, tmp, b
611 // with
612 // ADD tmp, a, b
613 // NEG dst, tmp
614 // The second version is not intrinsically better, but enables more
615 // transformations.
616 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left->AsNeg()->GetInput(), right);
617 instruction->GetBlock()->InsertInstructionBefore(add, instruction);
618 HNeg* neg = new (GetGraph()->GetArena()) HNeg(instruction->GetType(), add);
619 instruction->GetBlock()->InsertInstructionBefore(neg, instruction);
620 instruction->ReplaceWith(neg);
621 instruction->GetBlock()->RemoveInstruction(instruction);
622 RecordSimplification();
623 left->GetBlock()->RemoveInstruction(left);
624 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000625}
626
627void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
628 VisitShift(instruction);
629}
630
631void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
632 HConstant* input_cst = instruction->GetConstantRight();
633 HInstruction* input_other = instruction->GetLeastConstantLeft();
634
635 if ((input_cst != nullptr) && input_cst->IsZero()) {
636 // Replace code looking like
637 // XOR dst, src, 0
638 // with
639 // src
640 instruction->ReplaceWith(input_other);
641 instruction->GetBlock()->RemoveInstruction(instruction);
642 return;
643 }
644
645 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
646 // Replace code looking like
647 // XOR dst, src, 0xFFF...FF
648 // with
649 // NOT dst, src
650 HNot* bitwise_not = new (GetGraph()->GetArena()) HNot(instruction->GetType(), input_other);
651 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not);
Alexandre Rames188d4312015-04-09 18:30:21 +0100652 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000653 return;
654 }
655}
656
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100657} // namespace art