blob: 22bca2f111851378c6bf20336ce4829ee7e441c6 [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
434 if (value->IsArrayGet()) {
435 if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
436 // If the code is just swapping elements in the array, no need for a type check.
437 instruction->ClearNeedsTypeCheck();
438 }
439 }
Nicolas Geoffray07276db2015-05-18 14:22:09 +0100440
Nicolas Geoffray9fdb31e2015-07-01 12:56:46 +0100441 if (value->IsNullConstant()) {
442 instruction->ClearNeedsTypeCheck();
443 }
444
Nicolas Geoffray6e7455e2015-09-28 16:25:37 +0100445 if (CanEnsureNotNullAt(value, instruction)) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +0100446 instruction->ClearValueCanBeNull();
447 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +0000448}
449
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +0000450void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
451 if (instruction->GetResultType() == instruction->GetInputType()) {
452 // Remove the instruction if it's converting to the same type.
453 instruction->ReplaceWith(instruction->GetInput());
454 instruction->GetBlock()->RemoveInstruction(instruction);
455 }
456}
457
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000458void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
459 HConstant* input_cst = instruction->GetConstantRight();
460 HInstruction* input_other = instruction->GetLeastConstantLeft();
461 if ((input_cst != nullptr) && input_cst->IsZero()) {
462 // Replace code looking like
463 // ADD dst, src, 0
464 // with
465 // src
Serguei Katkov115b53f2015-08-05 17:03:30 +0600466 // Note that we cannot optimize `x + 0.0` to `x` for floating-point. When
467 // `x` is `-0.0`, the former expression yields `0.0`, while the later
468 // yields `-0.0`.
469 if (Primitive::IsIntegralType(instruction->GetType())) {
470 instruction->ReplaceWith(input_other);
471 instruction->GetBlock()->RemoveInstruction(instruction);
472 return;
473 }
Alexandre Rames188d4312015-04-09 18:30:21 +0100474 }
475
476 HInstruction* left = instruction->GetLeft();
477 HInstruction* right = instruction->GetRight();
478 bool left_is_neg = left->IsNeg();
479 bool right_is_neg = right->IsNeg();
480
481 if (left_is_neg && right_is_neg) {
482 if (TryMoveNegOnInputsAfterBinop(instruction)) {
483 return;
484 }
485 }
486
487 HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg();
488 if ((left_is_neg ^ right_is_neg) && neg->HasOnlyOneNonEnvironmentUse()) {
489 // Replace code looking like
490 // NEG tmp, b
491 // ADD dst, a, tmp
492 // with
493 // SUB dst, a, b
494 // We do not perform the optimization if the input negation has environment
495 // uses or multiple non-environment uses as it could lead to worse code. In
496 // particular, we do not want the live range of `b` to be extended if we are
497 // not sure the initial 'NEG' instruction can be removed.
498 HInstruction* other = left_is_neg ? right : left;
499 HSub* sub = new(GetGraph()->GetArena()) HSub(instruction->GetType(), other, neg->GetInput());
500 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub);
501 RecordSimplification();
502 neg->GetBlock()->RemoveInstruction(neg);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000503 }
504}
505
506void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
507 HConstant* input_cst = instruction->GetConstantRight();
508 HInstruction* input_other = instruction->GetLeastConstantLeft();
509
Vladimir Marko452c1b62015-09-25 14:44:17 +0100510 if (input_cst != nullptr) {
511 int64_t value = Int64FromConstant(input_cst);
512 if (value == -1) {
513 // Replace code looking like
514 // AND dst, src, 0xFFF...FF
515 // with
516 // src
517 instruction->ReplaceWith(input_other);
518 instruction->GetBlock()->RemoveInstruction(instruction);
519 RecordSimplification();
520 return;
521 }
522 // Eliminate And from UShr+And if the And-mask contains all the bits that
523 // can be non-zero after UShr. Transform Shr+And to UShr if the And-mask
524 // precisely clears the shifted-in sign bits.
525 if ((input_other->IsUShr() || input_other->IsShr()) && input_other->InputAt(1)->IsConstant()) {
526 size_t reg_bits = (instruction->GetResultType() == Primitive::kPrimLong) ? 64 : 32;
527 size_t shift = Int64FromConstant(input_other->InputAt(1)->AsConstant()) & (reg_bits - 1);
528 size_t num_tail_bits_set = CTZ(value + 1);
529 if ((num_tail_bits_set >= reg_bits - shift) && input_other->IsUShr()) {
530 // This AND clears only bits known to be clear, for example "(x >>> 24) & 0xff".
531 instruction->ReplaceWith(input_other);
532 instruction->GetBlock()->RemoveInstruction(instruction);
533 RecordSimplification();
534 return;
535 } else if ((num_tail_bits_set == reg_bits - shift) && IsPowerOfTwo(value + 1) &&
536 input_other->HasOnlyOneNonEnvironmentUse()) {
537 DCHECK(input_other->IsShr()); // For UShr, we would have taken the branch above.
538 // Replace SHR+AND with USHR, for example "(x >> 24) & 0xff" -> "x >>> 24".
539 HUShr* ushr = new (GetGraph()->GetArena()) HUShr(instruction->GetType(),
540 input_other->InputAt(0),
541 input_other->InputAt(1),
542 input_other->GetDexPc());
543 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, ushr);
544 input_other->GetBlock()->RemoveInstruction(input_other);
545 RecordSimplification();
546 return;
547 }
548 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000549 }
550
551 // We assume that GVN has run before, so we only perform a pointer comparison.
552 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100553 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000554 if (instruction->GetLeft() == instruction->GetRight()) {
555 // Replace code looking like
556 // AND dst, src, src
557 // with
558 // src
559 instruction->ReplaceWith(instruction->GetLeft());
560 instruction->GetBlock()->RemoveInstruction(instruction);
561 }
562}
563
Mark Mendellc4701932015-04-10 13:18:51 -0400564void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) {
565 VisitCondition(condition);
566}
567
568void InstructionSimplifierVisitor::VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) {
569 VisitCondition(condition);
570}
571
572void InstructionSimplifierVisitor::VisitLessThan(HLessThan* condition) {
573 VisitCondition(condition);
574}
575
576void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condition) {
577 VisitCondition(condition);
578}
579
580void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
581 // Try to fold an HCompare into this HCondition.
582
Roland Levillain7f63c522015-07-13 15:54:55 +0000583 // This simplification is currently supported on x86, x86_64, ARM and ARM64.
584 // TODO: Implement it for MIPS64.
Mark Mendellc4701932015-04-10 13:18:51 -0400585 InstructionSet instruction_set = GetGraph()->GetInstructionSet();
Roland Levillain7f63c522015-07-13 15:54:55 +0000586 if (instruction_set == kMips64) {
Mark Mendellc4701932015-04-10 13:18:51 -0400587 return;
588 }
589
590 HInstruction* left = condition->GetLeft();
591 HInstruction* right = condition->GetRight();
592 // We can only replace an HCondition which compares a Compare to 0.
593 // Both 'dx' and 'jack' generate a compare to 0 when compiling a
594 // condition with a long, float or double comparison as input.
595 if (!left->IsCompare() || !right->IsConstant() || right->AsIntConstant()->GetValue() != 0) {
596 // Conversion is not possible.
597 return;
598 }
599
600 // Is the Compare only used for this purpose?
601 if (!left->GetUses().HasOnlyOneUse()) {
602 // Someone else also wants the result of the compare.
603 return;
604 }
605
606 if (!left->GetEnvUses().IsEmpty()) {
607 // There is a reference to the compare result in an environment. Do we really need it?
608 if (GetGraph()->IsDebuggable()) {
609 return;
610 }
611
612 // We have to ensure that there are no deopt points in the sequence.
613 if (left->HasAnyEnvironmentUseBefore(condition)) {
614 return;
615 }
616 }
617
618 // Clean up any environment uses from the HCompare, if any.
619 left->RemoveEnvironmentUsers();
620
621 // We have decided to fold the HCompare into the HCondition. Transfer the information.
622 condition->SetBias(left->AsCompare()->GetBias());
623
624 // Replace the operands of the HCondition.
625 condition->ReplaceInput(left->InputAt(0), 0);
626 condition->ReplaceInput(left->InputAt(1), 1);
627
628 // Remove the HCompare.
629 left->GetBlock()->RemoveInstruction(left);
630
631 RecordSimplification();
632}
633
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000634void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
635 HConstant* input_cst = instruction->GetConstantRight();
636 HInstruction* input_other = instruction->GetLeastConstantLeft();
637 Primitive::Type type = instruction->GetType();
638
639 if ((input_cst != nullptr) && input_cst->IsOne()) {
640 // Replace code looking like
641 // DIV dst, src, 1
642 // with
643 // src
644 instruction->ReplaceWith(input_other);
645 instruction->GetBlock()->RemoveInstruction(instruction);
646 return;
647 }
648
Nicolas Geoffray0d221842015-04-27 08:53:46 +0000649 if ((input_cst != nullptr) && input_cst->IsMinusOne()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000650 // Replace code looking like
651 // DIV dst, src, -1
652 // with
653 // NEG dst, src
654 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
Nicolas Geoffray0d221842015-04-27 08:53:46 +0000655 instruction, new (GetGraph()->GetArena()) HNeg(type, input_other));
Alexandre Rames188d4312015-04-09 18:30:21 +0100656 RecordSimplification();
Nicolas Geoffray0d221842015-04-27 08:53:46 +0000657 return;
658 }
659
660 if ((input_cst != nullptr) && Primitive::IsFloatingPointType(type)) {
661 // Try replacing code looking like
662 // DIV dst, src, constant
663 // with
664 // MUL dst, src, 1 / constant
665 HConstant* reciprocal = nullptr;
666 if (type == Primitive::Primitive::kPrimDouble) {
667 double value = input_cst->AsDoubleConstant()->GetValue();
668 if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) {
669 reciprocal = GetGraph()->GetDoubleConstant(1.0 / value);
670 }
671 } else {
672 DCHECK_EQ(type, Primitive::kPrimFloat);
673 float value = input_cst->AsFloatConstant()->GetValue();
674 if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) {
675 reciprocal = GetGraph()->GetFloatConstant(1.0f / value);
676 }
677 }
678
679 if (reciprocal != nullptr) {
680 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
681 instruction, new (GetGraph()->GetArena()) HMul(type, input_other, reciprocal));
682 RecordSimplification();
683 return;
684 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000685 }
686}
687
688void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
689 HConstant* input_cst = instruction->GetConstantRight();
690 HInstruction* input_other = instruction->GetLeastConstantLeft();
691 Primitive::Type type = instruction->GetType();
692 HBasicBlock* block = instruction->GetBlock();
693 ArenaAllocator* allocator = GetGraph()->GetArena();
694
695 if (input_cst == nullptr) {
696 return;
697 }
698
699 if (input_cst->IsOne()) {
700 // Replace code looking like
701 // MUL dst, src, 1
702 // with
703 // src
704 instruction->ReplaceWith(input_other);
705 instruction->GetBlock()->RemoveInstruction(instruction);
706 return;
707 }
708
709 if (input_cst->IsMinusOne() &&
710 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
711 // Replace code looking like
712 // MUL dst, src, -1
713 // with
714 // NEG dst, src
715 HNeg* neg = new (allocator) HNeg(type, input_other);
716 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100717 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000718 return;
719 }
720
721 if (Primitive::IsFloatingPointType(type) &&
722 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
723 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
724 // Replace code looking like
725 // FP_MUL dst, src, 2.0
726 // with
727 // FP_ADD dst, src, src
728 // The 'int' and 'long' cases are handled below.
729 block->ReplaceAndRemoveInstructionWith(instruction,
730 new (allocator) HAdd(type, input_other, input_other));
Alexandre Rames188d4312015-04-09 18:30:21 +0100731 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000732 return;
733 }
734
735 if (Primitive::IsIntOrLongType(type)) {
736 int64_t factor = Int64FromConstant(input_cst);
Serguei Katkov53849192015-04-20 14:22:27 +0600737 // Even though constant propagation also takes care of the zero case, other
738 // optimizations can lead to having a zero multiplication.
739 if (factor == 0) {
740 // Replace code looking like
741 // MUL dst, src, 0
742 // with
743 // 0
744 instruction->ReplaceWith(input_cst);
745 instruction->GetBlock()->RemoveInstruction(instruction);
746 } else if (IsPowerOfTwo(factor)) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000747 // Replace code looking like
748 // MUL dst, src, pow_of_2
749 // with
750 // SHL dst, src, log2(pow_of_2)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000751 HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000752 HShl* shl = new(allocator) HShl(type, input_other, shift);
753 block->ReplaceAndRemoveInstructionWith(instruction, shl);
Alexandre Rames188d4312015-04-09 18:30:21 +0100754 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000755 }
756 }
757}
758
Alexandre Rames188d4312015-04-09 18:30:21 +0100759void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) {
760 HInstruction* input = instruction->GetInput();
761 if (input->IsNeg()) {
762 // Replace code looking like
763 // NEG tmp, src
764 // NEG dst, tmp
765 // with
766 // src
767 HNeg* previous_neg = input->AsNeg();
768 instruction->ReplaceWith(previous_neg->GetInput());
769 instruction->GetBlock()->RemoveInstruction(instruction);
770 // We perform the optimization even if the input negation has environment
771 // uses since it allows removing the current instruction. But we only delete
772 // the input negation only if it is does not have any uses left.
773 if (!previous_neg->HasUses()) {
774 previous_neg->GetBlock()->RemoveInstruction(previous_neg);
775 }
776 RecordSimplification();
777 return;
778 }
779
Serguei Katkov339dfc22015-04-20 12:29:32 +0600780 if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse() &&
781 !Primitive::IsFloatingPointType(input->GetType())) {
Alexandre Rames188d4312015-04-09 18:30:21 +0100782 // Replace code looking like
783 // SUB tmp, a, b
784 // NEG dst, tmp
785 // with
786 // SUB dst, b, a
787 // We do not perform the optimization if the input subtraction has
788 // environment uses or multiple non-environment uses as it could lead to
789 // worse code. In particular, we do not want the live ranges of `a` and `b`
790 // to be extended if we are not sure the initial 'SUB' instruction can be
791 // removed.
Serguei Katkov339dfc22015-04-20 12:29:32 +0600792 // We do not perform optimization for fp because we could lose the sign of zero.
Alexandre Rames188d4312015-04-09 18:30:21 +0100793 HSub* sub = input->AsSub();
794 HSub* new_sub =
795 new (GetGraph()->GetArena()) HSub(instruction->GetType(), sub->GetRight(), sub->GetLeft());
796 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub);
797 if (!sub->HasUses()) {
798 sub->GetBlock()->RemoveInstruction(sub);
799 }
800 RecordSimplification();
801 }
802}
803
804void InstructionSimplifierVisitor::VisitNot(HNot* instruction) {
805 HInstruction* input = instruction->GetInput();
806 if (input->IsNot()) {
807 // Replace code looking like
808 // NOT tmp, src
809 // NOT dst, tmp
810 // with
811 // src
812 // We perform the optimization even if the input negation has environment
813 // uses since it allows removing the current instruction. But we only delete
814 // the input negation only if it is does not have any uses left.
815 HNot* previous_not = input->AsNot();
816 instruction->ReplaceWith(previous_not->GetInput());
817 instruction->GetBlock()->RemoveInstruction(instruction);
818 if (!previous_not->HasUses()) {
819 previous_not->GetBlock()->RemoveInstruction(previous_not);
820 }
821 RecordSimplification();
822 }
823}
824
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000825void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
826 HConstant* input_cst = instruction->GetConstantRight();
827 HInstruction* input_other = instruction->GetLeastConstantLeft();
828
829 if ((input_cst != nullptr) && input_cst->IsZero()) {
830 // Replace code looking like
831 // OR dst, src, 0
832 // with
833 // src
834 instruction->ReplaceWith(input_other);
835 instruction->GetBlock()->RemoveInstruction(instruction);
836 return;
837 }
838
839 // We assume that GVN has run before, so we only perform a pointer comparison.
840 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100841 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000842 if (instruction->GetLeft() == instruction->GetRight()) {
843 // Replace code looking like
844 // OR dst, src, src
845 // with
846 // src
847 instruction->ReplaceWith(instruction->GetLeft());
848 instruction->GetBlock()->RemoveInstruction(instruction);
849 }
850}
851
852void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
853 VisitShift(instruction);
854}
855
856void InstructionSimplifierVisitor::VisitShr(HShr* instruction) {
857 VisitShift(instruction);
858}
859
860void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
861 HConstant* input_cst = instruction->GetConstantRight();
862 HInstruction* input_other = instruction->GetLeastConstantLeft();
863
Serguei Katkov115b53f2015-08-05 17:03:30 +0600864 Primitive::Type type = instruction->GetType();
865 if (Primitive::IsFloatingPointType(type)) {
866 return;
867 }
868
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000869 if ((input_cst != nullptr) && input_cst->IsZero()) {
870 // Replace code looking like
871 // SUB dst, src, 0
872 // with
873 // src
Serguei Katkov115b53f2015-08-05 17:03:30 +0600874 // Note that we cannot optimize `x - 0.0` to `x` for floating-point. When
875 // `x` is `-0.0`, the former expression yields `0.0`, while the later
876 // yields `-0.0`.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000877 instruction->ReplaceWith(input_other);
878 instruction->GetBlock()->RemoveInstruction(instruction);
879 return;
880 }
881
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000882 HBasicBlock* block = instruction->GetBlock();
883 ArenaAllocator* allocator = GetGraph()->GetArena();
884
Alexandre Rames188d4312015-04-09 18:30:21 +0100885 HInstruction* left = instruction->GetLeft();
886 HInstruction* right = instruction->GetRight();
887 if (left->IsConstant()) {
888 if (Int64FromConstant(left->AsConstant()) == 0) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000889 // Replace code looking like
890 // SUB dst, 0, src
891 // with
892 // NEG dst, src
Alexandre Rames188d4312015-04-09 18:30:21 +0100893 // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000894 // `x` is `0.0`, the former expression yields `0.0`, while the later
895 // yields `-0.0`.
Alexandre Rames188d4312015-04-09 18:30:21 +0100896 HNeg* neg = new (allocator) HNeg(type, right);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000897 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100898 RecordSimplification();
899 return;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000900 }
901 }
Alexandre Rames188d4312015-04-09 18:30:21 +0100902
903 if (left->IsNeg() && right->IsNeg()) {
904 if (TryMoveNegOnInputsAfterBinop(instruction)) {
905 return;
906 }
907 }
908
909 if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) {
910 // Replace code looking like
911 // NEG tmp, b
912 // SUB dst, a, tmp
913 // with
914 // ADD dst, a, b
915 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left, right->AsNeg()->GetInput());
916 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add);
917 RecordSimplification();
918 right->GetBlock()->RemoveInstruction(right);
919 return;
920 }
921
922 if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) {
923 // Replace code looking like
924 // NEG tmp, a
925 // SUB dst, tmp, b
926 // with
927 // ADD tmp, a, b
928 // NEG dst, tmp
929 // The second version is not intrinsically better, but enables more
930 // transformations.
931 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left->AsNeg()->GetInput(), right);
932 instruction->GetBlock()->InsertInstructionBefore(add, instruction);
933 HNeg* neg = new (GetGraph()->GetArena()) HNeg(instruction->GetType(), add);
934 instruction->GetBlock()->InsertInstructionBefore(neg, instruction);
935 instruction->ReplaceWith(neg);
936 instruction->GetBlock()->RemoveInstruction(instruction);
937 RecordSimplification();
938 left->GetBlock()->RemoveInstruction(left);
939 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000940}
941
942void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
943 VisitShift(instruction);
944}
945
946void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
947 HConstant* input_cst = instruction->GetConstantRight();
948 HInstruction* input_other = instruction->GetLeastConstantLeft();
949
950 if ((input_cst != nullptr) && input_cst->IsZero()) {
951 // Replace code looking like
952 // XOR dst, src, 0
953 // with
954 // src
955 instruction->ReplaceWith(input_other);
956 instruction->GetBlock()->RemoveInstruction(instruction);
957 return;
958 }
959
960 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
961 // Replace code looking like
962 // XOR dst, src, 0xFFF...FF
963 // with
964 // NOT dst, src
965 HNot* bitwise_not = new (GetGraph()->GetArena()) HNot(instruction->GetType(), input_other);
966 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not);
Alexandre Rames188d4312015-04-09 18:30:21 +0100967 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000968 return;
969 }
970}
971
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +0100972void InstructionSimplifierVisitor::VisitFakeString(HFakeString* instruction) {
973 HInstruction* actual_string = nullptr;
974
975 // Find the string we need to replace this instruction with. The actual string is
976 // the return value of a StringFactory call.
977 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
978 HInstruction* use = it.Current()->GetUser();
979 if (use->IsInvokeStaticOrDirect()
980 && use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction)) {
981 use->AsInvokeStaticOrDirect()->RemoveFakeStringArgumentAsLastInput();
982 actual_string = use;
983 break;
984 }
985 }
986
987 // Check that there is no other instruction that thinks it is the factory for that string.
988 if (kIsDebugBuild) {
989 CHECK(actual_string != nullptr);
990 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
991 HInstruction* use = it.Current()->GetUser();
992 if (use->IsInvokeStaticOrDirect()) {
993 CHECK(!use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction));
994 }
995 }
996 }
997
998 // We need to remove any environment uses of the fake string that are not dominated by
999 // `actual_string` to null.
1000 for (HUseIterator<HEnvironment*> it(instruction->GetEnvUses()); !it.Done(); it.Advance()) {
1001 HEnvironment* environment = it.Current()->GetUser();
1002 if (!actual_string->StrictlyDominates(environment->GetHolder())) {
1003 environment->RemoveAsUserOfInput(it.Current()->GetIndex());
1004 environment->SetRawEnvAt(it.Current()->GetIndex(), nullptr);
1005 }
1006 }
1007
1008 // Only uses dominated by `actual_string` must remain. We can safely replace and remove
1009 // `instruction`.
1010 instruction->ReplaceWith(actual_string);
1011 instruction->GetBlock()->RemoveInstruction(instruction);
1012}
1013
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001014} // namespace art