blob: 30dc9b303ae80ec91fba20c2f03c7daf53375c6f [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
510 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
511 // Replace code looking like
512 // AND dst, src, 0xFFF...FF
513 // with
514 // src
515 instruction->ReplaceWith(input_other);
516 instruction->GetBlock()->RemoveInstruction(instruction);
517 return;
518 }
519
520 // We assume that GVN has run before, so we only perform a pointer comparison.
521 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100522 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000523 if (instruction->GetLeft() == instruction->GetRight()) {
524 // Replace code looking like
525 // AND dst, src, src
526 // with
527 // src
528 instruction->ReplaceWith(instruction->GetLeft());
529 instruction->GetBlock()->RemoveInstruction(instruction);
530 }
531}
532
Mark Mendellc4701932015-04-10 13:18:51 -0400533void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) {
534 VisitCondition(condition);
535}
536
537void InstructionSimplifierVisitor::VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) {
538 VisitCondition(condition);
539}
540
541void InstructionSimplifierVisitor::VisitLessThan(HLessThan* condition) {
542 VisitCondition(condition);
543}
544
545void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condition) {
546 VisitCondition(condition);
547}
548
549void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
550 // Try to fold an HCompare into this HCondition.
551
Roland Levillain7f63c522015-07-13 15:54:55 +0000552 // This simplification is currently supported on x86, x86_64, ARM and ARM64.
553 // TODO: Implement it for MIPS64.
Mark Mendellc4701932015-04-10 13:18:51 -0400554 InstructionSet instruction_set = GetGraph()->GetInstructionSet();
Roland Levillain7f63c522015-07-13 15:54:55 +0000555 if (instruction_set == kMips64) {
Mark Mendellc4701932015-04-10 13:18:51 -0400556 return;
557 }
558
559 HInstruction* left = condition->GetLeft();
560 HInstruction* right = condition->GetRight();
561 // We can only replace an HCondition which compares a Compare to 0.
562 // Both 'dx' and 'jack' generate a compare to 0 when compiling a
563 // condition with a long, float or double comparison as input.
564 if (!left->IsCompare() || !right->IsConstant() || right->AsIntConstant()->GetValue() != 0) {
565 // Conversion is not possible.
566 return;
567 }
568
569 // Is the Compare only used for this purpose?
570 if (!left->GetUses().HasOnlyOneUse()) {
571 // Someone else also wants the result of the compare.
572 return;
573 }
574
575 if (!left->GetEnvUses().IsEmpty()) {
576 // There is a reference to the compare result in an environment. Do we really need it?
577 if (GetGraph()->IsDebuggable()) {
578 return;
579 }
580
581 // We have to ensure that there are no deopt points in the sequence.
582 if (left->HasAnyEnvironmentUseBefore(condition)) {
583 return;
584 }
585 }
586
587 // Clean up any environment uses from the HCompare, if any.
588 left->RemoveEnvironmentUsers();
589
590 // We have decided to fold the HCompare into the HCondition. Transfer the information.
591 condition->SetBias(left->AsCompare()->GetBias());
592
593 // Replace the operands of the HCondition.
594 condition->ReplaceInput(left->InputAt(0), 0);
595 condition->ReplaceInput(left->InputAt(1), 1);
596
597 // Remove the HCompare.
598 left->GetBlock()->RemoveInstruction(left);
599
600 RecordSimplification();
601}
602
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000603void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
604 HConstant* input_cst = instruction->GetConstantRight();
605 HInstruction* input_other = instruction->GetLeastConstantLeft();
606 Primitive::Type type = instruction->GetType();
607
608 if ((input_cst != nullptr) && input_cst->IsOne()) {
609 // Replace code looking like
610 // DIV dst, src, 1
611 // with
612 // src
613 instruction->ReplaceWith(input_other);
614 instruction->GetBlock()->RemoveInstruction(instruction);
615 return;
616 }
617
Nicolas Geoffray0d221842015-04-27 08:53:46 +0000618 if ((input_cst != nullptr) && input_cst->IsMinusOne()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000619 // Replace code looking like
620 // DIV dst, src, -1
621 // with
622 // NEG dst, src
623 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
Nicolas Geoffray0d221842015-04-27 08:53:46 +0000624 instruction, new (GetGraph()->GetArena()) HNeg(type, input_other));
Alexandre Rames188d4312015-04-09 18:30:21 +0100625 RecordSimplification();
Nicolas Geoffray0d221842015-04-27 08:53:46 +0000626 return;
627 }
628
629 if ((input_cst != nullptr) && Primitive::IsFloatingPointType(type)) {
630 // Try replacing code looking like
631 // DIV dst, src, constant
632 // with
633 // MUL dst, src, 1 / constant
634 HConstant* reciprocal = nullptr;
635 if (type == Primitive::Primitive::kPrimDouble) {
636 double value = input_cst->AsDoubleConstant()->GetValue();
637 if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) {
638 reciprocal = GetGraph()->GetDoubleConstant(1.0 / value);
639 }
640 } else {
641 DCHECK_EQ(type, Primitive::kPrimFloat);
642 float value = input_cst->AsFloatConstant()->GetValue();
643 if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) {
644 reciprocal = GetGraph()->GetFloatConstant(1.0f / value);
645 }
646 }
647
648 if (reciprocal != nullptr) {
649 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
650 instruction, new (GetGraph()->GetArena()) HMul(type, input_other, reciprocal));
651 RecordSimplification();
652 return;
653 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000654 }
655}
656
657void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
658 HConstant* input_cst = instruction->GetConstantRight();
659 HInstruction* input_other = instruction->GetLeastConstantLeft();
660 Primitive::Type type = instruction->GetType();
661 HBasicBlock* block = instruction->GetBlock();
662 ArenaAllocator* allocator = GetGraph()->GetArena();
663
664 if (input_cst == nullptr) {
665 return;
666 }
667
668 if (input_cst->IsOne()) {
669 // Replace code looking like
670 // MUL dst, src, 1
671 // with
672 // src
673 instruction->ReplaceWith(input_other);
674 instruction->GetBlock()->RemoveInstruction(instruction);
675 return;
676 }
677
678 if (input_cst->IsMinusOne() &&
679 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
680 // Replace code looking like
681 // MUL dst, src, -1
682 // with
683 // NEG dst, src
684 HNeg* neg = new (allocator) HNeg(type, input_other);
685 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100686 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000687 return;
688 }
689
690 if (Primitive::IsFloatingPointType(type) &&
691 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
692 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
693 // Replace code looking like
694 // FP_MUL dst, src, 2.0
695 // with
696 // FP_ADD dst, src, src
697 // The 'int' and 'long' cases are handled below.
698 block->ReplaceAndRemoveInstructionWith(instruction,
699 new (allocator) HAdd(type, input_other, input_other));
Alexandre Rames188d4312015-04-09 18:30:21 +0100700 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000701 return;
702 }
703
704 if (Primitive::IsIntOrLongType(type)) {
705 int64_t factor = Int64FromConstant(input_cst);
Serguei Katkov53849192015-04-20 14:22:27 +0600706 // Even though constant propagation also takes care of the zero case, other
707 // optimizations can lead to having a zero multiplication.
708 if (factor == 0) {
709 // Replace code looking like
710 // MUL dst, src, 0
711 // with
712 // 0
713 instruction->ReplaceWith(input_cst);
714 instruction->GetBlock()->RemoveInstruction(instruction);
715 } else if (IsPowerOfTwo(factor)) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000716 // Replace code looking like
717 // MUL dst, src, pow_of_2
718 // with
719 // SHL dst, src, log2(pow_of_2)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000720 HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000721 HShl* shl = new(allocator) HShl(type, input_other, shift);
722 block->ReplaceAndRemoveInstructionWith(instruction, shl);
Alexandre Rames188d4312015-04-09 18:30:21 +0100723 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000724 }
725 }
726}
727
Alexandre Rames188d4312015-04-09 18:30:21 +0100728void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) {
729 HInstruction* input = instruction->GetInput();
730 if (input->IsNeg()) {
731 // Replace code looking like
732 // NEG tmp, src
733 // NEG dst, tmp
734 // with
735 // src
736 HNeg* previous_neg = input->AsNeg();
737 instruction->ReplaceWith(previous_neg->GetInput());
738 instruction->GetBlock()->RemoveInstruction(instruction);
739 // We perform the optimization even if the input negation has environment
740 // uses since it allows removing the current instruction. But we only delete
741 // the input negation only if it is does not have any uses left.
742 if (!previous_neg->HasUses()) {
743 previous_neg->GetBlock()->RemoveInstruction(previous_neg);
744 }
745 RecordSimplification();
746 return;
747 }
748
Serguei Katkov339dfc22015-04-20 12:29:32 +0600749 if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse() &&
750 !Primitive::IsFloatingPointType(input->GetType())) {
Alexandre Rames188d4312015-04-09 18:30:21 +0100751 // Replace code looking like
752 // SUB tmp, a, b
753 // NEG dst, tmp
754 // with
755 // SUB dst, b, a
756 // We do not perform the optimization if the input subtraction has
757 // environment uses or multiple non-environment uses as it could lead to
758 // worse code. In particular, we do not want the live ranges of `a` and `b`
759 // to be extended if we are not sure the initial 'SUB' instruction can be
760 // removed.
Serguei Katkov339dfc22015-04-20 12:29:32 +0600761 // We do not perform optimization for fp because we could lose the sign of zero.
Alexandre Rames188d4312015-04-09 18:30:21 +0100762 HSub* sub = input->AsSub();
763 HSub* new_sub =
764 new (GetGraph()->GetArena()) HSub(instruction->GetType(), sub->GetRight(), sub->GetLeft());
765 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub);
766 if (!sub->HasUses()) {
767 sub->GetBlock()->RemoveInstruction(sub);
768 }
769 RecordSimplification();
770 }
771}
772
773void InstructionSimplifierVisitor::VisitNot(HNot* instruction) {
774 HInstruction* input = instruction->GetInput();
775 if (input->IsNot()) {
776 // Replace code looking like
777 // NOT tmp, src
778 // NOT dst, tmp
779 // with
780 // src
781 // We perform the optimization even if the input negation has environment
782 // uses since it allows removing the current instruction. But we only delete
783 // the input negation only if it is does not have any uses left.
784 HNot* previous_not = input->AsNot();
785 instruction->ReplaceWith(previous_not->GetInput());
786 instruction->GetBlock()->RemoveInstruction(instruction);
787 if (!previous_not->HasUses()) {
788 previous_not->GetBlock()->RemoveInstruction(previous_not);
789 }
790 RecordSimplification();
791 }
792}
793
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000794void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
795 HConstant* input_cst = instruction->GetConstantRight();
796 HInstruction* input_other = instruction->GetLeastConstantLeft();
797
798 if ((input_cst != nullptr) && input_cst->IsZero()) {
799 // Replace code looking like
800 // OR dst, src, 0
801 // with
802 // src
803 instruction->ReplaceWith(input_other);
804 instruction->GetBlock()->RemoveInstruction(instruction);
805 return;
806 }
807
808 // We assume that GVN has run before, so we only perform a pointer comparison.
809 // If for some reason the values are equal but the pointers are different, we
Alexandre Rames188d4312015-04-09 18:30:21 +0100810 // are still correct and only miss an optimization opportunity.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000811 if (instruction->GetLeft() == instruction->GetRight()) {
812 // Replace code looking like
813 // OR dst, src, src
814 // with
815 // src
816 instruction->ReplaceWith(instruction->GetLeft());
817 instruction->GetBlock()->RemoveInstruction(instruction);
818 }
819}
820
821void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
822 VisitShift(instruction);
823}
824
825void InstructionSimplifierVisitor::VisitShr(HShr* instruction) {
826 VisitShift(instruction);
827}
828
829void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
830 HConstant* input_cst = instruction->GetConstantRight();
831 HInstruction* input_other = instruction->GetLeastConstantLeft();
832
Serguei Katkov115b53f2015-08-05 17:03:30 +0600833 Primitive::Type type = instruction->GetType();
834 if (Primitive::IsFloatingPointType(type)) {
835 return;
836 }
837
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000838 if ((input_cst != nullptr) && input_cst->IsZero()) {
839 // Replace code looking like
840 // SUB dst, src, 0
841 // with
842 // src
Serguei Katkov115b53f2015-08-05 17:03:30 +0600843 // Note that we cannot optimize `x - 0.0` to `x` for floating-point. When
844 // `x` is `-0.0`, the former expression yields `0.0`, while the later
845 // yields `-0.0`.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000846 instruction->ReplaceWith(input_other);
847 instruction->GetBlock()->RemoveInstruction(instruction);
848 return;
849 }
850
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000851 HBasicBlock* block = instruction->GetBlock();
852 ArenaAllocator* allocator = GetGraph()->GetArena();
853
Alexandre Rames188d4312015-04-09 18:30:21 +0100854 HInstruction* left = instruction->GetLeft();
855 HInstruction* right = instruction->GetRight();
856 if (left->IsConstant()) {
857 if (Int64FromConstant(left->AsConstant()) == 0) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000858 // Replace code looking like
859 // SUB dst, 0, src
860 // with
861 // NEG dst, src
Alexandre Rames188d4312015-04-09 18:30:21 +0100862 // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000863 // `x` is `0.0`, the former expression yields `0.0`, while the later
864 // yields `-0.0`.
Alexandre Rames188d4312015-04-09 18:30:21 +0100865 HNeg* neg = new (allocator) HNeg(type, right);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000866 block->ReplaceAndRemoveInstructionWith(instruction, neg);
Alexandre Rames188d4312015-04-09 18:30:21 +0100867 RecordSimplification();
868 return;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000869 }
870 }
Alexandre Rames188d4312015-04-09 18:30:21 +0100871
872 if (left->IsNeg() && right->IsNeg()) {
873 if (TryMoveNegOnInputsAfterBinop(instruction)) {
874 return;
875 }
876 }
877
878 if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) {
879 // Replace code looking like
880 // NEG tmp, b
881 // SUB dst, a, tmp
882 // with
883 // ADD dst, a, b
884 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left, right->AsNeg()->GetInput());
885 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add);
886 RecordSimplification();
887 right->GetBlock()->RemoveInstruction(right);
888 return;
889 }
890
891 if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) {
892 // Replace code looking like
893 // NEG tmp, a
894 // SUB dst, tmp, b
895 // with
896 // ADD tmp, a, b
897 // NEG dst, tmp
898 // The second version is not intrinsically better, but enables more
899 // transformations.
900 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left->AsNeg()->GetInput(), right);
901 instruction->GetBlock()->InsertInstructionBefore(add, instruction);
902 HNeg* neg = new (GetGraph()->GetArena()) HNeg(instruction->GetType(), add);
903 instruction->GetBlock()->InsertInstructionBefore(neg, instruction);
904 instruction->ReplaceWith(neg);
905 instruction->GetBlock()->RemoveInstruction(instruction);
906 RecordSimplification();
907 left->GetBlock()->RemoveInstruction(left);
908 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000909}
910
911void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
912 VisitShift(instruction);
913}
914
915void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
916 HConstant* input_cst = instruction->GetConstantRight();
917 HInstruction* input_other = instruction->GetLeastConstantLeft();
918
919 if ((input_cst != nullptr) && input_cst->IsZero()) {
920 // Replace code looking like
921 // XOR dst, src, 0
922 // with
923 // src
924 instruction->ReplaceWith(input_other);
925 instruction->GetBlock()->RemoveInstruction(instruction);
926 return;
927 }
928
929 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
930 // Replace code looking like
931 // XOR dst, src, 0xFFF...FF
932 // with
933 // NOT dst, src
934 HNot* bitwise_not = new (GetGraph()->GetArena()) HNot(instruction->GetType(), input_other);
935 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not);
Alexandre Rames188d4312015-04-09 18:30:21 +0100936 RecordSimplification();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000937 return;
938 }
939}
940
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +0100941void InstructionSimplifierVisitor::VisitFakeString(HFakeString* instruction) {
942 HInstruction* actual_string = nullptr;
943
944 // Find the string we need to replace this instruction with. The actual string is
945 // the return value of a StringFactory call.
946 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
947 HInstruction* use = it.Current()->GetUser();
948 if (use->IsInvokeStaticOrDirect()
949 && use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction)) {
950 use->AsInvokeStaticOrDirect()->RemoveFakeStringArgumentAsLastInput();
951 actual_string = use;
952 break;
953 }
954 }
955
956 // Check that there is no other instruction that thinks it is the factory for that string.
957 if (kIsDebugBuild) {
958 CHECK(actual_string != nullptr);
959 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
960 HInstruction* use = it.Current()->GetUser();
961 if (use->IsInvokeStaticOrDirect()) {
962 CHECK(!use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction));
963 }
964 }
965 }
966
967 // We need to remove any environment uses of the fake string that are not dominated by
968 // `actual_string` to null.
969 for (HUseIterator<HEnvironment*> it(instruction->GetEnvUses()); !it.Done(); it.Advance()) {
970 HEnvironment* environment = it.Current()->GetUser();
971 if (!actual_string->StrictlyDominates(environment->GetHolder())) {
972 environment->RemoveAsUserOfInput(it.Current()->GetIndex());
973 environment->SetRawEnvAt(it.Current()->GetIndex(), nullptr);
974 }
975 }
976
977 // Only uses dominated by `actual_string` must remain. We can safely replace and remove
978 // `instruction`.
979 instruction->ReplaceWith(actual_string);
980 instruction->GetBlock()->RemoveInstruction(instruction);
981}
982
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100983} // namespace art