aboutsummaryrefslogtreecommitdiff
path: root/gcc/profile-count.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/profile-count.h')
-rw-r--r--gcc/profile-count.h92
1 files changed, 62 insertions, 30 deletions
diff --git a/gcc/profile-count.h b/gcc/profile-count.h
index 8fd22b8b68a..4546e199f24 100644
--- a/gcc/profile-count.h
+++ b/gcc/profile-count.h
@@ -43,6 +43,38 @@ enum profile_quality {
#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
+bool slow_safe_scale_64bit (uint64_t a, uint64_t b, uint64_t c, uint64_t *res);
+
+/* Compute RES=(a*b + c/2)/c capping and return false if overflow happened. */
+
+inline bool
+safe_scale_64bit (uint64_t a, uint64_t b, uint64_t c, uint64_t *res)
+{
+#if (GCC_VERSION >= 5000)
+ uint64_t tmp;
+ if (!__builtin_mul_overflow (a, b, &tmp)
+ && !__builtin_add_overflow (tmp, c/2, &tmp))
+ {
+ *res = tmp / c;
+ return true;
+ }
+ if (c == 1)
+ {
+ *res = (uint64_t) -1;
+ return false;
+ }
+#else
+ if (a < ((uint64_t)1 << 31)
+ && b < ((uint64_t)1 << 31)
+ && c < ((uint64_t)1 << 31))
+ {
+ *res = (a * b + (c / 2)) / c;
+ return true;
+ }
+#endif
+ return slow_safe_scale_64bit (a, b, c, res);
+}
+
/* Data type to hold probabilities. It implements fixed point arithmetics
with capping so probability is always in range [0,1] and scaling requiring
values greater than 1 needs to be represented otherwise.
@@ -82,12 +114,12 @@ enum profile_quality {
class GTY((user)) profile_probability
{
- /* For now use values in range 0...REG_BR_PROB_BASE. Later we can use full
- precision of 30 bits available. */
-
static const int n_bits = 30;
- static const uint32_t max_probability = REG_BR_PROB_BASE;
- static const uint32_t uninitialized_probability = ((uint32_t) 1 << n_bits) - 1;
+ /* We can technically use ((uint32_t) 1 << (n_bits - 1)) - 2 but that
+ will lead to harder multiplication sequences. */
+ static const uint32_t max_probability = (uint32_t) 1 << (n_bits - 2);
+ static const uint32_t uninitialized_probability
+ = ((uint32_t) 1 << (n_bits - 1)) - 1;
uint32_t m_val : 30;
enum profile_quality m_quality : 2;
@@ -171,7 +203,7 @@ public:
/* Return true if value can be trusted. */
bool reliable_p () const
{
- return initialized_p ();
+ return m_quality >= profile_adjusted;
}
/* Conversion from and to REG_BR_PROB_BASE integer fixpoint arithmetics.
@@ -180,14 +212,14 @@ public:
{
profile_probability ret;
gcc_checking_assert (v >= 0 && v <= REG_BR_PROB_BASE);
- ret.m_val = RDIV (v * max_probability, REG_BR_PROB_BASE);
+ ret.m_val = RDIV (v * (uint64_t) max_probability, REG_BR_PROB_BASE);
ret.m_quality = profile_guessed;
return ret;
}
int to_reg_br_prob_base () const
{
gcc_checking_assert (initialized_p ());
- return RDIV (m_val * REG_BR_PROB_BASE, max_probability);
+ return RDIV (m_val * (uint64_t) REG_BR_PROB_BASE, max_probability);
}
/* Conversion to and from RTL representation of profile probabilities. */
@@ -216,7 +248,12 @@ public:
if (val1 > val2)
ret.m_val = max_probability;
else
- ret.m_val = RDIV (val1 * max_probability, val2);
+ {
+ uint64_t tmp;
+ safe_scale_64bit (val1, max_probability, val2, &tmp);
+ gcc_checking_assert (tmp <= max_probability);
+ ret.m_val = tmp;
+ }
ret.m_quality = profile_precise;
return ret;
}
@@ -413,8 +450,9 @@ public:
if (!initialized_p ())
return profile_probability::uninitialized ();
profile_probability ret;
- ret.m_val = MIN (RDIV (m_val * num, den),
- max_probability);
+ uint64_t tmp;
+ safe_scale_64bit (m_val, num, den, &tmp);
+ ret.m_val = MIN (tmp, max_probability);
ret.m_quality = MIN (m_quality, profile_adjusted);
return ret;
}
@@ -452,7 +490,7 @@ public:
if (m_val == uninitialized_probability)
return m_quality == profile_guessed;
else
- return m_val <= REG_BR_PROB_BASE;
+ return m_val <= max_probability;
}
/* Comparsions are three-state and conservative. False is returned if
@@ -535,11 +573,6 @@ class GTY(()) profile_count
uint64_t m_val : n_bits;
enum profile_quality m_quality : 2;
-
- /* Assume numbers smaller than this to multiply. This is set to make
- testsuite pass, in future we may implement precise multiplication in higer
- rangers. */
- static const uint64_t max_safe_multiplier = 131072;
public:
/* Used for counters which are expected to be never executed. */
@@ -595,7 +628,7 @@ public:
/* Return true if value can be trusted. */
bool reliable_p () const
{
- return initialized_p ();
+ return m_quality >= profile_adjusted;
}
/* When merging basic blocks, the two different profile counts are unified.
@@ -756,8 +789,10 @@ public:
if (!initialized_p ())
return profile_count::uninitialized ();
profile_count ret;
- ret.m_val = RDIV (m_val * prob.m_val,
- profile_probability::max_probability);
+ uint64_t tmp;
+ safe_scale_64bit (m_val, prob.m_val, profile_probability::max_probability,
+ &tmp);
+ ret.m_val = tmp;
ret.m_quality = MIN (m_quality, prob.m_quality);
return ret;
}
@@ -769,11 +804,11 @@ public:
if (!initialized_p ())
return profile_count::uninitialized ();
profile_count ret;
+ uint64_t tmp;
+
gcc_checking_assert (num >= 0 && den > 0);
- /* FIXME: shrink wrapping violates this sanity check. */
- gcc_checking_assert ((num <= REG_BR_PROB_BASE
- || den <= REG_BR_PROB_BASE) || 1);
- ret.m_val = RDIV (m_val * num, den);
+ safe_scale_64bit (m_val, num, den, &tmp);
+ ret.m_val = MIN (tmp, max_count);
ret.m_quality = MIN (m_quality, profile_adjusted);
return ret;
}
@@ -790,12 +825,9 @@ public:
return *this;
profile_count ret;
- /* Take care for overflows! */
- if (num.m_val < max_safe_multiplier || m_val < max_safe_multiplier)
- ret.m_val = RDIV (m_val * num.m_val, den.m_val);
- else
- ret.m_val = RDIV (m_val * RDIV (num.m_val * max_safe_multiplier,
- den.m_val), max_safe_multiplier);
+ uint64_t val;
+ safe_scale_64bit (m_val, num.m_val, den.m_val, &val);
+ ret.m_val = MIN (val, max_count);
ret.m_quality = MIN (m_quality, profile_adjusted);
return ret;
}