instruction_simplifier_arm64.cc revision 8626b741716390a0119ffeb88b5b9fcf08e13010
144b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames/*
244b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames * Copyright (C) 2015 The Android Open Source Project
344b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames *
444b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames * Licensed under the Apache License, Version 2.0 (the "License");
544b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames * you may not use this file except in compliance with the License.
644b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames * You may obtain a copy of the License at
744b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames *
844b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames *      http://www.apache.org/licenses/LICENSE-2.0
944b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames *
1044b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames * Unless required by applicable law or agreed to in writing, software
1144b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames * distributed under the License is distributed on an "AS IS" BASIS,
1244b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1344b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames * See the License for the specific language governing permissions and
1444b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames * limitations under the License.
1544b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames */
1644b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames
1744b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames#include "instruction_simplifier_arm64.h"
1844b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames
198626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames#include "common_arm64.h"
20e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames#include "mirror/array-inl.h"
21e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames
2244b9cf937836bb33139123e15ca8b586b5853268Alexandre Ramesnamespace art {
2344b9cf937836bb33139123e15ca8b586b5853268Alexandre Ramesnamespace arm64 {
2444b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames
258626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Ramesusing helpers::CanFitInShifterOperand;
268626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Ramesusing helpers::HasShifterOperand;
278626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Ramesusing helpers::ShifterOperandSupportsExtension;
288626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
29e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Ramesvoid InstructionSimplifierArm64Visitor::TryExtractArrayAccessAddress(HInstruction* access,
30e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames                                                                     HInstruction* array,
31e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames                                                                     HInstruction* index,
32e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames                                                                     int access_size) {
33e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  if (index->IsConstant() ||
34e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames      (index->IsBoundsCheck() && index->AsBoundsCheck()->GetIndex()->IsConstant())) {
35e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames    // When the index is a constant all the addressing can be fitted in the
36e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames    // memory access instruction, so do not split the access.
37e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames    return;
38e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  }
39e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  if (access->IsArraySet() &&
40e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames      access->AsArraySet()->GetValue()->GetType() == Primitive::kPrimNot) {
41e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames    // The access may require a runtime call or the original array pointer.
42e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames    return;
43e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  }
44e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames
45e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // Proceed to extract the base address computation.
46e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  ArenaAllocator* arena = GetGraph()->GetArena();
47e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames
48e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  HIntConstant* offset =
49e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames      GetGraph()->GetIntConstant(mirror::Array::DataOffset(access_size).Uint32Value());
50e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  HArm64IntermediateAddress* address =
51e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames      new (arena) HArm64IntermediateAddress(array, offset, kNoDexPc);
52e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  access->GetBlock()->InsertInstructionBefore(address, access);
53e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  access->ReplaceInput(address, 0);
54e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // Both instructions must depend on GC to prevent any instruction that can
55e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // trigger GC to be inserted between the two.
56e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  access->AddSideEffects(SideEffects::DependsOnGC());
57e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  DCHECK(address->GetSideEffects().Includes(SideEffects::DependsOnGC()));
58e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  DCHECK(access->GetSideEffects().Includes(SideEffects::DependsOnGC()));
59e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // TODO: Code generation for HArrayGet and HArraySet will check whether the input address
60e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // is an HArm64IntermediateAddress and generate appropriate code.
61e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // We would like to replace the `HArrayGet` and `HArraySet` with custom instructions (maybe
62e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // `HArm64Load` and `HArm64Store`). We defer these changes because these new instructions would
63e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // not bring any advantages yet.
64e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // Also see the comments in
65e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // `InstructionCodeGeneratorARM64::VisitArrayGet()` and
66e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  // `InstructionCodeGeneratorARM64::VisitArraySet()`.
67e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  RecordSimplification();
68e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames}
69e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames
708626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Ramesbool InstructionSimplifierArm64Visitor::TryMergeIntoShifterOperand(HInstruction* use,
718626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames                                                                   HInstruction* bitfield_op,
728626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames                                                                   bool do_merge) {
738626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  DCHECK(HasShifterOperand(use));
748626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  DCHECK(use->IsBinaryOperation() || use->IsNeg());
758626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  DCHECK(CanFitInShifterOperand(bitfield_op));
768626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  DCHECK(!bitfield_op->HasEnvironmentUses());
778626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
788626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  Primitive::Type type = use->GetType();
798626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
808626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    return false;
818626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
828626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
838626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  HInstruction* left;
848626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  HInstruction* right;
858626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (use->IsBinaryOperation()) {
868626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    left = use->InputAt(0);
878626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    right = use->InputAt(1);
888626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  } else {
898626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    DCHECK(use->IsNeg());
908626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    right = use->AsNeg()->InputAt(0);
918626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    left = GetGraph()->GetConstant(right->GetType(), 0);
928626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
938626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  DCHECK(left == bitfield_op || right == bitfield_op);
948626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
958626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (left == right) {
968626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    // TODO: Handle special transformations in this situation?
978626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    // For example should we transform `(x << 1) + (x << 1)` into `(x << 2)`?
988626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    // Or should this be part of a separate transformation logic?
998626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    return false;
1008626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
1018626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1028626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  bool is_commutative = use->IsBinaryOperation() && use->AsBinaryOperation()->IsCommutative();
1038626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  HInstruction* other_input;
1048626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (bitfield_op == right) {
1058626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    other_input = left;
1068626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  } else {
1078626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    if (is_commutative) {
1088626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames      other_input = right;
1098626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    } else {
1108626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames      return false;
1118626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    }
1128626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
1138626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1148626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  HArm64DataProcWithShifterOp::OpKind op_kind;
1158626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  int shift_amount = 0;
1168626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  HArm64DataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
1178626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1188626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (HArm64DataProcWithShifterOp::IsExtensionOp(op_kind) &&
1198626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames      !ShifterOperandSupportsExtension(use)) {
1208626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    return false;
1218626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
1228626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1238626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (do_merge) {
1248626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    HArm64DataProcWithShifterOp* alu_with_op =
1258626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames        new (GetGraph()->GetArena()) HArm64DataProcWithShifterOp(use,
1268626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames                                                                 other_input,
1278626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames                                                                 bitfield_op->InputAt(0),
1288626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames                                                                 op_kind,
1298626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames                                                                 shift_amount,
1308626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames                                                                 use->GetDexPc());
1318626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op);
1328626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    if (bitfield_op->GetUses().IsEmpty()) {
1338626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames      bitfield_op->GetBlock()->RemoveInstruction(bitfield_op);
1348626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    }
1358626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    RecordSimplification();
1368626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
1378626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1388626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  return true;
1398626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames}
1408626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1418626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames// Merge a bitfield move instruction into its uses if it can be merged in all of them.
1428626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Ramesbool InstructionSimplifierArm64Visitor::TryMergeIntoUsersShifterOperand(HInstruction* bitfield_op) {
1438626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  DCHECK(CanFitInShifterOperand(bitfield_op));
1448626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1458626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (bitfield_op->HasEnvironmentUses()) {
1468626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    return false;
1478626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
1488626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1498626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  const HUseList<HInstruction*>& uses = bitfield_op->GetUses();
1508626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1518626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  // Check whether we can merge the instruction in all its users' shifter operand.
1528626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  for (HUseIterator<HInstruction*> it_use(uses); !it_use.Done(); it_use.Advance()) {
1538626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    HInstruction* use = it_use.Current()->GetUser();
1548626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    if (!HasShifterOperand(use)) {
1558626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames      return false;
1568626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    }
1578626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    if (!CanMergeIntoShifterOperand(use, bitfield_op)) {
1588626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames      return false;
1598626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    }
1608626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
1618626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1628626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  // Merge the instruction into its uses.
1638626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  for (HUseIterator<HInstruction*> it_use(uses); !it_use.Done(); it_use.Advance()) {
1648626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    HInstruction* use = it_use.Current()->GetUser();
1658626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    bool merged = MergeIntoShifterOperand(use, bitfield_op);
1668626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    DCHECK(merged);
1678626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
1688626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
1698626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  return true;
1708626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames}
1718626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
172418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Ramesbool InstructionSimplifierArm64Visitor::TrySimpleMultiplyAccumulatePatterns(
173418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    HMul* mul, HBinaryOperation* input_binop, HInstruction* input_other) {
174418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  DCHECK(Primitive::IsIntOrLongType(mul->GetType()));
175418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  DCHECK(input_binop->IsAdd() || input_binop->IsSub());
176418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  DCHECK_NE(input_binop, input_other);
177418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  if (!input_binop->HasOnlyOneNonEnvironmentUse()) {
178418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    return false;
179418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  }
180418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
181418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  // Try to interpret patterns like
182418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  //    a * (b <+/-> 1)
183418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  // as
184418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  //    (a * b) <+/-> a
185418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  HInstruction* input_a = input_other;
186418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  HInstruction* input_b = nullptr;  // Set to a non-null value if we found a pattern to optimize.
187418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  HInstruction::InstructionKind op_kind;
188418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
189418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  if (input_binop->IsAdd()) {
190418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    if ((input_binop->GetConstantRight() != nullptr) && input_binop->GetConstantRight()->IsOne()) {
191418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      // Interpret
192418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      //    a * (b + 1)
193418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      // as
194418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      //    (a * b) + a
195418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      input_b = input_binop->GetLeastConstantLeft();
196418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      op_kind = HInstruction::kAdd;
197418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    }
198418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  } else {
199418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    DCHECK(input_binop->IsSub());
200418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    if (input_binop->GetRight()->IsConstant() &&
201418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames        input_binop->GetRight()->AsConstant()->IsMinusOne()) {
202418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      // Interpret
203418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      //    a * (b - (-1))
204418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      // as
205418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      //    a + (a * b)
206418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      input_b = input_binop->GetLeft();
207418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      op_kind = HInstruction::kAdd;
208418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    } else if (input_binop->GetLeft()->IsConstant() &&
209418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames               input_binop->GetLeft()->AsConstant()->IsOne()) {
210418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      // Interpret
211418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      //    a * (1 - b)
212418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      // as
213418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      //    a - (a * b)
214418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      input_b = input_binop->GetRight();
215418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      op_kind = HInstruction::kSub;
216418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    }
217418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  }
218418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
219418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  if (input_b == nullptr) {
220418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // We did not find a pattern we can optimize.
221418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    return false;
222418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  }
223418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
224418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  HArm64MultiplyAccumulate* mulacc = new(GetGraph()->GetArena()) HArm64MultiplyAccumulate(
225418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      mul->GetType(), op_kind, input_a, input_a, input_b, mul->GetDexPc());
226418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
227418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  mul->GetBlock()->ReplaceAndRemoveInstructionWith(mul, mulacc);
228418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  input_binop->GetBlock()->RemoveInstruction(input_binop);
229418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
230418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  return false;
231418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames}
232418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
233e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Ramesvoid InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) {
234e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  TryExtractArrayAccessAddress(instruction,
235e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames                               instruction->GetArray(),
236e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames                               instruction->GetIndex(),
237e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames                               Primitive::ComponentSize(instruction->GetType()));
238e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames}
239e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames
240e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Ramesvoid InstructionSimplifierArm64Visitor::VisitArraySet(HArraySet* instruction) {
241e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames  TryExtractArrayAccessAddress(instruction,
242e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames                               instruction->GetArray(),
243e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames                               instruction->GetIndex(),
244e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames                               Primitive::ComponentSize(instruction->GetComponentType()));
245e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames}
246e6dbf48d7a549e58a3d798bbbdc391e4d091b432Alexandre Rames
247418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Ramesvoid InstructionSimplifierArm64Visitor::VisitMul(HMul* instruction) {
248418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  Primitive::Type type = instruction->GetType();
249418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  if (!Primitive::IsIntOrLongType(type)) {
250418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    return;
251418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  }
252418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
253418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  HInstruction* use = instruction->HasNonEnvironmentUses()
254418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      ? instruction->GetUses().GetFirst()->GetUser()
255418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      : nullptr;
256418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
257418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  if (instruction->HasOnlyOneNonEnvironmentUse() && (use->IsAdd() || use->IsSub())) {
258418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // Replace code looking like
259418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    //    MUL tmp, x, y
260418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    //    SUB dst, acc, tmp
261418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // with
262418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    //    MULSUB dst, acc, x, y
263418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // Note that we do not want to (unconditionally) perform the merge when the
264418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // multiplication has multiple uses and it can be merged in all of them.
265418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // Multiple uses could happen on the same control-flow path, and we would
266418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // then increase the amount of work. In the future we could try to evaluate
267418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // whether all uses are on different control-flow paths (using dominance and
268418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // reverse-dominance information) and only perform the merge when they are.
269418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    HInstruction* accumulator = nullptr;
270418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    HBinaryOperation* binop = use->AsBinaryOperation();
271418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    HInstruction* binop_left = binop->GetLeft();
272418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    HInstruction* binop_right = binop->GetRight();
273418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // Be careful after GVN. This should not happen since the `HMul` has only
274418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    // one use.
275418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    DCHECK_NE(binop_left, binop_right);
276418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    if (binop_right == instruction) {
277418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      accumulator = binop_left;
278418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    } else if (use->IsAdd()) {
279418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      DCHECK_EQ(binop_left, instruction);
280418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      accumulator = binop_right;
281418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    }
282418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
283418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    if (accumulator != nullptr) {
284418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      HArm64MultiplyAccumulate* mulacc =
285418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames          new (GetGraph()->GetArena()) HArm64MultiplyAccumulate(type,
286418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames                                                                binop->GetKind(),
287418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames                                                                accumulator,
288418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames                                                                instruction->GetLeft(),
289418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames                                                                instruction->GetRight());
290418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
291418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      binop->GetBlock()->ReplaceAndRemoveInstructionWith(binop, mulacc);
292418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      DCHECK(!instruction->HasUses());
293418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      instruction->GetBlock()->RemoveInstruction(instruction);
294418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      RecordSimplification();
295418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      return;
296418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    }
297418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  }
298418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
299418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  // Use multiply accumulate instruction for a few simple patterns.
300418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  // We prefer not applying the following transformations if the left and
301418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  // right inputs perform the same operation.
302418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  // We rely on GVN having squashed the inputs if appropriate. However the
303418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  // results are still correct even if that did not happen.
304418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  if (instruction->GetLeft() == instruction->GetRight()) {
305418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    return;
306418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  }
307418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
308418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  HInstruction* left = instruction->GetLeft();
309418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  HInstruction* right = instruction->GetRight();
310418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  if ((right->IsAdd() || right->IsSub()) &&
311418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      TrySimpleMultiplyAccumulatePatterns(instruction, right->AsBinaryOperation(), left)) {
312418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    return;
313418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  }
314418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  if ((left->IsAdd() || left->IsSub()) &&
315418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames      TrySimpleMultiplyAccumulatePatterns(instruction, left->AsBinaryOperation(), right)) {
316418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames    return;
317418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames  }
318418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames}
319418318f4d50e0cfc2d54330d7623ee030d4d727dAlexandre Rames
3208626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Ramesvoid InstructionSimplifierArm64Visitor::VisitShl(HShl* instruction) {
3218626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (instruction->InputAt(1)->IsConstant()) {
3228626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    TryMergeIntoUsersShifterOperand(instruction);
3238626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
3248626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames}
3258626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
3268626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Ramesvoid InstructionSimplifierArm64Visitor::VisitShr(HShr* instruction) {
3278626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (instruction->InputAt(1)->IsConstant()) {
3288626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    TryMergeIntoUsersShifterOperand(instruction);
3298626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
3308626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames}
3318626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
3328626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Ramesvoid InstructionSimplifierArm64Visitor::VisitTypeConversion(HTypeConversion* instruction) {
3338626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  Primitive::Type result_type = instruction->GetResultType();
3348626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  Primitive::Type input_type = instruction->GetInputType();
3358626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
3368626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (input_type == result_type) {
3378626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    // We let the arch-independent code handle this.
3388626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    return;
3398626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
3408626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
3418626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
3428626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    TryMergeIntoUsersShifterOperand(instruction);
3438626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
3448626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames}
3458626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
3468626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Ramesvoid InstructionSimplifierArm64Visitor::VisitUShr(HUShr* instruction) {
3478626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  if (instruction->InputAt(1)->IsConstant()) {
3488626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames    TryMergeIntoUsersShifterOperand(instruction);
3498626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames  }
3508626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames}
3518626b741716390a0119ffeb88b5b9fcf08e13010Alexandre Rames
35244b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames}  // namespace arm64
35344b9cf937836bb33139123e15ca8b586b5853268Alexandre Rames}  // namespace art
354