1/* 2 * Copyright (C) 2015 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_arm64.h" 18 19#include "common_arm64.h" 20#include "instruction_simplifier_shared.h" 21#include "mirror/array-inl.h" 22#include "mirror/string.h" 23 24namespace art { 25 26using helpers::CanFitInShifterOperand; 27using helpers::HasShifterOperand; 28 29namespace arm64 { 30 31using helpers::ShifterOperandSupportsExtension; 32 33bool InstructionSimplifierArm64Visitor::TryMergeIntoShifterOperand(HInstruction* use, 34 HInstruction* bitfield_op, 35 bool do_merge) { 36 DCHECK(HasShifterOperand(use, kArm64)); 37 DCHECK(use->IsBinaryOperation() || use->IsNeg()); 38 DCHECK(CanFitInShifterOperand(bitfield_op)); 39 DCHECK(!bitfield_op->HasEnvironmentUses()); 40 41 Primitive::Type type = use->GetType(); 42 if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) { 43 return false; 44 } 45 46 HInstruction* left; 47 HInstruction* right; 48 if (use->IsBinaryOperation()) { 49 left = use->InputAt(0); 50 right = use->InputAt(1); 51 } else { 52 DCHECK(use->IsNeg()); 53 right = use->AsNeg()->InputAt(0); 54 left = GetGraph()->GetConstant(right->GetType(), 0); 55 } 56 DCHECK(left == bitfield_op || right == bitfield_op); 57 58 if (left == right) { 59 // TODO: Handle special transformations in this situation? 60 // For example should we transform `(x << 1) + (x << 1)` into `(x << 2)`? 61 // Or should this be part of a separate transformation logic? 62 return false; 63 } 64 65 bool is_commutative = use->IsBinaryOperation() && use->AsBinaryOperation()->IsCommutative(); 66 HInstruction* other_input; 67 if (bitfield_op == right) { 68 other_input = left; 69 } else { 70 if (is_commutative) { 71 other_input = right; 72 } else { 73 return false; 74 } 75 } 76 77 HDataProcWithShifterOp::OpKind op_kind; 78 int shift_amount = 0; 79 HDataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount); 80 81 if (HDataProcWithShifterOp::IsExtensionOp(op_kind) && !ShifterOperandSupportsExtension(use)) { 82 return false; 83 } 84 85 if (do_merge) { 86 HDataProcWithShifterOp* alu_with_op = 87 new (GetGraph()->GetArena()) HDataProcWithShifterOp(use, 88 other_input, 89 bitfield_op->InputAt(0), 90 op_kind, 91 shift_amount, 92 use->GetDexPc()); 93 use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op); 94 if (bitfield_op->GetUses().empty()) { 95 bitfield_op->GetBlock()->RemoveInstruction(bitfield_op); 96 } 97 RecordSimplification(); 98 } 99 100 return true; 101} 102 103// Merge a bitfield move instruction into its uses if it can be merged in all of them. 104bool InstructionSimplifierArm64Visitor::TryMergeIntoUsersShifterOperand(HInstruction* bitfield_op) { 105 DCHECK(CanFitInShifterOperand(bitfield_op)); 106 107 if (bitfield_op->HasEnvironmentUses()) { 108 return false; 109 } 110 111 const HUseList<HInstruction*>& uses = bitfield_op->GetUses(); 112 113 // Check whether we can merge the instruction in all its users' shifter operand. 114 for (const HUseListNode<HInstruction*>& use : uses) { 115 HInstruction* user = use.GetUser(); 116 if (!HasShifterOperand(user, kArm64)) { 117 return false; 118 } 119 if (!CanMergeIntoShifterOperand(user, bitfield_op)) { 120 return false; 121 } 122 } 123 124 // Merge the instruction into its uses. 125 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) { 126 HInstruction* user = it->GetUser(); 127 // Increment `it` now because `*it` will disappear thanks to MergeIntoShifterOperand(). 128 ++it; 129 bool merged = MergeIntoShifterOperand(user, bitfield_op); 130 DCHECK(merged); 131 } 132 133 return true; 134} 135 136void InstructionSimplifierArm64Visitor::VisitAnd(HAnd* instruction) { 137 if (TryMergeNegatedInput(instruction)) { 138 RecordSimplification(); 139 } 140} 141 142void InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) { 143 size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction); 144 if (TryExtractArrayAccessAddress(instruction, 145 instruction->GetArray(), 146 instruction->GetIndex(), 147 data_offset)) { 148 RecordSimplification(); 149 } 150} 151 152void InstructionSimplifierArm64Visitor::VisitArraySet(HArraySet* instruction) { 153 size_t access_size = Primitive::ComponentSize(instruction->GetComponentType()); 154 size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value(); 155 if (TryExtractArrayAccessAddress(instruction, 156 instruction->GetArray(), 157 instruction->GetIndex(), 158 data_offset)) { 159 RecordSimplification(); 160 } 161} 162 163void InstructionSimplifierArm64Visitor::VisitMul(HMul* instruction) { 164 if (TryCombineMultiplyAccumulate(instruction, kArm64)) { 165 RecordSimplification(); 166 } 167} 168 169void InstructionSimplifierArm64Visitor::VisitOr(HOr* instruction) { 170 if (TryMergeNegatedInput(instruction)) { 171 RecordSimplification(); 172 } 173} 174 175void InstructionSimplifierArm64Visitor::VisitShl(HShl* instruction) { 176 if (instruction->InputAt(1)->IsConstant()) { 177 TryMergeIntoUsersShifterOperand(instruction); 178 } 179} 180 181void InstructionSimplifierArm64Visitor::VisitShr(HShr* instruction) { 182 if (instruction->InputAt(1)->IsConstant()) { 183 TryMergeIntoUsersShifterOperand(instruction); 184 } 185} 186 187void InstructionSimplifierArm64Visitor::VisitTypeConversion(HTypeConversion* instruction) { 188 Primitive::Type result_type = instruction->GetResultType(); 189 Primitive::Type input_type = instruction->GetInputType(); 190 191 if (input_type == result_type) { 192 // We let the arch-independent code handle this. 193 return; 194 } 195 196 if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) { 197 TryMergeIntoUsersShifterOperand(instruction); 198 } 199} 200 201void InstructionSimplifierArm64Visitor::VisitUShr(HUShr* instruction) { 202 if (instruction->InputAt(1)->IsConstant()) { 203 TryMergeIntoUsersShifterOperand(instruction); 204 } 205} 206 207void InstructionSimplifierArm64Visitor::VisitXor(HXor* instruction) { 208 if (TryMergeNegatedInput(instruction)) { 209 RecordSimplification(); 210 } 211} 212 213void InstructionSimplifierArm64Visitor::VisitVecMul(HVecMul* instruction) { 214 if (TryCombineVecMultiplyAccumulate(instruction, kArm64)) { 215 RecordSimplification(); 216 } 217} 218 219} // namespace arm64 220} // namespace art 221