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 "code_generator.h" 18 #include "common_arm.h" 19 #include "instruction_simplifier_arm.h" 20 #include "instruction_simplifier_shared.h" 21 #include "mirror/array-inl.h" 22 #include "mirror/string.h" 23 #include "nodes.h" 24 25 namespace art { 26 27 using helpers::CanFitInShifterOperand; 28 using helpers::HasShifterOperand; 29 30 namespace arm { 31 32 using helpers::ShifterOperandSupportsExtension; 33 34 bool InstructionSimplifierArmVisitor::TryMergeIntoShifterOperand(HInstruction* use, 35 HInstruction* bitfield_op, 36 bool do_merge) { 37 DCHECK(HasShifterOperand(use, kArm)); 38 DCHECK(use->IsBinaryOperation()); 39 DCHECK(CanFitInShifterOperand(bitfield_op)); 40 DCHECK(!bitfield_op->HasEnvironmentUses()); 41 42 Primitive::Type type = use->GetType(); 43 if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) { 44 return false; 45 } 46 47 HInstruction* left = use->InputAt(0); 48 HInstruction* right = use->InputAt(1); 49 DCHECK(left == bitfield_op || right == bitfield_op); 50 51 if (left == right) { 52 // TODO: Handle special transformations in this situation? 53 // For example should we transform `(x << 1) + (x << 1)` into `(x << 2)`? 54 // Or should this be part of a separate transformation logic? 55 return false; 56 } 57 58 bool is_commutative = use->AsBinaryOperation()->IsCommutative(); 59 HInstruction* other_input; 60 if (bitfield_op == right) { 61 other_input = left; 62 } else { 63 if (is_commutative) { 64 other_input = right; 65 } else { 66 return false; 67 } 68 } 69 70 HDataProcWithShifterOp::OpKind op_kind; 71 int shift_amount = 0; 72 73 HDataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount); 74 shift_amount &= use->GetType() == Primitive::kPrimInt 75 ? kMaxIntShiftDistance 76 : kMaxLongShiftDistance; 77 78 if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) { 79 if (!ShifterOperandSupportsExtension(use)) { 80 return false; 81 } 82 // Shift by 1 is a special case that results in the same number and type of instructions 83 // as this simplification, but potentially shorter code. 84 } else if (type == Primitive::kPrimLong && shift_amount == 1) { 85 return false; 86 } 87 88 if (do_merge) { 89 HDataProcWithShifterOp* alu_with_op = 90 new (GetGraph()->GetArena()) HDataProcWithShifterOp(use, 91 other_input, 92 bitfield_op->InputAt(0), 93 op_kind, 94 shift_amount, 95 use->GetDexPc()); 96 use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op); 97 if (bitfield_op->GetUses().empty()) { 98 bitfield_op->GetBlock()->RemoveInstruction(bitfield_op); 99 } 100 RecordSimplification(); 101 } 102 103 return true; 104 } 105 106 // Merge a bitfield move instruction into its uses if it can be merged in all of them. 107 bool InstructionSimplifierArmVisitor::TryMergeIntoUsersShifterOperand(HInstruction* bitfield_op) { 108 DCHECK(CanFitInShifterOperand(bitfield_op)); 109 110 if (bitfield_op->HasEnvironmentUses()) { 111 return false; 112 } 113 114 const HUseList<HInstruction*>& uses = bitfield_op->GetUses(); 115 116 // Check whether we can merge the instruction in all its users' shifter operand. 117 for (const HUseListNode<HInstruction*>& use : uses) { 118 HInstruction* user = use.GetUser(); 119 if (!HasShifterOperand(user, kArm)) { 120 return false; 121 } 122 if (!CanMergeIntoShifterOperand(user, bitfield_op)) { 123 return false; 124 } 125 } 126 127 // Merge the instruction into its uses. 128 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) { 129 HInstruction* user = it->GetUser(); 130 // Increment `it` now because `*it` will disappear thanks to MergeIntoShifterOperand(). 131 ++it; 132 bool merged = MergeIntoShifterOperand(user, bitfield_op); 133 DCHECK(merged); 134 } 135 136 return true; 137 } 138 139 void InstructionSimplifierArmVisitor::VisitAnd(HAnd* instruction) { 140 if (TryMergeNegatedInput(instruction)) { 141 RecordSimplification(); 142 } 143 } 144 145 void InstructionSimplifierArmVisitor::VisitArrayGet(HArrayGet* instruction) { 146 size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction); 147 Primitive::Type type = instruction->GetType(); 148 149 // TODO: Implement reading (length + compression) for String compression feature from 150 // negative offset (count_offset - data_offset). Thumb2Assembler does not support T4 151 // encoding of "LDR (immediate)" at the moment. 152 // Don't move array pointer if it is charAt because we need to take the count first. 153 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) { 154 return; 155 } 156 157 if (type == Primitive::kPrimLong 158 || type == Primitive::kPrimFloat 159 || type == Primitive::kPrimDouble) { 160 // T32 doesn't support ShiftedRegOffset mem address mode for these types 161 // to enable optimization. 162 return; 163 } 164 165 if (TryExtractArrayAccessAddress(instruction, 166 instruction->GetArray(), 167 instruction->GetIndex(), 168 data_offset)) { 169 RecordSimplification(); 170 } 171 } 172 173 void InstructionSimplifierArmVisitor::VisitArraySet(HArraySet* instruction) { 174 size_t access_size = Primitive::ComponentSize(instruction->GetComponentType()); 175 size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value(); 176 Primitive::Type type = instruction->GetComponentType(); 177 178 if (type == Primitive::kPrimLong 179 || type == Primitive::kPrimFloat 180 || type == Primitive::kPrimDouble) { 181 // T32 doesn't support ShiftedRegOffset mem address mode for these types 182 // to enable optimization. 183 return; 184 } 185 186 if (TryExtractArrayAccessAddress(instruction, 187 instruction->GetArray(), 188 instruction->GetIndex(), 189 data_offset)) { 190 RecordSimplification(); 191 } 192 } 193 194 void InstructionSimplifierArmVisitor::VisitMul(HMul* instruction) { 195 if (TryCombineMultiplyAccumulate(instruction, kArm)) { 196 RecordSimplification(); 197 } 198 } 199 200 void InstructionSimplifierArmVisitor::VisitOr(HOr* instruction) { 201 if (TryMergeNegatedInput(instruction)) { 202 RecordSimplification(); 203 } 204 } 205 206 void InstructionSimplifierArmVisitor::VisitShl(HShl* instruction) { 207 if (instruction->InputAt(1)->IsConstant()) { 208 TryMergeIntoUsersShifterOperand(instruction); 209 } 210 } 211 212 void InstructionSimplifierArmVisitor::VisitShr(HShr* instruction) { 213 if (instruction->InputAt(1)->IsConstant()) { 214 TryMergeIntoUsersShifterOperand(instruction); 215 } 216 } 217 218 void InstructionSimplifierArmVisitor::VisitTypeConversion(HTypeConversion* instruction) { 219 Primitive::Type result_type = instruction->GetResultType(); 220 Primitive::Type input_type = instruction->GetInputType(); 221 222 if (input_type == result_type) { 223 // We let the arch-independent code handle this. 224 return; 225 } 226 227 if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) { 228 TryMergeIntoUsersShifterOperand(instruction); 229 } 230 } 231 232 void InstructionSimplifierArmVisitor::VisitUShr(HUShr* instruction) { 233 if (instruction->InputAt(1)->IsConstant()) { 234 TryMergeIntoUsersShifterOperand(instruction); 235 } 236 } 237 238 } // namespace arm 239 } // namespace art 240