Shalini Salomi Bodapati | dd121f6 | 2018-10-26 15:03:53 +0530 | [diff] [blame] | 1 | /* Copyright (C) 2018 The Android Open Source Project |
| 2 | * |
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | * you may not use this file except in compliance with the License. |
| 5 | * You may obtain a copy of the License at |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software |
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | * See the License for the specific language governing permissions and |
| 13 | * limitations under the License. |
| 14 | */ |
| 15 | |
| 16 | #include "instruction_simplifier_x86_shared.h" |
| 17 | #include "nodes_x86.h" |
| 18 | |
Vladimir Marko | 0a51605 | 2019-10-14 13:00:44 +0000 | [diff] [blame] | 19 | namespace art { |
Shalini Salomi Bodapati | dd121f6 | 2018-10-26 15:03:53 +0530 | [diff] [blame] | 20 | |
| 21 | bool TryCombineAndNot(HAnd* instruction) { |
| 22 | DataType::Type type = instruction->GetType(); |
| 23 | if (!DataType::IsIntOrLongType(type)) { |
| 24 | return false; |
| 25 | } |
| 26 | // Replace code looking like |
| 27 | // Not tmp, y |
| 28 | // And dst, x, tmp |
| 29 | // with |
| 30 | // AndNot dst, x, y |
| 31 | HInstruction* left = instruction->GetLeft(); |
| 32 | HInstruction* right = instruction->GetRight(); |
| 33 | // Perform simplication only when either left or right |
| 34 | // is Not. When both are Not, instruction should be simplified with |
| 35 | // DeMorgan's Laws. |
| 36 | if (left->IsNot() ^ right->IsNot()) { |
| 37 | bool left_is_not = left->IsNot(); |
| 38 | HInstruction* other_ins = (left_is_not ? right : left); |
| 39 | HNot* not_ins = (left_is_not ? left : right)->AsNot(); |
| 40 | // Only do the simplification if instruction has only one use |
| 41 | // and thus can be safely removed. |
| 42 | if (not_ins->HasOnlyOneNonEnvironmentUse()) { |
| 43 | ArenaAllocator* arena = instruction->GetBlock()->GetGraph()->GetAllocator(); |
| 44 | HX86AndNot* and_not = new (arena) HX86AndNot(type, |
| 45 | not_ins->GetInput(), |
| 46 | other_ins, |
| 47 | instruction->GetDexPc()); |
| 48 | instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, and_not); |
| 49 | DCHECK(!not_ins->HasUses()); |
| 50 | not_ins->GetBlock()->RemoveInstruction(not_ins); |
| 51 | return true; |
| 52 | } |
| 53 | } |
| 54 | return false; |
| 55 | } |
| 56 | |
| 57 | bool TryGenerateResetLeastSetBit(HAnd* instruction) { |
| 58 | DataType::Type type = instruction->GetType(); |
| 59 | if (!DataType::IsIntOrLongType(type)) { |
| 60 | return false; |
| 61 | } |
| 62 | // Replace code looking like |
| 63 | // Add tmp, x, -1 or Sub tmp, x, 1 |
| 64 | // And dest x, tmp |
| 65 | // with |
| 66 | // MaskOrResetLeastSetBit dest, x |
| 67 | HInstruction* candidate = nullptr; |
| 68 | HInstruction* other = nullptr; |
| 69 | HInstruction* left = instruction->GetLeft(); |
| 70 | HInstruction* right = instruction->GetRight(); |
| 71 | if (AreLeastSetBitInputs(left, right)) { |
| 72 | candidate = left; |
| 73 | other = right; |
| 74 | } else if (AreLeastSetBitInputs(right, left)) { |
| 75 | candidate = right; |
| 76 | other = left; |
| 77 | } |
| 78 | if (candidate != nullptr && candidate->HasOnlyOneNonEnvironmentUse()) { |
| 79 | ArenaAllocator* arena = instruction->GetBlock()->GetGraph()->GetAllocator(); |
| 80 | HX86MaskOrResetLeastSetBit* lsb = new (arena) HX86MaskOrResetLeastSetBit( |
| 81 | type, HInstruction::kAnd, other, instruction->GetDexPc()); |
| 82 | instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, lsb); |
| 83 | DCHECK(!candidate->HasUses()); |
| 84 | candidate->GetBlock()->RemoveInstruction(candidate); |
| 85 | return true; |
| 86 | } |
| 87 | return false; |
| 88 | } |
| 89 | |
| 90 | bool TryGenerateMaskUptoLeastSetBit(HXor* instruction) { |
| 91 | DataType::Type type = instruction->GetType(); |
| 92 | if (!DataType::IsIntOrLongType(type)) { |
| 93 | return false; |
| 94 | } |
| 95 | // Replace code looking like |
| 96 | // Add tmp, x, -1 or Sub tmp, x, 1 |
| 97 | // Xor dest x, tmp |
| 98 | // with |
| 99 | // MaskOrResetLeastSetBit dest, x |
| 100 | HInstruction* left = instruction->GetLeft(); |
| 101 | HInstruction* right = instruction->GetRight(); |
| 102 | HInstruction* other = nullptr; |
| 103 | HInstruction* candidate = nullptr; |
| 104 | if (AreLeastSetBitInputs(left, right)) { |
| 105 | candidate = left; |
| 106 | other = right; |
| 107 | } else if (AreLeastSetBitInputs(right, left)) { |
| 108 | candidate = right; |
| 109 | other = left; |
| 110 | } |
| 111 | if (candidate != nullptr && candidate->HasOnlyOneNonEnvironmentUse()) { |
| 112 | ArenaAllocator* arena = instruction->GetBlock()->GetGraph()->GetAllocator(); |
| 113 | HX86MaskOrResetLeastSetBit* lsb = new (arena) HX86MaskOrResetLeastSetBit( |
| 114 | type, HInstruction::kXor, other, instruction->GetDexPc()); |
| 115 | instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, lsb); |
| 116 | DCHECK(!candidate->HasUses()); |
| 117 | candidate->GetBlock()->RemoveInstruction(candidate); |
| 118 | return true; |
| 119 | } |
| 120 | return false; |
| 121 | } |
| 122 | |
| 123 | bool AreLeastSetBitInputs(HInstruction* to_test, HInstruction* other) { |
| 124 | if (to_test->IsAdd()) { |
| 125 | HAdd* add = to_test->AsAdd(); |
| 126 | HConstant* cst = add->GetConstantRight(); |
| 127 | return cst != nullptr && cst->IsMinusOne() && other == add->GetLeastConstantLeft(); |
| 128 | } |
| 129 | if (to_test->IsSub()) { |
| 130 | HSub* sub = to_test->AsSub(); |
| 131 | HConstant* cst = sub->GetConstantRight(); |
| 132 | return cst != nullptr && cst->IsOne() && other == sub->GetLeastConstantLeft(); |
| 133 | } |
| 134 | return false; |
| 135 | } |
| 136 | |
| 137 | } // namespace art |