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