1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
|
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "code_generator_utils.h"
#include <android-base/logging.h>
#include "nodes.h"
namespace art HIDDEN {
void CalculateMagicAndShiftForDivRem(int64_t divisor, bool is_long,
int64_t* magic, int* shift) {
// It does not make sense to calculate magic and shift for zero divisor.
DCHECK_NE(divisor, 0);
/* Implementation according to H.S.Warren's "Hacker's Delight" (Addison Wesley, 2002)
* Chapter 10 and T.Grablund, P.L.Montogomery's "Division by Invariant Integers Using
* Multiplication" (PLDI 1994).
* The magic number M and shift S can be calculated in the following way:
* Let nc be the most positive value of numerator(n) such that nc = kd - 1,
* where divisor(d) >= 2.
* Let nc be the most negative value of numerator(n) such that nc = kd + 1,
* where divisor(d) <= -2.
* Thus nc can be calculated like:
* nc = exp + exp % d - 1, where d >= 2 and exp = 2^31 for int or 2^63 for long
* nc = -exp + (exp + 1) % d, where d >= 2 and exp = 2^31 for int or 2^63 for long
*
* So the shift p is the smallest p satisfying
* 2^p > nc * (d - 2^p % d), where d >= 2
* 2^p > nc * (d + 2^p % d), where d <= -2.
*
* The magic number M is calculated by
* M = (2^p + d - 2^p % d) / d, where d >= 2
* M = (2^p - d - 2^p % d) / d, where d <= -2.
*
* Notice that p is always bigger than or equal to 32 (resp. 64), so we just return 32 - p
* (resp. 64 - p) as the shift number S.
*/
int64_t p = is_long ? 63 : 31;
const uint64_t exp = is_long ? (UINT64_C(1) << 63) : (UINT32_C(1) << 31);
// Initialize the computations.
uint64_t abs_d = (divisor >= 0) ? divisor : -divisor;
uint64_t sign_bit = is_long ? static_cast<uint64_t>(divisor) >> 63 :
static_cast<uint32_t>(divisor) >> 31;
uint64_t tmp = exp + sign_bit;
uint64_t abs_nc = tmp - 1 - (tmp % abs_d);
uint64_t quotient1 = exp / abs_nc;
uint64_t remainder1 = exp % abs_nc;
uint64_t quotient2 = exp / abs_d;
uint64_t remainder2 = exp % abs_d;
/*
* To avoid handling both positive and negative divisor, "Hacker's Delight"
* introduces a method to handle these 2 cases together to avoid duplication.
*/
uint64_t delta;
do {
p++;
quotient1 = 2 * quotient1;
remainder1 = 2 * remainder1;
if (remainder1 >= abs_nc) {
quotient1++;
remainder1 = remainder1 - abs_nc;
}
quotient2 = 2 * quotient2;
remainder2 = 2 * remainder2;
if (remainder2 >= abs_d) {
quotient2++;
remainder2 = remainder2 - abs_d;
}
delta = abs_d - remainder2;
} while (quotient1 < delta || (quotient1 == delta && remainder1 == 0));
*magic = (divisor > 0) ? (quotient2 + 1) : (-quotient2 - 1);
if (!is_long) {
*magic = static_cast<int>(*magic);
}
*shift = is_long ? p - 64 : p - 32;
}
bool IsBooleanValueOrMaterializedCondition(HInstruction* cond_input) {
return !cond_input->IsCondition() || !cond_input->IsEmittedAtUseSite();
}
// A helper class to group functions analyzing if values are non-negative
// at the point of use. The class keeps some context used by the functions.
// The class is not supposed to be used directly or its instances to be kept.
// The main function using it is HasNonNegativeInputAt.
// If you want to use the class methods you need to become a friend of the class.
class UnsignedUseAnalyzer {
private:
explicit UnsignedUseAnalyzer(ArenaAllocator* allocator)
: seen_values_(allocator->Adapter(kArenaAllocCodeGenerator)) {
}
bool IsNonNegativeUse(HInstruction* target_user, HInstruction* value);
bool IsComparedValueNonNegativeInBlock(HInstruction* value,
HCondition* cond,
HBasicBlock* target_block);
ArenaSet<HInstruction*> seen_values_;
friend bool HasNonNegativeInputAt(HInstruction* instr, size_t i);
};
// Check that the value compared with a non-negavite value is
// non-negative in the specified basic block.
bool UnsignedUseAnalyzer::IsComparedValueNonNegativeInBlock(HInstruction* value,
HCondition* cond,
HBasicBlock* target_block) {
DCHECK(cond->HasInput(value));
// To simplify analysis, we require:
// 1. The condition basic block and target_block to be different.
// 2. The condition basic block to end with HIf.
// 3. HIf to use the condition.
if (cond->GetBlock() == target_block ||
!cond->GetBlock()->EndsWithIf() ||
cond->GetBlock()->GetLastInstruction()->InputAt(0) != cond) {
return false;
}
// We need to find a successor basic block of HIf for the case when instr is non-negative.
// If the successor dominates target_block, instructions in target_block see a non-negative value.
HIf* if_instr = cond->GetBlock()->GetLastInstruction()->AsIf();
HBasicBlock* successor = nullptr;
switch (cond->GetCondition()) {
case kCondGT:
case kCondGE: {
if (cond->GetLeft() == value) {
// The expression is v > A or v >= A.
// If A is non-negative, we need the true successor.
if (IsNonNegativeUse(cond, cond->GetRight())) {
successor = if_instr->IfTrueSuccessor();
} else {
return false;
}
} else {
DCHECK_EQ(cond->GetRight(), value);
// The expression is A > v or A >= v.
// If A is non-negative, we need the false successor.
if (IsNonNegativeUse(cond, cond->GetLeft())) {
successor = if_instr->IfFalseSuccessor();
} else {
return false;
}
}
break;
}
case kCondLT:
case kCondLE: {
if (cond->GetLeft() == value) {
// The expression is v < A or v <= A.
// If A is non-negative, we need the false successor.
if (IsNonNegativeUse(cond, cond->GetRight())) {
successor = if_instr->IfFalseSuccessor();
} else {
return false;
}
} else {
DCHECK_EQ(cond->GetRight(), value);
// The expression is A < v or A <= v.
// If A is non-negative, we need the true successor.
if (IsNonNegativeUse(cond, cond->GetLeft())) {
successor = if_instr->IfTrueSuccessor();
} else {
return false;
}
}
break;
}
default:
return false;
}
DCHECK_NE(successor, nullptr);
return successor->Dominates(target_block);
}
// Check the value used by target_user is non-negative.
bool UnsignedUseAnalyzer::IsNonNegativeUse(HInstruction* target_user, HInstruction* value) {
DCHECK(target_user->HasInput(value));
// Prevent infinitive recursion which can happen when the value is an induction variable.
if (!seen_values_.insert(value).second) {
return false;
}
// Check if the value is always non-negative.
if (IsGEZero(value)) {
return true;
}
for (const HUseListNode<HInstruction*>& use : value->GetUses()) {
HInstruction* user = use.GetUser();
if (user == target_user) {
continue;
}
// If the value is compared with some non-negative value, this can guarantee the value to be
// non-negative at its use.
// JFYI: We're not using HTypeConversion to bind the new information because it would
// increase the complexity of optimizations: HTypeConversion can create a dependency
// which does not exist in the input program, for example:
// between two uses, 1st - cmp, 2nd - target_user.
if (user->IsCondition()) {
// The condition must dominate target_user to guarantee that the value is always checked
// before it is used by target_user.
if (user->GetBlock()->Dominates(target_user->GetBlock()) &&
IsComparedValueNonNegativeInBlock(value, user->AsCondition(), target_user->GetBlock())) {
return true;
}
}
// TODO The value is non-negative if it is used as an array index before.
// TODO The value is non-negative if it is initialized by a positive number and all of its
// modifications keep the value non-negative, for example the division operation.
}
return false;
}
bool HasNonNegativeInputAt(HInstruction* instr, size_t i) {
UnsignedUseAnalyzer analyzer(instr->GetBlock()->GetGraph()->GetAllocator());
return analyzer.IsNonNegativeUse(instr, instr->InputAt(i));
}
bool HasNonNegativeOrMinIntInputAt(HInstruction* instr, size_t i) {
HInstruction* input = instr->InputAt(i);
return input->IsAbs() ||
IsInt64Value(input, DataType::MinValueOfIntegralType(input->GetType())) ||
HasNonNegativeInputAt(instr, i);
}
} // namespace art
|