1 /*
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
19 #include "art_method-inl.h"
20 #include "class_linker-inl.h"
21 #include "class_root-inl.h"
22 #include "data_type-inl.h"
23 #include "escape.h"
24 #include "intrinsics.h"
25 #include "mirror/class-inl.h"
26 #include "optimizing/nodes.h"
27 #include "scoped_thread_state_change-inl.h"
28 #include "sharpening.h"
29 #include "string_builder_append.h"
30
31 namespace art {
32
33 // Whether to run an exhaustive test of individual HInstructions cloning when each instruction
34 // is replaced with its copy if it is clonable.
35 static constexpr bool kTestInstructionClonerExhaustively = false;
36
37 class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
38 public:
InstructionSimplifierVisitor(HGraph * graph,CodeGenerator * codegen,OptimizingCompilerStats * stats,bool be_loop_friendly)39 InstructionSimplifierVisitor(HGraph* graph,
40 CodeGenerator* codegen,
41 OptimizingCompilerStats* stats,
42 bool be_loop_friendly)
43 : HGraphDelegateVisitor(graph),
44 codegen_(codegen),
45 stats_(stats),
46 be_loop_friendly_(be_loop_friendly) {}
47
48 bool Run();
49
50 private:
RecordSimplification()51 void RecordSimplification() {
52 simplification_occurred_ = true;
53 simplifications_at_current_position_++;
54 MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSimplifications);
55 }
56
57 bool ReplaceRotateWithRor(HBinaryOperation* op, HUShr* ushr, HShl* shl);
58 bool TryReplaceWithRotate(HBinaryOperation* instruction);
59 bool TryReplaceWithRotateConstantPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
60 bool TryReplaceWithRotateRegisterNegPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
61 bool TryReplaceWithRotateRegisterSubPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
62
63 bool TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop);
64 // `op` should be either HOr or HAnd.
65 // De Morgan's laws:
66 // ~a & ~b = ~(a | b) and ~a | ~b = ~(a & b)
67 bool TryDeMorganNegationFactoring(HBinaryOperation* op);
68 bool TryHandleAssociativeAndCommutativeOperation(HBinaryOperation* instruction);
69 bool TrySubtractionChainSimplification(HBinaryOperation* instruction);
70 bool TryCombineVecMultiplyAccumulate(HVecMul* mul);
71 void TryToReuseDiv(HRem* rem);
72
73 void VisitShift(HBinaryOperation* shift);
74 void VisitEqual(HEqual* equal) override;
75 void VisitNotEqual(HNotEqual* equal) override;
76 void VisitBooleanNot(HBooleanNot* bool_not) override;
77 void VisitInstanceFieldSet(HInstanceFieldSet* equal) override;
78 void VisitStaticFieldSet(HStaticFieldSet* equal) override;
79 void VisitArraySet(HArraySet* equal) override;
80 void VisitTypeConversion(HTypeConversion* instruction) override;
81 void VisitNullCheck(HNullCheck* instruction) override;
82 void VisitArrayLength(HArrayLength* instruction) override;
83 void VisitCheckCast(HCheckCast* instruction) override;
84 void VisitAbs(HAbs* instruction) override;
85 void VisitAdd(HAdd* instruction) override;
86 void VisitAnd(HAnd* instruction) override;
87 void VisitCondition(HCondition* instruction) override;
88 void VisitGreaterThan(HGreaterThan* condition) override;
89 void VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) override;
90 void VisitLessThan(HLessThan* condition) override;
91 void VisitLessThanOrEqual(HLessThanOrEqual* condition) override;
92 void VisitBelow(HBelow* condition) override;
93 void VisitBelowOrEqual(HBelowOrEqual* condition) override;
94 void VisitAbove(HAbove* condition) override;
95 void VisitAboveOrEqual(HAboveOrEqual* condition) override;
96 void VisitDiv(HDiv* instruction) override;
97 void VisitRem(HRem* instruction) override;
98 void VisitMul(HMul* instruction) override;
99 void VisitNeg(HNeg* instruction) override;
100 void VisitNot(HNot* instruction) override;
101 void VisitOr(HOr* instruction) override;
102 void VisitShl(HShl* instruction) override;
103 void VisitShr(HShr* instruction) override;
104 void VisitSub(HSub* instruction) override;
105 void VisitUShr(HUShr* instruction) override;
106 void VisitXor(HXor* instruction) override;
107 void VisitSelect(HSelect* select) override;
108 void VisitIf(HIf* instruction) override;
109 void VisitInstanceOf(HInstanceOf* instruction) override;
110 void VisitInvoke(HInvoke* invoke) override;
111 void VisitDeoptimize(HDeoptimize* deoptimize) override;
112 void VisitVecMul(HVecMul* instruction) override;
113 void VisitPredicatedInstanceFieldGet(HPredicatedInstanceFieldGet* instruction) override;
114
115 bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const;
116
117 void SimplifySystemArrayCopy(HInvoke* invoke);
118 void SimplifyStringEquals(HInvoke* invoke);
119 void SimplifyFP2Int(HInvoke* invoke);
120 void SimplifyStringCharAt(HInvoke* invoke);
121 void SimplifyStringLength(HInvoke* invoke);
122 void SimplifyStringIndexOf(HInvoke* invoke);
123 void SimplifyNPEOnArgN(HInvoke* invoke, size_t);
124 void SimplifyReturnThis(HInvoke* invoke);
125 void SimplifyAllocationIntrinsic(HInvoke* invoke);
126
127 CodeGenerator* codegen_;
128 OptimizingCompilerStats* stats_;
129 bool simplification_occurred_ = false;
130 int simplifications_at_current_position_ = 0;
131 // Prohibit optimizations which can affect HInductionVarAnalysis/HLoopOptimization
132 // and prevent loop optimizations:
133 // true - avoid such optimizations.
134 // false - allow such optimizations.
135 // Checked by the following optimizations:
136 // - TryToReuseDiv: simplification of Div+Rem into Div+Mul+Sub.
137 bool be_loop_friendly_;
138 // We ensure we do not loop infinitely. The value should not be too high, since that
139 // would allow looping around the same basic block too many times. The value should
140 // not be too low either, however, since we want to allow revisiting a basic block
141 // with many statements and simplifications at least once.
142 static constexpr int kMaxSamePositionSimplifications = 50;
143 };
144
Run()145 bool InstructionSimplifier::Run() {
146 if (kTestInstructionClonerExhaustively) {
147 CloneAndReplaceInstructionVisitor visitor(graph_);
148 visitor.VisitReversePostOrder();
149 }
150
151 bool be_loop_friendly = (use_all_optimizations_ == false);
152
153 InstructionSimplifierVisitor visitor(graph_, codegen_, stats_, be_loop_friendly);
154 return visitor.Run();
155 }
156
Run()157 bool InstructionSimplifierVisitor::Run() {
158 bool didSimplify = false;
159 // Iterate in reverse post order to open up more simplifications to users
160 // of instructions that got simplified.
161 for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) {
162 // The simplification of an instruction to another instruction may yield
163 // possibilities for other simplifications. So although we perform a reverse
164 // post order visit, we sometimes need to revisit an instruction index.
165 do {
166 simplification_occurred_ = false;
167 VisitBasicBlock(block);
168 if (simplification_occurred_) {
169 didSimplify = true;
170 }
171 } while (simplification_occurred_ &&
172 (simplifications_at_current_position_ < kMaxSamePositionSimplifications));
173 simplifications_at_current_position_ = 0;
174 }
175 return didSimplify;
176 }
177
178 namespace {
179
AreAllBitsSet(HConstant * constant)180 bool AreAllBitsSet(HConstant* constant) {
181 return Int64FromConstant(constant) == -1;
182 }
183
184 } // namespace
185
186 // Returns true if the code was simplified to use only one negation operation
187 // after the binary operation instead of one on each of the inputs.
TryMoveNegOnInputsAfterBinop(HBinaryOperation * binop)188 bool InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop) {
189 DCHECK(binop->IsAdd() || binop->IsSub());
190 DCHECK(binop->GetLeft()->IsNeg() && binop->GetRight()->IsNeg());
191 HNeg* left_neg = binop->GetLeft()->AsNeg();
192 HNeg* right_neg = binop->GetRight()->AsNeg();
193 if (!left_neg->HasOnlyOneNonEnvironmentUse() ||
194 !right_neg->HasOnlyOneNonEnvironmentUse()) {
195 return false;
196 }
197 // Replace code looking like
198 // NEG tmp1, a
199 // NEG tmp2, b
200 // ADD dst, tmp1, tmp2
201 // with
202 // ADD tmp, a, b
203 // NEG dst, tmp
204 // Note that we cannot optimize `(-a) + (-b)` to `-(a + b)` for floating-point.
205 // When `a` is `-0.0` and `b` is `0.0`, the former expression yields `0.0`,
206 // while the later yields `-0.0`.
207 if (!DataType::IsIntegralType(binop->GetType())) {
208 return false;
209 }
210 binop->ReplaceInput(left_neg->GetInput(), 0);
211 binop->ReplaceInput(right_neg->GetInput(), 1);
212 left_neg->GetBlock()->RemoveInstruction(left_neg);
213 right_neg->GetBlock()->RemoveInstruction(right_neg);
214 HNeg* neg = new (GetGraph()->GetAllocator()) HNeg(binop->GetType(), binop);
215 binop->GetBlock()->InsertInstructionBefore(neg, binop->GetNext());
216 binop->ReplaceWithExceptInReplacementAtIndex(neg, 0);
217 RecordSimplification();
218 return true;
219 }
220
TryDeMorganNegationFactoring(HBinaryOperation * op)221 bool InstructionSimplifierVisitor::TryDeMorganNegationFactoring(HBinaryOperation* op) {
222 DCHECK(op->IsAnd() || op->IsOr()) << op->DebugName();
223 DataType::Type type = op->GetType();
224 HInstruction* left = op->GetLeft();
225 HInstruction* right = op->GetRight();
226
227 // We can apply De Morgan's laws if both inputs are Not's and are only used
228 // by `op`.
229 if (((left->IsNot() && right->IsNot()) ||
230 (left->IsBooleanNot() && right->IsBooleanNot())) &&
231 left->HasOnlyOneNonEnvironmentUse() &&
232 right->HasOnlyOneNonEnvironmentUse()) {
233 // Replace code looking like
234 // NOT nota, a
235 // NOT notb, b
236 // AND dst, nota, notb (respectively OR)
237 // with
238 // OR or, a, b (respectively AND)
239 // NOT dest, or
240 HInstruction* src_left = left->InputAt(0);
241 HInstruction* src_right = right->InputAt(0);
242 uint32_t dex_pc = op->GetDexPc();
243
244 // Remove the negations on the inputs.
245 left->ReplaceWith(src_left);
246 right->ReplaceWith(src_right);
247 left->GetBlock()->RemoveInstruction(left);
248 right->GetBlock()->RemoveInstruction(right);
249
250 // Replace the `HAnd` or `HOr`.
251 HBinaryOperation* hbin;
252 if (op->IsAnd()) {
253 hbin = new (GetGraph()->GetAllocator()) HOr(type, src_left, src_right, dex_pc);
254 } else {
255 hbin = new (GetGraph()->GetAllocator()) HAnd(type, src_left, src_right, dex_pc);
256 }
257 HInstruction* hnot;
258 if (left->IsBooleanNot()) {
259 hnot = new (GetGraph()->GetAllocator()) HBooleanNot(hbin, dex_pc);
260 } else {
261 hnot = new (GetGraph()->GetAllocator()) HNot(type, hbin, dex_pc);
262 }
263
264 op->GetBlock()->InsertInstructionBefore(hbin, op);
265 op->GetBlock()->ReplaceAndRemoveInstructionWith(op, hnot);
266
267 RecordSimplification();
268 return true;
269 }
270
271 return false;
272 }
273
TryCombineVecMultiplyAccumulate(HVecMul * mul)274 bool InstructionSimplifierVisitor::TryCombineVecMultiplyAccumulate(HVecMul* mul) {
275 DataType::Type type = mul->GetPackedType();
276 InstructionSet isa = codegen_->GetInstructionSet();
277 switch (isa) {
278 case InstructionSet::kArm64:
279 if (!(type == DataType::Type::kUint8 ||
280 type == DataType::Type::kInt8 ||
281 type == DataType::Type::kUint16 ||
282 type == DataType::Type::kInt16 ||
283 type == DataType::Type::kInt32)) {
284 return false;
285 }
286 break;
287 default:
288 return false;
289 }
290
291 ArenaAllocator* allocator = mul->GetBlock()->GetGraph()->GetAllocator();
292 if (!mul->HasOnlyOneNonEnvironmentUse()) {
293 return false;
294 }
295 HInstruction* binop = mul->GetUses().front().GetUser();
296 if (!binop->IsVecAdd() && !binop->IsVecSub()) {
297 return false;
298 }
299
300 // Replace code looking like
301 // VECMUL tmp, x, y
302 // VECADD/SUB dst, acc, tmp
303 // with
304 // VECMULACC dst, acc, x, y
305 // Note that we do not want to (unconditionally) perform the merge when the
306 // multiplication has multiple uses and it can be merged in all of them.
307 // Multiple uses could happen on the same control-flow path, and we would
308 // then increase the amount of work. In the future we could try to evaluate
309 // whether all uses are on different control-flow paths (using dominance and
310 // reverse-dominance information) and only perform the merge when they are.
311 HInstruction* accumulator = nullptr;
312 HVecBinaryOperation* vec_binop = binop->AsVecBinaryOperation();
313 HInstruction* binop_left = vec_binop->GetLeft();
314 HInstruction* binop_right = vec_binop->GetRight();
315 // This is always true since the `HVecMul` has only one use (which is checked above).
316 DCHECK_NE(binop_left, binop_right);
317 if (binop_right == mul) {
318 accumulator = binop_left;
319 } else {
320 DCHECK_EQ(binop_left, mul);
321 // Only addition is commutative.
322 if (!binop->IsVecAdd()) {
323 return false;
324 }
325 accumulator = binop_right;
326 }
327
328 DCHECK(accumulator != nullptr);
329 HInstruction::InstructionKind kind =
330 binop->IsVecAdd() ? HInstruction::kAdd : HInstruction::kSub;
331
332 bool predicated_simd = vec_binop->IsPredicated();
333 if (predicated_simd && !HVecOperation::HaveSamePredicate(vec_binop, mul)) {
334 return false;
335 }
336
337 HVecMultiplyAccumulate* mulacc =
338 new (allocator) HVecMultiplyAccumulate(allocator,
339 kind,
340 accumulator,
341 mul->GetLeft(),
342 mul->GetRight(),
343 vec_binop->GetPackedType(),
344 vec_binop->GetVectorLength(),
345 vec_binop->GetDexPc());
346
347
348
349 vec_binop->GetBlock()->ReplaceAndRemoveInstructionWith(vec_binop, mulacc);
350 if (predicated_simd) {
351 mulacc->SetGoverningPredicate(vec_binop->GetGoverningPredicate(),
352 vec_binop->GetPredicationKind());
353 }
354
355 DCHECK(!mul->HasUses());
356 mul->GetBlock()->RemoveInstruction(mul);
357 return true;
358 }
359
VisitShift(HBinaryOperation * instruction)360 void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
361 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
362 HInstruction* shift_amount = instruction->GetRight();
363 HInstruction* value = instruction->GetLeft();
364
365 int64_t implicit_mask = (value->GetType() == DataType::Type::kInt64)
366 ? kMaxLongShiftDistance
367 : kMaxIntShiftDistance;
368
369 if (shift_amount->IsConstant()) {
370 int64_t cst = Int64FromConstant(shift_amount->AsConstant());
371 int64_t masked_cst = cst & implicit_mask;
372 if (masked_cst == 0) {
373 // Replace code looking like
374 // SHL dst, value, 0
375 // with
376 // value
377 instruction->ReplaceWith(value);
378 instruction->GetBlock()->RemoveInstruction(instruction);
379 RecordSimplification();
380 return;
381 } else if (masked_cst != cst) {
382 // Replace code looking like
383 // SHL dst, value, cst
384 // where cst exceeds maximum distance with the equivalent
385 // SHL dst, value, cst & implicit_mask
386 // (as defined by shift semantics). This ensures other
387 // optimizations do not need to special case for such situations.
388 DCHECK_EQ(shift_amount->GetType(), DataType::Type::kInt32);
389 instruction->ReplaceInput(GetGraph()->GetIntConstant(masked_cst), /* index= */ 1);
390 RecordSimplification();
391 return;
392 }
393 }
394
395 // Shift operations implicitly mask the shift amount according to the type width. Get rid of
396 // unnecessary And/Or/Xor/Add/Sub/TypeConversion operations on the shift amount that do not
397 // affect the relevant bits.
398 // Replace code looking like
399 // AND adjusted_shift, shift, <superset of implicit mask>
400 // [OR/XOR/ADD/SUB adjusted_shift, shift, <value not overlapping with implicit mask>]
401 // [<conversion-from-integral-non-64-bit-type> adjusted_shift, shift]
402 // SHL dst, value, adjusted_shift
403 // with
404 // SHL dst, value, shift
405 if (shift_amount->IsAnd() ||
406 shift_amount->IsOr() ||
407 shift_amount->IsXor() ||
408 shift_amount->IsAdd() ||
409 shift_amount->IsSub()) {
410 int64_t required_result = shift_amount->IsAnd() ? implicit_mask : 0;
411 HBinaryOperation* bin_op = shift_amount->AsBinaryOperation();
412 HConstant* mask = bin_op->GetConstantRight();
413 if (mask != nullptr && (Int64FromConstant(mask) & implicit_mask) == required_result) {
414 instruction->ReplaceInput(bin_op->GetLeastConstantLeft(), 1);
415 RecordSimplification();
416 return;
417 }
418 } else if (shift_amount->IsTypeConversion()) {
419 DCHECK_NE(shift_amount->GetType(), DataType::Type::kBool); // We never convert to bool.
420 DataType::Type source_type = shift_amount->InputAt(0)->GetType();
421 // Non-integral and 64-bit source types require an explicit type conversion.
422 if (DataType::IsIntegralType(source_type) && !DataType::Is64BitType(source_type)) {
423 instruction->ReplaceInput(shift_amount->AsTypeConversion()->GetInput(), 1);
424 RecordSimplification();
425 return;
426 }
427 }
428 }
429
IsSubRegBitsMinusOther(HSub * sub,size_t reg_bits,HInstruction * other)430 static bool IsSubRegBitsMinusOther(HSub* sub, size_t reg_bits, HInstruction* other) {
431 return (sub->GetRight() == other &&
432 sub->GetLeft()->IsConstant() &&
433 (Int64FromConstant(sub->GetLeft()->AsConstant()) & (reg_bits - 1)) == 0);
434 }
435
ReplaceRotateWithRor(HBinaryOperation * op,HUShr * ushr,HShl * shl)436 bool InstructionSimplifierVisitor::ReplaceRotateWithRor(HBinaryOperation* op,
437 HUShr* ushr,
438 HShl* shl) {
439 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()) << op->DebugName();
440 HRor* ror =
441 new (GetGraph()->GetAllocator()) HRor(ushr->GetType(), ushr->GetLeft(), ushr->GetRight());
442 op->GetBlock()->ReplaceAndRemoveInstructionWith(op, ror);
443 if (!ushr->HasUses()) {
444 ushr->GetBlock()->RemoveInstruction(ushr);
445 }
446 if (!ushr->GetRight()->HasUses()) {
447 ushr->GetRight()->GetBlock()->RemoveInstruction(ushr->GetRight());
448 }
449 if (!shl->HasUses()) {
450 shl->GetBlock()->RemoveInstruction(shl);
451 }
452 if (!shl->GetRight()->HasUses()) {
453 shl->GetRight()->GetBlock()->RemoveInstruction(shl->GetRight());
454 }
455 RecordSimplification();
456 return true;
457 }
458
459 // Try to replace a binary operation flanked by one UShr and one Shl with a bitfield rotation.
TryReplaceWithRotate(HBinaryOperation * op)460 bool InstructionSimplifierVisitor::TryReplaceWithRotate(HBinaryOperation* op) {
461 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
462 HInstruction* left = op->GetLeft();
463 HInstruction* right = op->GetRight();
464 // If we have an UShr and a Shl (in either order).
465 if ((left->IsUShr() && right->IsShl()) || (left->IsShl() && right->IsUShr())) {
466 HUShr* ushr = left->IsUShr() ? left->AsUShr() : right->AsUShr();
467 HShl* shl = left->IsShl() ? left->AsShl() : right->AsShl();
468 DCHECK(DataType::IsIntOrLongType(ushr->GetType()));
469 if (ushr->GetType() == shl->GetType() &&
470 ushr->GetLeft() == shl->GetLeft()) {
471 if (ushr->GetRight()->IsConstant() && shl->GetRight()->IsConstant()) {
472 // Shift distances are both constant, try replacing with Ror if they
473 // add up to the register size.
474 return TryReplaceWithRotateConstantPattern(op, ushr, shl);
475 } else if (ushr->GetRight()->IsSub() || shl->GetRight()->IsSub()) {
476 // Shift distances are potentially of the form x and (reg_size - x).
477 return TryReplaceWithRotateRegisterSubPattern(op, ushr, shl);
478 } else if (ushr->GetRight()->IsNeg() || shl->GetRight()->IsNeg()) {
479 // Shift distances are potentially of the form d and -d.
480 return TryReplaceWithRotateRegisterNegPattern(op, ushr, shl);
481 }
482 }
483 }
484 return false;
485 }
486
487 // Try replacing code looking like (x >>> #rdist OP x << #ldist):
488 // UShr dst, x, #rdist
489 // Shl tmp, x, #ldist
490 // OP dst, dst, tmp
491 // or like (x >>> #rdist OP x << #-ldist):
492 // UShr dst, x, #rdist
493 // Shl tmp, x, #-ldist
494 // OP dst, dst, tmp
495 // with
496 // Ror dst, x, #rdist
TryReplaceWithRotateConstantPattern(HBinaryOperation * op,HUShr * ushr,HShl * shl)497 bool InstructionSimplifierVisitor::TryReplaceWithRotateConstantPattern(HBinaryOperation* op,
498 HUShr* ushr,
499 HShl* shl) {
500 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
501 size_t reg_bits = DataType::Size(ushr->GetType()) * kBitsPerByte;
502 size_t rdist = Int64FromConstant(ushr->GetRight()->AsConstant());
503 size_t ldist = Int64FromConstant(shl->GetRight()->AsConstant());
504 if (((ldist + rdist) & (reg_bits - 1)) == 0) {
505 ReplaceRotateWithRor(op, ushr, shl);
506 return true;
507 }
508 return false;
509 }
510
511 // Replace code looking like (x >>> -d OP x << d):
512 // Neg neg, d
513 // UShr dst, x, neg
514 // Shl tmp, x, d
515 // OP dst, dst, tmp
516 // with
517 // Neg neg, d
518 // Ror dst, x, neg
519 // *** OR ***
520 // Replace code looking like (x >>> d OP x << -d):
521 // UShr dst, x, d
522 // Neg neg, d
523 // Shl tmp, x, neg
524 // OP dst, dst, tmp
525 // with
526 // Ror dst, x, d
TryReplaceWithRotateRegisterNegPattern(HBinaryOperation * op,HUShr * ushr,HShl * shl)527 bool InstructionSimplifierVisitor::TryReplaceWithRotateRegisterNegPattern(HBinaryOperation* op,
528 HUShr* ushr,
529 HShl* shl) {
530 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
531 DCHECK(ushr->GetRight()->IsNeg() || shl->GetRight()->IsNeg());
532 bool neg_is_left = shl->GetRight()->IsNeg();
533 HNeg* neg = neg_is_left ? shl->GetRight()->AsNeg() : ushr->GetRight()->AsNeg();
534 // And the shift distance being negated is the distance being shifted the other way.
535 if (neg->InputAt(0) == (neg_is_left ? ushr->GetRight() : shl->GetRight())) {
536 ReplaceRotateWithRor(op, ushr, shl);
537 }
538 return false;
539 }
540
541 // Try replacing code looking like (x >>> d OP x << (#bits - d)):
542 // UShr dst, x, d
543 // Sub ld, #bits, d
544 // Shl tmp, x, ld
545 // OP dst, dst, tmp
546 // with
547 // Ror dst, x, d
548 // *** OR ***
549 // Replace code looking like (x >>> (#bits - d) OP x << d):
550 // Sub rd, #bits, d
551 // UShr dst, x, rd
552 // Shl tmp, x, d
553 // OP dst, dst, tmp
554 // with
555 // Neg neg, d
556 // Ror dst, x, neg
TryReplaceWithRotateRegisterSubPattern(HBinaryOperation * op,HUShr * ushr,HShl * shl)557 bool InstructionSimplifierVisitor::TryReplaceWithRotateRegisterSubPattern(HBinaryOperation* op,
558 HUShr* ushr,
559 HShl* shl) {
560 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
561 DCHECK(ushr->GetRight()->IsSub() || shl->GetRight()->IsSub());
562 size_t reg_bits = DataType::Size(ushr->GetType()) * kBitsPerByte;
563 HInstruction* shl_shift = shl->GetRight();
564 HInstruction* ushr_shift = ushr->GetRight();
565 if ((shl_shift->IsSub() && IsSubRegBitsMinusOther(shl_shift->AsSub(), reg_bits, ushr_shift)) ||
566 (ushr_shift->IsSub() && IsSubRegBitsMinusOther(ushr_shift->AsSub(), reg_bits, shl_shift))) {
567 return ReplaceRotateWithRor(op, ushr, shl);
568 }
569 return false;
570 }
571
VisitNullCheck(HNullCheck * null_check)572 void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) {
573 HInstruction* obj = null_check->InputAt(0);
574 if (!obj->CanBeNull()) {
575 null_check->ReplaceWith(obj);
576 null_check->GetBlock()->RemoveInstruction(null_check);
577 if (stats_ != nullptr) {
578 stats_->RecordStat(MethodCompilationStat::kRemovedNullCheck);
579 }
580 }
581 }
582
CanEnsureNotNullAt(HInstruction * input,HInstruction * at) const583 bool InstructionSimplifierVisitor::CanEnsureNotNullAt(HInstruction* input, HInstruction* at) const {
584 if (!input->CanBeNull()) {
585 return true;
586 }
587
588 for (const HUseListNode<HInstruction*>& use : input->GetUses()) {
589 HInstruction* user = use.GetUser();
590 if (user->IsNullCheck() && user->StrictlyDominates(at)) {
591 return true;
592 }
593 }
594
595 return false;
596 }
597
598 // Returns whether doing a type test between the class of `object` against `klass` has
599 // a statically known outcome. The result of the test is stored in `outcome`.
TypeCheckHasKnownOutcome(ReferenceTypeInfo class_rti,HInstruction * object,bool * outcome)600 static bool TypeCheckHasKnownOutcome(ReferenceTypeInfo class_rti,
601 HInstruction* object,
602 /*out*/bool* outcome) {
603 DCHECK(!object->IsNullConstant()) << "Null constants should be special cased";
604 ReferenceTypeInfo obj_rti = object->GetReferenceTypeInfo();
605 ScopedObjectAccess soa(Thread::Current());
606 if (!obj_rti.IsValid()) {
607 // We run the simplifier before the reference type propagation so type info might not be
608 // available.
609 return false;
610 }
611
612 if (!class_rti.IsValid()) {
613 // Happens when the loaded class is unresolved.
614 if (obj_rti.IsExact()) {
615 // outcome == 'true' && obj_rti is valid implies that class_rti is valid.
616 // Since that's a contradiction we must not pass this check.
617 *outcome = false;
618 return true;
619 } else {
620 // We aren't able to say anything in particular since we don't know the
621 // exact type of the object.
622 return false;
623 }
624 }
625 DCHECK(class_rti.IsExact());
626 if (class_rti.IsSupertypeOf(obj_rti)) {
627 *outcome = true;
628 return true;
629 } else if (obj_rti.IsExact()) {
630 // The test failed at compile time so will also fail at runtime.
631 *outcome = false;
632 return true;
633 } else if (!class_rti.IsInterface()
634 && !obj_rti.IsInterface()
635 && !obj_rti.IsSupertypeOf(class_rti)) {
636 // Different type hierarchy. The test will fail.
637 *outcome = false;
638 return true;
639 }
640 return false;
641 }
642
VisitCheckCast(HCheckCast * check_cast)643 void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
644 HInstruction* object = check_cast->InputAt(0);
645 if (CanEnsureNotNullAt(object, check_cast)) {
646 check_cast->ClearMustDoNullCheck();
647 }
648
649 if (object->IsNullConstant()) {
650 check_cast->GetBlock()->RemoveInstruction(check_cast);
651 MaybeRecordStat(stats_, MethodCompilationStat::kRemovedCheckedCast);
652 return;
653 }
654
655 // Minor correctness check.
656 DCHECK(check_cast->GetTargetClass()->StrictlyDominates(check_cast))
657 << "Illegal graph!\n"
658 << check_cast->DumpWithArgs();
659
660 // Historical note: The `outcome` was initialized to please Valgrind - the compiler can reorder
661 // the return value check with the `outcome` check, b/27651442.
662 bool outcome = false;
663 if (TypeCheckHasKnownOutcome(check_cast->GetTargetClassRTI(), object, &outcome)) {
664 if (outcome) {
665 check_cast->GetBlock()->RemoveInstruction(check_cast);
666 MaybeRecordStat(stats_, MethodCompilationStat::kRemovedCheckedCast);
667 if (check_cast->GetTypeCheckKind() != TypeCheckKind::kBitstringCheck) {
668 HLoadClass* load_class = check_cast->GetTargetClass();
669 if (!load_class->HasUses() && !load_class->NeedsAccessCheck()) {
670 // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw.
671 // However, here we know that it cannot because the checkcast was successful, hence
672 // the class was already loaded.
673 load_class->GetBlock()->RemoveInstruction(load_class);
674 }
675 }
676 } else {
677 // TODO Don't do anything for exceptional cases for now. Ideally we should
678 // remove all instructions and blocks this instruction dominates and
679 // replace it with a manual throw.
680 }
681 }
682 }
683
VisitInstanceOf(HInstanceOf * instruction)684 void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) {
685 HInstruction* object = instruction->InputAt(0);
686
687 bool can_be_null = true;
688 if (CanEnsureNotNullAt(object, instruction)) {
689 can_be_null = false;
690 instruction->ClearMustDoNullCheck();
691 }
692
693 HGraph* graph = GetGraph();
694 if (object->IsNullConstant()) {
695 MaybeRecordStat(stats_, MethodCompilationStat::kRemovedInstanceOf);
696 instruction->ReplaceWith(graph->GetIntConstant(0));
697 instruction->GetBlock()->RemoveInstruction(instruction);
698 RecordSimplification();
699 return;
700 }
701
702 // Minor correctness check.
703 DCHECK(instruction->GetTargetClass()->StrictlyDominates(instruction))
704 << "Illegal graph!\n"
705 << instruction->DumpWithArgs();
706
707 // Historical note: The `outcome` was initialized to please Valgrind - the compiler can reorder
708 // the return value check with the `outcome` check, b/27651442.
709 bool outcome = false;
710 if (TypeCheckHasKnownOutcome(instruction->GetTargetClassRTI(), object, &outcome)) {
711 MaybeRecordStat(stats_, MethodCompilationStat::kRemovedInstanceOf);
712 if (outcome && can_be_null) {
713 // Type test will succeed, we just need a null test.
714 HNotEqual* test = new (graph->GetAllocator()) HNotEqual(graph->GetNullConstant(), object);
715 instruction->GetBlock()->InsertInstructionBefore(test, instruction);
716 instruction->ReplaceWith(test);
717 } else {
718 // We've statically determined the result of the instanceof.
719 instruction->ReplaceWith(graph->GetIntConstant(outcome));
720 }
721 RecordSimplification();
722 instruction->GetBlock()->RemoveInstruction(instruction);
723 if (outcome && instruction->GetTypeCheckKind() != TypeCheckKind::kBitstringCheck) {
724 HLoadClass* load_class = instruction->GetTargetClass();
725 if (!load_class->HasUses() && !load_class->NeedsAccessCheck()) {
726 // We cannot rely on DCE to remove the class because the `HLoadClass`
727 // thinks it can throw. However, here we know that it cannot because the
728 // instanceof check was successful and we don't need to check the
729 // access, hence the class was already loaded.
730 load_class->GetBlock()->RemoveInstruction(load_class);
731 }
732 }
733 }
734 }
735
VisitInstanceFieldSet(HInstanceFieldSet * instruction)736 void InstructionSimplifierVisitor::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
737 if ((instruction->GetValue()->GetType() == DataType::Type::kReference)
738 && CanEnsureNotNullAt(instruction->GetValue(), instruction)) {
739 instruction->ClearValueCanBeNull();
740 }
741 }
742
VisitStaticFieldSet(HStaticFieldSet * instruction)743 void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruction) {
744 if ((instruction->GetValue()->GetType() == DataType::Type::kReference)
745 && CanEnsureNotNullAt(instruction->GetValue(), instruction)) {
746 instruction->ClearValueCanBeNull();
747 }
748 }
749
GetOppositeConditionSwapOps(ArenaAllocator * allocator,HInstruction * cond)750 static HCondition* GetOppositeConditionSwapOps(ArenaAllocator* allocator, HInstruction* cond) {
751 HInstruction *lhs = cond->InputAt(0);
752 HInstruction *rhs = cond->InputAt(1);
753 switch (cond->GetKind()) {
754 case HInstruction::kEqual:
755 return new (allocator) HEqual(rhs, lhs);
756 case HInstruction::kNotEqual:
757 return new (allocator) HNotEqual(rhs, lhs);
758 case HInstruction::kLessThan:
759 return new (allocator) HGreaterThan(rhs, lhs);
760 case HInstruction::kLessThanOrEqual:
761 return new (allocator) HGreaterThanOrEqual(rhs, lhs);
762 case HInstruction::kGreaterThan:
763 return new (allocator) HLessThan(rhs, lhs);
764 case HInstruction::kGreaterThanOrEqual:
765 return new (allocator) HLessThanOrEqual(rhs, lhs);
766 case HInstruction::kBelow:
767 return new (allocator) HAbove(rhs, lhs);
768 case HInstruction::kBelowOrEqual:
769 return new (allocator) HAboveOrEqual(rhs, lhs);
770 case HInstruction::kAbove:
771 return new (allocator) HBelow(rhs, lhs);
772 case HInstruction::kAboveOrEqual:
773 return new (allocator) HBelowOrEqual(rhs, lhs);
774 default:
775 LOG(FATAL) << "Unknown ConditionType " << cond->GetKind();
776 UNREACHABLE();
777 }
778 }
779
VisitEqual(HEqual * equal)780 void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
781 HInstruction* input_const = equal->GetConstantRight();
782 if (input_const != nullptr) {
783 HInstruction* input_value = equal->GetLeastConstantLeft();
784 if ((input_value->GetType() == DataType::Type::kBool) && input_const->IsIntConstant()) {
785 HBasicBlock* block = equal->GetBlock();
786 // We are comparing the boolean to a constant which is of type int and can
787 // be any constant.
788 if (input_const->AsIntConstant()->IsTrue()) {
789 // Replace (bool_value == true) with bool_value
790 equal->ReplaceWith(input_value);
791 block->RemoveInstruction(equal);
792 RecordSimplification();
793 } else if (input_const->AsIntConstant()->IsFalse()) {
794 // Replace (bool_value == false) with !bool_value
795 equal->ReplaceWith(GetGraph()->InsertOppositeCondition(input_value, equal));
796 block->RemoveInstruction(equal);
797 RecordSimplification();
798 } else {
799 // Replace (bool_value == integer_not_zero_nor_one_constant) with false
800 equal->ReplaceWith(GetGraph()->GetIntConstant(0));
801 block->RemoveInstruction(equal);
802 RecordSimplification();
803 }
804 } else {
805 VisitCondition(equal);
806 }
807 } else {
808 VisitCondition(equal);
809 }
810 }
811
VisitNotEqual(HNotEqual * not_equal)812 void InstructionSimplifierVisitor::VisitNotEqual(HNotEqual* not_equal) {
813 HInstruction* input_const = not_equal->GetConstantRight();
814 if (input_const != nullptr) {
815 HInstruction* input_value = not_equal->GetLeastConstantLeft();
816 if ((input_value->GetType() == DataType::Type::kBool) && input_const->IsIntConstant()) {
817 HBasicBlock* block = not_equal->GetBlock();
818 // We are comparing the boolean to a constant which is of type int and can
819 // be any constant.
820 if (input_const->AsIntConstant()->IsTrue()) {
821 // Replace (bool_value != true) with !bool_value
822 not_equal->ReplaceWith(GetGraph()->InsertOppositeCondition(input_value, not_equal));
823 block->RemoveInstruction(not_equal);
824 RecordSimplification();
825 } else if (input_const->AsIntConstant()->IsFalse()) {
826 // Replace (bool_value != false) with bool_value
827 not_equal->ReplaceWith(input_value);
828 block->RemoveInstruction(not_equal);
829 RecordSimplification();
830 } else {
831 // Replace (bool_value != integer_not_zero_nor_one_constant) with true
832 not_equal->ReplaceWith(GetGraph()->GetIntConstant(1));
833 block->RemoveInstruction(not_equal);
834 RecordSimplification();
835 }
836 } else {
837 VisitCondition(not_equal);
838 }
839 } else {
840 VisitCondition(not_equal);
841 }
842 }
843
VisitBooleanNot(HBooleanNot * bool_not)844 void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) {
845 HInstruction* input = bool_not->InputAt(0);
846 HInstruction* replace_with = nullptr;
847
848 if (input->IsIntConstant()) {
849 // Replace !(true/false) with false/true.
850 if (input->AsIntConstant()->IsTrue()) {
851 replace_with = GetGraph()->GetIntConstant(0);
852 } else {
853 DCHECK(input->AsIntConstant()->IsFalse()) << input->AsIntConstant()->GetValue();
854 replace_with = GetGraph()->GetIntConstant(1);
855 }
856 } else if (input->IsBooleanNot()) {
857 // Replace (!(!bool_value)) with bool_value.
858 replace_with = input->InputAt(0);
859 } else if (input->IsCondition() &&
860 // Don't change FP compares. The definition of compares involving
861 // NaNs forces the compares to be done as written by the user.
862 !DataType::IsFloatingPointType(input->InputAt(0)->GetType())) {
863 // Replace condition with its opposite.
864 replace_with = GetGraph()->InsertOppositeCondition(input->AsCondition(), bool_not);
865 }
866
867 if (replace_with != nullptr) {
868 bool_not->ReplaceWith(replace_with);
869 bool_not->GetBlock()->RemoveInstruction(bool_not);
870 RecordSimplification();
871 }
872 }
873
874 // Constructs a new ABS(x) node in the HIR.
NewIntegralAbs(ArenaAllocator * allocator,HInstruction * x,HInstruction * cursor)875 static HInstruction* NewIntegralAbs(ArenaAllocator* allocator,
876 HInstruction* x,
877 HInstruction* cursor) {
878 DataType::Type type = DataType::Kind(x->GetType());
879 DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
880 HAbs* abs = new (allocator) HAbs(type, x, cursor->GetDexPc());
881 cursor->GetBlock()->InsertInstructionBefore(abs, cursor);
882 return abs;
883 }
884
885 // Constructs a new MIN/MAX(x, y) node in the HIR.
NewIntegralMinMax(ArenaAllocator * allocator,HInstruction * x,HInstruction * y,HInstruction * cursor,bool is_min)886 static HInstruction* NewIntegralMinMax(ArenaAllocator* allocator,
887 HInstruction* x,
888 HInstruction* y,
889 HInstruction* cursor,
890 bool is_min) {
891 DataType::Type type = DataType::Kind(x->GetType());
892 DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
893 HBinaryOperation* minmax = nullptr;
894 if (is_min) {
895 minmax = new (allocator) HMin(type, x, y, cursor->GetDexPc());
896 } else {
897 minmax = new (allocator) HMax(type, x, y, cursor->GetDexPc());
898 }
899 cursor->GetBlock()->InsertInstructionBefore(minmax, cursor);
900 return minmax;
901 }
902
903 // Returns true if operands a and b consists of widening type conversions
904 // (either explicit or implicit) to the given to_type.
AreLowerPrecisionArgs(DataType::Type to_type,HInstruction * a,HInstruction * b)905 static bool AreLowerPrecisionArgs(DataType::Type to_type, HInstruction* a, HInstruction* b) {
906 if (a->IsTypeConversion() && a->GetType() == to_type) {
907 a = a->InputAt(0);
908 }
909 if (b->IsTypeConversion() && b->GetType() == to_type) {
910 b = b->InputAt(0);
911 }
912 DataType::Type type1 = a->GetType();
913 DataType::Type type2 = b->GetType();
914 return (type1 == DataType::Type::kUint8 && type2 == DataType::Type::kUint8) ||
915 (type1 == DataType::Type::kInt8 && type2 == DataType::Type::kInt8) ||
916 (type1 == DataType::Type::kInt16 && type2 == DataType::Type::kInt16) ||
917 (type1 == DataType::Type::kUint16 && type2 == DataType::Type::kUint16) ||
918 (type1 == DataType::Type::kInt32 && type2 == DataType::Type::kInt32 &&
919 to_type == DataType::Type::kInt64);
920 }
921
922 // Returns an acceptable substitution for "a" on the select
923 // construct "a <cmp> b ? c : .." during MIN/MAX recognition.
AllowInMinMax(IfCondition cmp,HInstruction * a,HInstruction * b,HInstruction * c)924 static HInstruction* AllowInMinMax(IfCondition cmp,
925 HInstruction* a,
926 HInstruction* b,
927 HInstruction* c) {
928 int64_t value = 0;
929 if (IsInt64AndGet(b, /*out*/ &value) &&
930 (((cmp == kCondLT || cmp == kCondLE) && c->IsMax()) ||
931 ((cmp == kCondGT || cmp == kCondGE) && c->IsMin()))) {
932 HConstant* other = c->AsBinaryOperation()->GetConstantRight();
933 if (other != nullptr && a == c->AsBinaryOperation()->GetLeastConstantLeft()) {
934 int64_t other_value = Int64FromConstant(other);
935 bool is_max = (cmp == kCondLT || cmp == kCondLE);
936 // Allow the max for a < 100 ? max(a, -100) : ..
937 // or the min for a > -100 ? min(a, 100) : ..
938 if (is_max ? (value >= other_value) : (value <= other_value)) {
939 return c;
940 }
941 }
942 }
943 return nullptr;
944 }
945
946 // TODO This should really be done by LSE itself since there is significantly
947 // more information available there.
VisitPredicatedInstanceFieldGet(HPredicatedInstanceFieldGet * pred_get)948 void InstructionSimplifierVisitor::VisitPredicatedInstanceFieldGet(
949 HPredicatedInstanceFieldGet* pred_get) {
950 HInstruction* target = pred_get->GetTarget();
951 HInstruction* default_val = pred_get->GetDefaultValue();
952 if (target->IsNullConstant()) {
953 pred_get->ReplaceWith(default_val);
954 pred_get->GetBlock()->RemoveInstruction(pred_get);
955 RecordSimplification();
956 return;
957 } else if (!target->CanBeNull()) {
958 HInstruction* replace_with = new (GetGraph()->GetAllocator())
959 HInstanceFieldGet(pred_get->GetTarget(),
960 pred_get->GetFieldInfo().GetField(),
961 pred_get->GetFieldType(),
962 pred_get->GetFieldOffset(),
963 pred_get->IsVolatile(),
964 pred_get->GetFieldInfo().GetFieldIndex(),
965 pred_get->GetFieldInfo().GetDeclaringClassDefIndex(),
966 pred_get->GetFieldInfo().GetDexFile(),
967 pred_get->GetDexPc());
968 if (pred_get->GetType() == DataType::Type::kReference) {
969 replace_with->SetReferenceTypeInfo(pred_get->GetReferenceTypeInfo());
970 }
971 pred_get->GetBlock()->InsertInstructionBefore(replace_with, pred_get);
972 pred_get->ReplaceWith(replace_with);
973 pred_get->GetBlock()->RemoveInstruction(pred_get);
974 RecordSimplification();
975 return;
976 }
977 if (!target->IsPhi() || !default_val->IsPhi() || default_val->GetBlock() != target->GetBlock()) {
978 // The iget has already been reduced. We know the target or the phi
979 // selection will differ between the target and default.
980 return;
981 }
982 DCHECK_EQ(default_val->InputCount(), target->InputCount());
983 // In the same block both phis only one non-null we can remove the phi from default_val.
984 HInstruction* single_value = nullptr;
985 auto inputs = target->GetInputs();
986 for (auto [input, idx] : ZipCount(MakeIterationRange(inputs))) {
987 if (input->CanBeNull()) {
988 if (single_value == nullptr) {
989 single_value = default_val->InputAt(idx);
990 } else if (single_value != default_val->InputAt(idx) &&
991 !single_value->Equals(default_val->InputAt(idx))) {
992 // Multiple values are associated with potential nulls, can't combine.
993 return;
994 }
995 }
996 }
997 DCHECK(single_value != nullptr) << "All target values are non-null but the phi as a whole still"
998 << " can be null? This should not be possible." << std::endl
999 << pred_get->DumpWithArgs();
1000 if (single_value->StrictlyDominates(pred_get)) {
1001 // Combine all the maybe null values into one.
1002 pred_get->ReplaceInput(single_value, 0);
1003 RecordSimplification();
1004 }
1005 }
1006
VisitSelect(HSelect * select)1007 void InstructionSimplifierVisitor::VisitSelect(HSelect* select) {
1008 HInstruction* replace_with = nullptr;
1009 HInstruction* condition = select->GetCondition();
1010 HInstruction* true_value = select->GetTrueValue();
1011 HInstruction* false_value = select->GetFalseValue();
1012
1013 if (condition->IsBooleanNot()) {
1014 // Change ((!cond) ? x : y) to (cond ? y : x).
1015 condition = condition->InputAt(0);
1016 std::swap(true_value, false_value);
1017 select->ReplaceInput(false_value, 0);
1018 select->ReplaceInput(true_value, 1);
1019 select->ReplaceInput(condition, 2);
1020 RecordSimplification();
1021 }
1022
1023 if (true_value == false_value) {
1024 // Replace (cond ? x : x) with (x).
1025 replace_with = true_value;
1026 } else if (condition->IsIntConstant()) {
1027 if (condition->AsIntConstant()->IsTrue()) {
1028 // Replace (true ? x : y) with (x).
1029 replace_with = true_value;
1030 } else {
1031 // Replace (false ? x : y) with (y).
1032 DCHECK(condition->AsIntConstant()->IsFalse()) << condition->AsIntConstant()->GetValue();
1033 replace_with = false_value;
1034 }
1035 } else if (true_value->IsIntConstant() && false_value->IsIntConstant()) {
1036 if (true_value->AsIntConstant()->IsTrue() && false_value->AsIntConstant()->IsFalse()) {
1037 // Replace (cond ? true : false) with (cond).
1038 replace_with = condition;
1039 } else if (true_value->AsIntConstant()->IsFalse() && false_value->AsIntConstant()->IsTrue()) {
1040 // Replace (cond ? false : true) with (!cond).
1041 replace_with = GetGraph()->InsertOppositeCondition(condition, select);
1042 }
1043 } else if (condition->IsCondition()) {
1044 IfCondition cmp = condition->AsCondition()->GetCondition();
1045 HInstruction* a = condition->InputAt(0);
1046 HInstruction* b = condition->InputAt(1);
1047 DataType::Type t_type = true_value->GetType();
1048 DataType::Type f_type = false_value->GetType();
1049 // Here we have a <cmp> b ? true_value : false_value.
1050 // Test if both values are compatible integral types (resulting MIN/MAX/ABS
1051 // type will be int or long, like the condition). Replacements are general,
1052 // but assume conditions prefer constants on the right.
1053 if (DataType::IsIntegralType(t_type) && DataType::Kind(t_type) == DataType::Kind(f_type)) {
1054 // Allow a < 100 ? max(a, -100) : ..
1055 // or a > -100 ? min(a, 100) : ..
1056 // to use min/max instead of a to detect nested min/max expressions.
1057 HInstruction* new_a = AllowInMinMax(cmp, a, b, true_value);
1058 if (new_a != nullptr) {
1059 a = new_a;
1060 }
1061 // Try to replace typical integral MIN/MAX/ABS constructs.
1062 if ((cmp == kCondLT || cmp == kCondLE || cmp == kCondGT || cmp == kCondGE) &&
1063 ((a == true_value && b == false_value) ||
1064 (b == true_value && a == false_value))) {
1065 // Found a < b ? a : b (MIN) or a < b ? b : a (MAX)
1066 // or a > b ? a : b (MAX) or a > b ? b : a (MIN).
1067 bool is_min = (cmp == kCondLT || cmp == kCondLE) == (a == true_value);
1068 replace_with = NewIntegralMinMax(GetGraph()->GetAllocator(), a, b, select, is_min);
1069 } else if (((cmp == kCondLT || cmp == kCondLE) && true_value->IsNeg()) ||
1070 ((cmp == kCondGT || cmp == kCondGE) && false_value->IsNeg())) {
1071 bool negLeft = (cmp == kCondLT || cmp == kCondLE);
1072 HInstruction* the_negated = negLeft ? true_value->InputAt(0) : false_value->InputAt(0);
1073 HInstruction* not_negated = negLeft ? false_value : true_value;
1074 if (a == the_negated && a == not_negated && IsInt64Value(b, 0)) {
1075 // Found a < 0 ? -a : a
1076 // or a > 0 ? a : -a
1077 // which can be replaced by ABS(a).
1078 replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), a, select);
1079 }
1080 } else if (true_value->IsSub() && false_value->IsSub()) {
1081 HInstruction* true_sub1 = true_value->InputAt(0);
1082 HInstruction* true_sub2 = true_value->InputAt(1);
1083 HInstruction* false_sub1 = false_value->InputAt(0);
1084 HInstruction* false_sub2 = false_value->InputAt(1);
1085 if ((((cmp == kCondGT || cmp == kCondGE) &&
1086 (a == true_sub1 && b == true_sub2 && a == false_sub2 && b == false_sub1)) ||
1087 ((cmp == kCondLT || cmp == kCondLE) &&
1088 (a == true_sub2 && b == true_sub1 && a == false_sub1 && b == false_sub2))) &&
1089 AreLowerPrecisionArgs(t_type, a, b)) {
1090 // Found a > b ? a - b : b - a
1091 // or a < b ? b - a : a - b
1092 // which can be replaced by ABS(a - b) for lower precision operands a, b.
1093 replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), true_value, select);
1094 }
1095 }
1096 }
1097 }
1098
1099 if (replace_with != nullptr) {
1100 select->ReplaceWith(replace_with);
1101 select->GetBlock()->RemoveInstruction(select);
1102 RecordSimplification();
1103 }
1104 }
1105
VisitIf(HIf * instruction)1106 void InstructionSimplifierVisitor::VisitIf(HIf* instruction) {
1107 HInstruction* condition = instruction->InputAt(0);
1108 if (condition->IsBooleanNot()) {
1109 // Swap successors if input is negated.
1110 instruction->ReplaceInput(condition->InputAt(0), 0);
1111 instruction->GetBlock()->SwapSuccessors();
1112 RecordSimplification();
1113 }
1114 }
1115
VisitArrayLength(HArrayLength * instruction)1116 void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) {
1117 HInstruction* input = instruction->InputAt(0);
1118 // If the array is a NewArray with constant size, replace the array length
1119 // with the constant instruction. This helps the bounds check elimination phase.
1120 if (input->IsNewArray()) {
1121 input = input->AsNewArray()->GetLength();
1122 if (input->IsIntConstant()) {
1123 instruction->ReplaceWith(input);
1124 }
1125 }
1126 }
1127
VisitArraySet(HArraySet * instruction)1128 void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
1129 HInstruction* value = instruction->GetValue();
1130 if (value->GetType() != DataType::Type::kReference) {
1131 return;
1132 }
1133
1134 if (CanEnsureNotNullAt(value, instruction)) {
1135 instruction->ClearValueCanBeNull();
1136 }
1137
1138 if (value->IsArrayGet()) {
1139 if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
1140 // If the code is just swapping elements in the array, no need for a type check.
1141 instruction->ClearNeedsTypeCheck();
1142 return;
1143 }
1144 }
1145
1146 if (value->IsNullConstant()) {
1147 instruction->ClearNeedsTypeCheck();
1148 return;
1149 }
1150
1151 ScopedObjectAccess soa(Thread::Current());
1152 ReferenceTypeInfo array_rti = instruction->GetArray()->GetReferenceTypeInfo();
1153 ReferenceTypeInfo value_rti = value->GetReferenceTypeInfo();
1154 if (!array_rti.IsValid()) {
1155 return;
1156 }
1157
1158 if (value_rti.IsValid() && array_rti.CanArrayHold(value_rti)) {
1159 instruction->ClearNeedsTypeCheck();
1160 return;
1161 }
1162
1163 if (array_rti.IsObjectArray()) {
1164 if (array_rti.IsExact()) {
1165 instruction->ClearNeedsTypeCheck();
1166 return;
1167 }
1168 instruction->SetStaticTypeOfArrayIsObjectArray();
1169 }
1170 }
1171
IsTypeConversionLossless(DataType::Type input_type,DataType::Type result_type)1172 static bool IsTypeConversionLossless(DataType::Type input_type, DataType::Type result_type) {
1173 // Make sure all implicit conversions have been simplified and no new ones have been introduced.
1174 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
1175 << input_type << "," << result_type;
1176 // The conversion to a larger type is loss-less with the exception of two cases,
1177 // - conversion to the unsigned type Uint16, where we may lose some bits, and
1178 // - conversion from float to long, the only FP to integral conversion with smaller FP type.
1179 // For integral to FP conversions this holds because the FP mantissa is large enough.
1180 // Note: The size check excludes Uint8 as the result type.
1181 return DataType::Size(result_type) > DataType::Size(input_type) &&
1182 result_type != DataType::Type::kUint16 &&
1183 !(result_type == DataType::Type::kInt64 && input_type == DataType::Type::kFloat32);
1184 }
1185
TryReplaceFieldOrArrayGetType(HInstruction * maybe_get,DataType::Type new_type)1186 static inline bool TryReplaceFieldOrArrayGetType(HInstruction* maybe_get, DataType::Type new_type) {
1187 if (maybe_get->IsInstanceFieldGet()) {
1188 maybe_get->AsInstanceFieldGet()->SetType(new_type);
1189 return true;
1190 } else if (maybe_get->IsPredicatedInstanceFieldGet()) {
1191 maybe_get->AsPredicatedInstanceFieldGet()->SetType(new_type);
1192 return true;
1193 } else if (maybe_get->IsStaticFieldGet()) {
1194 maybe_get->AsStaticFieldGet()->SetType(new_type);
1195 return true;
1196 } else if (maybe_get->IsArrayGet() && !maybe_get->AsArrayGet()->IsStringCharAt()) {
1197 maybe_get->AsArrayGet()->SetType(new_type);
1198 return true;
1199 } else {
1200 return false;
1201 }
1202 }
1203
1204 // The type conversion is only used for storing into a field/element of the
1205 // same/narrower size.
IsTypeConversionForStoringIntoNoWiderFieldOnly(HTypeConversion * type_conversion)1206 static bool IsTypeConversionForStoringIntoNoWiderFieldOnly(HTypeConversion* type_conversion) {
1207 if (type_conversion->HasEnvironmentUses()) {
1208 return false;
1209 }
1210 DataType::Type input_type = type_conversion->GetInputType();
1211 DataType::Type result_type = type_conversion->GetResultType();
1212 if (!DataType::IsIntegralType(input_type) ||
1213 !DataType::IsIntegralType(result_type) ||
1214 input_type == DataType::Type::kInt64 ||
1215 result_type == DataType::Type::kInt64) {
1216 // Type conversion is needed if non-integer types are involved, or 64-bit
1217 // types are involved, which may use different number of registers.
1218 return false;
1219 }
1220 if (DataType::Size(input_type) >= DataType::Size(result_type)) {
1221 // Type conversion is not necessary when storing to a field/element of the
1222 // same/smaller size.
1223 } else {
1224 // We do not handle this case here.
1225 return false;
1226 }
1227
1228 // Check if the converted value is only used for storing into heap.
1229 for (const HUseListNode<HInstruction*>& use : type_conversion->GetUses()) {
1230 HInstruction* instruction = use.GetUser();
1231 if (instruction->IsInstanceFieldSet() &&
1232 instruction->AsInstanceFieldSet()->GetFieldType() == result_type) {
1233 DCHECK_EQ(instruction->AsInstanceFieldSet()->GetValue(), type_conversion);
1234 continue;
1235 }
1236 if (instruction->IsStaticFieldSet() &&
1237 instruction->AsStaticFieldSet()->GetFieldType() == result_type) {
1238 DCHECK_EQ(instruction->AsStaticFieldSet()->GetValue(), type_conversion);
1239 continue;
1240 }
1241 if (instruction->IsArraySet() &&
1242 instruction->AsArraySet()->GetComponentType() == result_type &&
1243 // not index use.
1244 instruction->AsArraySet()->GetIndex() != type_conversion) {
1245 DCHECK_EQ(instruction->AsArraySet()->GetValue(), type_conversion);
1246 continue;
1247 }
1248 // The use is not as a store value, or the field/element type is not the
1249 // same as the result_type, keep the type conversion.
1250 return false;
1251 }
1252 // Codegen automatically handles the type conversion during the store.
1253 return true;
1254 }
1255
VisitTypeConversion(HTypeConversion * instruction)1256 void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
1257 HInstruction* input = instruction->GetInput();
1258 DataType::Type input_type = input->GetType();
1259 DataType::Type result_type = instruction->GetResultType();
1260 if (instruction->IsImplicitConversion()) {
1261 instruction->ReplaceWith(input);
1262 instruction->GetBlock()->RemoveInstruction(instruction);
1263 RecordSimplification();
1264 return;
1265 }
1266
1267 if (input->IsTypeConversion()) {
1268 HTypeConversion* input_conversion = input->AsTypeConversion();
1269 HInstruction* original_input = input_conversion->GetInput();
1270 DataType::Type original_type = original_input->GetType();
1271
1272 // When the first conversion is lossless, a direct conversion from the original type
1273 // to the final type yields the same result, even for a lossy second conversion, for
1274 // example float->double->int or int->double->float.
1275 bool is_first_conversion_lossless = IsTypeConversionLossless(original_type, input_type);
1276
1277 // For integral conversions, see if the first conversion loses only bits that the second
1278 // doesn't need, i.e. the final type is no wider than the intermediate. If so, direct
1279 // conversion yields the same result, for example long->int->short or int->char->short.
1280 bool integral_conversions_with_non_widening_second =
1281 DataType::IsIntegralType(input_type) &&
1282 DataType::IsIntegralType(original_type) &&
1283 DataType::IsIntegralType(result_type) &&
1284 DataType::Size(result_type) <= DataType::Size(input_type);
1285
1286 if (is_first_conversion_lossless || integral_conversions_with_non_widening_second) {
1287 // If the merged conversion is implicit, do the simplification unconditionally.
1288 if (DataType::IsTypeConversionImplicit(original_type, result_type)) {
1289 instruction->ReplaceWith(original_input);
1290 instruction->GetBlock()->RemoveInstruction(instruction);
1291 if (!input_conversion->HasUses()) {
1292 // Don't wait for DCE.
1293 input_conversion->GetBlock()->RemoveInstruction(input_conversion);
1294 }
1295 RecordSimplification();
1296 return;
1297 }
1298 // Otherwise simplify only if the first conversion has no other use.
1299 if (input_conversion->HasOnlyOneNonEnvironmentUse()) {
1300 input_conversion->ReplaceWith(original_input);
1301 input_conversion->GetBlock()->RemoveInstruction(input_conversion);
1302 RecordSimplification();
1303 return;
1304 }
1305 }
1306 } else if (input->IsAnd() && DataType::IsIntegralType(result_type)) {
1307 DCHECK(DataType::IsIntegralType(input_type));
1308 HAnd* input_and = input->AsAnd();
1309 HConstant* constant = input_and->GetConstantRight();
1310 if (constant != nullptr) {
1311 int64_t value = Int64FromConstant(constant);
1312 DCHECK_NE(value, -1); // "& -1" would have been optimized away in VisitAnd().
1313 size_t trailing_ones = CTZ(~static_cast<uint64_t>(value));
1314 if (trailing_ones >= kBitsPerByte * DataType::Size(result_type)) {
1315 // The `HAnd` is useless, for example in `(byte) (x & 0xff)`, get rid of it.
1316 HInstruction* original_input = input_and->GetLeastConstantLeft();
1317 if (DataType::IsTypeConversionImplicit(original_input->GetType(), result_type)) {
1318 instruction->ReplaceWith(original_input);
1319 instruction->GetBlock()->RemoveInstruction(instruction);
1320 RecordSimplification();
1321 return;
1322 } else if (input->HasOnlyOneNonEnvironmentUse()) {
1323 input_and->ReplaceWith(original_input);
1324 input_and->GetBlock()->RemoveInstruction(input_and);
1325 RecordSimplification();
1326 return;
1327 }
1328 }
1329 }
1330 } else if (input->HasOnlyOneNonEnvironmentUse() &&
1331 ((input_type == DataType::Type::kInt8 && result_type == DataType::Type::kUint8) ||
1332 (input_type == DataType::Type::kUint8 && result_type == DataType::Type::kInt8) ||
1333 (input_type == DataType::Type::kInt16 && result_type == DataType::Type::kUint16) ||
1334 (input_type == DataType::Type::kUint16 && result_type == DataType::Type::kInt16))) {
1335 // Try to modify the type of the load to `result_type` and remove the explicit type conversion.
1336 if (TryReplaceFieldOrArrayGetType(input, result_type)) {
1337 instruction->ReplaceWith(input);
1338 instruction->GetBlock()->RemoveInstruction(instruction);
1339 RecordSimplification();
1340 return;
1341 }
1342 }
1343
1344 if (IsTypeConversionForStoringIntoNoWiderFieldOnly(instruction)) {
1345 instruction->ReplaceWith(input);
1346 instruction->GetBlock()->RemoveInstruction(instruction);
1347 RecordSimplification();
1348 return;
1349 }
1350 }
1351
VisitAbs(HAbs * instruction)1352 void InstructionSimplifierVisitor::VisitAbs(HAbs* instruction) {
1353 HInstruction* input = instruction->GetInput();
1354 if (DataType::IsZeroExtension(input->GetType(), instruction->GetResultType())) {
1355 // Zero extension from narrow to wide can never set sign bit in the wider
1356 // operand, making the subsequent Abs redundant (e.g., abs(b & 0xff) for byte b).
1357 instruction->ReplaceWith(input);
1358 instruction->GetBlock()->RemoveInstruction(instruction);
1359 RecordSimplification();
1360 }
1361 }
1362
VisitAdd(HAdd * instruction)1363 void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
1364 HConstant* input_cst = instruction->GetConstantRight();
1365 HInstruction* input_other = instruction->GetLeastConstantLeft();
1366 bool integral_type = DataType::IsIntegralType(instruction->GetType());
1367 if ((input_cst != nullptr) && input_cst->IsArithmeticZero()) {
1368 // Replace code looking like
1369 // ADD dst, src, 0
1370 // with
1371 // src
1372 // Note that we cannot optimize `x + 0.0` to `x` for floating-point. When
1373 // `x` is `-0.0`, the former expression yields `0.0`, while the later
1374 // yields `-0.0`.
1375 if (integral_type) {
1376 instruction->ReplaceWith(input_other);
1377 instruction->GetBlock()->RemoveInstruction(instruction);
1378 RecordSimplification();
1379 return;
1380 }
1381 }
1382
1383 HInstruction* left = instruction->GetLeft();
1384 HInstruction* right = instruction->GetRight();
1385 bool left_is_neg = left->IsNeg();
1386 bool right_is_neg = right->IsNeg();
1387
1388 if (left_is_neg && right_is_neg) {
1389 if (TryMoveNegOnInputsAfterBinop(instruction)) {
1390 return;
1391 }
1392 }
1393
1394 HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg();
1395 if (left_is_neg != right_is_neg && neg->HasOnlyOneNonEnvironmentUse()) {
1396 // Replace code looking like
1397 // NEG tmp, b
1398 // ADD dst, a, tmp
1399 // with
1400 // SUB dst, a, b
1401 // We do not perform the optimization if the input negation has environment
1402 // uses or multiple non-environment uses as it could lead to worse code. In
1403 // particular, we do not want the live range of `b` to be extended if we are
1404 // not sure the initial 'NEG' instruction can be removed.
1405 HInstruction* other = left_is_neg ? right : left;
1406 HSub* sub =
1407 new(GetGraph()->GetAllocator()) HSub(instruction->GetType(), other, neg->GetInput());
1408 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub);
1409 RecordSimplification();
1410 neg->GetBlock()->RemoveInstruction(neg);
1411 return;
1412 }
1413
1414 if (TryReplaceWithRotate(instruction)) {
1415 return;
1416 }
1417
1418 // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
1419 // so no need to return.
1420 TryHandleAssociativeAndCommutativeOperation(instruction);
1421
1422 if ((left->IsSub() || right->IsSub()) &&
1423 TrySubtractionChainSimplification(instruction)) {
1424 return;
1425 }
1426
1427 if (integral_type) {
1428 // Replace code patterns looking like
1429 // SUB dst1, x, y SUB dst1, x, y
1430 // ADD dst2, dst1, y ADD dst2, y, dst1
1431 // with
1432 // SUB dst1, x, y
1433 // ADD instruction is not needed in this case, we may use
1434 // one of inputs of SUB instead.
1435 if (left->IsSub() && left->InputAt(1) == right) {
1436 instruction->ReplaceWith(left->InputAt(0));
1437 RecordSimplification();
1438 instruction->GetBlock()->RemoveInstruction(instruction);
1439 return;
1440 } else if (right->IsSub() && right->InputAt(1) == left) {
1441 instruction->ReplaceWith(right->InputAt(0));
1442 RecordSimplification();
1443 instruction->GetBlock()->RemoveInstruction(instruction);
1444 return;
1445 }
1446 }
1447 }
1448
VisitAnd(HAnd * instruction)1449 void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
1450 DCHECK(DataType::IsIntegralType(instruction->GetType()));
1451 HConstant* input_cst = instruction->GetConstantRight();
1452 HInstruction* input_other = instruction->GetLeastConstantLeft();
1453
1454 if (input_cst != nullptr) {
1455 int64_t value = Int64FromConstant(input_cst);
1456 if (value == -1 ||
1457 // Similar cases under zero extension.
1458 (DataType::IsUnsignedType(input_other->GetType()) &&
1459 ((DataType::MaxValueOfIntegralType(input_other->GetType()) & ~value) == 0))) {
1460 // Replace code looking like
1461 // AND dst, src, 0xFFF...FF
1462 // with
1463 // src
1464 instruction->ReplaceWith(input_other);
1465 instruction->GetBlock()->RemoveInstruction(instruction);
1466 RecordSimplification();
1467 return;
1468 }
1469 if (input_other->IsTypeConversion() &&
1470 input_other->GetType() == DataType::Type::kInt64 &&
1471 DataType::IsIntegralType(input_other->InputAt(0)->GetType()) &&
1472 IsInt<32>(value) &&
1473 input_other->HasOnlyOneNonEnvironmentUse()) {
1474 // The AND can be reordered before the TypeConversion. Replace
1475 // LongConstant cst, <32-bit-constant-sign-extended-to-64-bits>
1476 // TypeConversion<Int64> tmp, src
1477 // AND dst, tmp, cst
1478 // with
1479 // IntConstant cst, <32-bit-constant>
1480 // AND tmp, src, cst
1481 // TypeConversion<Int64> dst, tmp
1482 // This helps 32-bit targets and does not hurt 64-bit targets.
1483 // This also simplifies detection of other patterns, such as Uint8 loads.
1484 HInstruction* new_and_input = input_other->InputAt(0);
1485 // Implicit conversion Int64->Int64 would have been removed previously.
1486 DCHECK_NE(new_and_input->GetType(), DataType::Type::kInt64);
1487 HConstant* new_const = GetGraph()->GetConstant(DataType::Type::kInt32, value);
1488 HAnd* new_and =
1489 new (GetGraph()->GetAllocator()) HAnd(DataType::Type::kInt32, new_and_input, new_const);
1490 instruction->GetBlock()->InsertInstructionBefore(new_and, instruction);
1491 HTypeConversion* new_conversion =
1492 new (GetGraph()->GetAllocator()) HTypeConversion(DataType::Type::kInt64, new_and);
1493 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_conversion);
1494 input_other->GetBlock()->RemoveInstruction(input_other);
1495 RecordSimplification();
1496 // Try to process the new And now, do not wait for the next round of simplifications.
1497 instruction = new_and;
1498 input_other = new_and_input;
1499 }
1500 // Eliminate And from UShr+And if the And-mask contains all the bits that
1501 // can be non-zero after UShr. Transform Shr+And to UShr if the And-mask
1502 // precisely clears the shifted-in sign bits.
1503 if ((input_other->IsUShr() || input_other->IsShr()) && input_other->InputAt(1)->IsConstant()) {
1504 size_t reg_bits = (instruction->GetResultType() == DataType::Type::kInt64) ? 64 : 32;
1505 size_t shift = Int64FromConstant(input_other->InputAt(1)->AsConstant()) & (reg_bits - 1);
1506 size_t num_tail_bits_set = CTZ(value + 1);
1507 if ((num_tail_bits_set >= reg_bits - shift) && input_other->IsUShr()) {
1508 // This AND clears only bits known to be clear, for example "(x >>> 24) & 0xff".
1509 instruction->ReplaceWith(input_other);
1510 instruction->GetBlock()->RemoveInstruction(instruction);
1511 RecordSimplification();
1512 return;
1513 } else if ((num_tail_bits_set == reg_bits - shift) && IsPowerOfTwo(value + 1) &&
1514 input_other->HasOnlyOneNonEnvironmentUse()) {
1515 DCHECK(input_other->IsShr()); // For UShr, we would have taken the branch above.
1516 // Replace SHR+AND with USHR, for example "(x >> 24) & 0xff" -> "x >>> 24".
1517 HUShr* ushr = new (GetGraph()->GetAllocator()) HUShr(instruction->GetType(),
1518 input_other->InputAt(0),
1519 input_other->InputAt(1),
1520 input_other->GetDexPc());
1521 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, ushr);
1522 input_other->GetBlock()->RemoveInstruction(input_other);
1523 RecordSimplification();
1524 return;
1525 }
1526 }
1527 if ((value == 0xff || value == 0xffff) && instruction->GetType() != DataType::Type::kInt64) {
1528 // Transform AND to a type conversion to Uint8/Uint16. If `input_other` is a field
1529 // or array Get with only a single use, short-circuit the subsequent simplification
1530 // of the Get+TypeConversion and change the Get's type to `new_type` instead.
1531 DataType::Type new_type = (value == 0xff) ? DataType::Type::kUint8 : DataType::Type::kUint16;
1532 DataType::Type find_type = (value == 0xff) ? DataType::Type::kInt8 : DataType::Type::kInt16;
1533 if (input_other->GetType() == find_type &&
1534 input_other->HasOnlyOneNonEnvironmentUse() &&
1535 TryReplaceFieldOrArrayGetType(input_other, new_type)) {
1536 instruction->ReplaceWith(input_other);
1537 instruction->GetBlock()->RemoveInstruction(instruction);
1538 } else if (DataType::IsTypeConversionImplicit(input_other->GetType(), new_type)) {
1539 instruction->ReplaceWith(input_other);
1540 instruction->GetBlock()->RemoveInstruction(instruction);
1541 } else {
1542 HTypeConversion* type_conversion = new (GetGraph()->GetAllocator()) HTypeConversion(
1543 new_type, input_other, instruction->GetDexPc());
1544 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, type_conversion);
1545 }
1546 RecordSimplification();
1547 return;
1548 }
1549 }
1550
1551 // We assume that GVN has run before, so we only perform a pointer comparison.
1552 // If for some reason the values are equal but the pointers are different, we
1553 // are still correct and only miss an optimization opportunity.
1554 if (instruction->GetLeft() == instruction->GetRight()) {
1555 // Replace code looking like
1556 // AND dst, src, src
1557 // with
1558 // src
1559 instruction->ReplaceWith(instruction->GetLeft());
1560 instruction->GetBlock()->RemoveInstruction(instruction);
1561 RecordSimplification();
1562 return;
1563 }
1564
1565 if (TryDeMorganNegationFactoring(instruction)) {
1566 return;
1567 }
1568
1569 // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
1570 // so no need to return.
1571 TryHandleAssociativeAndCommutativeOperation(instruction);
1572 }
1573
VisitGreaterThan(HGreaterThan * condition)1574 void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) {
1575 VisitCondition(condition);
1576 }
1577
VisitGreaterThanOrEqual(HGreaterThanOrEqual * condition)1578 void InstructionSimplifierVisitor::VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) {
1579 VisitCondition(condition);
1580 }
1581
VisitLessThan(HLessThan * condition)1582 void InstructionSimplifierVisitor::VisitLessThan(HLessThan* condition) {
1583 VisitCondition(condition);
1584 }
1585
VisitLessThanOrEqual(HLessThanOrEqual * condition)1586 void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condition) {
1587 VisitCondition(condition);
1588 }
1589
VisitBelow(HBelow * condition)1590 void InstructionSimplifierVisitor::VisitBelow(HBelow* condition) {
1591 VisitCondition(condition);
1592 }
1593
VisitBelowOrEqual(HBelowOrEqual * condition)1594 void InstructionSimplifierVisitor::VisitBelowOrEqual(HBelowOrEqual* condition) {
1595 VisitCondition(condition);
1596 }
1597
VisitAbove(HAbove * condition)1598 void InstructionSimplifierVisitor::VisitAbove(HAbove* condition) {
1599 VisitCondition(condition);
1600 }
1601
VisitAboveOrEqual(HAboveOrEqual * condition)1602 void InstructionSimplifierVisitor::VisitAboveOrEqual(HAboveOrEqual* condition) {
1603 VisitCondition(condition);
1604 }
1605
1606 // Recognize the following pattern:
1607 // obj.getClass() ==/!= Foo.class
1608 // And replace it with a constant value if the type of `obj` is statically known.
RecognizeAndSimplifyClassCheck(HCondition * condition)1609 static bool RecognizeAndSimplifyClassCheck(HCondition* condition) {
1610 HInstruction* input_one = condition->InputAt(0);
1611 HInstruction* input_two = condition->InputAt(1);
1612 HLoadClass* load_class = input_one->IsLoadClass()
1613 ? input_one->AsLoadClass()
1614 : input_two->AsLoadClass();
1615 if (load_class == nullptr) {
1616 return false;
1617 }
1618
1619 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
1620 if (!class_rti.IsValid()) {
1621 // Unresolved class.
1622 return false;
1623 }
1624
1625 HInstanceFieldGet* field_get = (load_class == input_one)
1626 ? input_two->AsInstanceFieldGet()
1627 : input_one->AsInstanceFieldGet();
1628 if (field_get == nullptr) {
1629 return false;
1630 }
1631
1632 HInstruction* receiver = field_get->InputAt(0);
1633 ReferenceTypeInfo receiver_type = receiver->GetReferenceTypeInfo();
1634 if (!receiver_type.IsExact()) {
1635 return false;
1636 }
1637
1638 {
1639 ScopedObjectAccess soa(Thread::Current());
1640 ArtField* field = GetClassRoot<mirror::Object>()->GetInstanceField(0);
1641 DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_");
1642 if (field_get->GetFieldInfo().GetField() != field) {
1643 return false;
1644 }
1645
1646 // We can replace the compare.
1647 int value = 0;
1648 if (receiver_type.IsEqual(class_rti)) {
1649 value = condition->IsEqual() ? 1 : 0;
1650 } else {
1651 value = condition->IsNotEqual() ? 1 : 0;
1652 }
1653 condition->ReplaceWith(condition->GetBlock()->GetGraph()->GetIntConstant(value));
1654 return true;
1655 }
1656 }
1657
VisitCondition(HCondition * condition)1658 void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
1659 if (condition->IsEqual() || condition->IsNotEqual()) {
1660 if (RecognizeAndSimplifyClassCheck(condition)) {
1661 return;
1662 }
1663 }
1664
1665 // Reverse condition if left is constant. Our code generators prefer constant
1666 // on the right hand side.
1667 if (condition->GetLeft()->IsConstant() && !condition->GetRight()->IsConstant()) {
1668 HBasicBlock* block = condition->GetBlock();
1669 HCondition* replacement =
1670 GetOppositeConditionSwapOps(block->GetGraph()->GetAllocator(), condition);
1671 // If it is a fp we must set the opposite bias.
1672 if (replacement != nullptr) {
1673 if (condition->IsLtBias()) {
1674 replacement->SetBias(ComparisonBias::kGtBias);
1675 } else if (condition->IsGtBias()) {
1676 replacement->SetBias(ComparisonBias::kLtBias);
1677 }
1678 block->ReplaceAndRemoveInstructionWith(condition, replacement);
1679 RecordSimplification();
1680
1681 condition = replacement;
1682 }
1683 }
1684
1685 HInstruction* left = condition->GetLeft();
1686 HInstruction* right = condition->GetRight();
1687
1688 // Try to fold an HCompare into this HCondition.
1689
1690 // We can only replace an HCondition which compares a Compare to 0.
1691 // Both 'dx' and 'jack' generate a compare to 0 when compiling a
1692 // condition with a long, float or double comparison as input.
1693 if (!left->IsCompare() || !right->IsConstant() || right->AsIntConstant()->GetValue() != 0) {
1694 // Conversion is not possible.
1695 return;
1696 }
1697
1698 // Is the Compare only used for this purpose?
1699 if (!left->GetUses().HasExactlyOneElement()) {
1700 // Someone else also wants the result of the compare.
1701 return;
1702 }
1703
1704 if (!left->GetEnvUses().empty()) {
1705 // There is a reference to the compare result in an environment. Do we really need it?
1706 if (GetGraph()->IsDebuggable()) {
1707 return;
1708 }
1709
1710 // We have to ensure that there are no deopt points in the sequence.
1711 if (left->HasAnyEnvironmentUseBefore(condition)) {
1712 return;
1713 }
1714 }
1715
1716 // Clean up any environment uses from the HCompare, if any.
1717 left->RemoveEnvironmentUsers();
1718
1719 // We have decided to fold the HCompare into the HCondition. Transfer the information.
1720 condition->SetBias(left->AsCompare()->GetBias());
1721
1722 // Replace the operands of the HCondition.
1723 condition->ReplaceInput(left->InputAt(0), 0);
1724 condition->ReplaceInput(left->InputAt(1), 1);
1725
1726 // Remove the HCompare.
1727 left->GetBlock()->RemoveInstruction(left);
1728
1729 RecordSimplification();
1730 }
1731
1732 // Return whether x / divisor == x * (1.0f / divisor), for every float x.
CanDivideByReciprocalMultiplyFloat(int32_t divisor)1733 static constexpr bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) {
1734 // True, if the most significant bits of divisor are 0.
1735 return ((divisor & 0x7fffff) == 0);
1736 }
1737
1738 // Return whether x / divisor == x * (1.0 / divisor), for every double x.
CanDivideByReciprocalMultiplyDouble(int64_t divisor)1739 static constexpr bool CanDivideByReciprocalMultiplyDouble(int64_t divisor) {
1740 // True, if the most significant bits of divisor are 0.
1741 return ((divisor & ((UINT64_C(1) << 52) - 1)) == 0);
1742 }
1743
VisitDiv(HDiv * instruction)1744 void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
1745 HConstant* input_cst = instruction->GetConstantRight();
1746 HInstruction* input_other = instruction->GetLeastConstantLeft();
1747 DataType::Type type = instruction->GetType();
1748
1749 if ((input_cst != nullptr) && input_cst->IsOne()) {
1750 // Replace code looking like
1751 // DIV dst, src, 1
1752 // with
1753 // src
1754 instruction->ReplaceWith(input_other);
1755 instruction->GetBlock()->RemoveInstruction(instruction);
1756 RecordSimplification();
1757 return;
1758 }
1759
1760 if ((input_cst != nullptr) && input_cst->IsMinusOne()) {
1761 // Replace code looking like
1762 // DIV dst, src, -1
1763 // with
1764 // NEG dst, src
1765 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
1766 instruction, new (GetGraph()->GetAllocator()) HNeg(type, input_other));
1767 RecordSimplification();
1768 return;
1769 }
1770
1771 if ((input_cst != nullptr) && DataType::IsFloatingPointType(type)) {
1772 // Try replacing code looking like
1773 // DIV dst, src, constant
1774 // with
1775 // MUL dst, src, 1 / constant
1776 HConstant* reciprocal = nullptr;
1777 if (type == DataType::Type::kFloat64) {
1778 double value = input_cst->AsDoubleConstant()->GetValue();
1779 if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) {
1780 reciprocal = GetGraph()->GetDoubleConstant(1.0 / value);
1781 }
1782 } else {
1783 DCHECK_EQ(type, DataType::Type::kFloat32);
1784 float value = input_cst->AsFloatConstant()->GetValue();
1785 if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) {
1786 reciprocal = GetGraph()->GetFloatConstant(1.0f / value);
1787 }
1788 }
1789
1790 if (reciprocal != nullptr) {
1791 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
1792 instruction, new (GetGraph()->GetAllocator()) HMul(type, input_other, reciprocal));
1793 RecordSimplification();
1794 return;
1795 }
1796 }
1797 }
1798
1799
1800 // Search HDiv having the specified dividend and divisor which is in the specified basic block.
1801 // Return nullptr if nothing has been found.
FindDivWithInputsInBasicBlock(HInstruction * dividend,HInstruction * divisor,HBasicBlock * basic_block)1802 static HInstruction* FindDivWithInputsInBasicBlock(HInstruction* dividend,
1803 HInstruction* divisor,
1804 HBasicBlock* basic_block) {
1805 for (const HUseListNode<HInstruction*>& use : dividend->GetUses()) {
1806 HInstruction* user = use.GetUser();
1807 if (user->GetBlock() == basic_block && user->IsDiv() && user->InputAt(1) == divisor) {
1808 return user;
1809 }
1810 }
1811 return nullptr;
1812 }
1813
1814 // If there is Div with the same inputs as Rem and in the same basic block, it can be reused.
1815 // Rem is replaced with Mul+Sub which use the found Div.
TryToReuseDiv(HRem * rem)1816 void InstructionSimplifierVisitor::TryToReuseDiv(HRem* rem) {
1817 // As the optimization replaces Rem with Mul+Sub they prevent some loop optimizations
1818 // if the Rem is in a loop.
1819 // Check if it is allowed to optimize such Rems.
1820 if (rem->IsInLoop() && be_loop_friendly_) {
1821 return;
1822 }
1823 DataType::Type type = rem->GetResultType();
1824 if (!DataType::IsIntOrLongType(type)) {
1825 return;
1826 }
1827
1828 HBasicBlock* basic_block = rem->GetBlock();
1829 HInstruction* dividend = rem->GetLeft();
1830 HInstruction* divisor = rem->GetRight();
1831
1832 if (divisor->IsConstant()) {
1833 HConstant* input_cst = rem->GetConstantRight();
1834 DCHECK(input_cst->IsIntConstant() || input_cst->IsLongConstant());
1835 int64_t cst_value = Int64FromConstant(input_cst);
1836 if (cst_value == std::numeric_limits<int64_t>::min() || IsPowerOfTwo(std::abs(cst_value))) {
1837 // Such cases are usually handled in the code generator because they don't need Div at all.
1838 return;
1839 }
1840 }
1841
1842 HInstruction* quotient = FindDivWithInputsInBasicBlock(dividend, divisor, basic_block);
1843 if (quotient == nullptr) {
1844 return;
1845 }
1846 if (!quotient->StrictlyDominates(rem)) {
1847 quotient->MoveBefore(rem);
1848 }
1849
1850 ArenaAllocator* allocator = GetGraph()->GetAllocator();
1851 HInstruction* mul = new (allocator) HMul(type, quotient, divisor);
1852 basic_block->InsertInstructionBefore(mul, rem);
1853 HInstruction* sub = new (allocator) HSub(type, dividend, mul);
1854 basic_block->InsertInstructionBefore(sub, rem);
1855 rem->ReplaceWith(sub);
1856 basic_block->RemoveInstruction(rem);
1857 RecordSimplification();
1858 }
1859
VisitRem(HRem * rem)1860 void InstructionSimplifierVisitor::VisitRem(HRem* rem) {
1861 TryToReuseDiv(rem);
1862 }
1863
VisitMul(HMul * instruction)1864 void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
1865 HConstant* input_cst = instruction->GetConstantRight();
1866 HInstruction* input_other = instruction->GetLeastConstantLeft();
1867 DataType::Type type = instruction->GetType();
1868 HBasicBlock* block = instruction->GetBlock();
1869 ArenaAllocator* allocator = GetGraph()->GetAllocator();
1870
1871 if (input_cst == nullptr) {
1872 return;
1873 }
1874
1875 if (input_cst->IsOne()) {
1876 // Replace code looking like
1877 // MUL dst, src, 1
1878 // with
1879 // src
1880 instruction->ReplaceWith(input_other);
1881 instruction->GetBlock()->RemoveInstruction(instruction);
1882 RecordSimplification();
1883 return;
1884 }
1885
1886 if (input_cst->IsMinusOne() &&
1887 (DataType::IsFloatingPointType(type) || DataType::IsIntOrLongType(type))) {
1888 // Replace code looking like
1889 // MUL dst, src, -1
1890 // with
1891 // NEG dst, src
1892 HNeg* neg = new (allocator) HNeg(type, input_other);
1893 block->ReplaceAndRemoveInstructionWith(instruction, neg);
1894 RecordSimplification();
1895 return;
1896 }
1897
1898 if (DataType::IsFloatingPointType(type) &&
1899 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
1900 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
1901 // Replace code looking like
1902 // FP_MUL dst, src, 2.0
1903 // with
1904 // FP_ADD dst, src, src
1905 // The 'int' and 'long' cases are handled below.
1906 block->ReplaceAndRemoveInstructionWith(instruction,
1907 new (allocator) HAdd(type, input_other, input_other));
1908 RecordSimplification();
1909 return;
1910 }
1911
1912 if (DataType::IsIntOrLongType(type)) {
1913 int64_t factor = Int64FromConstant(input_cst);
1914 // Even though constant propagation also takes care of the zero case, other
1915 // optimizations can lead to having a zero multiplication.
1916 if (factor == 0) {
1917 // Replace code looking like
1918 // MUL dst, src, 0
1919 // with
1920 // 0
1921 instruction->ReplaceWith(input_cst);
1922 instruction->GetBlock()->RemoveInstruction(instruction);
1923 RecordSimplification();
1924 return;
1925 } else if (IsPowerOfTwo(factor)) {
1926 // Replace code looking like
1927 // MUL dst, src, pow_of_2
1928 // with
1929 // SHL dst, src, log2(pow_of_2)
1930 HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
1931 HShl* shl = new (allocator) HShl(type, input_other, shift);
1932 block->ReplaceAndRemoveInstructionWith(instruction, shl);
1933 RecordSimplification();
1934 return;
1935 } else if (IsPowerOfTwo(factor - 1)) {
1936 // Transform code looking like
1937 // MUL dst, src, (2^n + 1)
1938 // into
1939 // SHL tmp, src, n
1940 // ADD dst, src, tmp
1941 HShl* shl = new (allocator) HShl(type,
1942 input_other,
1943 GetGraph()->GetIntConstant(WhichPowerOf2(factor - 1)));
1944 HAdd* add = new (allocator) HAdd(type, input_other, shl);
1945
1946 block->InsertInstructionBefore(shl, instruction);
1947 block->ReplaceAndRemoveInstructionWith(instruction, add);
1948 RecordSimplification();
1949 return;
1950 } else if (IsPowerOfTwo(factor + 1)) {
1951 // Transform code looking like
1952 // MUL dst, src, (2^n - 1)
1953 // into
1954 // SHL tmp, src, n
1955 // SUB dst, tmp, src
1956 HShl* shl = new (allocator) HShl(type,
1957 input_other,
1958 GetGraph()->GetIntConstant(WhichPowerOf2(factor + 1)));
1959 HSub* sub = new (allocator) HSub(type, shl, input_other);
1960
1961 block->InsertInstructionBefore(shl, instruction);
1962 block->ReplaceAndRemoveInstructionWith(instruction, sub);
1963 RecordSimplification();
1964 return;
1965 }
1966 }
1967
1968 // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
1969 // so no need to return.
1970 TryHandleAssociativeAndCommutativeOperation(instruction);
1971 }
1972
VisitNeg(HNeg * instruction)1973 void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) {
1974 HInstruction* input = instruction->GetInput();
1975 if (input->IsNeg()) {
1976 // Replace code looking like
1977 // NEG tmp, src
1978 // NEG dst, tmp
1979 // with
1980 // src
1981 HNeg* previous_neg = input->AsNeg();
1982 instruction->ReplaceWith(previous_neg->GetInput());
1983 instruction->GetBlock()->RemoveInstruction(instruction);
1984 // We perform the optimization even if the input negation has environment
1985 // uses since it allows removing the current instruction. But we only delete
1986 // the input negation only if it is does not have any uses left.
1987 if (!previous_neg->HasUses()) {
1988 previous_neg->GetBlock()->RemoveInstruction(previous_neg);
1989 }
1990 RecordSimplification();
1991 return;
1992 }
1993
1994 if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse() &&
1995 !DataType::IsFloatingPointType(input->GetType())) {
1996 // Replace code looking like
1997 // SUB tmp, a, b
1998 // NEG dst, tmp
1999 // with
2000 // SUB dst, b, a
2001 // We do not perform the optimization if the input subtraction has
2002 // environment uses or multiple non-environment uses as it could lead to
2003 // worse code. In particular, we do not want the live ranges of `a` and `b`
2004 // to be extended if we are not sure the initial 'SUB' instruction can be
2005 // removed.
2006 // We do not perform optimization for fp because we could lose the sign of zero.
2007 HSub* sub = input->AsSub();
2008 HSub* new_sub = new (GetGraph()->GetAllocator()) HSub(
2009 instruction->GetType(), sub->GetRight(), sub->GetLeft());
2010 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub);
2011 if (!sub->HasUses()) {
2012 sub->GetBlock()->RemoveInstruction(sub);
2013 }
2014 RecordSimplification();
2015 }
2016 }
2017
VisitNot(HNot * instruction)2018 void InstructionSimplifierVisitor::VisitNot(HNot* instruction) {
2019 HInstruction* input = instruction->GetInput();
2020 if (input->IsNot()) {
2021 // Replace code looking like
2022 // NOT tmp, src
2023 // NOT dst, tmp
2024 // with
2025 // src
2026 // We perform the optimization even if the input negation has environment
2027 // uses since it allows removing the current instruction. But we only delete
2028 // the input negation only if it is does not have any uses left.
2029 HNot* previous_not = input->AsNot();
2030 instruction->ReplaceWith(previous_not->GetInput());
2031 instruction->GetBlock()->RemoveInstruction(instruction);
2032 if (!previous_not->HasUses()) {
2033 previous_not->GetBlock()->RemoveInstruction(previous_not);
2034 }
2035 RecordSimplification();
2036 }
2037 }
2038
VisitOr(HOr * instruction)2039 void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
2040 HConstant* input_cst = instruction->GetConstantRight();
2041 HInstruction* input_other = instruction->GetLeastConstantLeft();
2042
2043 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
2044 // Replace code looking like
2045 // OR dst, src, 0
2046 // with
2047 // src
2048 instruction->ReplaceWith(input_other);
2049 instruction->GetBlock()->RemoveInstruction(instruction);
2050 RecordSimplification();
2051 return;
2052 }
2053
2054 // We assume that GVN has run before, so we only perform a pointer comparison.
2055 // If for some reason the values are equal but the pointers are different, we
2056 // are still correct and only miss an optimization opportunity.
2057 if (instruction->GetLeft() == instruction->GetRight()) {
2058 // Replace code looking like
2059 // OR dst, src, src
2060 // with
2061 // src
2062 instruction->ReplaceWith(instruction->GetLeft());
2063 instruction->GetBlock()->RemoveInstruction(instruction);
2064 RecordSimplification();
2065 return;
2066 }
2067
2068 if (TryDeMorganNegationFactoring(instruction)) return;
2069
2070 if (TryReplaceWithRotate(instruction)) {
2071 return;
2072 }
2073
2074 // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
2075 // so no need to return.
2076 TryHandleAssociativeAndCommutativeOperation(instruction);
2077 }
2078
VisitShl(HShl * instruction)2079 void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
2080 VisitShift(instruction);
2081 }
2082
VisitShr(HShr * instruction)2083 void InstructionSimplifierVisitor::VisitShr(HShr* instruction) {
2084 VisitShift(instruction);
2085 }
2086
VisitSub(HSub * instruction)2087 void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
2088 HConstant* input_cst = instruction->GetConstantRight();
2089 HInstruction* input_other = instruction->GetLeastConstantLeft();
2090
2091 DataType::Type type = instruction->GetType();
2092 if (DataType::IsFloatingPointType(type)) {
2093 return;
2094 }
2095
2096 if ((input_cst != nullptr) && input_cst->IsArithmeticZero()) {
2097 // Replace code looking like
2098 // SUB dst, src, 0
2099 // with
2100 // src
2101 // Note that we cannot optimize `x - 0.0` to `x` for floating-point. When
2102 // `x` is `-0.0`, the former expression yields `0.0`, while the later
2103 // yields `-0.0`.
2104 instruction->ReplaceWith(input_other);
2105 instruction->GetBlock()->RemoveInstruction(instruction);
2106 RecordSimplification();
2107 return;
2108 }
2109
2110 HBasicBlock* block = instruction->GetBlock();
2111 ArenaAllocator* allocator = GetGraph()->GetAllocator();
2112
2113 HInstruction* left = instruction->GetLeft();
2114 HInstruction* right = instruction->GetRight();
2115 if (left->IsConstant()) {
2116 if (Int64FromConstant(left->AsConstant()) == 0) {
2117 // Replace code looking like
2118 // SUB dst, 0, src
2119 // with
2120 // NEG dst, src
2121 // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When
2122 // `x` is `0.0`, the former expression yields `0.0`, while the later
2123 // yields `-0.0`.
2124 HNeg* neg = new (allocator) HNeg(type, right);
2125 block->ReplaceAndRemoveInstructionWith(instruction, neg);
2126 RecordSimplification();
2127 return;
2128 }
2129 }
2130
2131 if (left->IsNeg() && right->IsNeg()) {
2132 if (TryMoveNegOnInputsAfterBinop(instruction)) {
2133 return;
2134 }
2135 }
2136
2137 if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) {
2138 // Replace code looking like
2139 // NEG tmp, b
2140 // SUB dst, a, tmp
2141 // with
2142 // ADD dst, a, b
2143 HAdd* add = new(GetGraph()->GetAllocator()) HAdd(type, left, right->AsNeg()->GetInput());
2144 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add);
2145 RecordSimplification();
2146 right->GetBlock()->RemoveInstruction(right);
2147 return;
2148 }
2149
2150 if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) {
2151 // Replace code looking like
2152 // NEG tmp, a
2153 // SUB dst, tmp, b
2154 // with
2155 // ADD tmp, a, b
2156 // NEG dst, tmp
2157 // The second version is not intrinsically better, but enables more
2158 // transformations.
2159 HAdd* add = new(GetGraph()->GetAllocator()) HAdd(type, left->AsNeg()->GetInput(), right);
2160 instruction->GetBlock()->InsertInstructionBefore(add, instruction);
2161 HNeg* neg = new (GetGraph()->GetAllocator()) HNeg(instruction->GetType(), add);
2162 instruction->GetBlock()->InsertInstructionBefore(neg, instruction);
2163 instruction->ReplaceWith(neg);
2164 instruction->GetBlock()->RemoveInstruction(instruction);
2165 RecordSimplification();
2166 left->GetBlock()->RemoveInstruction(left);
2167 return;
2168 }
2169
2170 if (TrySubtractionChainSimplification(instruction)) {
2171 return;
2172 }
2173
2174 if (left->IsAdd()) {
2175 // Replace code patterns looking like
2176 // ADD dst1, x, y ADD dst1, x, y
2177 // SUB dst2, dst1, y SUB dst2, dst1, x
2178 // with
2179 // ADD dst1, x, y
2180 // SUB instruction is not needed in this case, we may use
2181 // one of inputs of ADD instead.
2182 // It is applicable to integral types only.
2183 DCHECK(DataType::IsIntegralType(type));
2184 if (left->InputAt(1) == right) {
2185 instruction->ReplaceWith(left->InputAt(0));
2186 RecordSimplification();
2187 instruction->GetBlock()->RemoveInstruction(instruction);
2188 return;
2189 } else if (left->InputAt(0) == right) {
2190 instruction->ReplaceWith(left->InputAt(1));
2191 RecordSimplification();
2192 instruction->GetBlock()->RemoveInstruction(instruction);
2193 return;
2194 }
2195 }
2196 }
2197
VisitUShr(HUShr * instruction)2198 void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
2199 VisitShift(instruction);
2200 }
2201
VisitXor(HXor * instruction)2202 void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
2203 HConstant* input_cst = instruction->GetConstantRight();
2204 HInstruction* input_other = instruction->GetLeastConstantLeft();
2205
2206 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
2207 // Replace code looking like
2208 // XOR dst, src, 0
2209 // with
2210 // src
2211 instruction->ReplaceWith(input_other);
2212 instruction->GetBlock()->RemoveInstruction(instruction);
2213 RecordSimplification();
2214 return;
2215 }
2216
2217 if ((input_cst != nullptr) && input_cst->IsOne()
2218 && input_other->GetType() == DataType::Type::kBool) {
2219 // Replace code looking like
2220 // XOR dst, src, 1
2221 // with
2222 // BOOLEAN_NOT dst, src
2223 HBooleanNot* boolean_not = new (GetGraph()->GetAllocator()) HBooleanNot(input_other);
2224 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, boolean_not);
2225 RecordSimplification();
2226 return;
2227 }
2228
2229 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
2230 // Replace code looking like
2231 // XOR dst, src, 0xFFF...FF
2232 // with
2233 // NOT dst, src
2234 HNot* bitwise_not = new (GetGraph()->GetAllocator()) HNot(instruction->GetType(), input_other);
2235 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not);
2236 RecordSimplification();
2237 return;
2238 }
2239
2240 HInstruction* left = instruction->GetLeft();
2241 HInstruction* right = instruction->GetRight();
2242 if (((left->IsNot() && right->IsNot()) ||
2243 (left->IsBooleanNot() && right->IsBooleanNot())) &&
2244 left->HasOnlyOneNonEnvironmentUse() &&
2245 right->HasOnlyOneNonEnvironmentUse()) {
2246 // Replace code looking like
2247 // NOT nota, a
2248 // NOT notb, b
2249 // XOR dst, nota, notb
2250 // with
2251 // XOR dst, a, b
2252 instruction->ReplaceInput(left->InputAt(0), 0);
2253 instruction->ReplaceInput(right->InputAt(0), 1);
2254 left->GetBlock()->RemoveInstruction(left);
2255 right->GetBlock()->RemoveInstruction(right);
2256 RecordSimplification();
2257 return;
2258 }
2259
2260 if (TryReplaceWithRotate(instruction)) {
2261 return;
2262 }
2263
2264 // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
2265 // so no need to return.
2266 TryHandleAssociativeAndCommutativeOperation(instruction);
2267 }
2268
SimplifyStringEquals(HInvoke * instruction)2269 void InstructionSimplifierVisitor::SimplifyStringEquals(HInvoke* instruction) {
2270 HInstruction* argument = instruction->InputAt(1);
2271 HInstruction* receiver = instruction->InputAt(0);
2272 if (receiver == argument) {
2273 // Because String.equals is an instance call, the receiver is
2274 // a null check if we don't know it's null. The argument however, will
2275 // be the actual object. So we cannot end up in a situation where both
2276 // are equal but could be null.
2277 DCHECK(CanEnsureNotNullAt(argument, instruction));
2278 instruction->ReplaceWith(GetGraph()->GetIntConstant(1));
2279 instruction->GetBlock()->RemoveInstruction(instruction);
2280 } else {
2281 StringEqualsOptimizations optimizations(instruction);
2282 if (CanEnsureNotNullAt(argument, instruction)) {
2283 optimizations.SetArgumentNotNull();
2284 }
2285 ScopedObjectAccess soa(Thread::Current());
2286 ReferenceTypeInfo argument_rti = argument->GetReferenceTypeInfo();
2287 if (argument_rti.IsValid() && argument_rti.IsStringClass()) {
2288 optimizations.SetArgumentIsString();
2289 }
2290 }
2291 }
2292
IsArrayLengthOf(HInstruction * potential_length,HInstruction * potential_array)2293 static bool IsArrayLengthOf(HInstruction* potential_length, HInstruction* potential_array) {
2294 if (potential_length->IsArrayLength()) {
2295 return potential_length->InputAt(0) == potential_array;
2296 }
2297
2298 if (potential_array->IsNewArray()) {
2299 return potential_array->AsNewArray()->GetLength() == potential_length;
2300 }
2301
2302 return false;
2303 }
2304
SimplifySystemArrayCopy(HInvoke * instruction)2305 void InstructionSimplifierVisitor::SimplifySystemArrayCopy(HInvoke* instruction) {
2306 HInstruction* source = instruction->InputAt(0);
2307 HInstruction* destination = instruction->InputAt(2);
2308 HInstruction* count = instruction->InputAt(4);
2309 SystemArrayCopyOptimizations optimizations(instruction);
2310 if (CanEnsureNotNullAt(source, instruction)) {
2311 optimizations.SetSourceIsNotNull();
2312 }
2313 if (CanEnsureNotNullAt(destination, instruction)) {
2314 optimizations.SetDestinationIsNotNull();
2315 }
2316 if (destination == source) {
2317 optimizations.SetDestinationIsSource();
2318 }
2319
2320 if (IsArrayLengthOf(count, source)) {
2321 optimizations.SetCountIsSourceLength();
2322 }
2323
2324 if (IsArrayLengthOf(count, destination)) {
2325 optimizations.SetCountIsDestinationLength();
2326 }
2327
2328 {
2329 ScopedObjectAccess soa(Thread::Current());
2330 DataType::Type source_component_type = DataType::Type::kVoid;
2331 DataType::Type destination_component_type = DataType::Type::kVoid;
2332 ReferenceTypeInfo destination_rti = destination->GetReferenceTypeInfo();
2333 if (destination_rti.IsValid()) {
2334 if (destination_rti.IsObjectArray()) {
2335 if (destination_rti.IsExact()) {
2336 optimizations.SetDoesNotNeedTypeCheck();
2337 }
2338 optimizations.SetDestinationIsTypedObjectArray();
2339 }
2340 if (destination_rti.IsPrimitiveArrayClass()) {
2341 destination_component_type = DataTypeFromPrimitive(
2342 destination_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType());
2343 optimizations.SetDestinationIsPrimitiveArray();
2344 } else if (destination_rti.IsNonPrimitiveArrayClass()) {
2345 optimizations.SetDestinationIsNonPrimitiveArray();
2346 }
2347 }
2348 ReferenceTypeInfo source_rti = source->GetReferenceTypeInfo();
2349 if (source_rti.IsValid()) {
2350 if (destination_rti.IsValid() && destination_rti.CanArrayHoldValuesOf(source_rti)) {
2351 optimizations.SetDoesNotNeedTypeCheck();
2352 }
2353 if (source_rti.IsPrimitiveArrayClass()) {
2354 optimizations.SetSourceIsPrimitiveArray();
2355 source_component_type = DataTypeFromPrimitive(
2356 source_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType());
2357 } else if (source_rti.IsNonPrimitiveArrayClass()) {
2358 optimizations.SetSourceIsNonPrimitiveArray();
2359 }
2360 }
2361 // For primitive arrays, use their optimized ArtMethod implementations.
2362 if ((source_component_type != DataType::Type::kVoid) &&
2363 (source_component_type == destination_component_type)) {
2364 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
2365 PointerSize image_size = class_linker->GetImagePointerSize();
2366 HInvokeStaticOrDirect* invoke = instruction->AsInvokeStaticOrDirect();
2367 ObjPtr<mirror::Class> system = invoke->GetResolvedMethod()->GetDeclaringClass();
2368 ArtMethod* method = nullptr;
2369 switch (source_component_type) {
2370 case DataType::Type::kBool:
2371 method = system->FindClassMethod("arraycopy", "([ZI[ZII)V", image_size);
2372 break;
2373 case DataType::Type::kInt8:
2374 method = system->FindClassMethod("arraycopy", "([BI[BII)V", image_size);
2375 break;
2376 case DataType::Type::kUint16:
2377 method = system->FindClassMethod("arraycopy", "([CI[CII)V", image_size);
2378 break;
2379 case DataType::Type::kInt16:
2380 method = system->FindClassMethod("arraycopy", "([SI[SII)V", image_size);
2381 break;
2382 case DataType::Type::kInt32:
2383 method = system->FindClassMethod("arraycopy", "([II[III)V", image_size);
2384 break;
2385 case DataType::Type::kFloat32:
2386 method = system->FindClassMethod("arraycopy", "([FI[FII)V", image_size);
2387 break;
2388 case DataType::Type::kInt64:
2389 method = system->FindClassMethod("arraycopy", "([JI[JII)V", image_size);
2390 break;
2391 case DataType::Type::kFloat64:
2392 method = system->FindClassMethod("arraycopy", "([DI[DII)V", image_size);
2393 break;
2394 default:
2395 LOG(FATAL) << "Unreachable";
2396 }
2397 DCHECK(method != nullptr);
2398 DCHECK(method->IsStatic());
2399 DCHECK(method->GetDeclaringClass() == system);
2400 invoke->SetResolvedMethod(method);
2401 // Sharpen the new invoke. Note that we do not update the dex method index of
2402 // the invoke, as we would need to look it up in the current dex file, and it
2403 // is unlikely that it exists. The most usual situation for such typed
2404 // arraycopy methods is a direct pointer to the boot image.
2405 invoke->SetDispatchInfo(HSharpening::SharpenLoadMethod(
2406 method,
2407 /* has_method_id= */ true,
2408 /* for_interface_call= */ false,
2409 codegen_));
2410 }
2411 }
2412 }
2413
SimplifyFP2Int(HInvoke * invoke)2414 void InstructionSimplifierVisitor::SimplifyFP2Int(HInvoke* invoke) {
2415 DCHECK(invoke->IsInvokeStaticOrDirect());
2416 uint32_t dex_pc = invoke->GetDexPc();
2417 HInstruction* x = invoke->InputAt(0);
2418 DataType::Type type = x->GetType();
2419 // Set proper bit pattern for NaN and replace intrinsic with raw version.
2420 HInstruction* nan;
2421 if (type == DataType::Type::kFloat64) {
2422 nan = GetGraph()->GetLongConstant(0x7ff8000000000000L);
2423 invoke->SetIntrinsic(Intrinsics::kDoubleDoubleToRawLongBits,
2424 kNeedsEnvironment,
2425 kNoSideEffects,
2426 kNoThrow);
2427 } else {
2428 DCHECK_EQ(type, DataType::Type::kFloat32);
2429 nan = GetGraph()->GetIntConstant(0x7fc00000);
2430 invoke->SetIntrinsic(Intrinsics::kFloatFloatToRawIntBits,
2431 kNeedsEnvironment,
2432 kNoSideEffects,
2433 kNoThrow);
2434 }
2435 // Test IsNaN(x), which is the same as x != x.
2436 HCondition* condition = new (GetGraph()->GetAllocator()) HNotEqual(x, x, dex_pc);
2437 condition->SetBias(ComparisonBias::kLtBias);
2438 invoke->GetBlock()->InsertInstructionBefore(condition, invoke->GetNext());
2439 // Select between the two.
2440 HInstruction* select = new (GetGraph()->GetAllocator()) HSelect(condition, nan, invoke, dex_pc);
2441 invoke->GetBlock()->InsertInstructionBefore(select, condition->GetNext());
2442 invoke->ReplaceWithExceptInReplacementAtIndex(select, 0); // false at index 0
2443 }
2444
SimplifyStringCharAt(HInvoke * invoke)2445 void InstructionSimplifierVisitor::SimplifyStringCharAt(HInvoke* invoke) {
2446 HInstruction* str = invoke->InputAt(0);
2447 HInstruction* index = invoke->InputAt(1);
2448 uint32_t dex_pc = invoke->GetDexPc();
2449 ArenaAllocator* allocator = GetGraph()->GetAllocator();
2450 // We treat String as an array to allow DCE and BCE to seamlessly work on strings,
2451 // so create the HArrayLength, HBoundsCheck and HArrayGet.
2452 HArrayLength* length = new (allocator) HArrayLength(str, dex_pc, /* is_string_length= */ true);
2453 invoke->GetBlock()->InsertInstructionBefore(length, invoke);
2454 HBoundsCheck* bounds_check = new (allocator) HBoundsCheck(
2455 index, length, dex_pc, /* is_string_char_at= */ true);
2456 invoke->GetBlock()->InsertInstructionBefore(bounds_check, invoke);
2457 HArrayGet* array_get = new (allocator) HArrayGet(str,
2458 bounds_check,
2459 DataType::Type::kUint16,
2460 SideEffects::None(), // Strings are immutable.
2461 dex_pc,
2462 /* is_string_char_at= */ true);
2463 invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, array_get);
2464 bounds_check->CopyEnvironmentFrom(invoke->GetEnvironment());
2465 GetGraph()->SetHasBoundsChecks(true);
2466 }
2467
SimplifyStringLength(HInvoke * invoke)2468 void InstructionSimplifierVisitor::SimplifyStringLength(HInvoke* invoke) {
2469 HInstruction* str = invoke->InputAt(0);
2470 uint32_t dex_pc = invoke->GetDexPc();
2471 // We treat String as an array to allow DCE and BCE to seamlessly work on strings,
2472 // so create the HArrayLength.
2473 HArrayLength* length =
2474 new (GetGraph()->GetAllocator()) HArrayLength(str, dex_pc, /* is_string_length= */ true);
2475 invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, length);
2476 }
2477
SimplifyStringIndexOf(HInvoke * invoke)2478 void InstructionSimplifierVisitor::SimplifyStringIndexOf(HInvoke* invoke) {
2479 DCHECK(invoke->GetIntrinsic() == Intrinsics::kStringIndexOf ||
2480 invoke->GetIntrinsic() == Intrinsics::kStringIndexOfAfter);
2481 if (invoke->InputAt(0)->IsLoadString()) {
2482 HLoadString* load_string = invoke->InputAt(0)->AsLoadString();
2483 const DexFile& dex_file = load_string->GetDexFile();
2484 uint32_t utf16_length;
2485 const char* data =
2486 dex_file.StringDataAndUtf16LengthByIdx(load_string->GetStringIndex(), &utf16_length);
2487 if (utf16_length == 0) {
2488 invoke->ReplaceWith(GetGraph()->GetIntConstant(-1));
2489 invoke->GetBlock()->RemoveInstruction(invoke);
2490 RecordSimplification();
2491 return;
2492 }
2493 if (utf16_length == 1 && invoke->GetIntrinsic() == Intrinsics::kStringIndexOf) {
2494 // Simplify to HSelect(HEquals(., load_string.charAt(0)), 0, -1).
2495 // If the sought character is supplementary, this gives the correct result, i.e. -1.
2496 uint32_t c = GetUtf16FromUtf8(&data);
2497 DCHECK_EQ(GetTrailingUtf16Char(c), 0u);
2498 DCHECK_EQ(GetLeadingUtf16Char(c), c);
2499 uint32_t dex_pc = invoke->GetDexPc();
2500 ArenaAllocator* allocator = GetGraph()->GetAllocator();
2501 HEqual* equal =
2502 new (allocator) HEqual(invoke->InputAt(1), GetGraph()->GetIntConstant(c), dex_pc);
2503 invoke->GetBlock()->InsertInstructionBefore(equal, invoke);
2504 HSelect* result = new (allocator) HSelect(equal,
2505 GetGraph()->GetIntConstant(0),
2506 GetGraph()->GetIntConstant(-1),
2507 dex_pc);
2508 invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, result);
2509 RecordSimplification();
2510 return;
2511 }
2512 }
2513 }
2514
2515 // This method should only be used on intrinsics whose sole way of throwing an
2516 // exception is raising a NPE when the nth argument is null. If that argument
2517 // is provably non-null, we can clear the flag.
SimplifyNPEOnArgN(HInvoke * invoke,size_t n)2518 void InstructionSimplifierVisitor::SimplifyNPEOnArgN(HInvoke* invoke, size_t n) {
2519 HInstruction* arg = invoke->InputAt(n);
2520 if (invoke->CanThrow() && !arg->CanBeNull()) {
2521 invoke->SetCanThrow(false);
2522 }
2523 }
2524
2525 // Methods that return "this" can replace the returned value with the receiver.
SimplifyReturnThis(HInvoke * invoke)2526 void InstructionSimplifierVisitor::SimplifyReturnThis(HInvoke* invoke) {
2527 if (invoke->HasUses()) {
2528 HInstruction* receiver = invoke->InputAt(0);
2529 invoke->ReplaceWith(receiver);
2530 RecordSimplification();
2531 }
2532 }
2533
2534 // Helper method for StringBuffer escape analysis.
NoEscapeForStringBufferReference(HInstruction * reference,HInstruction * user)2535 static bool NoEscapeForStringBufferReference(HInstruction* reference, HInstruction* user) {
2536 if (user->IsInvokeStaticOrDirect()) {
2537 // Any constructor on StringBuffer is okay.
2538 return user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
2539 user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
2540 user->InputAt(0) == reference;
2541 } else if (user->IsInvokeVirtual()) {
2542 switch (user->AsInvokeVirtual()->GetIntrinsic()) {
2543 case Intrinsics::kStringBufferLength:
2544 case Intrinsics::kStringBufferToString:
2545 DCHECK_EQ(user->InputAt(0), reference);
2546 return true;
2547 case Intrinsics::kStringBufferAppend:
2548 // Returns "this", so only okay if no further uses.
2549 DCHECK_EQ(user->InputAt(0), reference);
2550 DCHECK_NE(user->InputAt(1), reference);
2551 return !user->HasUses();
2552 default:
2553 break;
2554 }
2555 }
2556 return false;
2557 }
2558
TryReplaceStringBuilderAppend(HInvoke * invoke)2559 static bool TryReplaceStringBuilderAppend(HInvoke* invoke) {
2560 DCHECK_EQ(invoke->GetIntrinsic(), Intrinsics::kStringBuilderToString);
2561 if (invoke->CanThrowIntoCatchBlock()) {
2562 return false;
2563 }
2564
2565 HBasicBlock* block = invoke->GetBlock();
2566 HInstruction* sb = invoke->InputAt(0);
2567
2568 // We support only a new StringBuilder, otherwise we cannot ensure that
2569 // the StringBuilder data does not need to be populated for other users.
2570 if (!sb->IsNewInstance()) {
2571 return false;
2572 }
2573
2574 // For now, we support only single-block recognition.
2575 // (Ternary operators feeding the append could be implemented.)
2576 for (const HUseListNode<HInstruction*>& use : sb->GetUses()) {
2577 if (use.GetUser()->GetBlock() != block) {
2578 return false;
2579 }
2580 // The append pattern uses the StringBuilder only as the first argument.
2581 if (use.GetIndex() != 0u) {
2582 return false;
2583 }
2584 }
2585
2586 // Collect args and check for unexpected uses.
2587 // We expect one call to a constructor with no arguments, one constructor fence (unless
2588 // eliminated), some number of append calls and one call to StringBuilder.toString().
2589 bool seen_constructor = false;
2590 bool seen_constructor_fence = false;
2591 bool seen_to_string = false;
2592 uint32_t format = 0u;
2593 uint32_t num_args = 0u;
2594 HInstruction* args[StringBuilderAppend::kMaxArgs]; // Added in reverse order.
2595 for (HBackwardInstructionIterator iter(block->GetInstructions()); !iter.Done(); iter.Advance()) {
2596 HInstruction* user = iter.Current();
2597 // Instructions of interest apply to `sb`, skip those that do not involve `sb`.
2598 if (user->InputCount() == 0u || user->InputAt(0u) != sb) {
2599 continue;
2600 }
2601 // We visit the uses in reverse order, so the StringBuilder.toString() must come first.
2602 if (!seen_to_string) {
2603 if (user == invoke) {
2604 seen_to_string = true;
2605 continue;
2606 } else {
2607 return false;
2608 }
2609 }
2610 // Then we should see the arguments.
2611 if (user->IsInvokeVirtual()) {
2612 HInvokeVirtual* as_invoke_virtual = user->AsInvokeVirtual();
2613 DCHECK(!seen_constructor);
2614 DCHECK(!seen_constructor_fence);
2615 StringBuilderAppend::Argument arg;
2616 switch (as_invoke_virtual->GetIntrinsic()) {
2617 case Intrinsics::kStringBuilderAppendObject:
2618 // TODO: Unimplemented, needs to call String.valueOf().
2619 return false;
2620 case Intrinsics::kStringBuilderAppendString:
2621 arg = StringBuilderAppend::Argument::kString;
2622 break;
2623 case Intrinsics::kStringBuilderAppendCharArray:
2624 // TODO: Unimplemented, StringBuilder.append(char[]) can throw NPE and we would
2625 // not have the correct stack trace for it.
2626 return false;
2627 case Intrinsics::kStringBuilderAppendBoolean:
2628 arg = StringBuilderAppend::Argument::kBoolean;
2629 break;
2630 case Intrinsics::kStringBuilderAppendChar:
2631 arg = StringBuilderAppend::Argument::kChar;
2632 break;
2633 case Intrinsics::kStringBuilderAppendInt:
2634 arg = StringBuilderAppend::Argument::kInt;
2635 break;
2636 case Intrinsics::kStringBuilderAppendLong:
2637 arg = StringBuilderAppend::Argument::kLong;
2638 break;
2639 case Intrinsics::kStringBuilderAppendCharSequence: {
2640 ReferenceTypeInfo rti = user->AsInvokeVirtual()->InputAt(1)->GetReferenceTypeInfo();
2641 if (!rti.IsValid()) {
2642 return false;
2643 }
2644 ScopedObjectAccess soa(Thread::Current());
2645 Handle<mirror::Class> input_type = rti.GetTypeHandle();
2646 DCHECK(input_type != nullptr);
2647 if (input_type.Get() == GetClassRoot<mirror::String>()) {
2648 arg = StringBuilderAppend::Argument::kString;
2649 } else {
2650 // TODO: Check and implement for StringBuilder. We could find the StringBuilder's
2651 // internal char[] inconsistent with the length, or the string compression
2652 // of the result could be compromised with a concurrent modification, and
2653 // we would need to throw appropriate exceptions.
2654 return false;
2655 }
2656 break;
2657 }
2658 case Intrinsics::kStringBuilderAppendFloat:
2659 case Intrinsics::kStringBuilderAppendDouble:
2660 // TODO: Unimplemented, needs to call FloatingDecimal.getBinaryToASCIIConverter().
2661 return false;
2662 default: {
2663 return false;
2664 }
2665 }
2666 // Uses of the append return value should have been replaced with the first input.
2667 DCHECK(!as_invoke_virtual->HasUses());
2668 DCHECK(!as_invoke_virtual->HasEnvironmentUses());
2669 if (num_args == StringBuilderAppend::kMaxArgs) {
2670 return false;
2671 }
2672 format = (format << StringBuilderAppend::kBitsPerArg) | static_cast<uint32_t>(arg);
2673 args[num_args] = as_invoke_virtual->InputAt(1u);
2674 ++num_args;
2675 } else if (user->IsInvokeStaticOrDirect() &&
2676 user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
2677 user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
2678 user->AsInvokeStaticOrDirect()->GetNumberOfArguments() == 1u) {
2679 // After arguments, we should see the constructor.
2680 // We accept only the constructor with no extra arguments.
2681 DCHECK(!seen_constructor);
2682 DCHECK(!seen_constructor_fence);
2683 seen_constructor = true;
2684 } else if (user->IsConstructorFence()) {
2685 // The last use we see is the constructor fence.
2686 DCHECK(seen_constructor);
2687 DCHECK(!seen_constructor_fence);
2688 seen_constructor_fence = true;
2689 } else {
2690 return false;
2691 }
2692 }
2693
2694 if (num_args == 0u) {
2695 return false;
2696 }
2697
2698 // Check environment uses.
2699 for (const HUseListNode<HEnvironment*>& use : sb->GetEnvUses()) {
2700 HInstruction* holder = use.GetUser()->GetHolder();
2701 if (holder->GetBlock() != block) {
2702 return false;
2703 }
2704 // Accept only calls on the StringBuilder (which shall all be removed).
2705 // TODO: Carve-out for const-string? Or rely on environment pruning (to be implemented)?
2706 if (holder->InputCount() == 0 || holder->InputAt(0) != sb) {
2707 return false;
2708 }
2709 }
2710
2711 // Create replacement instruction.
2712 HIntConstant* fmt = block->GetGraph()->GetIntConstant(static_cast<int32_t>(format));
2713 ArenaAllocator* allocator = block->GetGraph()->GetAllocator();
2714 HStringBuilderAppend* append =
2715 new (allocator) HStringBuilderAppend(fmt, num_args, allocator, invoke->GetDexPc());
2716 append->SetReferenceTypeInfo(invoke->GetReferenceTypeInfo());
2717 for (size_t i = 0; i != num_args; ++i) {
2718 append->SetArgumentAt(i, args[num_args - 1u - i]);
2719 }
2720 block->InsertInstructionBefore(append, invoke);
2721 DCHECK(!invoke->CanBeNull());
2722 DCHECK(!append->CanBeNull());
2723 invoke->ReplaceWith(append);
2724 // Copy environment, except for the StringBuilder uses.
2725 for (HEnvironment* env = invoke->GetEnvironment(); env != nullptr; env = env->GetParent()) {
2726 for (size_t i = 0, size = env->Size(); i != size; ++i) {
2727 if (env->GetInstructionAt(i) == sb) {
2728 env->RemoveAsUserOfInput(i);
2729 env->SetRawEnvAt(i, /*instruction=*/ nullptr);
2730 }
2731 }
2732 }
2733 append->CopyEnvironmentFrom(invoke->GetEnvironment());
2734 // Remove the old instruction.
2735 block->RemoveInstruction(invoke);
2736 // Remove the StringBuilder's uses and StringBuilder.
2737 while (sb->HasNonEnvironmentUses()) {
2738 block->RemoveInstruction(sb->GetUses().front().GetUser());
2739 }
2740 DCHECK(!sb->HasEnvironmentUses());
2741 block->RemoveInstruction(sb);
2742 return true;
2743 }
2744
2745 // Certain allocation intrinsics are not removed by dead code elimination
2746 // because of potentially throwing an OOM exception or other side effects.
2747 // This method removes such intrinsics when special circumstances allow.
SimplifyAllocationIntrinsic(HInvoke * invoke)2748 void InstructionSimplifierVisitor::SimplifyAllocationIntrinsic(HInvoke* invoke) {
2749 if (!invoke->HasUses()) {
2750 // Instruction has no uses. If unsynchronized, we can remove right away, safely ignoring
2751 // the potential OOM of course. Otherwise, we must ensure the receiver object of this
2752 // call does not escape since only thread-local synchronization may be removed.
2753 bool is_synchronized = invoke->GetIntrinsic() == Intrinsics::kStringBufferToString;
2754 HInstruction* receiver = invoke->InputAt(0);
2755 if (!is_synchronized || DoesNotEscape(receiver, NoEscapeForStringBufferReference)) {
2756 invoke->GetBlock()->RemoveInstruction(invoke);
2757 RecordSimplification();
2758 }
2759 } else if (invoke->GetIntrinsic() == Intrinsics::kStringBuilderToString &&
2760 TryReplaceStringBuilderAppend(invoke)) {
2761 RecordSimplification();
2762 }
2763 }
2764
VisitInvoke(HInvoke * instruction)2765 void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) {
2766 switch (instruction->GetIntrinsic()) {
2767 case Intrinsics::kStringEquals:
2768 SimplifyStringEquals(instruction);
2769 break;
2770 case Intrinsics::kSystemArrayCopy:
2771 SimplifySystemArrayCopy(instruction);
2772 break;
2773 case Intrinsics::kFloatFloatToIntBits:
2774 case Intrinsics::kDoubleDoubleToLongBits:
2775 SimplifyFP2Int(instruction);
2776 break;
2777 case Intrinsics::kStringCharAt:
2778 // Instruction builder creates intermediate representation directly
2779 // but the inliner can sharpen CharSequence.charAt() to String.charAt().
2780 SimplifyStringCharAt(instruction);
2781 break;
2782 case Intrinsics::kStringLength:
2783 // Instruction builder creates intermediate representation directly
2784 // but the inliner can sharpen CharSequence.length() to String.length().
2785 SimplifyStringLength(instruction);
2786 break;
2787 case Intrinsics::kStringIndexOf:
2788 case Intrinsics::kStringIndexOfAfter:
2789 SimplifyStringIndexOf(instruction);
2790 break;
2791 case Intrinsics::kStringStringIndexOf:
2792 case Intrinsics::kStringStringIndexOfAfter:
2793 SimplifyNPEOnArgN(instruction, 1); // 0th has own NullCheck
2794 break;
2795 case Intrinsics::kStringBufferAppend:
2796 case Intrinsics::kStringBuilderAppendObject:
2797 case Intrinsics::kStringBuilderAppendString:
2798 case Intrinsics::kStringBuilderAppendCharSequence:
2799 case Intrinsics::kStringBuilderAppendCharArray:
2800 case Intrinsics::kStringBuilderAppendBoolean:
2801 case Intrinsics::kStringBuilderAppendChar:
2802 case Intrinsics::kStringBuilderAppendInt:
2803 case Intrinsics::kStringBuilderAppendLong:
2804 case Intrinsics::kStringBuilderAppendFloat:
2805 case Intrinsics::kStringBuilderAppendDouble:
2806 SimplifyReturnThis(instruction);
2807 break;
2808 case Intrinsics::kStringBufferToString:
2809 case Intrinsics::kStringBuilderToString:
2810 SimplifyAllocationIntrinsic(instruction);
2811 break;
2812 case Intrinsics::kIntegerRotateRight:
2813 case Intrinsics::kLongRotateRight:
2814 case Intrinsics::kIntegerRotateLeft:
2815 case Intrinsics::kLongRotateLeft:
2816 case Intrinsics::kIntegerCompare:
2817 case Intrinsics::kLongCompare:
2818 case Intrinsics::kIntegerSignum:
2819 case Intrinsics::kLongSignum:
2820 case Intrinsics::kFloatIsNaN:
2821 case Intrinsics::kDoubleIsNaN:
2822 case Intrinsics::kStringIsEmpty:
2823 case Intrinsics::kUnsafeLoadFence:
2824 case Intrinsics::kUnsafeStoreFence:
2825 case Intrinsics::kUnsafeFullFence:
2826 case Intrinsics::kVarHandleFullFence:
2827 case Intrinsics::kVarHandleAcquireFence:
2828 case Intrinsics::kVarHandleReleaseFence:
2829 case Intrinsics::kVarHandleLoadLoadFence:
2830 case Intrinsics::kVarHandleStoreStoreFence:
2831 case Intrinsics::kMathMinIntInt:
2832 case Intrinsics::kMathMinLongLong:
2833 case Intrinsics::kMathMinFloatFloat:
2834 case Intrinsics::kMathMinDoubleDouble:
2835 case Intrinsics::kMathMaxIntInt:
2836 case Intrinsics::kMathMaxLongLong:
2837 case Intrinsics::kMathMaxFloatFloat:
2838 case Intrinsics::kMathMaxDoubleDouble:
2839 case Intrinsics::kMathAbsInt:
2840 case Intrinsics::kMathAbsLong:
2841 case Intrinsics::kMathAbsFloat:
2842 case Intrinsics::kMathAbsDouble:
2843 // These are replaced by intermediate representation in the instruction builder.
2844 LOG(FATAL) << "Unexpected " << static_cast<Intrinsics>(instruction->GetIntrinsic());
2845 UNREACHABLE();
2846 default:
2847 break;
2848 }
2849 }
2850
VisitDeoptimize(HDeoptimize * deoptimize)2851 void InstructionSimplifierVisitor::VisitDeoptimize(HDeoptimize* deoptimize) {
2852 HInstruction* cond = deoptimize->InputAt(0);
2853 if (cond->IsConstant()) {
2854 if (cond->AsIntConstant()->IsFalse()) {
2855 // Never deopt: instruction can be removed.
2856 if (deoptimize->GuardsAnInput()) {
2857 deoptimize->ReplaceWith(deoptimize->GuardedInput());
2858 }
2859 deoptimize->GetBlock()->RemoveInstruction(deoptimize);
2860 } else {
2861 // Always deopt.
2862 }
2863 }
2864 }
2865
2866 // Replace code looking like
2867 // OP y, x, const1
2868 // OP z, y, const2
2869 // with
2870 // OP z, x, const3
2871 // where OP is both an associative and a commutative operation.
TryHandleAssociativeAndCommutativeOperation(HBinaryOperation * instruction)2872 bool InstructionSimplifierVisitor::TryHandleAssociativeAndCommutativeOperation(
2873 HBinaryOperation* instruction) {
2874 DCHECK(instruction->IsCommutative());
2875
2876 if (!DataType::IsIntegralType(instruction->GetType())) {
2877 return false;
2878 }
2879
2880 HInstruction* left = instruction->GetLeft();
2881 HInstruction* right = instruction->GetRight();
2882 // Variable names as described above.
2883 HConstant* const2;
2884 HBinaryOperation* y;
2885
2886 if (instruction->GetKind() == left->GetKind() && right->IsConstant()) {
2887 const2 = right->AsConstant();
2888 y = left->AsBinaryOperation();
2889 } else if (left->IsConstant() && instruction->GetKind() == right->GetKind()) {
2890 const2 = left->AsConstant();
2891 y = right->AsBinaryOperation();
2892 } else {
2893 // The node does not match the pattern.
2894 return false;
2895 }
2896
2897 // If `y` has more than one use, we do not perform the optimization
2898 // because it might increase code size (e.g. if the new constant is
2899 // no longer encodable as an immediate operand in the target ISA).
2900 if (!y->HasOnlyOneNonEnvironmentUse()) {
2901 return false;
2902 }
2903
2904 // GetConstantRight() can return both left and right constants
2905 // for commutative operations.
2906 HConstant* const1 = y->GetConstantRight();
2907 if (const1 == nullptr) {
2908 return false;
2909 }
2910
2911 instruction->ReplaceInput(const1, 0);
2912 instruction->ReplaceInput(const2, 1);
2913 HConstant* const3 = instruction->TryStaticEvaluation();
2914 DCHECK(const3 != nullptr);
2915 instruction->ReplaceInput(y->GetLeastConstantLeft(), 0);
2916 instruction->ReplaceInput(const3, 1);
2917 RecordSimplification();
2918 return true;
2919 }
2920
AsAddOrSub(HInstruction * binop)2921 static HBinaryOperation* AsAddOrSub(HInstruction* binop) {
2922 return (binop->IsAdd() || binop->IsSub()) ? binop->AsBinaryOperation() : nullptr;
2923 }
2924
2925 // Helper function that performs addition statically, considering the result type.
ComputeAddition(DataType::Type type,int64_t x,int64_t y)2926 static int64_t ComputeAddition(DataType::Type type, int64_t x, int64_t y) {
2927 // Use the Compute() method for consistency with TryStaticEvaluation().
2928 if (type == DataType::Type::kInt32) {
2929 return HAdd::Compute<int32_t>(x, y);
2930 } else {
2931 DCHECK_EQ(type, DataType::Type::kInt64);
2932 return HAdd::Compute<int64_t>(x, y);
2933 }
2934 }
2935
2936 // Helper function that handles the child classes of HConstant
2937 // and returns an integer with the appropriate sign.
GetValue(HConstant * constant,bool is_negated)2938 static int64_t GetValue(HConstant* constant, bool is_negated) {
2939 int64_t ret = Int64FromConstant(constant);
2940 return is_negated ? -ret : ret;
2941 }
2942
2943 // Replace code looking like
2944 // OP1 y, x, const1
2945 // OP2 z, y, const2
2946 // with
2947 // OP3 z, x, const3
2948 // where OPx is either ADD or SUB, and at least one of OP{1,2} is SUB.
TrySubtractionChainSimplification(HBinaryOperation * instruction)2949 bool InstructionSimplifierVisitor::TrySubtractionChainSimplification(
2950 HBinaryOperation* instruction) {
2951 DCHECK(instruction->IsAdd() || instruction->IsSub()) << instruction->DebugName();
2952
2953 DataType::Type type = instruction->GetType();
2954 if (!DataType::IsIntegralType(type)) {
2955 return false;
2956 }
2957
2958 HInstruction* left = instruction->GetLeft();
2959 HInstruction* right = instruction->GetRight();
2960 // Variable names as described above.
2961 HConstant* const2 = right->IsConstant() ? right->AsConstant() : left->AsConstant();
2962 if (const2 == nullptr) {
2963 return false;
2964 }
2965
2966 HBinaryOperation* y = (AsAddOrSub(left) != nullptr)
2967 ? left->AsBinaryOperation()
2968 : AsAddOrSub(right);
2969 // If y has more than one use, we do not perform the optimization because
2970 // it might increase code size (e.g. if the new constant is no longer
2971 // encodable as an immediate operand in the target ISA).
2972 if ((y == nullptr) || !y->HasOnlyOneNonEnvironmentUse()) {
2973 return false;
2974 }
2975
2976 left = y->GetLeft();
2977 HConstant* const1 = left->IsConstant() ? left->AsConstant() : y->GetRight()->AsConstant();
2978 if (const1 == nullptr) {
2979 return false;
2980 }
2981
2982 HInstruction* x = (const1 == left) ? y->GetRight() : left;
2983 // If both inputs are constants, let the constant folding pass deal with it.
2984 if (x->IsConstant()) {
2985 return false;
2986 }
2987
2988 bool is_const2_negated = (const2 == right) && instruction->IsSub();
2989 int64_t const2_val = GetValue(const2, is_const2_negated);
2990 bool is_y_negated = (y == right) && instruction->IsSub();
2991 right = y->GetRight();
2992 bool is_const1_negated = is_y_negated ^ ((const1 == right) && y->IsSub());
2993 int64_t const1_val = GetValue(const1, is_const1_negated);
2994 bool is_x_negated = is_y_negated ^ ((x == right) && y->IsSub());
2995 int64_t const3_val = ComputeAddition(type, const1_val, const2_val);
2996 HBasicBlock* block = instruction->GetBlock();
2997 HConstant* const3 = block->GetGraph()->GetConstant(type, const3_val);
2998 ArenaAllocator* allocator = instruction->GetAllocator();
2999 HInstruction* z;
3000
3001 if (is_x_negated) {
3002 z = new (allocator) HSub(type, const3, x, instruction->GetDexPc());
3003 } else {
3004 z = new (allocator) HAdd(type, x, const3, instruction->GetDexPc());
3005 }
3006
3007 block->ReplaceAndRemoveInstructionWith(instruction, z);
3008 RecordSimplification();
3009 return true;
3010 }
3011
VisitVecMul(HVecMul * instruction)3012 void InstructionSimplifierVisitor::VisitVecMul(HVecMul* instruction) {
3013 if (TryCombineVecMultiplyAccumulate(instruction)) {
3014 RecordSimplification();
3015 }
3016 }
3017
3018 } // namespace art
3019