This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Optimize sreal::normalize
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 16 Dec 2014 21:37:16 +0100
- Subject: Optimize sreal::normalize
- Authentication-results: sourceware.org; auth=none
Hi,
I have optimized inliner to take advantage that the heap is now in sreal and
found that using small numbers leads to excessive time (7% of WPA) spent by
sreal::normalize. This is because the normalization is implemented by loops
that are unnecesary and can account considerable time when tripped too often.
This patch implements it via floor_log2 and brings normalize inline. The
motivation is to make the constructors from compile time constants to be
optimized into constant write.
I broke normalize into normalize_up/normalize_down and the hot path to futher
aid inlininig (w/o profile inliner will most of time inline everything together
but still it is better than one big function with profile feedback at least.)
Bootstrapped/regtested x86_64-linux, OK?
Honza
* sreal.h (sreal::normalize): Implement inline.
(sreal::normalize_up): New function.
(sreal::normalize_down): New function.
Index: sreal.h
===================================================================
--- sreal.h (revision 218765)
+++ sreal.h (working copy)
@@ -116,7 +116,9 @@ public:
}
private:
- void normalize ();
+ inline void normalize ();
+ inline void normalize_up ();
+ inline void normalize_down ();
void shift_right (int amount);
static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
@@ -178,4 +180,85 @@ inline sreal operator>> (const sreal &a,
return a.shift (-exp);
}
+/* Make significant to be >= SREAL_MIN_SIG.
+
+ Make this separate method so inliner can handle hot path better. */
+
+inline void
+sreal::normalize_up ()
+{
+ int64_t s = m_sig < 0 ? -1 : 1;
+ unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);
+ int shift = SREAL_PART_BITS - 2 - floor_log2 (sig);
+
+ gcc_checking_assert (shift > 0);
+ sig <<= shift;
+ m_exp -= shift;
+ gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
+
+ /* Check underflow. */
+ if (m_exp < -SREAL_MAX_EXP)
+ {
+ m_exp = -SREAL_MAX_EXP;
+ sig = 0;
+ }
+ if (s == -1)
+ m_sig = -sig;
+ else
+ m_sig = sig;
+}
+
+/* Make significant to be <= SREAL_MAX_SIG.
+
+ Make this separate method so inliner can handle hot path better. */
+
+inline void
+sreal::normalize_down ()
+{
+ int64_t s = m_sig < 0 ? -1 : 1;
+ int last_bit;
+ unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);
+ int shift = floor_log2 (sig) - SREAL_PART_BITS + 2;
+
+ gcc_checking_assert (shift > 0);
+ last_bit = (sig >> (shift-1)) & 1;
+ sig >>= shift;
+ m_exp += shift;
+ gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
+
+ /* Round the number. */
+ sig += last_bit;
+ if (sig > SREAL_MAX_SIG)
+ {
+ sig >>= 1;
+ m_exp++;
+ }
+
+ /* Check overflow. */
+ if (m_exp > SREAL_MAX_EXP)
+ {
+ m_exp = SREAL_MAX_EXP;
+ sig = SREAL_MAX_SIG;
+ }
+ if (s == -1)
+ m_sig = -sig;
+ else
+ m_sig = sig;
+}
+
+/* Normalize *this; the hot path. */
+
+inline void
+sreal::normalize ()
+{
+ unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);
+
+ if (sig == 0)
+ m_exp = -SREAL_MAX_EXP;
+ else if (sig > SREAL_MAX_SIG)
+ normalize_down ();
+ else if (sig < SREAL_MIN_SIG)
+ normalize_up ();
+}
+
#endif
Index: sreal.c
===================================================================
--- sreal.c (revision 218765)
+++ sreal.c (working copy)
@@ -96,64 +96,6 @@ sreal::shift_right (int s)
m_sig >>= s;
}
-/* Normalize *this. */
-
-void
-sreal::normalize ()
-{
- int64_t s = m_sig < 0 ? -1 : 1;
- unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);
-
- if (sig == 0)
- {
- m_exp = -SREAL_MAX_EXP;
- }
- else if (sig < SREAL_MIN_SIG)
- {
- do
- {
- sig <<= 1;
- m_exp--;
- }
- while (sig < SREAL_MIN_SIG);
-
- /* Check underflow. */
- if (m_exp < -SREAL_MAX_EXP)
- {
- m_exp = -SREAL_MAX_EXP;
- sig = 0;
- }
- }
- else if (sig > SREAL_MAX_SIG)
- {
- int last_bit;
- do
- {
- last_bit = sig & 1;
- sig >>= 1;
- m_exp++;
- }
- while (sig > SREAL_MAX_SIG);
-
- /* Round the number. */
- sig += last_bit;
- if (sig > SREAL_MAX_SIG)
- {
- sig >>= 1;
- m_exp++;
- }
-
- /* Check overflow. */
- if (m_exp > SREAL_MAX_EXP)
- {
- m_exp = SREAL_MAX_EXP;
- sig = SREAL_MAX_SIG;
- }
- }
-
- m_sig = s * sig;
-}
-
/* Return integer value of *this. */
int64_t