buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2012 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 | |
buzbee | 311ca16 | 2013-02-28 15:56:43 -0800 | [diff] [blame] | 17 | #include "local_value_numbering.h" |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 18 | |
Vladimir Marko | be0e546 | 2014-02-26 11:24:15 +0000 | [diff] [blame] | 19 | #include "mir_field_info.h" |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 20 | #include "mir_graph.h" |
| 21 | |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 22 | namespace art { |
| 23 | |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 24 | namespace { // anonymous namespace |
| 25 | |
| 26 | // Operations used for value map keys instead of actual opcode. |
| 27 | static constexpr uint16_t kInvokeMemoryVersionBumpOp = Instruction::INVOKE_DIRECT; |
| 28 | static constexpr uint16_t kUnresolvedSFieldOp = Instruction::SPUT; |
| 29 | static constexpr uint16_t kResolvedSFieldOp = Instruction::SGET; |
| 30 | static constexpr uint16_t kUnresolvedIFieldOp = Instruction::IPUT; |
| 31 | static constexpr uint16_t kNonAliasingIFieldOp = Instruction::IGET; |
| 32 | static constexpr uint16_t kAliasingIFieldOp = Instruction::IGET_WIDE; |
| 33 | static constexpr uint16_t kAliasingIFieldStartVersionOp = Instruction::IGET_WIDE; |
| 34 | static constexpr uint16_t kAliasingIFieldBumpVersionOp = Instruction::IGET_OBJECT; |
| 35 | static constexpr uint16_t kArrayAccessLocOp = Instruction::APUT; |
| 36 | static constexpr uint16_t kNonAliasingArrayOp = Instruction::AGET; |
| 37 | static constexpr uint16_t kNonAliasingArrayStartVersionOp = Instruction::AGET_WIDE; |
| 38 | static constexpr uint16_t kAliasingArrayOp = Instruction::AGET_OBJECT; |
| 39 | static constexpr uint16_t kAliasingArrayMemoryVersionOp = Instruction::AGET_BOOLEAN; |
| 40 | static constexpr uint16_t kAliasingArrayBumpVersionOp = Instruction::AGET_BYTE; |
| 41 | |
| 42 | } // anonymous namespace |
| 43 | |
| 44 | LocalValueNumbering::LocalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator) |
| 45 | : cu_(cu), |
| 46 | last_value_(0u), |
| 47 | sreg_value_map_(std::less<uint16_t>(), allocator->Adapter()), |
| 48 | sreg_wide_value_map_(std::less<uint16_t>(), allocator->Adapter()), |
| 49 | value_map_(std::less<uint64_t>(), allocator->Adapter()), |
| 50 | global_memory_version_(0u), |
| 51 | aliasing_ifield_version_map_(std::less<uint16_t>(), allocator->Adapter()), |
| 52 | non_aliasing_array_version_map_(std::less<uint16_t>(), allocator->Adapter()), |
| 53 | field_index_map_(FieldReferenceComparator(), allocator->Adapter()), |
| 54 | non_aliasing_refs_(std::less<uint16_t>(), allocator->Adapter()), |
| 55 | non_aliasing_ifields_(NonAliasingIFieldKeyComparator(), allocator->Adapter()), |
| 56 | escaped_array_refs_(EscapedArrayKeyComparator(), allocator->Adapter()), |
| 57 | range_checked_(RangeCheckKeyComparator() , allocator->Adapter()), |
| 58 | null_checked_(std::less<uint16_t>(), allocator->Adapter()) { |
| 59 | std::fill_n(unresolved_sfield_version_, kFieldTypeCount, 0u); |
| 60 | std::fill_n(unresolved_ifield_version_, kFieldTypeCount, 0u); |
| 61 | std::fill_n(aliasing_array_version_, kFieldTypeCount, 0u); |
| 62 | } |
| 63 | |
| 64 | uint16_t LocalValueNumbering::GetFieldId(const MirFieldInfo& field_info) { |
| 65 | FieldReference key = { field_info.DeclaringDexFile(), field_info.DeclaringFieldIndex() }; |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 66 | auto it = field_index_map_.find(key); |
| 67 | if (it != field_index_map_.end()) { |
| 68 | return it->second; |
| 69 | } |
| 70 | uint16_t id = field_index_map_.size(); |
| 71 | field_index_map_.Put(key, id); |
| 72 | return id; |
| 73 | } |
| 74 | |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 75 | uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) { |
| 76 | uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]); |
| 77 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 78 | DCHECK(null_checked_.find(res) == null_checked_.end()); |
| 79 | null_checked_.insert(res); |
| 80 | non_aliasing_refs_.insert(res); |
| 81 | return res; |
| 82 | } |
| 83 | |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 84 | bool LocalValueNumbering::IsNonAliasing(uint16_t reg) { |
| 85 | return non_aliasing_refs_.find(reg) != non_aliasing_refs_.end(); |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 86 | } |
| 87 | |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 88 | bool LocalValueNumbering::IsNonAliasingIField(uint16_t reg, uint16_t field_id, uint16_t type) { |
| 89 | if (IsNonAliasing(reg)) { |
| 90 | return true; |
| 91 | } |
| 92 | NonAliasingIFieldKey key = { reg, field_id, type }; |
| 93 | return non_aliasing_ifields_.count(key) != 0u; |
| 94 | } |
| 95 | |
| 96 | bool LocalValueNumbering::IsNonAliasingArray(uint16_t reg, uint16_t type) { |
| 97 | if (IsNonAliasing(reg)) { |
| 98 | return true; |
| 99 | } |
| 100 | EscapedArrayKey key = { reg, type }; |
| 101 | return escaped_array_refs_.count(key) != 0u; |
| 102 | } |
| 103 | |
| 104 | |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 105 | void LocalValueNumbering::HandleNullCheck(MIR* mir, uint16_t reg) { |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 106 | auto lb = null_checked_.lower_bound(reg); |
| 107 | if (lb != null_checked_.end() && *lb == reg) { |
| 108 | if (LIKELY(Good())) { |
| 109 | if (cu_->verbose) { |
| 110 | LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset; |
| 111 | } |
| 112 | mir->optimization_flags |= MIR_IGNORE_NULL_CHECK; |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 113 | } |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 114 | } else { |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 115 | null_checked_.insert(lb, reg); |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 116 | } |
| 117 | } |
| 118 | |
| 119 | void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index) { |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 120 | RangeCheckKey key = { array, index }; |
| 121 | auto lb = range_checked_.lower_bound(key); |
| 122 | if (lb != range_checked_.end() && !RangeCheckKeyComparator()(key, *lb)) { |
| 123 | if (LIKELY(Good())) { |
| 124 | if (cu_->verbose) { |
| 125 | LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset; |
| 126 | } |
| 127 | mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK; |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 128 | } |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 129 | } else { |
| 130 | // Mark range check completed. |
| 131 | range_checked_.insert(lb, key); |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 132 | } |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | void LocalValueNumbering::HandlePutObject(MIR* mir) { |
| 136 | // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now. |
| 137 | uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 138 | HandleEscapingRef(base); |
| 139 | } |
| 140 | |
| 141 | void LocalValueNumbering::HandleEscapingRef(uint16_t base) { |
| 142 | auto it = non_aliasing_refs_.find(base); |
| 143 | if (it != non_aliasing_refs_.end()) { |
| 144 | uint64_t iget_key = BuildKey(Instruction::IGET, base, 0u, 0u); |
| 145 | for (auto iget_it = value_map_.lower_bound(iget_key), iget_end = value_map_.end(); |
| 146 | iget_it != iget_end && EqualOpAndOperand1(iget_it->first, iget_key); ++iget_it) { |
| 147 | uint16_t field_id = ExtractOperand2(iget_it->first); |
| 148 | uint16_t type = ExtractModifier(iget_it->first); |
| 149 | NonAliasingIFieldKey key = { base, field_id, type }; |
| 150 | non_aliasing_ifields_.insert(key); |
| 151 | } |
| 152 | uint64_t aget_key = BuildKey(kNonAliasingArrayStartVersionOp, base, 0u, 0u); |
| 153 | auto aget_it = value_map_.lower_bound(aget_key); |
| 154 | if (aget_it != value_map_.end() && EqualOpAndOperand1(aget_key, aget_it->first)) { |
| 155 | DCHECK_EQ(ExtractOperand2(aget_it->first), kNoValue); |
| 156 | uint16_t type = ExtractModifier(aget_it->first); |
| 157 | EscapedArrayKey key = { base, type }; |
| 158 | escaped_array_refs_.insert(key); |
| 159 | } |
| 160 | non_aliasing_refs_.erase(it); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | uint16_t LocalValueNumbering::HandleAGet(MIR* mir, uint16_t opcode) { |
| 165 | // uint16_t type = opcode - Instruction::AGET; |
| 166 | uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]); |
| 167 | HandleNullCheck(mir, array); |
| 168 | uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]); |
| 169 | HandleRangeCheck(mir, array, index); |
| 170 | uint16_t type = opcode - Instruction::AGET; |
| 171 | // Establish value number for loaded register. |
| 172 | uint16_t res; |
| 173 | if (IsNonAliasingArray(array, type)) { |
| 174 | // Get the start version that accounts for aliasing within the array (different index names). |
| 175 | uint16_t start_version = LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, type); |
| 176 | // Find the current version from the non_aliasing_array_version_map_. |
| 177 | uint16_t memory_version = start_version; |
| 178 | auto it = non_aliasing_array_version_map_.find(start_version); |
| 179 | if (it != non_aliasing_array_version_map_.end()) { |
| 180 | memory_version = it->second; |
| 181 | } else { |
| 182 | // Just use the start_version. |
| 183 | } |
| 184 | res = LookupValue(kNonAliasingArrayOp, array, index, memory_version); |
| 185 | } else { |
| 186 | // Get the memory version of aliased array accesses of this type. |
| 187 | uint16_t memory_version = LookupValue(kAliasingArrayMemoryVersionOp, global_memory_version_, |
| 188 | aliasing_array_version_[type], kNoValue); |
| 189 | res = LookupValue(kAliasingArrayOp, array, index, memory_version); |
| 190 | } |
| 191 | if (opcode == Instruction::AGET_WIDE) { |
| 192 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
| 193 | } else { |
| 194 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 195 | } |
| 196 | return res; |
| 197 | } |
| 198 | |
| 199 | void LocalValueNumbering::HandleAPut(MIR* mir, uint16_t opcode) { |
| 200 | int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1; |
| 201 | int index_idx = array_idx + 1; |
| 202 | uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]); |
| 203 | HandleNullCheck(mir, array); |
| 204 | uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]); |
| 205 | HandleRangeCheck(mir, array, index); |
| 206 | |
| 207 | uint16_t type = opcode - Instruction::APUT; |
| 208 | uint16_t value = (opcode == Instruction::APUT_WIDE) |
| 209 | ? GetOperandValueWide(mir->ssa_rep->uses[0]) |
| 210 | : GetOperandValue(mir->ssa_rep->uses[0]); |
| 211 | if (IsNonAliasing(array)) { |
| 212 | // Get the start version that accounts for aliasing within the array (different index values). |
| 213 | uint16_t start_version = LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, type); |
| 214 | auto it = non_aliasing_array_version_map_.find(start_version); |
| 215 | uint16_t memory_version = start_version; |
| 216 | if (it != non_aliasing_array_version_map_.end()) { |
| 217 | memory_version = it->second; |
| 218 | } |
| 219 | // We need to take 4 values (array, index, memory_version, value) into account for bumping |
| 220 | // the memory version but the key can take only 3. Merge array and index into a location. |
| 221 | uint16_t array_access_location = LookupValue(kArrayAccessLocOp, array, index, kNoValue); |
| 222 | // Bump the version, adding to the chain. |
| 223 | memory_version = LookupValue(kAliasingArrayBumpVersionOp, memory_version, |
| 224 | array_access_location, value); |
| 225 | non_aliasing_array_version_map_.Overwrite(start_version, memory_version); |
| 226 | StoreValue(kNonAliasingArrayOp, array, index, memory_version, value); |
| 227 | } else { |
| 228 | // Get the memory version based on global_memory_version_ and aliasing_array_version_[type]. |
| 229 | uint16_t memory_version = LookupValue(kAliasingArrayMemoryVersionOp, global_memory_version_, |
| 230 | aliasing_array_version_[type], kNoValue); |
| 231 | if (HasValue(kAliasingArrayOp, array, index, memory_version, value)) { |
| 232 | // This APUT can be eliminated, it stores the same value that's already in the field. |
| 233 | // TODO: Eliminate the APUT. |
| 234 | return; |
| 235 | } |
| 236 | // We need to take 4 values (array, index, memory_version, value) into account for bumping |
| 237 | // the memory version but the key can take only 3. Merge array and index into a location. |
| 238 | uint16_t array_access_location = LookupValue(kArrayAccessLocOp, array, index, kNoValue); |
| 239 | // Bump the version, adding to the chain. |
| 240 | uint16_t bumped_version = LookupValue(kAliasingArrayBumpVersionOp, memory_version, |
| 241 | array_access_location, value); |
| 242 | aliasing_array_version_[type] = bumped_version; |
| 243 | memory_version = LookupValue(kAliasingArrayMemoryVersionOp, global_memory_version_, |
| 244 | bumped_version, kNoValue); |
| 245 | StoreValue(kAliasingArrayOp, array, index, memory_version, value); |
| 246 | |
| 247 | // Clear escaped array refs for this type. |
| 248 | EscapedArrayKey array_key = { type, 0u }; |
| 249 | auto it = escaped_array_refs_.lower_bound(array_key), end = escaped_array_refs_.end(); |
| 250 | while (it != end && it->type == type) { |
| 251 | it = escaped_array_refs_.erase(it); |
| 252 | } |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | uint16_t LocalValueNumbering::HandleIGet(MIR* mir, uint16_t opcode) { |
| 257 | uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]); |
| 258 | HandleNullCheck(mir, base); |
| 259 | const MirFieldInfo& field_info = cu_->mir_graph->GetIFieldLoweringInfo(mir); |
| 260 | uint16_t res; |
| 261 | if (!field_info.IsResolved() || field_info.IsVolatile()) { |
| 262 | // Volatile fields always get a new memory version; field id is irrelevant. |
| 263 | // Unresolved fields may be volatile, so handle them as such to be safe. |
| 264 | // Use result s_reg - will be unique. |
| 265 | res = LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue); |
| 266 | } else { |
| 267 | uint16_t type = opcode - Instruction::IGET; |
| 268 | uint16_t field_id = GetFieldId(field_info); |
| 269 | if (IsNonAliasingIField(base, field_id, type)) { |
| 270 | res = LookupValue(kNonAliasingIFieldOp, base, field_id, type); |
| 271 | } else { |
| 272 | // Get the start version that accounts for aliasing with unresolved fields of the same type |
| 273 | // and make it unique for the field by including the field_id. |
| 274 | uint16_t start_version = LookupValue(kAliasingIFieldStartVersionOp, global_memory_version_, |
| 275 | unresolved_ifield_version_[type], field_id); |
| 276 | // Find the current version from the aliasing_ifield_version_map_. |
| 277 | uint16_t memory_version = start_version; |
| 278 | auto version_it = aliasing_ifield_version_map_.find(start_version); |
| 279 | if (version_it != aliasing_ifield_version_map_.end()) { |
| 280 | memory_version = version_it->second; |
| 281 | } else { |
| 282 | // Just use the start_version. |
| 283 | } |
| 284 | res = LookupValue(kAliasingIFieldOp, base, field_id, memory_version); |
| 285 | } |
| 286 | } |
| 287 | if (opcode == Instruction::IGET_WIDE) { |
| 288 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
| 289 | } else { |
| 290 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 291 | } |
| 292 | return res; |
| 293 | } |
| 294 | |
| 295 | void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) { |
| 296 | uint16_t type = opcode - Instruction::IPUT; |
| 297 | int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1; |
| 298 | uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]); |
| 299 | HandleNullCheck(mir, base); |
| 300 | const MirFieldInfo& field_info = cu_->mir_graph->GetIFieldLoweringInfo(mir); |
| 301 | if (!field_info.IsResolved()) { |
| 302 | // Unresolved fields always alias with everything of the same type. |
| 303 | // Use mir->offset as modifier; without elaborate inlining, it will be unique. |
| 304 | unresolved_ifield_version_[type] = |
| 305 | LookupValue(kUnresolvedIFieldOp, kNoValue, kNoValue, mir->offset); |
| 306 | |
| 307 | // Treat fields of escaped references of the same type as potentially modified. |
| 308 | NonAliasingIFieldKey key = { type, 0u, 0u }; // lowest possible key of this type. |
| 309 | auto it = non_aliasing_ifields_.lower_bound(key), end = non_aliasing_ifields_.end(); |
| 310 | while (it != end && it->type == type) { |
| 311 | it = non_aliasing_ifields_.erase(it); |
| 312 | } |
| 313 | } else if (field_info.IsVolatile()) { |
| 314 | // Nothing to do, resolved volatile fields always get a new memory version anyway and |
| 315 | // can't alias with resolved non-volatile fields. |
| 316 | } else { |
| 317 | uint16_t field_id = GetFieldId(field_info); |
| 318 | uint16_t value = (opcode == Instruction::IPUT_WIDE) |
| 319 | ? GetOperandValueWide(mir->ssa_rep->uses[0]) |
| 320 | : GetOperandValue(mir->ssa_rep->uses[0]); |
| 321 | if (IsNonAliasing(base)) { |
| 322 | StoreValue(kNonAliasingIFieldOp, base, field_id, type, value); |
| 323 | } else { |
| 324 | // Get the start version that accounts for aliasing with unresolved fields of the same type |
| 325 | // and make it unique for the field by including the field_id. |
| 326 | uint16_t start_version = LookupValue(kAliasingIFieldStartVersionOp, global_memory_version_, |
| 327 | unresolved_ifield_version_[type], field_id); |
| 328 | // Find the old version from the aliasing_ifield_version_map_. |
| 329 | uint16_t old_version = start_version; |
| 330 | auto version_it = aliasing_ifield_version_map_.find(start_version); |
| 331 | if (version_it != aliasing_ifield_version_map_.end()) { |
| 332 | old_version = version_it->second; |
| 333 | } |
| 334 | // Check if the field currently contains the value, making this a NOP. |
| 335 | if (HasValue(kAliasingIFieldOp, base, field_id, old_version, value)) { |
| 336 | // This IPUT can be eliminated, it stores the same value that's already in the field. |
| 337 | // TODO: Eliminate the IPUT. |
| 338 | return; |
| 339 | } |
| 340 | // Bump the version, adding to the chain started by start_version. |
| 341 | uint16_t memory_version = LookupValue(kAliasingIFieldBumpVersionOp, old_version, base, value); |
| 342 | // Update the aliasing_ifield_version_map_ so that HandleIGet() can get the memory_version |
| 343 | // without knowing the values used to build the chain. |
| 344 | aliasing_ifield_version_map_.Overwrite(start_version, memory_version); |
| 345 | StoreValue(kAliasingIFieldOp, base, field_id, memory_version, value); |
| 346 | |
| 347 | // Clear non-aliasing fields for this field_id. |
| 348 | NonAliasingIFieldKey field_key = { type, field_id, 0u }; |
| 349 | auto it = non_aliasing_ifields_.lower_bound(field_key), end = non_aliasing_ifields_.end(); |
| 350 | while (it != end && it->field_id == field_id) { |
| 351 | DCHECK_EQ(type, it->type); |
| 352 | it = non_aliasing_ifields_.erase(it); |
| 353 | } |
| 354 | } |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) { |
Vladimir Marko | f418f32 | 2014-07-09 14:45:36 +0100 | [diff] [blame^] | 359 | const MirSFieldLoweringInfo& field_info = cu_->mir_graph->GetSFieldLoweringInfo(mir); |
| 360 | if (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) { |
| 361 | // Class initialization can call arbitrary functions, we need to wipe aliasing values. |
| 362 | HandleInvokeOrClInit(mir); |
| 363 | } |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 364 | uint16_t res; |
| 365 | if (!field_info.IsResolved() || field_info.IsVolatile()) { |
| 366 | // Volatile fields always get a new memory version; field id is irrelevant. |
| 367 | // Unresolved fields may be volatile, so handle them as such to be safe. |
| 368 | // Use result s_reg - will be unique. |
| 369 | res = LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue); |
| 370 | } else { |
| 371 | uint16_t field_id = GetFieldId(field_info); |
| 372 | // Resolved non-volatile static fields can alias with non-resolved fields of the same type, |
| 373 | // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_ |
| 374 | // to determine the version of the field. |
| 375 | uint16_t type = opcode - Instruction::SGET; |
| 376 | res = LookupValue(kResolvedSFieldOp, field_id, |
| 377 | unresolved_sfield_version_[type], global_memory_version_); |
| 378 | } |
| 379 | if (opcode == Instruction::SGET_WIDE) { |
| 380 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
| 381 | } else { |
| 382 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 383 | } |
| 384 | return res; |
| 385 | } |
| 386 | |
| 387 | void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) { |
Vladimir Marko | f418f32 | 2014-07-09 14:45:36 +0100 | [diff] [blame^] | 388 | const MirSFieldLoweringInfo& field_info = cu_->mir_graph->GetSFieldLoweringInfo(mir); |
| 389 | if (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) { |
| 390 | // Class initialization can call arbitrary functions, we need to wipe aliasing values. |
| 391 | HandleInvokeOrClInit(mir); |
| 392 | } |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 393 | uint16_t type = opcode - Instruction::SPUT; |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 394 | if (!field_info.IsResolved()) { |
| 395 | // Unresolved fields always alias with everything of the same type. |
| 396 | // Use mir->offset as modifier; without elaborate inlining, it will be unique. |
| 397 | unresolved_sfield_version_[type] = |
| 398 | LookupValue(kUnresolvedSFieldOp, kNoValue, kNoValue, mir->offset); |
| 399 | } else if (field_info.IsVolatile()) { |
| 400 | // Nothing to do, resolved volatile fields always get a new memory version anyway and |
| 401 | // can't alias with resolved non-volatile fields. |
| 402 | } else { |
| 403 | uint16_t field_id = GetFieldId(field_info); |
| 404 | uint16_t value = (opcode == Instruction::SPUT_WIDE) |
| 405 | ? GetOperandValueWide(mir->ssa_rep->uses[0]) |
| 406 | : GetOperandValue(mir->ssa_rep->uses[0]); |
| 407 | // Resolved non-volatile static fields can alias with non-resolved fields of the same type, |
| 408 | // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_ |
| 409 | // to determine the version of the field. |
| 410 | uint16_t type = opcode - Instruction::SGET; |
| 411 | StoreValue(kResolvedSFieldOp, field_id, |
| 412 | unresolved_sfield_version_[type], global_memory_version_, value); |
| 413 | } |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 414 | } |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 415 | |
Vladimir Marko | f418f32 | 2014-07-09 14:45:36 +0100 | [diff] [blame^] | 416 | void LocalValueNumbering::HandleInvokeOrClInit(MIR* mir) { |
| 417 | // Use mir->offset as modifier; without elaborate inlining, it will be unique. |
| 418 | global_memory_version_ = LookupValue(kInvokeMemoryVersionBumpOp, 0u, 0u, mir->offset); |
| 419 | // All fields of escaped references need to be treated as potentially modified. |
| 420 | non_aliasing_ifields_.clear(); |
| 421 | // Array elements may also have been modified via escaped array refs. |
| 422 | escaped_array_refs_.clear(); |
| 423 | } |
| 424 | |
Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 425 | uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) { |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 426 | uint16_t res = kNoValue; |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 427 | uint16_t opcode = mir->dalvikInsn.opcode; |
| 428 | switch (opcode) { |
| 429 | case Instruction::NOP: |
| 430 | case Instruction::RETURN_VOID: |
| 431 | case Instruction::RETURN: |
| 432 | case Instruction::RETURN_OBJECT: |
| 433 | case Instruction::RETURN_WIDE: |
| 434 | case Instruction::MONITOR_ENTER: |
| 435 | case Instruction::MONITOR_EXIT: |
| 436 | case Instruction::GOTO: |
| 437 | case Instruction::GOTO_16: |
| 438 | case Instruction::GOTO_32: |
| 439 | case Instruction::CHECK_CAST: |
| 440 | case Instruction::THROW: |
| 441 | case Instruction::FILL_ARRAY_DATA: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 442 | case Instruction::PACKED_SWITCH: |
| 443 | case Instruction::SPARSE_SWITCH: |
| 444 | case Instruction::IF_EQ: |
| 445 | case Instruction::IF_NE: |
| 446 | case Instruction::IF_LT: |
| 447 | case Instruction::IF_GE: |
| 448 | case Instruction::IF_GT: |
| 449 | case Instruction::IF_LE: |
| 450 | case Instruction::IF_EQZ: |
| 451 | case Instruction::IF_NEZ: |
| 452 | case Instruction::IF_LTZ: |
| 453 | case Instruction::IF_GEZ: |
| 454 | case Instruction::IF_GTZ: |
| 455 | case Instruction::IF_LEZ: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 456 | case kMirOpFusedCmplFloat: |
| 457 | case kMirOpFusedCmpgFloat: |
| 458 | case kMirOpFusedCmplDouble: |
| 459 | case kMirOpFusedCmpgDouble: |
| 460 | case kMirOpFusedCmpLong: |
| 461 | // Nothing defined - take no action. |
| 462 | break; |
| 463 | |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 464 | case Instruction::FILLED_NEW_ARRAY: |
| 465 | case Instruction::FILLED_NEW_ARRAY_RANGE: |
| 466 | // Nothing defined but the result will be unique and non-null. |
| 467 | if (mir->next != nullptr && mir->next->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { |
| 468 | MarkNonAliasingNonNull(mir->next); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 469 | // TUNING: We could track value names stored in the array. |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 470 | // The MOVE_RESULT_OBJECT will be processed next and we'll return the value name then. |
| 471 | } |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 472 | // All args escaped (if references). |
| 473 | for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) { |
| 474 | uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]); |
| 475 | HandleEscapingRef(reg); |
| 476 | } |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 477 | break; |
| 478 | |
| 479 | case Instruction::INVOKE_DIRECT: |
| 480 | case Instruction::INVOKE_DIRECT_RANGE: |
| 481 | case Instruction::INVOKE_VIRTUAL: |
| 482 | case Instruction::INVOKE_VIRTUAL_RANGE: |
| 483 | case Instruction::INVOKE_SUPER: |
| 484 | case Instruction::INVOKE_SUPER_RANGE: |
| 485 | case Instruction::INVOKE_INTERFACE: |
| 486 | case Instruction::INVOKE_INTERFACE_RANGE: { |
| 487 | // Nothing defined but handle the null check. |
| 488 | uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]); |
| 489 | HandleNullCheck(mir, reg); |
| 490 | } |
| 491 | // Intentional fall-through. |
| 492 | case Instruction::INVOKE_STATIC: |
| 493 | case Instruction::INVOKE_STATIC_RANGE: |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 494 | if ((mir->optimization_flags & MIR_INLINED) == 0) { |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 495 | // Make ref args aliasing. |
| 496 | for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) { |
| 497 | uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]); |
| 498 | non_aliasing_refs_.erase(reg); |
| 499 | } |
Vladimir Marko | f418f32 | 2014-07-09 14:45:36 +0100 | [diff] [blame^] | 500 | HandleInvokeOrClInit(mir); |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 501 | } |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 502 | break; |
| 503 | |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 504 | case Instruction::MOVE_RESULT: |
| 505 | case Instruction::MOVE_RESULT_OBJECT: |
| 506 | case Instruction::INSTANCE_OF: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 507 | // 1 result, treat as unique each time, use result s_reg - will be unique. |
| 508 | res = GetOperandValue(mir->ssa_rep->defs[0]); |
| 509 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 510 | break; |
| 511 | case Instruction::MOVE_EXCEPTION: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 512 | case Instruction::NEW_INSTANCE: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 513 | case Instruction::CONST_CLASS: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 514 | case Instruction::NEW_ARRAY: |
Vladimir Marko | b3e527b | 2014-04-04 12:37:07 +0100 | [diff] [blame] | 515 | // 1 result, treat as unique each time, use result s_reg - will be unique. |
| 516 | res = MarkNonAliasingNonNull(mir); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 517 | break; |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 518 | case Instruction::CONST_STRING: |
| 519 | case Instruction::CONST_STRING_JUMBO: |
| 520 | // These strings are internalized, so assign value based on the string pool index. |
| 521 | res = LookupValue(Instruction::CONST_STRING, Low16Bits(mir->dalvikInsn.vB), |
| 522 | High16Bits(mir->dalvikInsn.vB), 0); |
| 523 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 524 | null_checked_.insert(res); // May already be there. |
| 525 | // NOTE: Hacking the contents of an internalized string via reflection is possible |
| 526 | // but the behavior is undefined. Therefore, we consider the string constant and |
| 527 | // the reference non-aliasing. |
| 528 | // TUNING: We could keep this property even if the reference "escapes". |
| 529 | non_aliasing_refs_.insert(res); // May already be there. |
| 530 | break; |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 531 | case Instruction::MOVE_RESULT_WIDE: |
Vladimir Marko | b3e527b | 2014-04-04 12:37:07 +0100 | [diff] [blame] | 532 | // 1 wide result, treat as unique each time, use result s_reg - will be unique. |
| 533 | res = GetOperandValueWide(mir->ssa_rep->defs[0]); |
| 534 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 535 | break; |
| 536 | |
| 537 | case kMirOpPhi: |
| 538 | /* |
| 539 | * Because we'll only see phi nodes at the beginning of an extended basic block, |
| 540 | * we can ignore them. Revisit if we shift to global value numbering. |
| 541 | */ |
| 542 | break; |
| 543 | |
| 544 | case Instruction::MOVE: |
| 545 | case Instruction::MOVE_OBJECT: |
| 546 | case Instruction::MOVE_16: |
| 547 | case Instruction::MOVE_OBJECT_16: |
| 548 | case Instruction::MOVE_FROM16: |
| 549 | case Instruction::MOVE_OBJECT_FROM16: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 550 | case kMirOpCopy: |
| 551 | // Just copy value number of source to value number of result. |
| 552 | res = GetOperandValue(mir->ssa_rep->uses[0]); |
| 553 | SetOperandValue(mir->ssa_rep->defs[0], res); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 554 | break; |
| 555 | |
| 556 | case Instruction::MOVE_WIDE: |
| 557 | case Instruction::MOVE_WIDE_16: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 558 | case Instruction::MOVE_WIDE_FROM16: |
| 559 | // Just copy value number of source to value number of result. |
| 560 | res = GetOperandValueWide(mir->ssa_rep->uses[0]); |
| 561 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 562 | break; |
| 563 | |
| 564 | case Instruction::CONST: |
| 565 | case Instruction::CONST_4: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 566 | case Instruction::CONST_16: |
| 567 | res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB), |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 568 | High16Bits(mir->dalvikInsn.vB), 0); |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 569 | SetOperandValue(mir->ssa_rep->defs[0], res); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 570 | break; |
| 571 | |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 572 | case Instruction::CONST_HIGH16: |
| 573 | res = LookupValue(Instruction::CONST, 0, mir->dalvikInsn.vB, 0); |
| 574 | SetOperandValue(mir->ssa_rep->defs[0], res); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 575 | break; |
| 576 | |
| 577 | case Instruction::CONST_WIDE_16: |
| 578 | case Instruction::CONST_WIDE_32: { |
| 579 | uint16_t low_res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB), |
| 580 | High16Bits(mir->dalvikInsn.vB >> 16), 1); |
| 581 | uint16_t high_res; |
| 582 | if (mir->dalvikInsn.vB & 0x80000000) { |
| 583 | high_res = LookupValue(Instruction::CONST, 0xffff, 0xffff, 2); |
| 584 | } else { |
| 585 | high_res = LookupValue(Instruction::CONST, 0, 0, 2); |
| 586 | } |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 587 | res = LookupValue(Instruction::CONST, low_res, high_res, 3); |
| 588 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 589 | } |
| 590 | break; |
| 591 | |
| 592 | case Instruction::CONST_WIDE: { |
| 593 | uint32_t low_word = Low32Bits(mir->dalvikInsn.vB_wide); |
| 594 | uint32_t high_word = High32Bits(mir->dalvikInsn.vB_wide); |
| 595 | uint16_t low_res = LookupValue(Instruction::CONST, Low16Bits(low_word), |
| 596 | High16Bits(low_word), 1); |
| 597 | uint16_t high_res = LookupValue(Instruction::CONST, Low16Bits(high_word), |
| 598 | High16Bits(high_word), 2); |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 599 | res = LookupValue(Instruction::CONST, low_res, high_res, 3); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 600 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
| 601 | } |
| 602 | break; |
| 603 | |
| 604 | case Instruction::CONST_WIDE_HIGH16: { |
| 605 | uint16_t low_res = LookupValue(Instruction::CONST, 0, 0, 1); |
| 606 | uint16_t high_res = LookupValue(Instruction::CONST, 0, Low16Bits(mir->dalvikInsn.vB), 2); |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 607 | res = LookupValue(Instruction::CONST, low_res, high_res, 3); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 608 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
| 609 | } |
| 610 | break; |
| 611 | |
| 612 | case Instruction::ARRAY_LENGTH: |
| 613 | case Instruction::NEG_INT: |
| 614 | case Instruction::NOT_INT: |
| 615 | case Instruction::NEG_FLOAT: |
| 616 | case Instruction::INT_TO_BYTE: |
| 617 | case Instruction::INT_TO_SHORT: |
| 618 | case Instruction::INT_TO_CHAR: |
| 619 | case Instruction::INT_TO_FLOAT: |
| 620 | case Instruction::FLOAT_TO_INT: { |
| 621 | // res = op + 1 operand |
| 622 | uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 623 | res = LookupValue(opcode, operand1, kNoValue, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 624 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 625 | } |
| 626 | break; |
| 627 | |
| 628 | case Instruction::LONG_TO_FLOAT: |
| 629 | case Instruction::LONG_TO_INT: |
| 630 | case Instruction::DOUBLE_TO_FLOAT: |
| 631 | case Instruction::DOUBLE_TO_INT: { |
| 632 | // res = op + 1 wide operand |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 633 | uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]); |
| 634 | res = LookupValue(opcode, operand1, kNoValue, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 635 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 636 | } |
| 637 | break; |
| 638 | |
| 639 | |
| 640 | case Instruction::DOUBLE_TO_LONG: |
| 641 | case Instruction::LONG_TO_DOUBLE: |
| 642 | case Instruction::NEG_LONG: |
| 643 | case Instruction::NOT_LONG: |
| 644 | case Instruction::NEG_DOUBLE: { |
| 645 | // wide res = op + 1 wide operand |
| 646 | uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 647 | res = LookupValue(opcode, operand1, kNoValue, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 648 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
| 649 | } |
| 650 | break; |
| 651 | |
| 652 | case Instruction::FLOAT_TO_DOUBLE: |
| 653 | case Instruction::FLOAT_TO_LONG: |
| 654 | case Instruction::INT_TO_DOUBLE: |
| 655 | case Instruction::INT_TO_LONG: { |
| 656 | // wide res = op + 1 operand |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 657 | uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]); |
| 658 | res = LookupValue(opcode, operand1, kNoValue, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 659 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
| 660 | } |
| 661 | break; |
| 662 | |
| 663 | case Instruction::CMPL_DOUBLE: |
| 664 | case Instruction::CMPG_DOUBLE: |
| 665 | case Instruction::CMP_LONG: { |
| 666 | // res = op + 2 wide operands |
| 667 | uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]); |
| 668 | uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 669 | res = LookupValue(opcode, operand1, operand2, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 670 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 671 | } |
| 672 | break; |
| 673 | |
| 674 | case Instruction::CMPG_FLOAT: |
| 675 | case Instruction::CMPL_FLOAT: |
| 676 | case Instruction::ADD_INT: |
| 677 | case Instruction::ADD_INT_2ADDR: |
| 678 | case Instruction::MUL_INT: |
| 679 | case Instruction::MUL_INT_2ADDR: |
| 680 | case Instruction::AND_INT: |
| 681 | case Instruction::AND_INT_2ADDR: |
| 682 | case Instruction::OR_INT: |
| 683 | case Instruction::OR_INT_2ADDR: |
| 684 | case Instruction::XOR_INT: |
| 685 | case Instruction::XOR_INT_2ADDR: |
| 686 | case Instruction::SUB_INT: |
| 687 | case Instruction::SUB_INT_2ADDR: |
| 688 | case Instruction::DIV_INT: |
| 689 | case Instruction::DIV_INT_2ADDR: |
| 690 | case Instruction::REM_INT: |
| 691 | case Instruction::REM_INT_2ADDR: |
| 692 | case Instruction::SHL_INT: |
| 693 | case Instruction::SHL_INT_2ADDR: |
| 694 | case Instruction::SHR_INT: |
| 695 | case Instruction::SHR_INT_2ADDR: |
| 696 | case Instruction::USHR_INT: |
| 697 | case Instruction::USHR_INT_2ADDR: { |
| 698 | // res = op + 2 operands |
| 699 | uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]); |
| 700 | uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 701 | res = LookupValue(opcode, operand1, operand2, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 702 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 703 | } |
| 704 | break; |
| 705 | |
| 706 | case Instruction::ADD_LONG: |
| 707 | case Instruction::SUB_LONG: |
| 708 | case Instruction::MUL_LONG: |
| 709 | case Instruction::DIV_LONG: |
| 710 | case Instruction::REM_LONG: |
| 711 | case Instruction::AND_LONG: |
| 712 | case Instruction::OR_LONG: |
| 713 | case Instruction::XOR_LONG: |
| 714 | case Instruction::ADD_LONG_2ADDR: |
| 715 | case Instruction::SUB_LONG_2ADDR: |
| 716 | case Instruction::MUL_LONG_2ADDR: |
| 717 | case Instruction::DIV_LONG_2ADDR: |
| 718 | case Instruction::REM_LONG_2ADDR: |
| 719 | case Instruction::AND_LONG_2ADDR: |
| 720 | case Instruction::OR_LONG_2ADDR: |
| 721 | case Instruction::XOR_LONG_2ADDR: |
| 722 | case Instruction::ADD_DOUBLE: |
| 723 | case Instruction::SUB_DOUBLE: |
| 724 | case Instruction::MUL_DOUBLE: |
| 725 | case Instruction::DIV_DOUBLE: |
| 726 | case Instruction::REM_DOUBLE: |
| 727 | case Instruction::ADD_DOUBLE_2ADDR: |
| 728 | case Instruction::SUB_DOUBLE_2ADDR: |
| 729 | case Instruction::MUL_DOUBLE_2ADDR: |
| 730 | case Instruction::DIV_DOUBLE_2ADDR: |
| 731 | case Instruction::REM_DOUBLE_2ADDR: { |
| 732 | // wide res = op + 2 wide operands |
| 733 | uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]); |
| 734 | uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 735 | res = LookupValue(opcode, operand1, operand2, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 736 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
| 737 | } |
| 738 | break; |
| 739 | |
| 740 | case Instruction::SHL_LONG: |
| 741 | case Instruction::SHR_LONG: |
| 742 | case Instruction::USHR_LONG: |
| 743 | case Instruction::SHL_LONG_2ADDR: |
| 744 | case Instruction::SHR_LONG_2ADDR: |
| 745 | case Instruction::USHR_LONG_2ADDR: { |
| 746 | // wide res = op + 1 wide operand + 1 operand |
| 747 | uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 748 | uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[2]); |
| 749 | res = LookupValue(opcode, operand1, operand2, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 750 | SetOperandValueWide(mir->ssa_rep->defs[0], res); |
| 751 | } |
| 752 | break; |
| 753 | |
| 754 | case Instruction::ADD_FLOAT: |
| 755 | case Instruction::SUB_FLOAT: |
| 756 | case Instruction::MUL_FLOAT: |
| 757 | case Instruction::DIV_FLOAT: |
| 758 | case Instruction::REM_FLOAT: |
| 759 | case Instruction::ADD_FLOAT_2ADDR: |
| 760 | case Instruction::SUB_FLOAT_2ADDR: |
| 761 | case Instruction::MUL_FLOAT_2ADDR: |
| 762 | case Instruction::DIV_FLOAT_2ADDR: |
| 763 | case Instruction::REM_FLOAT_2ADDR: { |
| 764 | // res = op + 2 operands |
| 765 | uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]); |
| 766 | uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 767 | res = LookupValue(opcode, operand1, operand2, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 768 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 769 | } |
| 770 | break; |
| 771 | |
| 772 | case Instruction::RSUB_INT: |
| 773 | case Instruction::ADD_INT_LIT16: |
| 774 | case Instruction::MUL_INT_LIT16: |
| 775 | case Instruction::DIV_INT_LIT16: |
| 776 | case Instruction::REM_INT_LIT16: |
| 777 | case Instruction::AND_INT_LIT16: |
| 778 | case Instruction::OR_INT_LIT16: |
| 779 | case Instruction::XOR_INT_LIT16: |
| 780 | case Instruction::ADD_INT_LIT8: |
| 781 | case Instruction::RSUB_INT_LIT8: |
| 782 | case Instruction::MUL_INT_LIT8: |
| 783 | case Instruction::DIV_INT_LIT8: |
| 784 | case Instruction::REM_INT_LIT8: |
| 785 | case Instruction::AND_INT_LIT8: |
| 786 | case Instruction::OR_INT_LIT8: |
| 787 | case Instruction::XOR_INT_LIT8: |
| 788 | case Instruction::SHL_INT_LIT8: |
| 789 | case Instruction::SHR_INT_LIT8: |
| 790 | case Instruction::USHR_INT_LIT8: { |
nikolay serdjuk | ee40aa4 | 2014-03-25 12:21:29 +0700 | [diff] [blame] | 791 | // Same as res = op + 2 operands, except use vC as operand 2 |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 792 | uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]); |
nikolay serdjuk | ee40aa4 | 2014-03-25 12:21:29 +0700 | [diff] [blame] | 793 | uint16_t operand2 = LookupValue(Instruction::CONST, mir->dalvikInsn.vC, 0, 0); |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 794 | res = LookupValue(opcode, operand1, operand2, kNoValue); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 795 | SetOperandValue(mir->ssa_rep->defs[0], res); |
| 796 | } |
| 797 | break; |
| 798 | |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 799 | case Instruction::AGET_OBJECT: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 800 | case Instruction::AGET: |
| 801 | case Instruction::AGET_WIDE: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 802 | case Instruction::AGET_BOOLEAN: |
| 803 | case Instruction::AGET_BYTE: |
| 804 | case Instruction::AGET_CHAR: |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 805 | case Instruction::AGET_SHORT: |
| 806 | res = HandleAGet(mir, opcode); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 807 | break; |
| 808 | |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 809 | case Instruction::APUT_OBJECT: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 810 | HandlePutObject(mir); |
| 811 | // Intentional fall-through. |
| 812 | case Instruction::APUT: |
| 813 | case Instruction::APUT_WIDE: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 814 | case Instruction::APUT_BYTE: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 815 | case Instruction::APUT_BOOLEAN: |
| 816 | case Instruction::APUT_SHORT: |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 817 | case Instruction::APUT_CHAR: |
| 818 | HandleAPut(mir, opcode); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 819 | break; |
| 820 | |
| 821 | case Instruction::IGET_OBJECT: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 822 | case Instruction::IGET: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 823 | case Instruction::IGET_WIDE: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 824 | case Instruction::IGET_BOOLEAN: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 825 | case Instruction::IGET_BYTE: |
| 826 | case Instruction::IGET_CHAR: |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 827 | case Instruction::IGET_SHORT: |
| 828 | res = HandleIGet(mir, opcode); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 829 | break; |
| 830 | |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 831 | case Instruction::IPUT_OBJECT: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 832 | HandlePutObject(mir); |
| 833 | // Intentional fall-through. |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 834 | case Instruction::IPUT: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 835 | case Instruction::IPUT_WIDE: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 836 | case Instruction::IPUT_BOOLEAN: |
| 837 | case Instruction::IPUT_BYTE: |
| 838 | case Instruction::IPUT_CHAR: |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 839 | case Instruction::IPUT_SHORT: |
| 840 | HandleIPut(mir, opcode); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 841 | break; |
| 842 | |
| 843 | case Instruction::SGET_OBJECT: |
| 844 | case Instruction::SGET: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 845 | case Instruction::SGET_WIDE: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 846 | case Instruction::SGET_BOOLEAN: |
| 847 | case Instruction::SGET_BYTE: |
| 848 | case Instruction::SGET_CHAR: |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 849 | case Instruction::SGET_SHORT: |
| 850 | res = HandleSGet(mir, opcode); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 851 | break; |
| 852 | |
| 853 | case Instruction::SPUT_OBJECT: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 854 | HandlePutObject(mir); |
| 855 | // Intentional fall-through. |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 856 | case Instruction::SPUT: |
Vladimir Marko | f59f18b | 2014-02-17 15:53:57 +0000 | [diff] [blame] | 857 | case Instruction::SPUT_WIDE: |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 858 | case Instruction::SPUT_BOOLEAN: |
| 859 | case Instruction::SPUT_BYTE: |
| 860 | case Instruction::SPUT_CHAR: |
Vladimir Marko | 2ac01fc | 2014-05-22 12:09:08 +0100 | [diff] [blame] | 861 | case Instruction::SPUT_SHORT: |
| 862 | HandleSPut(mir, opcode); |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 863 | break; |
buzbee | 2502e00 | 2012-12-31 16:05:53 -0800 | [diff] [blame] | 864 | } |
| 865 | return res; |
| 866 | } |
| 867 | |
| 868 | } // namespace art |