diff options
Diffstat (limited to 'gcc/profile-count.h')
-rw-r--r-- | gcc/profile-count.h | 92 |
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; } |