blob: 3287a0a119c7306d3b27bb58ac3e467c9079d3a3 [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 Geoffray07276db2015-05-18 14:22:09 +010048 void VisitInstanceFieldSet(HInstanceFieldSet* equal) OVERRIDE;
49 void VisitStaticFieldSet(HStaticFieldSet* equal) OVERRIDE;
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000050 void VisitArraySet(HArraySet* equal) OVERRIDE;
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +000051 void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
Calin Juravle10e244f2015-01-26 18:54:32 +000052 void VisitNullCheck(HNullCheck* instruction) OVERRIDE;
Mingyao Yang0304e182015-01-30 16:41:29 -080053 void VisitArrayLength(HArrayLength* instruction) OVERRIDE;
Calin Juravleacf735c2015-02-12 15:25:22 +000054 void VisitCheckCast(HCheckCast* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000055 void VisitAdd(HAdd* instruction) OVERRIDE;
56 void VisitAnd(HAnd* instruction) OVERRIDE;
Mark Mendellc4701932015-04-10 13:18:51 -040057 void VisitCondition(HCondition* instruction) OVERRIDE;
58 void VisitGreaterThan(HGreaterThan* condition) OVERRIDE;
59 void VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) OVERRIDE;
60 void VisitLessThan(HLessThan* condition) OVERRIDE;
61 void VisitLessThanOrEqual(HLessThanOrEqual* condition) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000062 void VisitDiv(HDiv* instruction) OVERRIDE;
63 void VisitMul(HMul* instruction) OVERRIDE;
Alexandre Rames188d4312015-04-09 18:30:21 +010064 void VisitNeg(HNeg* instruction) OVERRIDE;
65 void VisitNot(HNot* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000066 void VisitOr(HOr* instruction) OVERRIDE;
67 void VisitShl(HShl* instruction) OVERRIDE;
68 void VisitShr(HShr* instruction) OVERRIDE;
69 void VisitSub(HSub* instruction) OVERRIDE;
70 void VisitUShr(HUShr* instruction) OVERRIDE;
71 void VisitXor(HXor* instruction) OVERRIDE;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +010072 void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE;
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +010073 void VisitFakeString(HFakeString* fake_string) OVERRIDE;
Nicolas Geoffray6e7455e2015-09-28 16:25:37 +010074
75 bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const;
Calin Juravleacf735c2015-02-12 15:25:22 +000076
77 OptimizingCompilerStats* stats_;
Alexandre Rames188d4312015-04-09 18:30:21 +010078 bool simplification_occurred_ = false;
79 int simplifications_at_current_position_ = 0;
80 // We ensure we do not loop infinitely. The value is a finger in the air guess
81 // that should allow enough simplification.
82 static constexpr int kMaxSamePositionSimplifications = 10;
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000083};
84
Nicolas Geoffray3c049742014-09-24 18:10:46 +010085void InstructionSimplifier::Run() {
Calin Juravleacf735c2015-02-12 15:25:22 +000086 InstructionSimplifierVisitor visitor(graph_, stats_);
Alexandre Rames188d4312015-04-09 18:30:21 +010087 visitor.Run();
88}
89
90void InstructionSimplifierVisitor::Run() {
Nicolas Geoffray07276db2015-05-18 14:22:09 +010091 // Iterate in reverse post order to open up more simplifications to users
92 // of instructions that got simplified.
Alexandre Rames188d4312015-04-09 18:30:21 +010093 for (HReversePostOrderIterator it(*GetGraph()); !it.Done();) {
94 // The simplification of an instruction to another instruction may yield
95 // possibilities for other simplifications. So although we perform a reverse
96 // post order visit, we sometimes need to revisit an instruction index.
97 simplification_occurred_ = false;
98 VisitBasicBlock(it.Current());
99 if (simplification_occurred_ &&
100 (simplifications_at_current_position_ < kMaxSamePositionSimplifications)) {
101 // New simplifications may be applicable to the instruction at the
102 // current index, so don't advance the iterator.
103 continue;
104 }
Alexandre Rames188d4312015-04-09 18:30:21 +0100105 simplifications_at_current_position_ = 0;
106 it.Advance();
107 }
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100108}
109
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000110namespace {
111
112bool AreAllBitsSet(HConstant* constant) {
113 return Int64FromConstant(constant) == -1;
114}
115
116} // namespace
117
Alexandre Rames188d4312015-04-09 18:30:21 +0100118// Returns true if the code was simplified to use only one negation operation
119// after the binary operation instead of one on each of the inputs.
120bool InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop) {
121 DCHECK(binop->IsAdd() || binop->IsSub());
122 DCHECK(binop->GetLeft()->IsNeg() && binop->GetRight()->IsNeg());
123 HNeg* left_neg = binop->GetLeft()->AsNeg();
124 HNeg* right_neg = binop->GetRight()->AsNeg();
125 if (!left_neg->HasOnlyOneNonEnvironmentUse() ||
126 !right_neg->HasOnlyOneNonEnvironmentUse()) {
127 return false;
128 }
129 // Replace code looking like
130 // NEG tmp1, a
131 // NEG tmp2, b
132 // ADD dst, tmp1, tmp2
133 // with
134 // ADD tmp, a, b
135 // NEG dst, tmp
Serdjuk, Nikolay Yaae9e662015-08-21 13:26:34 +0600136 // Note that we cannot optimize `(-a) + (-b)` to `-(a + b)` for floating-point.
137 // When `a` is `-0.0` and `b` is `0.0`, the former expression yields `0.0`,
138 // while the later yields `-0.0`.
139 if (!Primitive::IsIntegralType(binop->GetType())) {
140 return false;
141 }
Alexandre Rames188d4312015-04-09 18:30:21 +0100142 binop->ReplaceInput(left_neg->GetInput(), 0);
143 binop->ReplaceInput(right_neg->GetInput(), 1);
144 left_neg->GetBlock()->RemoveInstruction(left_neg);
145 right_neg->GetBlock()->RemoveInstruction(right_neg);
146 HNeg* neg = new (GetGraph()->GetArena()) HNeg(binop->GetType(), binop);
147 binop->GetBlock()->InsertInstructionBefore(neg, binop->GetNext());
148 binop->ReplaceWithExceptInReplacementAtIndex(neg, 0);
149 RecordSimplification();
150 return true;
151}
152
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000153void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
154 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
155 HConstant* input_cst = instruction->GetConstantRight();
156 HInstruction* input_other = instruction->GetLeastConstantLeft();
157
Mark Mendellba56d062015-05-05 21:34:03 -0400158 if (input_cst != nullptr) {
159 if (input_cst->IsZero()) {
160 // Replace code looking like
161 // SHL dst, src, 0
162 // with
163 // src
164 instruction->ReplaceWith(input_other);
165 instruction->GetBlock()->RemoveInstruction(instruction);
166 } else if (instruction->IsShl() && input_cst->IsOne()) {
167 // Replace Shl looking like
168 // SHL dst, src, 1
169 // with
170 // ADD dst, src, src
171 HAdd *add = new(GetGraph()->GetArena()) HAdd(instruction->GetType(),
172 input_other,
173 input_other);
174 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add);
175 RecordSimplification();
176 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000177 }
178}
179
Calin Juravle10e244f2015-01-26 18:54:32 +0000180void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) {
181 HInstruction* obj = null_check->InputAt(0);
182 if (!obj->CanBeNull()) {
183 null_check->ReplaceWith(obj);
184 null_check->GetBlock()->RemoveInstruction(null_check);
Calin Juravleacf735c2015-02-12 15:25:22 +0000185 if (stats_ != nullptr) {
186 stats_->RecordStat(MethodCompilationStat::kRemovedNullCheck);
187 }
188 }
189}
190
Nicolas Geoffray6e7455e2015-09-28 16:25:37 +0100191bool InstructionSimplifierVisitor::CanEnsureNotNullAt(HInstruction* input, HInstruction* at) const {
192 if (!input->CanBeNull()) {
193 return true;
194 }
195
Guillaume "Vermeille" Sanchez8909baf2015-04-23 21:35:11 +0100196 for (HUseIterator<HInstruction*> it(input->GetUses()); !it.Done(); it.Advance()) {
197 HInstruction* use = it.Current()->GetUser();
Nicolas Geoffray6e7455e2015-09-28 16:25:37 +0100198 if (use->IsNullCheck() && use->StrictlyDominates(at)) {
Guillaume "Vermeille" Sanchez8909baf2015-04-23 21:35:11 +0100199 return true;
200 }
201 }
Nicolas Geoffray6e7455e2015-09-28 16:25:37 +0100202
Guillaume "Vermeille" Sanchez8909baf2015-04-23 21:35:11 +0100203 return false;
204}
205
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100206// Returns whether doing a type test between the class of `object` against `klass` has
207// a statically known outcome. The result of the test is stored in `outcome`.
208static bool TypeCheckHasKnownOutcome(HLoadClass* klass, HInstruction* object, bool* outcome) {
Calin Juravle2e768302015-07-28 14:41:11 +0000209 DCHECK(!object->IsNullConstant()) << "Null constants should be special cased";
210 ReferenceTypeInfo obj_rti = object->GetReferenceTypeInfo();
211 ScopedObjectAccess soa(Thread::Current());
212 if (!obj_rti.IsValid()) {
213 // We run the simplifier before the reference type propagation so type info might not be
214 // available.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100215 return false;
Calin Juravleacf735c2015-02-12 15:25:22 +0000216 }
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100217
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100218 ReferenceTypeInfo class_rti = klass->GetLoadedClassRTI();
Calin Juravle2e768302015-07-28 14:41:11 +0000219 DCHECK(class_rti.IsValid() && class_rti.IsExact());
Calin Juravleacf735c2015-02-12 15:25:22 +0000220 if (class_rti.IsSupertypeOf(obj_rti)) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100221 *outcome = true;
222 return true;
223 } else if (obj_rti.IsExact()) {
224 // The test failed at compile time so will also fail at runtime.
225 *outcome = false;
226 return true;
Nicolas Geoffray7cb499b2015-06-17 11:35:11 +0100227 } else if (!class_rti.IsInterface()
228 && !obj_rti.IsInterface()
229 && !obj_rti.IsSupertypeOf(class_rti)) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100230 // Different type hierarchy. The test will fail.
231 *outcome = false;
232 return true;
233 }
234 return false;
235}
236
237void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
238 HInstruction* object = check_cast->InputAt(0);
Nicolas Geoffray6e7455e2015-09-28 16:25:37 +0100239 if (CanEnsureNotNullAt(object, check_cast)) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100240 check_cast->ClearMustDoNullCheck();
241 }
242
243 if (object->IsNullConstant()) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000244 check_cast->GetBlock()->RemoveInstruction(check_cast);
245 if (stats_ != nullptr) {
246 stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
247 }
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100248 return;
249 }
250
251 bool outcome;
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700252 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
253 if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100254 if (outcome) {
255 check_cast->GetBlock()->RemoveInstruction(check_cast);
256 if (stats_ != nullptr) {
257 stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
258 }
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700259 if (!load_class->HasUses()) {
260 // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw.
261 // However, here we know that it cannot because the checkcast was successfull, hence
262 // the class was already loaded.
263 load_class->GetBlock()->RemoveInstruction(load_class);
264 }
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100265 } else {
266 // Don't do anything for exceptional cases for now. Ideally we should remove
267 // all instructions and blocks this instruction dominates.
268 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000269 }
270}
271
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +0100272void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100273 HInstruction* object = instruction->InputAt(0);
274 bool can_be_null = true;
Nicolas Geoffray6e7455e2015-09-28 16:25:37 +0100275 if (CanEnsureNotNullAt(object, instruction)) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100276 can_be_null = false;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +0100277 instruction->ClearMustDoNullCheck();
278 }
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100279
280 HGraph* graph = GetGraph();
281 if (object->IsNullConstant()) {
282 instruction->ReplaceWith(graph->GetIntConstant(0));
283 instruction->GetBlock()->RemoveInstruction(instruction);
284 RecordSimplification();
285 return;
286 }
287
288 bool outcome;
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700289 HLoadClass* load_class = instruction->InputAt(1)->AsLoadClass();
290 if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100291 if (outcome && can_be_null) {
292 // Type test will succeed, we just need a null test.
293 HNotEqual* test = new (graph->GetArena()) HNotEqual(graph->GetNullConstant(), object);
294 instruction->GetBlock()->InsertInstructionBefore(test, instruction);
295 instruction->ReplaceWith(test);
296 } else {
297 // We've statically determined the result of the instanceof.
298 instruction->ReplaceWith(graph->GetIntConstant(outcome));
299 }
300 RecordSimplification();
301 instruction->GetBlock()->RemoveInstruction(instruction);
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700302 if (outcome && !load_class->HasUses()) {
303 // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw.
304 // However, here we know that it cannot because the instanceof check was successfull, hence
305 // the class was already loaded.
306 load_class->GetBlock()->RemoveInstruction(load_class);
307 }
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100308 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +0100309}
310
Nicolas Geoffray07276db2015-05-18 14:22:09 +0100311void InstructionSimplifierVisitor::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
312 if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
Nicolas Geoffray6e7455e2015-09-28 16:25:37 +0100313 && CanEnsureNotNullAt(instruction->GetValue(), instruction)) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +0100314 instruction->ClearValueCanBeNull();
315 }
316}
317
318void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruction) {
319 if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
Nicolas Geoffray6e7455e2015-09-28 16:25:37 +0100320 && CanEnsureNotNullAt(instruction->GetValue(), instruction)) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +0100321 instruction->ClearValueCanBeNull();
322 }
323}
324
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000325void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100326 HBasicBlock* block = check->GetBlock();
327 // Currently always keep the suspend check at entry.
328 if (block->IsEntryBlock()) return;
329
330 // Currently always keep suspend checks at loop entry.
331 if (block->IsLoopHeader() && block->GetFirstInstruction() == check) {
332 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == check);
333 return;
334 }
335
336 // Remove the suspend check that was added at build time for the baseline
337 // compiler.
338 block->RemoveInstruction(check);
339}
340
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000341void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
David Brazdil0d13fee2015-04-17 14:52:19 +0100342 HInstruction* input_const = equal->GetConstantRight();
343 if (input_const != nullptr) {
344 HInstruction* input_value = equal->GetLeastConstantLeft();
345 if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) {
346 HBasicBlock* block = equal->GetBlock();
Nicolas Geoffray3c4ab802015-06-19 11:42:07 +0100347 // We are comparing the boolean to a constant which is of type int and can
348 // be any constant.
David Brazdil0d13fee2015-04-17 14:52:19 +0100349 if (input_const->AsIntConstant()->IsOne()) {
350 // Replace (bool_value == true) with bool_value
351 equal->ReplaceWith(input_value);
352 block->RemoveInstruction(equal);
353 RecordSimplification();
Nicolas Geoffray3c4ab802015-06-19 11:42:07 +0100354 } else if (input_const->AsIntConstant()->IsZero()) {
David Brazdil0d13fee2015-04-17 14:52:19 +0100355 // Replace (bool_value == false) with !bool_value
David Brazdil0d13fee2015-04-17 14:52:19 +0100356 block->ReplaceAndRemoveInstructionWith(
357 equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
358 RecordSimplification();
David Brazdil1e9ec052015-06-22 10:26:45 +0100359 } else {
360 // Replace (bool_value == integer_not_zero_nor_one_constant) with false
361 equal->ReplaceWith(GetGraph()->GetIntConstant(0));
362 block->RemoveInstruction(equal);
363 RecordSimplification();
David Brazdil0d13fee2015-04-17 14:52:19 +0100364 }
Mark Mendellc4701932015-04-10 13:18:51 -0400365 } else {
366 VisitCondition(equal);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100367 }
Mark Mendellc4701932015-04-10 13:18:51 -0400368 } else {
369 VisitCondition(equal);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100370 }
371}
372
David Brazdil0d13fee2015-04-17 14:52:19 +0100373void InstructionSimplifierVisitor::VisitNotEqual(HNotEqual* not_equal) {
374 HInstruction* input_const = not_equal->GetConstantRight();
375 if (input_const != nullptr) {
376 HInstruction* input_value = not_equal->GetLeastConstantLeft();
377 if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) {
378 HBasicBlock* block = not_equal->GetBlock();
Nicolas Geoffray3c4ab802015-06-19 11:42:07 +0100379 // We are comparing the boolean to a constant which is of type int and can
380 // be any constant.
David Brazdil0d13fee2015-04-17 14:52:19 +0100381 if (input_const->AsIntConstant()->IsOne()) {
382 // Replace (bool_value != true) with !bool_value
383 block->ReplaceAndRemoveInstructionWith(
384 not_equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
385 RecordSimplification();
Nicolas Geoffray3c4ab802015-06-19 11:42:07 +0100386 } else if (input_const->AsIntConstant()->IsZero()) {
David Brazdil0d13fee2015-04-17 14:52:19 +0100387 // Replace (bool_value != false) with bool_value
David Brazdil0d13fee2015-04-17 14:52:19 +0100388 not_equal->ReplaceWith(input_value);
389 block->RemoveInstruction(not_equal);
390 RecordSimplification();
David Brazdil1e9ec052015-06-22 10:26:45 +0100391 } else {
392 // Replace (bool_value != integer_not_zero_nor_one_constant) with true
393 not_equal->ReplaceWith(GetGraph()->GetIntConstant(1));
394 block->RemoveInstruction(not_equal);
395 RecordSimplification();
David Brazdil0d13fee2015-04-17 14:52:19 +0100396 }
Mark Mendellc4701932015-04-10 13:18:51 -0400397 } else {
398 VisitCondition(not_equal);
David Brazdil0d13fee2015-04-17 14:52:19 +0100399 }
Mark Mendellc4701932015-04-10 13:18:51 -0400400 } else {
401 VisitCondition(not_equal);
David Brazdil0d13fee2015-04-17 14:52:19 +0100402 }
403}
404
405void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) {
406 HInstruction* parent = bool_not->InputAt(0);
407 if (parent->IsBooleanNot()) {
408 HInstruction* value = parent->InputAt(0);
409 // Replace (!(!bool_value)) with bool_value
410 bool_not->ReplaceWith(value);
411 bool_not->GetBlock()->RemoveInstruction(bool_not);
412 // It is possible that `parent` is dead at this point but we leave
413 // its removal to DCE for simplicity.
414 RecordSimplification();
415 }
416}
417
Mingyao Yang0304e182015-01-30 16:41:29 -0800418void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) {
419 HInstruction* input = instruction->InputAt(0);
420 // If the array is a NewArray with constant size, replace the array length
421 // with the constant instruction. This helps the bounds check elimination phase.
422 if (input->IsNewArray()) {
423 input = input->InputAt(0);
424 if (input->IsIntConstant()) {
425 instruction->ReplaceWith(input);
426 }
427 }
428}
429
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000430void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +0000431 HInstruction* value = instruction->GetValue();
432 if (value->GetType() != Primitive::kPrimNot) return;
433
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100434 if (CanEnsureNotNullAt(value, instruction)) {
435 instruction->ClearValueCanBeNull();
436 }
437
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +0000438 if (value->IsArrayGet()) {
439 if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
440 // If the code is just swapping elements in the array, no need for a type check.
441 instruction->ClearNeedsTypeCheck();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100442 return;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +0000443 }
444 }
Nicolas Geoffray07276db2015-05-18 14:22:09 +0100445
Nicolas Geoffray9fdb31e2015-07-01 12:56:46 +0100446 if (value->IsNullConstant()) {
447 instruction->ClearNeedsTypeCheck();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100448 return;
Nicolas Geoffray9fdb31e2015-07-01 12:56:46 +0100449 }
450
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100451 ScopedObjectAccess soa(Thread::Current());
452 ReferenceTypeInfo array_rti = instruction->GetArray()->GetReferenceTypeInfo();
453 ReferenceTypeInfo value_rti = value->GetReferenceTypeInfo();
454 if (!array_rti.IsValid()) {
455 return;
456 }
457
458 if (value_rti.IsValid() && array_rti.CanArrayHold(value_rti)) {
459 instruction->ClearNeedsTypeCheck();
460 return;
461 }
462
463 if (array_rti.IsObjectArray()) {
464 if (array_rti.IsExact()) {
465 instruction->ClearNeedsTypeCheck();
466 return;
467 }
468 instruction->SetStaticTypeOfArrayIsObjectArray();
Nicolas Geoffray07276db2015-05-18 14:22:09 +0100469 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +0000470}
471
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +0000472void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
473 if (instruction->GetResultType() == instruction->GetInputType()) {
474 // Remove the instruction if it's converting to the same type.
475 instruction->ReplaceWith(instruction->GetInput());
476 instruction->GetBlock()->RemoveInstruction(instruction);
477 }
478}
479
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000480void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
481 HConstant* input_cst = instruction->GetConstantRight();
482 HInstruction* input_other = instruction->GetLeastConstantLeft();
483 if ((input_cst != nullptr) && input_cst->IsZero()) {
484 // Replace code looking like
485 // ADD dst, src, 0
486 // with
487 // src
Serguei Katkov115b53f2015-08-05 17:03:30 +0600488 // Note that we cannot optimize `x + 0.0` to `x` for floating-point. When
489 // `x` is `-0.0`, the former expression yields `0.0`, while the later
490 // yields `-0.0`.
491 if (Primitive::IsIntegralType(instruction->GetType())) {
492 instruction->ReplaceWith(input_other);
493 instruction->GetBlock()->RemoveInstruction(instruction);
494 return;
495 }
Alexandre Rames188d4312015-04-09 18:30:21 +0100496 }
497
498 HInstruction* left = instruction->GetLeft();
499 HInstruction* right = instruction->GetRight();
500 bool left_is_neg = left->IsNeg();
501 bool right_is_neg = right->IsNeg();
502
503 if (left_is_neg && right_is_neg) {
504 if (TryMoveNegOnInputsAfterBinop(instruction)) {
505 return;
506 }
507 }
508
509 HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg();
510 if ((left_is_neg ^ right_is_neg) && neg->HasOnlyOneNonEnvironmentUse()) {
511 // Replace code looking like
512 // NEG tmp, b
513 // ADD dst, a, tmp
514 // with
515 // SUB dst, a, b
516 // We do not perform the optimization if the input negation has environment
517 // uses or multiple non-environment uses as it could lead to worse code. In
518 // particular, we do not want the live range of `b` to be extended if we are
519 // not sure the initial 'NEG' instruction can be removed.
520 HInstruction* other = left_is_neg ? right : left;
521 HSub* sub = new(GetGraph()->GetArena()) HSub(instruction->GetType(), other, neg->GetInput());
522 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub);
523 RecordSimplification();
524 neg->GetBlock()->RemoveInstruction(neg);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000525 }
526}
527
528void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
529 HConstant* input_cst = instruction->GetConstantRight();
530 HInstruction* input_other = instruction->GetLeastConstantLeft();
531
Vladimir Marko452c1b62015-09-25 14:44:17 +0100532 if (input_cst != nullptr) {
533 int64_t value = Int64FromConstant(input_cst);
534 if (value == -1) {
535 // Replace code looking like
536 // AND dst, src, 0xFFF...FF
537 // with
538 // src
539 instruction->ReplaceWith(input_other);
540 instruction->GetBlock()->RemoveInstruction(instruction);
541 RecordSimplification();
542 return;
543 }
544 // Eliminate And from UShr+And if the And-mask contains all the bits that
545 // can be non-zero after UShr. Transform Shr+And to UShr if the And-mask
546 // precisely clears the shifted-in sign bits.
547 if ((input_other->IsUShr() || input_other->IsShr()) && input_other->InputAt(1)->IsConstant()) {
548 size_t reg_bits = (instruction->GetResultType() == Primitive::kPrimLong) ? 64 : 32;
549 size_t shift = Int64FromConstant(input_other->InputAt(1)->AsConstant()) & (reg_bits - 1);
550 size_t num_tail_bits_set = CTZ(value + 1);
551 if ((num_tail_bits_set >= reg_bits - shift) && input_other->IsUShr()) {
552 // This AND clears only bits known to be clear, for example "(x >>> 24) & 0xff".
553 instruction->ReplaceWith(input_other);
554 instruction->GetBlock()->RemoveInstruction(instruction);
555 RecordSimplification();
556 return;
557 } else if ((num_tail_bits_set == reg_bits - shift) && IsPowerOfTwo(value + 1) &&
558 input_other->HasOnlyOneNonEnvironmentUse()) {
559 DCHECK(input_other->IsShr()); // For UShr, we would have taken the branch above.
560 // Replace SHR+AND with USHR, for example "(x >> 24) & 0xff" -> "x >>> 24".
561 HUShr* ushr = new (GetGraph()->GetArena()) HUShr(instruction->GetType(),
562 input_other->InputAt(0),
563 input_other->InputAt(1),
564 input_other->GetDexPc());
565 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, ushr);
566 input_other->GetBlock()->RemoveInstruction(input_other);
567 RecordSimplification();
568 return;
569 }
570 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000571 }
572
573 // We assume that GVN has run before, so we only perform a pointer comparison.
574 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100575 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000576 if (instruction->GetLeft() == instruction->GetRight()) {
577 // Replace code looking like
578 // AND dst, src, src
579 // with
580 // src
581 instruction->ReplaceWith(instruction->GetLeft());
582 instruction->GetBlock()->RemoveInstruction(instruction);
583 }
584}
585
Mark Mendellc4701932015-04-10 13:18:51 -0400586void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) {
587 VisitCondition(condition);
588}
589
590void InstructionSimplifierVisitor::VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) {
591 VisitCondition(condition);
592}
593
594void InstructionSimplifierVisitor::VisitLessThan(HLessThan* condition) {
595 VisitCondition(condition);
596}
597
598void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condition) {
599 VisitCondition(condition);
600}
601
602void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
603 // Try to fold an HCompare into this HCondition.
604
Roland Levillain7f63c522015-07-13 15:54:55 +0000605 // This simplification is currently supported on x86, x86_64, ARM and ARM64.
606 // TODO: Implement it for MIPS64.
Mark Mendellc4701932015-04-10 13:18:51 -0400607 InstructionSet instruction_set = GetGraph()->GetInstructionSet();
Roland Levillain7f63c522015-07-13 15:54:55 +0000608 if (instruction_set == kMips64) {
Mark Mendellc4701932015-04-10 13:18:51 -0400609 return;
610 }
611
612 HInstruction* left = condition->GetLeft();
613 HInstruction* right = condition->GetRight();
614 // We can only replace an HCondition which compares a Compare to 0.
615 // Both 'dx' and 'jack' generate a compare to 0 when compiling a
616 // condition with a long, float or double comparison as input.
617 if (!left->IsCompare() || !right->IsConstant() || right->AsIntConstant()->GetValue() != 0) {
618 // Conversion is not possible.
619 return;
620 }
621
622 // Is the Compare only used for this purpose?
623 if (!left->GetUses().HasOnlyOneUse()) {
624 // Someone else also wants the result of the compare.
625 return;
626 }
627
628 if (!left->GetEnvUses().IsEmpty()) {
629 // There is a reference to the compare result in an environment. Do we really need it?
630 if (GetGraph()->IsDebuggable()) {
631 return;
632 }
633
634 // We have to ensure that there are no deopt points in the sequence.
635 if (left->HasAnyEnvironmentUseBefore(condition)) {
636 return;
637 }
638 }
639
640 // Clean up any environment uses from the HCompare, if any.
641 left->RemoveEnvironmentUsers();
642
643 // We have decided to fold the HCompare into the HCondition. Transfer the information.
644 condition->SetBias(left->AsCompare()->GetBias());
645
646 // Replace the operands of the HCondition.
647 condition->ReplaceInput(left->InputAt(0), 0);
648 condition->ReplaceInput(left->InputAt(1), 1);
649
650 // Remove the HCompare.
651 left->GetBlock()->RemoveInstruction(left);
652
653 RecordSimplification();
654}
655
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000656void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
657 HConstant* input_cst = instruction->GetConstantRight();
658 HInstruction* input_other = instruction->GetLeastConstantLeft();
659 Primitive::Type type = instruction->GetType();
660
661 if ((input_cst != nullptr) && input_cst->IsOne()) {
662 // Replace code looking like
663 // DIV dst, src, 1
664 // with
665 // src
666 instruction->ReplaceWith(input_other);
667 instruction->GetBlock()->RemoveInstruction(instruction);
668 return;
669 }
670
Nicolas Geoffray0d221842015-04-27 08:53:46 +0000671 if ((input_cst != nullptr) && input_cst->IsMinusOne()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000672 // Replace code looking like
673 // DIV dst, src, -1
674 // with
675 // NEG dst, src
676 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
Nicolas Geoffray0d221842015-04-27 08:53:46 +0000677 instruction, new (GetGraph()->GetArena()) HNeg(type, input_other));
Alexandre Rames188d4312015-04-09 18:30:21 +0100678 RecordSimplification();
Nicolas Geoffray0d221842015-04-27 08:53:46 +0000679 return;
680 }
681
682 if ((input_cst != nullptr) && Primitive::IsFloatingPointType(type)) {
683 // Try replacing code looking like
684 // DIV dst, src, constant
685 // with
686 // MUL dst, src, 1 / constant
687 HConstant* reciprocal = nullptr;
688 if (type == Primitive::Primitive::kPrimDouble) {
689 double value = input_cst->AsDoubleConstant()->GetValue();
690 if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) {
691 reciprocal = GetGraph()->GetDoubleConstant(1.0 / value);
692 }
693 } else {
694 DCHECK_EQ(type, Primitive::kPrimFloat);
695 float value = input_cst->AsFloatConstant()->GetValue();
696 if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) {
697 reciprocal = GetGraph()->GetFloatConstant(1.0f / value);
698 }
699 }
700
701 if (reciprocal != nullptr) {
702 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
703 instruction, new (GetGraph()->GetArena()) HMul(type, input_other, reciprocal));
704 RecordSimplification();
705 return;
706 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000707 }
708}
709
710void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
711 HConstant* input_cst = instruction->GetConstantRight();
712 HInstruction* input_other = instruction->GetLeastConstantLeft();
713 Primitive::Type type = instruction->GetType();
714 HBasicBlock* block = instruction->GetBlock();
715 ArenaAllocator* allocator = GetGraph()->GetArena();
716
717 if (input_cst == nullptr) {
718 return;
719 }
720
721 if (input_cst->IsOne()) {
722 // Replace code looking like
723 // MUL dst, src, 1
724 // with
725 // src
726 instruction->ReplaceWith(input_other);
727 instruction->GetBlock()->RemoveInstruction(instruction);
728 return;
729 }
730
731 if (input_cst->IsMinusOne() &&
732 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
733 // Replace code looking like
734 // MUL dst, src, -1
735 // with
736 // NEG dst, src
737 HNeg* neg = new (allocator) HNeg(type, input_other);
738 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100739 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000740 return;
741 }
742
743 if (Primitive::IsFloatingPointType(type) &&
744 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
745 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
746 // Replace code looking like
747 // FP_MUL dst, src, 2.0
748 // with
749 // FP_ADD dst, src, src
750 // The 'int' and 'long' cases are handled below.
751 block->ReplaceAndRemoveInstructionWith(instruction,
752 new (allocator) HAdd(type, input_other, input_other));
Alexandre Rames188d4312015-04-09 18:30:21 +0100753 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000754 return;
755 }
756
757 if (Primitive::IsIntOrLongType(type)) {
758 int64_t factor = Int64FromConstant(input_cst);
Serguei Katkov53849192015-04-20 14:22:27 +0600759 // Even though constant propagation also takes care of the zero case, other
760 // optimizations can lead to having a zero multiplication.
761 if (factor == 0) {
762 // Replace code looking like
763 // MUL dst, src, 0
764 // with
765 // 0
766 instruction->ReplaceWith(input_cst);
767 instruction->GetBlock()->RemoveInstruction(instruction);
768 } else if (IsPowerOfTwo(factor)) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000769 // Replace code looking like
770 // MUL dst, src, pow_of_2
771 // with
772 // SHL dst, src, log2(pow_of_2)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000773 HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000774 HShl* shl = new(allocator) HShl(type, input_other, shift);
775 block->ReplaceAndRemoveInstructionWith(instruction, shl);
Alexandre Rames188d4312015-04-09 18:30:21 +0100776 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000777 }
778 }
779}
780
Alexandre Rames188d4312015-04-09 18:30:21 +0100781void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) {
782 HInstruction* input = instruction->GetInput();
783 if (input->IsNeg()) {
784 // Replace code looking like
785 // NEG tmp, src
786 // NEG dst, tmp
787 // with
788 // src
789 HNeg* previous_neg = input->AsNeg();
790 instruction->ReplaceWith(previous_neg->GetInput());
791 instruction->GetBlock()->RemoveInstruction(instruction);
792 // We perform the optimization even if the input negation has environment
793 // uses since it allows removing the current instruction. But we only delete
794 // the input negation only if it is does not have any uses left.
795 if (!previous_neg->HasUses()) {
796 previous_neg->GetBlock()->RemoveInstruction(previous_neg);
797 }
798 RecordSimplification();
799 return;
800 }
801
Serguei Katkov339dfc22015-04-20 12:29:32 +0600802 if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse() &&
803 !Primitive::IsFloatingPointType(input->GetType())) {
Alexandre Rames188d4312015-04-09 18:30:21 +0100804 // Replace code looking like
805 // SUB tmp, a, b
806 // NEG dst, tmp
807 // with
808 // SUB dst, b, a
809 // We do not perform the optimization if the input subtraction has
810 // environment uses or multiple non-environment uses as it could lead to
811 // worse code. In particular, we do not want the live ranges of `a` and `b`
812 // to be extended if we are not sure the initial 'SUB' instruction can be
813 // removed.
Serguei Katkov339dfc22015-04-20 12:29:32 +0600814 // We do not perform optimization for fp because we could lose the sign of zero.
Alexandre Rames188d4312015-04-09 18:30:21 +0100815 HSub* sub = input->AsSub();
816 HSub* new_sub =
817 new (GetGraph()->GetArena()) HSub(instruction->GetType(), sub->GetRight(), sub->GetLeft());
818 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub);
819 if (!sub->HasUses()) {
820 sub->GetBlock()->RemoveInstruction(sub);
821 }
822 RecordSimplification();
823 }
824}
825
826void InstructionSimplifierVisitor::VisitNot(HNot* instruction) {
827 HInstruction* input = instruction->GetInput();
828 if (input->IsNot()) {
829 // Replace code looking like
830 // NOT tmp, src
831 // NOT dst, tmp
832 // with
833 // src
834 // We perform the optimization even if the input negation has environment
835 // uses since it allows removing the current instruction. But we only delete
836 // the input negation only if it is does not have any uses left.
837 HNot* previous_not = input->AsNot();
838 instruction->ReplaceWith(previous_not->GetInput());
839 instruction->GetBlock()->RemoveInstruction(instruction);
840 if (!previous_not->HasUses()) {
841 previous_not->GetBlock()->RemoveInstruction(previous_not);
842 }
843 RecordSimplification();
844 }
845}
846
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000847void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
848 HConstant* input_cst = instruction->GetConstantRight();
849 HInstruction* input_other = instruction->GetLeastConstantLeft();
850
851 if ((input_cst != nullptr) && input_cst->IsZero()) {
852 // Replace code looking like
853 // OR dst, src, 0
854 // with
855 // src
856 instruction->ReplaceWith(input_other);
857 instruction->GetBlock()->RemoveInstruction(instruction);
858 return;
859 }
860
861 // We assume that GVN has run before, so we only perform a pointer comparison.
862 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100863 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000864 if (instruction->GetLeft() == instruction->GetRight()) {
865 // Replace code looking like
866 // OR dst, src, src
867 // with
868 // src
869 instruction->ReplaceWith(instruction->GetLeft());
870 instruction->GetBlock()->RemoveInstruction(instruction);
871 }
872}
873
874void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
875 VisitShift(instruction);
876}
877
878void InstructionSimplifierVisitor::VisitShr(HShr* instruction) {
879 VisitShift(instruction);
880}
881
882void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
883 HConstant* input_cst = instruction->GetConstantRight();
884 HInstruction* input_other = instruction->GetLeastConstantLeft();
885
Serguei Katkov115b53f2015-08-05 17:03:30 +0600886 Primitive::Type type = instruction->GetType();
887 if (Primitive::IsFloatingPointType(type)) {
888 return;
889 }
890
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000891 if ((input_cst != nullptr) && input_cst->IsZero()) {
892 // Replace code looking like
893 // SUB dst, src, 0
894 // with
895 // src
Serguei Katkov115b53f2015-08-05 17:03:30 +0600896 // Note that we cannot optimize `x - 0.0` to `x` for floating-point. When
897 // `x` is `-0.0`, the former expression yields `0.0`, while the later
898 // yields `-0.0`.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000899 instruction->ReplaceWith(input_other);
900 instruction->GetBlock()->RemoveInstruction(instruction);
901 return;
902 }
903
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000904 HBasicBlock* block = instruction->GetBlock();
905 ArenaAllocator* allocator = GetGraph()->GetArena();
906
Alexandre Rames188d4312015-04-09 18:30:21 +0100907 HInstruction* left = instruction->GetLeft();
908 HInstruction* right = instruction->GetRight();
909 if (left->IsConstant()) {
910 if (Int64FromConstant(left->AsConstant()) == 0) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000911 // Replace code looking like
912 // SUB dst, 0, src
913 // with
914 // NEG dst, src
Alexandre Rames188d4312015-04-09 18:30:21 +0100915 // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000916 // `x` is `0.0`, the former expression yields `0.0`, while the later
917 // yields `-0.0`.
Alexandre Rames188d4312015-04-09 18:30:21 +0100918 HNeg* neg = new (allocator) HNeg(type, right);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000919 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100920 RecordSimplification();
921 return;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000922 }
923 }
Alexandre Rames188d4312015-04-09 18:30:21 +0100924
925 if (left->IsNeg() && right->IsNeg()) {
926 if (TryMoveNegOnInputsAfterBinop(instruction)) {
927 return;
928 }
929 }
930
931 if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) {
932 // Replace code looking like
933 // NEG tmp, b
934 // SUB dst, a, tmp
935 // with
936 // ADD dst, a, b
937 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left, right->AsNeg()->GetInput());
938 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add);
939 RecordSimplification();
940 right->GetBlock()->RemoveInstruction(right);
941 return;
942 }
943
944 if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) {
945 // Replace code looking like
946 // NEG tmp, a
947 // SUB dst, tmp, b
948 // with
949 // ADD tmp, a, b
950 // NEG dst, tmp
951 // The second version is not intrinsically better, but enables more
952 // transformations.
953 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left->AsNeg()->GetInput(), right);
954 instruction->GetBlock()->InsertInstructionBefore(add, instruction);
955 HNeg* neg = new (GetGraph()->GetArena()) HNeg(instruction->GetType(), add);
956 instruction->GetBlock()->InsertInstructionBefore(neg, instruction);
957 instruction->ReplaceWith(neg);
958 instruction->GetBlock()->RemoveInstruction(instruction);
959 RecordSimplification();
960 left->GetBlock()->RemoveInstruction(left);
961 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000962}
963
964void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
965 VisitShift(instruction);
966}
967
968void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
969 HConstant* input_cst = instruction->GetConstantRight();
970 HInstruction* input_other = instruction->GetLeastConstantLeft();
971
972 if ((input_cst != nullptr) && input_cst->IsZero()) {
973 // Replace code looking like
974 // XOR dst, src, 0
975 // with
976 // src
977 instruction->ReplaceWith(input_other);
978 instruction->GetBlock()->RemoveInstruction(instruction);
979 return;
980 }
981
982 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
983 // Replace code looking like
984 // XOR dst, src, 0xFFF...FF
985 // with
986 // NOT dst, src
987 HNot* bitwise_not = new (GetGraph()->GetArena()) HNot(instruction->GetType(), input_other);
988 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not);
Alexandre Rames188d4312015-04-09 18:30:21 +0100989 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000990 return;
991 }
992}
993
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +0100994void InstructionSimplifierVisitor::VisitFakeString(HFakeString* instruction) {
995 HInstruction* actual_string = nullptr;
996
997 // Find the string we need to replace this instruction with. The actual string is
998 // the return value of a StringFactory call.
999 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
1000 HInstruction* use = it.Current()->GetUser();
1001 if (use->IsInvokeStaticOrDirect()
1002 && use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction)) {
1003 use->AsInvokeStaticOrDirect()->RemoveFakeStringArgumentAsLastInput();
1004 actual_string = use;
1005 break;
1006 }
1007 }
1008
1009 // Check that there is no other instruction that thinks it is the factory for that string.
1010 if (kIsDebugBuild) {
1011 CHECK(actual_string != nullptr);
1012 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
1013 HInstruction* use = it.Current()->GetUser();
1014 if (use->IsInvokeStaticOrDirect()) {
1015 CHECK(!use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction));
1016 }
1017 }
1018 }
1019
1020 // We need to remove any environment uses of the fake string that are not dominated by
1021 // `actual_string` to null.
1022 for (HUseIterator<HEnvironment*> it(instruction->GetEnvUses()); !it.Done(); it.Advance()) {
1023 HEnvironment* environment = it.Current()->GetUser();
1024 if (!actual_string->StrictlyDominates(environment->GetHolder())) {
1025 environment->RemoveAsUserOfInput(it.Current()->GetIndex());
1026 environment->SetRawEnvAt(it.Current()->GetIndex(), nullptr);
1027 }
1028 }
1029
1030 // Only uses dominated by `actual_string` must remain. We can safely replace and remove
1031 // `instruction`.
1032 instruction->ReplaceWith(actual_string);
1033 instruction->GetBlock()->RemoveInstruction(instruction);
1034}
1035
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001036} // namespace art