blob: 0013b72c43dff1b5b308055f1f12e13dbb9f2fb1 [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);
Mark Mendellb0bd8912015-04-15 19:57:22 -040042 bool IsExactFPPowerOfTwo(HConstant* constant);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000043 void VisitShift(HBinaryOperation* shift);
44
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000045 void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
46 void VisitEqual(HEqual* equal) OVERRIDE;
David Brazdil0d13fee2015-04-17 14:52:19 +010047 void VisitNotEqual(HNotEqual* equal) OVERRIDE;
48 void VisitBooleanNot(HBooleanNot* bool_not) OVERRIDE;
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000049 void VisitArraySet(HArraySet* equal) OVERRIDE;
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +000050 void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
Calin Juravle10e244f2015-01-26 18:54:32 +000051 void VisitNullCheck(HNullCheck* instruction) OVERRIDE;
Mingyao Yang0304e182015-01-30 16:41:29 -080052 void VisitArrayLength(HArrayLength* instruction) OVERRIDE;
Calin Juravleacf735c2015-02-12 15:25:22 +000053 void VisitCheckCast(HCheckCast* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000054 void VisitAdd(HAdd* instruction) OVERRIDE;
55 void VisitAnd(HAnd* instruction) OVERRIDE;
56 void VisitDiv(HDiv* instruction) OVERRIDE;
57 void VisitMul(HMul* instruction) OVERRIDE;
Alexandre Rames188d4312015-04-09 18:30:21 +010058 void VisitNeg(HNeg* instruction) OVERRIDE;
59 void VisitNot(HNot* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000060 void VisitOr(HOr* instruction) OVERRIDE;
61 void VisitShl(HShl* instruction) OVERRIDE;
62 void VisitShr(HShr* instruction) OVERRIDE;
63 void VisitSub(HSub* instruction) OVERRIDE;
64 void VisitUShr(HUShr* instruction) OVERRIDE;
65 void VisitXor(HXor* instruction) OVERRIDE;
Calin Juravleacf735c2015-02-12 15:25:22 +000066
67 OptimizingCompilerStats* stats_;
Alexandre Rames188d4312015-04-09 18:30:21 +010068 bool simplification_occurred_ = false;
69 int simplifications_at_current_position_ = 0;
70 // We ensure we do not loop infinitely. The value is a finger in the air guess
71 // that should allow enough simplification.
72 static constexpr int kMaxSamePositionSimplifications = 10;
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000073};
74
Nicolas Geoffray3c049742014-09-24 18:10:46 +010075void InstructionSimplifier::Run() {
Calin Juravleacf735c2015-02-12 15:25:22 +000076 InstructionSimplifierVisitor visitor(graph_, stats_);
Alexandre Rames188d4312015-04-09 18:30:21 +010077 visitor.Run();
78}
79
80void InstructionSimplifierVisitor::Run() {
81 for (HReversePostOrderIterator it(*GetGraph()); !it.Done();) {
82 // The simplification of an instruction to another instruction may yield
83 // possibilities for other simplifications. So although we perform a reverse
84 // post order visit, we sometimes need to revisit an instruction index.
85 simplification_occurred_ = false;
86 VisitBasicBlock(it.Current());
87 if (simplification_occurred_ &&
88 (simplifications_at_current_position_ < kMaxSamePositionSimplifications)) {
89 // New simplifications may be applicable to the instruction at the
90 // current index, so don't advance the iterator.
91 continue;
92 }
93 if (simplifications_at_current_position_ >= kMaxSamePositionSimplifications) {
94 LOG(WARNING) << "Too many simplifications (" << simplifications_at_current_position_
95 << ") occurred at the current position.";
96 }
97 simplifications_at_current_position_ = 0;
98 it.Advance();
99 }
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100100}
101
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000102namespace {
103
104bool AreAllBitsSet(HConstant* constant) {
105 return Int64FromConstant(constant) == -1;
106}
107
108} // namespace
109
Alexandre Rames188d4312015-04-09 18:30:21 +0100110// Returns true if the code was simplified to use only one negation operation
111// after the binary operation instead of one on each of the inputs.
112bool InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop) {
113 DCHECK(binop->IsAdd() || binop->IsSub());
114 DCHECK(binop->GetLeft()->IsNeg() && binop->GetRight()->IsNeg());
115 HNeg* left_neg = binop->GetLeft()->AsNeg();
116 HNeg* right_neg = binop->GetRight()->AsNeg();
117 if (!left_neg->HasOnlyOneNonEnvironmentUse() ||
118 !right_neg->HasOnlyOneNonEnvironmentUse()) {
119 return false;
120 }
121 // Replace code looking like
122 // NEG tmp1, a
123 // NEG tmp2, b
124 // ADD dst, tmp1, tmp2
125 // with
126 // ADD tmp, a, b
127 // NEG dst, tmp
128 binop->ReplaceInput(left_neg->GetInput(), 0);
129 binop->ReplaceInput(right_neg->GetInput(), 1);
130 left_neg->GetBlock()->RemoveInstruction(left_neg);
131 right_neg->GetBlock()->RemoveInstruction(right_neg);
132 HNeg* neg = new (GetGraph()->GetArena()) HNeg(binop->GetType(), binop);
133 binop->GetBlock()->InsertInstructionBefore(neg, binop->GetNext());
134 binop->ReplaceWithExceptInReplacementAtIndex(neg, 0);
135 RecordSimplification();
136 return true;
137}
138
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000139void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
140 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
141 HConstant* input_cst = instruction->GetConstantRight();
142 HInstruction* input_other = instruction->GetLeastConstantLeft();
143
144 if ((input_cst != nullptr) && input_cst->IsZero()) {
145 // Replace code looking like
146 // SHL dst, src, 0
147 // with
148 // src
149 instruction->ReplaceWith(input_other);
150 instruction->GetBlock()->RemoveInstruction(instruction);
151 }
152}
153
Calin Juravle10e244f2015-01-26 18:54:32 +0000154void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) {
155 HInstruction* obj = null_check->InputAt(0);
156 if (!obj->CanBeNull()) {
157 null_check->ReplaceWith(obj);
158 null_check->GetBlock()->RemoveInstruction(null_check);
Calin Juravleacf735c2015-02-12 15:25:22 +0000159 if (stats_ != nullptr) {
160 stats_->RecordStat(MethodCompilationStat::kRemovedNullCheck);
161 }
162 }
163}
164
165void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
166 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
167 if (!load_class->IsResolved()) {
168 // If the class couldn't be resolve it's not safe to compare against it. It's
169 // default type would be Top which might be wider that the actual class type
170 // and thus producing wrong results.
171 return;
172 }
173 ReferenceTypeInfo obj_rti = check_cast->InputAt(0)->GetReferenceTypeInfo();
174 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
175 ScopedObjectAccess soa(Thread::Current());
176 if (class_rti.IsSupertypeOf(obj_rti)) {
177 check_cast->GetBlock()->RemoveInstruction(check_cast);
178 if (stats_ != nullptr) {
179 stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
180 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000181 }
182}
183
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000184void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100185 HBasicBlock* block = check->GetBlock();
186 // Currently always keep the suspend check at entry.
187 if (block->IsEntryBlock()) return;
188
189 // Currently always keep suspend checks at loop entry.
190 if (block->IsLoopHeader() && block->GetFirstInstruction() == check) {
191 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == check);
192 return;
193 }
194
195 // Remove the suspend check that was added at build time for the baseline
196 // compiler.
197 block->RemoveInstruction(check);
198}
199
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000200void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
David Brazdil0d13fee2015-04-17 14:52:19 +0100201 HInstruction* input_const = equal->GetConstantRight();
202 if (input_const != nullptr) {
203 HInstruction* input_value = equal->GetLeastConstantLeft();
204 if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) {
205 HBasicBlock* block = equal->GetBlock();
206 if (input_const->AsIntConstant()->IsOne()) {
207 // Replace (bool_value == true) with bool_value
208 equal->ReplaceWith(input_value);
209 block->RemoveInstruction(equal);
210 RecordSimplification();
211 } else {
212 // Replace (bool_value == false) with !bool_value
213 DCHECK(input_const->AsIntConstant()->IsZero());
214 block->ReplaceAndRemoveInstructionWith(
215 equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
216 RecordSimplification();
217 }
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100218 }
219 }
220}
221
David Brazdil0d13fee2015-04-17 14:52:19 +0100222void InstructionSimplifierVisitor::VisitNotEqual(HNotEqual* not_equal) {
223 HInstruction* input_const = not_equal->GetConstantRight();
224 if (input_const != nullptr) {
225 HInstruction* input_value = not_equal->GetLeastConstantLeft();
226 if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) {
227 HBasicBlock* block = not_equal->GetBlock();
228 if (input_const->AsIntConstant()->IsOne()) {
229 // Replace (bool_value != true) with !bool_value
230 block->ReplaceAndRemoveInstructionWith(
231 not_equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
232 RecordSimplification();
233 } else {
234 // Replace (bool_value != false) with bool_value
235 DCHECK(input_const->AsIntConstant()->IsZero());
236 not_equal->ReplaceWith(input_value);
237 block->RemoveInstruction(not_equal);
238 RecordSimplification();
239 }
240 }
241 }
242}
243
244void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) {
245 HInstruction* parent = bool_not->InputAt(0);
246 if (parent->IsBooleanNot()) {
247 HInstruction* value = parent->InputAt(0);
248 // Replace (!(!bool_value)) with bool_value
249 bool_not->ReplaceWith(value);
250 bool_not->GetBlock()->RemoveInstruction(bool_not);
251 // It is possible that `parent` is dead at this point but we leave
252 // its removal to DCE for simplicity.
253 RecordSimplification();
254 }
255}
256
Mingyao Yang0304e182015-01-30 16:41:29 -0800257void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) {
258 HInstruction* input = instruction->InputAt(0);
259 // If the array is a NewArray with constant size, replace the array length
260 // with the constant instruction. This helps the bounds check elimination phase.
261 if (input->IsNewArray()) {
262 input = input->InputAt(0);
263 if (input->IsIntConstant()) {
264 instruction->ReplaceWith(input);
265 }
266 }
267}
268
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000269void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +0000270 HInstruction* value = instruction->GetValue();
271 if (value->GetType() != Primitive::kPrimNot) return;
272
273 if (value->IsArrayGet()) {
274 if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
275 // If the code is just swapping elements in the array, no need for a type check.
276 instruction->ClearNeedsTypeCheck();
277 }
278 }
279}
280
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +0000281void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
282 if (instruction->GetResultType() == instruction->GetInputType()) {
283 // Remove the instruction if it's converting to the same type.
284 instruction->ReplaceWith(instruction->GetInput());
285 instruction->GetBlock()->RemoveInstruction(instruction);
286 }
287}
288
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000289void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
290 HConstant* input_cst = instruction->GetConstantRight();
291 HInstruction* input_other = instruction->GetLeastConstantLeft();
292 if ((input_cst != nullptr) && input_cst->IsZero()) {
293 // Replace code looking like
294 // ADD dst, src, 0
295 // with
296 // src
297 instruction->ReplaceWith(input_other);
298 instruction->GetBlock()->RemoveInstruction(instruction);
Alexandre Rames188d4312015-04-09 18:30:21 +0100299 return;
300 }
301
302 HInstruction* left = instruction->GetLeft();
303 HInstruction* right = instruction->GetRight();
304 bool left_is_neg = left->IsNeg();
305 bool right_is_neg = right->IsNeg();
306
307 if (left_is_neg && right_is_neg) {
308 if (TryMoveNegOnInputsAfterBinop(instruction)) {
309 return;
310 }
311 }
312
313 HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg();
314 if ((left_is_neg ^ right_is_neg) && neg->HasOnlyOneNonEnvironmentUse()) {
315 // Replace code looking like
316 // NEG tmp, b
317 // ADD dst, a, tmp
318 // with
319 // SUB dst, a, b
320 // We do not perform the optimization if the input negation has environment
321 // uses or multiple non-environment uses as it could lead to worse code. In
322 // particular, we do not want the live range of `b` to be extended if we are
323 // not sure the initial 'NEG' instruction can be removed.
324 HInstruction* other = left_is_neg ? right : left;
325 HSub* sub = new(GetGraph()->GetArena()) HSub(instruction->GetType(), other, neg->GetInput());
326 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub);
327 RecordSimplification();
328 neg->GetBlock()->RemoveInstruction(neg);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000329 }
330}
331
332void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
333 HConstant* input_cst = instruction->GetConstantRight();
334 HInstruction* input_other = instruction->GetLeastConstantLeft();
335
336 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
337 // Replace code looking like
338 // AND dst, src, 0xFFF...FF
339 // with
340 // src
341 instruction->ReplaceWith(input_other);
342 instruction->GetBlock()->RemoveInstruction(instruction);
343 return;
344 }
345
346 // We assume that GVN has run before, so we only perform a pointer comparison.
347 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100348 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000349 if (instruction->GetLeft() == instruction->GetRight()) {
350 // Replace code looking like
351 // AND dst, src, src
352 // with
353 // src
354 instruction->ReplaceWith(instruction->GetLeft());
355 instruction->GetBlock()->RemoveInstruction(instruction);
356 }
357}
358
359void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
360 HConstant* input_cst = instruction->GetConstantRight();
361 HInstruction* input_other = instruction->GetLeastConstantLeft();
362 Primitive::Type type = instruction->GetType();
363
364 if ((input_cst != nullptr) && input_cst->IsOne()) {
365 // Replace code looking like
366 // DIV dst, src, 1
367 // with
368 // src
369 instruction->ReplaceWith(input_other);
370 instruction->GetBlock()->RemoveInstruction(instruction);
371 return;
372 }
373
374 if ((input_cst != nullptr) && input_cst->IsMinusOne() &&
375 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
376 // Replace code looking like
377 // DIV dst, src, -1
378 // with
379 // NEG dst, src
380 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
381 instruction, (new (GetGraph()->GetArena()) HNeg(type, input_other)));
Alexandre Rames188d4312015-04-09 18:30:21 +0100382 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000383 }
Mark Mendellb0bd8912015-04-15 19:57:22 -0400384
385 // FP Handle division by powers of 2.
386 if ((input_cst != nullptr) && Primitive::IsFloatingPointType(type) &&
387 IsExactFPPowerOfTwo(input_cst)) {
388 // We can replace this by a multiplication by the reciprocal.
389 // We know that since the value is an exact power of 2, there is no precision lost.
390 HConstant *recip;
391 if (type == Primitive::Primitive::kPrimDouble) {
392 double recip_value = 1.0 / input_cst->AsDoubleConstant()->GetValue();
393 recip = GetGraph()->GetDoubleConstant(recip_value);
394 } else {
395 DCHECK_EQ(type, Primitive::kPrimFloat);
396 float recip_value = 1.0f / input_cst->AsFloatConstant()->GetValue();
397 recip = GetGraph()->GetFloatConstant(recip_value);
398 }
399 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
400 instruction, (new (GetGraph()->GetArena()) HMul(type, input_other, recip)));
401 RecordSimplification();
402 }
403}
404
405
406bool InstructionSimplifierVisitor::IsExactFPPowerOfTwo(HConstant* constant) {
407 if (constant->IsDoubleConstant()) {
408 // We will examine the value as an unsigned value.
409 uint64_t value = bit_cast<uint64_t, double>(constant->AsDoubleConstant()->GetValue());
410
411 // Make sure the double constant is power of 2.0, so that we can have the
412 // exact result after converting value to 1.0/value.
413 // The uint64_t value is 0 from bit 51 to bit 0.
414 if ((value & INT64_C(0x000FFFFFFFFFFFFF)) != 0) {
415 return false;
416 }
417
418 // For the double constant, we support the range 2.0^-1022 to 2.0^1022
419 // or -(2.0^-1022) to -(2.0^1022)
420 // The uint64_t value is from 0x0010000000000000 to 0x7FD0000000000000 or
421 // from 0x8010000000000000 to 0xFFD0000000000000.
422 if ((value < INT64_C(0x0010000000000000) || value > INT64_C(0x7FD0000000000000)) &&
423 (value < INT64_C(0x8010000000000000) || value > INT64_C(0xFFD0000000000000))) {
424 return false;
425 }
426 } else {
427 DCHECK(constant->IsFloatConstant());
428 // We will examine the value as an unsigned value.
429 uint32_t value = bit_cast<uint32_t, float>(constant->AsFloatConstant()->GetValue());
430
431 // Make sure the float constant is power of 2.0, so that we can have the
432 // exact result after converting value to 1.0/value.
433 // The uint32_t value is 0 from bit 22 to bit 0.
434 if ((value & 0x007FFFFF) != 0) {
435 return false;
436 }
437
438 // For the float constant, we support the range 2.0^-126 to 2.0^126
439 // or -(2.0^-126) to -(2.0^126)
440 // The uint32_t value is from 0x00800000 to 0x7E800000 or
441 // from 0x80800000 to 0xFE800000.
442 if ((value < 0x00800000 || value > 0x7E800000) &&
443 (value < 0x80800000 || value > 0xFE800000)) {
444 return false;
445 }
446 }
447
448 // This is a proper FP power of two.
449 return true;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000450}
451
452void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
453 HConstant* input_cst = instruction->GetConstantRight();
454 HInstruction* input_other = instruction->GetLeastConstantLeft();
455 Primitive::Type type = instruction->GetType();
456 HBasicBlock* block = instruction->GetBlock();
457 ArenaAllocator* allocator = GetGraph()->GetArena();
458
459 if (input_cst == nullptr) {
460 return;
461 }
462
463 if (input_cst->IsOne()) {
464 // Replace code looking like
465 // MUL dst, src, 1
466 // with
467 // src
468 instruction->ReplaceWith(input_other);
469 instruction->GetBlock()->RemoveInstruction(instruction);
470 return;
471 }
472
473 if (input_cst->IsMinusOne() &&
474 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
475 // Replace code looking like
476 // MUL dst, src, -1
477 // with
478 // NEG dst, src
479 HNeg* neg = new (allocator) HNeg(type, input_other);
480 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100481 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000482 return;
483 }
484
485 if (Primitive::IsFloatingPointType(type) &&
486 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
487 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
488 // Replace code looking like
489 // FP_MUL dst, src, 2.0
490 // with
491 // FP_ADD dst, src, src
492 // The 'int' and 'long' cases are handled below.
493 block->ReplaceAndRemoveInstructionWith(instruction,
494 new (allocator) HAdd(type, input_other, input_other));
Alexandre Rames188d4312015-04-09 18:30:21 +0100495 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000496 return;
497 }
498
499 if (Primitive::IsIntOrLongType(type)) {
500 int64_t factor = Int64FromConstant(input_cst);
501 // We expect the `0` case to have been handled in the constant folding pass.
502 DCHECK_NE(factor, 0);
503 if (IsPowerOfTwo(factor)) {
504 // Replace code looking like
505 // MUL dst, src, pow_of_2
506 // with
507 // SHL dst, src, log2(pow_of_2)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000508 HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000509 HShl* shl = new(allocator) HShl(type, input_other, shift);
510 block->ReplaceAndRemoveInstructionWith(instruction, shl);
Alexandre Rames188d4312015-04-09 18:30:21 +0100511 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000512 }
513 }
514}
515
Alexandre Rames188d4312015-04-09 18:30:21 +0100516void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) {
517 HInstruction* input = instruction->GetInput();
518 if (input->IsNeg()) {
519 // Replace code looking like
520 // NEG tmp, src
521 // NEG dst, tmp
522 // with
523 // src
524 HNeg* previous_neg = input->AsNeg();
525 instruction->ReplaceWith(previous_neg->GetInput());
526 instruction->GetBlock()->RemoveInstruction(instruction);
527 // We perform the optimization even if the input negation has environment
528 // uses since it allows removing the current instruction. But we only delete
529 // the input negation only if it is does not have any uses left.
530 if (!previous_neg->HasUses()) {
531 previous_neg->GetBlock()->RemoveInstruction(previous_neg);
532 }
533 RecordSimplification();
534 return;
535 }
536
537 if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse()) {
538 // Replace code looking like
539 // SUB tmp, a, b
540 // NEG dst, tmp
541 // with
542 // SUB dst, b, a
543 // We do not perform the optimization if the input subtraction has
544 // environment uses or multiple non-environment uses as it could lead to
545 // worse code. In particular, we do not want the live ranges of `a` and `b`
546 // to be extended if we are not sure the initial 'SUB' instruction can be
547 // removed.
548 HSub* sub = input->AsSub();
549 HSub* new_sub =
550 new (GetGraph()->GetArena()) HSub(instruction->GetType(), sub->GetRight(), sub->GetLeft());
551 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub);
552 if (!sub->HasUses()) {
553 sub->GetBlock()->RemoveInstruction(sub);
554 }
555 RecordSimplification();
556 }
557}
558
559void InstructionSimplifierVisitor::VisitNot(HNot* instruction) {
560 HInstruction* input = instruction->GetInput();
561 if (input->IsNot()) {
562 // Replace code looking like
563 // NOT tmp, src
564 // NOT dst, tmp
565 // with
566 // src
567 // We perform the optimization even if the input negation has environment
568 // uses since it allows removing the current instruction. But we only delete
569 // the input negation only if it is does not have any uses left.
570 HNot* previous_not = input->AsNot();
571 instruction->ReplaceWith(previous_not->GetInput());
572 instruction->GetBlock()->RemoveInstruction(instruction);
573 if (!previous_not->HasUses()) {
574 previous_not->GetBlock()->RemoveInstruction(previous_not);
575 }
576 RecordSimplification();
577 }
578}
579
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000580void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
581 HConstant* input_cst = instruction->GetConstantRight();
582 HInstruction* input_other = instruction->GetLeastConstantLeft();
583
584 if ((input_cst != nullptr) && input_cst->IsZero()) {
585 // Replace code looking like
586 // OR dst, src, 0
587 // with
588 // src
589 instruction->ReplaceWith(input_other);
590 instruction->GetBlock()->RemoveInstruction(instruction);
591 return;
592 }
593
594 // We assume that GVN has run before, so we only perform a pointer comparison.
595 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100596 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000597 if (instruction->GetLeft() == instruction->GetRight()) {
598 // Replace code looking like
599 // OR dst, src, src
600 // with
601 // src
602 instruction->ReplaceWith(instruction->GetLeft());
603 instruction->GetBlock()->RemoveInstruction(instruction);
604 }
605}
606
607void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
608 VisitShift(instruction);
609}
610
611void InstructionSimplifierVisitor::VisitShr(HShr* instruction) {
612 VisitShift(instruction);
613}
614
615void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
616 HConstant* input_cst = instruction->GetConstantRight();
617 HInstruction* input_other = instruction->GetLeastConstantLeft();
618
619 if ((input_cst != nullptr) && input_cst->IsZero()) {
620 // Replace code looking like
621 // SUB dst, src, 0
622 // with
623 // src
624 instruction->ReplaceWith(input_other);
625 instruction->GetBlock()->RemoveInstruction(instruction);
626 return;
627 }
628
629 Primitive::Type type = instruction->GetType();
630 if (!Primitive::IsIntegralType(type)) {
631 return;
632 }
633
634 HBasicBlock* block = instruction->GetBlock();
635 ArenaAllocator* allocator = GetGraph()->GetArena();
636
Alexandre Rames188d4312015-04-09 18:30:21 +0100637 HInstruction* left = instruction->GetLeft();
638 HInstruction* right = instruction->GetRight();
639 if (left->IsConstant()) {
640 if (Int64FromConstant(left->AsConstant()) == 0) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000641 // Replace code looking like
642 // SUB dst, 0, src
643 // with
644 // NEG dst, src
Alexandre Rames188d4312015-04-09 18:30:21 +0100645 // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000646 // `x` is `0.0`, the former expression yields `0.0`, while the later
647 // yields `-0.0`.
Alexandre Rames188d4312015-04-09 18:30:21 +0100648 HNeg* neg = new (allocator) HNeg(type, right);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000649 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100650 RecordSimplification();
651 return;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000652 }
653 }
Alexandre Rames188d4312015-04-09 18:30:21 +0100654
655 if (left->IsNeg() && right->IsNeg()) {
656 if (TryMoveNegOnInputsAfterBinop(instruction)) {
657 return;
658 }
659 }
660
661 if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) {
662 // Replace code looking like
663 // NEG tmp, b
664 // SUB dst, a, tmp
665 // with
666 // ADD dst, a, b
667 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left, right->AsNeg()->GetInput());
668 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add);
669 RecordSimplification();
670 right->GetBlock()->RemoveInstruction(right);
671 return;
672 }
673
674 if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) {
675 // Replace code looking like
676 // NEG tmp, a
677 // SUB dst, tmp, b
678 // with
679 // ADD tmp, a, b
680 // NEG dst, tmp
681 // The second version is not intrinsically better, but enables more
682 // transformations.
683 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left->AsNeg()->GetInput(), right);
684 instruction->GetBlock()->InsertInstructionBefore(add, instruction);
685 HNeg* neg = new (GetGraph()->GetArena()) HNeg(instruction->GetType(), add);
686 instruction->GetBlock()->InsertInstructionBefore(neg, instruction);
687 instruction->ReplaceWith(neg);
688 instruction->GetBlock()->RemoveInstruction(instruction);
689 RecordSimplification();
690 left->GetBlock()->RemoveInstruction(left);
691 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000692}
693
694void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
695 VisitShift(instruction);
696}
697
698void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
699 HConstant* input_cst = instruction->GetConstantRight();
700 HInstruction* input_other = instruction->GetLeastConstantLeft();
701
702 if ((input_cst != nullptr) && input_cst->IsZero()) {
703 // Replace code looking like
704 // XOR dst, src, 0
705 // with
706 // src
707 instruction->ReplaceWith(input_other);
708 instruction->GetBlock()->RemoveInstruction(instruction);
709 return;
710 }
711
712 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
713 // Replace code looking like
714 // XOR dst, src, 0xFFF...FF
715 // with
716 // NOT dst, src
717 HNot* bitwise_not = new (GetGraph()->GetArena()) HNot(instruction->GetType(), input_other);
718 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not);
Alexandre Rames188d4312015-04-09 18:30:21 +0100719 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000720 return;
721 }
722}
723
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100724} // namespace art