blob: 56ec8a7ed18db9a164096fac2d83ab68fdbe7df3 [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)
27 : HGraphVisitor(graph), stats_(stats) {}
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000028
29 private:
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000030 void VisitShift(HBinaryOperation* shift);
31
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000032 void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
33 void VisitEqual(HEqual* equal) OVERRIDE;
34 void VisitArraySet(HArraySet* equal) OVERRIDE;
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +000035 void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
Calin Juravle10e244f2015-01-26 18:54:32 +000036 void VisitNullCheck(HNullCheck* instruction) OVERRIDE;
Mingyao Yang0304e182015-01-30 16:41:29 -080037 void VisitArrayLength(HArrayLength* instruction) OVERRIDE;
Calin Juravleacf735c2015-02-12 15:25:22 +000038 void VisitCheckCast(HCheckCast* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000039 void VisitAdd(HAdd* instruction) OVERRIDE;
40 void VisitAnd(HAnd* instruction) OVERRIDE;
41 void VisitDiv(HDiv* instruction) OVERRIDE;
42 void VisitMul(HMul* instruction) OVERRIDE;
43 void VisitOr(HOr* instruction) OVERRIDE;
44 void VisitShl(HShl* instruction) OVERRIDE;
45 void VisitShr(HShr* instruction) OVERRIDE;
46 void VisitSub(HSub* instruction) OVERRIDE;
47 void VisitUShr(HUShr* instruction) OVERRIDE;
48 void VisitXor(HXor* instruction) OVERRIDE;
Calin Juravleacf735c2015-02-12 15:25:22 +000049
50 OptimizingCompilerStats* stats_;
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000051};
52
Nicolas Geoffray3c049742014-09-24 18:10:46 +010053void InstructionSimplifier::Run() {
Calin Juravleacf735c2015-02-12 15:25:22 +000054 InstructionSimplifierVisitor visitor(graph_, stats_);
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000055 visitor.VisitInsertionOrder();
Nicolas Geoffray3c049742014-09-24 18:10:46 +010056}
57
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000058namespace {
59
60bool AreAllBitsSet(HConstant* constant) {
61 return Int64FromConstant(constant) == -1;
62}
63
64} // namespace
65
66void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
67 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
68 HConstant* input_cst = instruction->GetConstantRight();
69 HInstruction* input_other = instruction->GetLeastConstantLeft();
70
71 if ((input_cst != nullptr) && input_cst->IsZero()) {
72 // Replace code looking like
73 // SHL dst, src, 0
74 // with
75 // src
76 instruction->ReplaceWith(input_other);
77 instruction->GetBlock()->RemoveInstruction(instruction);
78 }
79}
80
Calin Juravle10e244f2015-01-26 18:54:32 +000081void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) {
82 HInstruction* obj = null_check->InputAt(0);
83 if (!obj->CanBeNull()) {
84 null_check->ReplaceWith(obj);
85 null_check->GetBlock()->RemoveInstruction(null_check);
Calin Juravleacf735c2015-02-12 15:25:22 +000086 if (stats_ != nullptr) {
87 stats_->RecordStat(MethodCompilationStat::kRemovedNullCheck);
88 }
89 }
90}
91
92void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
93 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
94 if (!load_class->IsResolved()) {
95 // If the class couldn't be resolve it's not safe to compare against it. It's
96 // default type would be Top which might be wider that the actual class type
97 // and thus producing wrong results.
98 return;
99 }
100 ReferenceTypeInfo obj_rti = check_cast->InputAt(0)->GetReferenceTypeInfo();
101 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
102 ScopedObjectAccess soa(Thread::Current());
103 if (class_rti.IsSupertypeOf(obj_rti)) {
104 check_cast->GetBlock()->RemoveInstruction(check_cast);
105 if (stats_ != nullptr) {
106 stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
107 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000108 }
109}
110
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000111void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100112 HBasicBlock* block = check->GetBlock();
113 // Currently always keep the suspend check at entry.
114 if (block->IsEntryBlock()) return;
115
116 // Currently always keep suspend checks at loop entry.
117 if (block->IsLoopHeader() && block->GetFirstInstruction() == check) {
118 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == check);
119 return;
120 }
121
122 // Remove the suspend check that was added at build time for the baseline
123 // compiler.
124 block->RemoveInstruction(check);
125}
126
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000127void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100128 HInstruction* input1 = equal->InputAt(0);
129 HInstruction* input2 = equal->InputAt(1);
130 if (input1->GetType() == Primitive::kPrimBoolean && input2->IsIntConstant()) {
131 if (input2->AsIntConstant()->GetValue() == 1) {
132 // Replace (bool_value == 1) with bool_value
133 equal->ReplaceWith(equal->InputAt(0));
134 equal->GetBlock()->RemoveInstruction(equal);
135 } else {
Nicolas Geoffrayfa93b502015-01-21 15:44:16 +0000136 // We should replace (bool_value == 0) with !bool_value, but we unfortunately
137 // do not have such instruction.
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100138 DCHECK_EQ(input2->AsIntConstant()->GetValue(), 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100139 }
140 }
141}
142
Mingyao Yang0304e182015-01-30 16:41:29 -0800143void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) {
144 HInstruction* input = instruction->InputAt(0);
145 // If the array is a NewArray with constant size, replace the array length
146 // with the constant instruction. This helps the bounds check elimination phase.
147 if (input->IsNewArray()) {
148 input = input->InputAt(0);
149 if (input->IsIntConstant()) {
150 instruction->ReplaceWith(input);
151 }
152 }
153}
154
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +0000155void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +0000156 HInstruction* value = instruction->GetValue();
157 if (value->GetType() != Primitive::kPrimNot) return;
158
159 if (value->IsArrayGet()) {
160 if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
161 // If the code is just swapping elements in the array, no need for a type check.
162 instruction->ClearNeedsTypeCheck();
163 }
164 }
165}
166
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +0000167void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
168 if (instruction->GetResultType() == instruction->GetInputType()) {
169 // Remove the instruction if it's converting to the same type.
170 instruction->ReplaceWith(instruction->GetInput());
171 instruction->GetBlock()->RemoveInstruction(instruction);
172 }
173}
174
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000175void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
176 HConstant* input_cst = instruction->GetConstantRight();
177 HInstruction* input_other = instruction->GetLeastConstantLeft();
178 if ((input_cst != nullptr) && input_cst->IsZero()) {
179 // Replace code looking like
180 // ADD dst, src, 0
181 // with
182 // src
183 instruction->ReplaceWith(input_other);
184 instruction->GetBlock()->RemoveInstruction(instruction);
185 }
186}
187
188void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
189 HConstant* input_cst = instruction->GetConstantRight();
190 HInstruction* input_other = instruction->GetLeastConstantLeft();
191
192 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
193 // Replace code looking like
194 // AND dst, src, 0xFFF...FF
195 // with
196 // src
197 instruction->ReplaceWith(input_other);
198 instruction->GetBlock()->RemoveInstruction(instruction);
199 return;
200 }
201
202 // We assume that GVN has run before, so we only perform a pointer comparison.
203 // If for some reason the values are equal but the pointers are different, we
204 // are still correct and only miss an optimisation opportunity.
205 if (instruction->GetLeft() == instruction->GetRight()) {
206 // Replace code looking like
207 // AND dst, src, src
208 // with
209 // src
210 instruction->ReplaceWith(instruction->GetLeft());
211 instruction->GetBlock()->RemoveInstruction(instruction);
212 }
213}
214
215void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
216 HConstant* input_cst = instruction->GetConstantRight();
217 HInstruction* input_other = instruction->GetLeastConstantLeft();
218 Primitive::Type type = instruction->GetType();
219
220 if ((input_cst != nullptr) && input_cst->IsOne()) {
221 // Replace code looking like
222 // DIV dst, src, 1
223 // with
224 // src
225 instruction->ReplaceWith(input_other);
226 instruction->GetBlock()->RemoveInstruction(instruction);
227 return;
228 }
229
230 if ((input_cst != nullptr) && input_cst->IsMinusOne() &&
231 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
232 // Replace code looking like
233 // DIV dst, src, -1
234 // with
235 // NEG dst, src
236 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
237 instruction, (new (GetGraph()->GetArena()) HNeg(type, input_other)));
238 }
239}
240
241void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
242 HConstant* input_cst = instruction->GetConstantRight();
243 HInstruction* input_other = instruction->GetLeastConstantLeft();
244 Primitive::Type type = instruction->GetType();
245 HBasicBlock* block = instruction->GetBlock();
246 ArenaAllocator* allocator = GetGraph()->GetArena();
247
248 if (input_cst == nullptr) {
249 return;
250 }
251
252 if (input_cst->IsOne()) {
253 // Replace code looking like
254 // MUL dst, src, 1
255 // with
256 // src
257 instruction->ReplaceWith(input_other);
258 instruction->GetBlock()->RemoveInstruction(instruction);
259 return;
260 }
261
262 if (input_cst->IsMinusOne() &&
263 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
264 // Replace code looking like
265 // MUL dst, src, -1
266 // with
267 // NEG dst, src
268 HNeg* neg = new (allocator) HNeg(type, input_other);
269 block->ReplaceAndRemoveInstructionWith(instruction, neg);
270 return;
271 }
272
273 if (Primitive::IsFloatingPointType(type) &&
274 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
275 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
276 // Replace code looking like
277 // FP_MUL dst, src, 2.0
278 // with
279 // FP_ADD dst, src, src
280 // The 'int' and 'long' cases are handled below.
281 block->ReplaceAndRemoveInstructionWith(instruction,
282 new (allocator) HAdd(type, input_other, input_other));
283 return;
284 }
285
286 if (Primitive::IsIntOrLongType(type)) {
287 int64_t factor = Int64FromConstant(input_cst);
288 // We expect the `0` case to have been handled in the constant folding pass.
289 DCHECK_NE(factor, 0);
290 if (IsPowerOfTwo(factor)) {
291 // Replace code looking like
292 // MUL dst, src, pow_of_2
293 // with
294 // SHL dst, src, log2(pow_of_2)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000295 HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000296 HShl* shl = new(allocator) HShl(type, input_other, shift);
297 block->ReplaceAndRemoveInstructionWith(instruction, shl);
298 }
299 }
300}
301
302void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
303 HConstant* input_cst = instruction->GetConstantRight();
304 HInstruction* input_other = instruction->GetLeastConstantLeft();
305
306 if ((input_cst != nullptr) && input_cst->IsZero()) {
307 // Replace code looking like
308 // OR dst, src, 0
309 // with
310 // src
311 instruction->ReplaceWith(input_other);
312 instruction->GetBlock()->RemoveInstruction(instruction);
313 return;
314 }
315
316 // We assume that GVN has run before, so we only perform a pointer comparison.
317 // If for some reason the values are equal but the pointers are different, we
318 // are still correct and only miss an optimisation opportunity.
319 if (instruction->GetLeft() == instruction->GetRight()) {
320 // Replace code looking like
321 // OR dst, src, src
322 // with
323 // src
324 instruction->ReplaceWith(instruction->GetLeft());
325 instruction->GetBlock()->RemoveInstruction(instruction);
326 }
327}
328
329void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
330 VisitShift(instruction);
331}
332
333void InstructionSimplifierVisitor::VisitShr(HShr* instruction) {
334 VisitShift(instruction);
335}
336
337void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
338 HConstant* input_cst = instruction->GetConstantRight();
339 HInstruction* input_other = instruction->GetLeastConstantLeft();
340
341 if ((input_cst != nullptr) && input_cst->IsZero()) {
342 // Replace code looking like
343 // SUB dst, src, 0
344 // with
345 // src
346 instruction->ReplaceWith(input_other);
347 instruction->GetBlock()->RemoveInstruction(instruction);
348 return;
349 }
350
351 Primitive::Type type = instruction->GetType();
352 if (!Primitive::IsIntegralType(type)) {
353 return;
354 }
355
356 HBasicBlock* block = instruction->GetBlock();
357 ArenaAllocator* allocator = GetGraph()->GetArena();
358
359 if (instruction->GetLeft()->IsConstant()) {
360 int64_t left = Int64FromConstant(instruction->GetLeft()->AsConstant());
361 if (left == 0) {
362 // Replace code looking like
363 // SUB dst, 0, src
364 // with
365 // NEG dst, src
366 // Note that we cannot optimise `0.0 - x` to `-x` for floating-point. When
367 // `x` is `0.0`, the former expression yields `0.0`, while the later
368 // yields `-0.0`.
369 HNeg* neg = new (allocator) HNeg(type, instruction->GetRight());
370 block->ReplaceAndRemoveInstructionWith(instruction, neg);
371 }
372 }
373}
374
375void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
376 VisitShift(instruction);
377}
378
379void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
380 HConstant* input_cst = instruction->GetConstantRight();
381 HInstruction* input_other = instruction->GetLeastConstantLeft();
382
383 if ((input_cst != nullptr) && input_cst->IsZero()) {
384 // Replace code looking like
385 // XOR dst, src, 0
386 // with
387 // src
388 instruction->ReplaceWith(input_other);
389 instruction->GetBlock()->RemoveInstruction(instruction);
390 return;
391 }
392
393 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
394 // Replace code looking like
395 // XOR dst, src, 0xFFF...FF
396 // with
397 // NOT dst, src
398 HNot* bitwise_not = new (GetGraph()->GetArena()) HNot(instruction->GetType(), input_other);
399 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not);
400 return;
401 }
402}
403
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100404} // namespace art