summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/internal-fn.c20
-rw-r--r--gcc/wide-int.h14
2 files changed, 23 insertions, 11 deletions
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index c2845f0276e..68b2b66fbe7 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -478,7 +478,7 @@ ubsan_expand_si_overflow_mul_check (gimple stmt)
rtx do_overflow = gen_label_rtx ();
rtx hipart_different = gen_label_rtx ();
- int hprec = GET_MODE_PRECISION (hmode);
+ unsigned int hprec = GET_MODE_PRECISION (hmode);
rtx hipart0 = expand_shift (RSHIFT_EXPR, mode, op0, hprec,
NULL_RTX, 0);
hipart0 = gen_lowpart (hmode, hipart0);
@@ -513,12 +513,11 @@ ubsan_expand_si_overflow_mul_check (gimple stmt)
wide_int arg0_min, arg0_max;
if (get_range_info (arg0, &arg0_min, &arg0_max) == VR_RANGE)
{
- if (wi::les_p (arg0_max, wi::max_value (hprec, SIGNED))
- && wi::les_p (wi::min_value (hprec, SIGNED), arg0_min))
+ unsigned int mprec0 = wi::min_precision (arg0_min, SIGNED);
+ unsigned int mprec1 = wi::min_precision (arg0_max, SIGNED);
+ if (mprec0 <= hprec && mprec1 <= hprec)
op0_small_p = true;
- else if (wi::les_p (arg0_max, wi::max_value (hprec, UNSIGNED))
- && wi::les_p (~wi::max_value (hprec, UNSIGNED),
- arg0_min))
+ else if (mprec0 <= hprec + 1 && mprec1 <= hprec + 1)
op0_medium_p = true;
if (!wi::neg_p (arg0_min, TYPE_SIGN (TREE_TYPE (arg0))))
op0_sign = 0;
@@ -531,12 +530,11 @@ ubsan_expand_si_overflow_mul_check (gimple stmt)
wide_int arg1_min, arg1_max;
if (get_range_info (arg1, &arg1_min, &arg1_max) == VR_RANGE)
{
- if (wi::les_p (arg1_max, wi::max_value (hprec, SIGNED))
- && wi::les_p (wi::min_value (hprec, SIGNED), arg1_min))
+ unsigned int mprec0 = wi::min_precision (arg1_min, SIGNED);
+ unsigned int mprec1 = wi::min_precision (arg1_max, SIGNED);
+ if (mprec0 <= hprec && mprec1 <= hprec)
op1_small_p = true;
- else if (wi::les_p (arg1_max, wi::max_value (hprec, UNSIGNED))
- && wi::les_p (~wi::max_value (hprec, UNSIGNED),
- arg1_min))
+ else if (mprec0 <= hprec + 1 && mprec1 <= hprec + 1)
op1_medium_p = true;
if (!wi::neg_p (arg1_min, TYPE_SIGN (TREE_TYPE (arg1))))
op1_sign = 0;
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
index 767f24a2307..cbb7f273c2f 100644
--- a/gcc/wide-int.h
+++ b/gcc/wide-int.h
@@ -563,6 +563,9 @@ namespace wi
template <typename T>
unsigned HOST_WIDE_INT extract_uhwi (const T &, unsigned int, unsigned int);
+
+ template <typename T>
+ unsigned int min_precision (const T &, signop);
}
namespace wi
@@ -3003,6 +3006,17 @@ wi::extract_uhwi (const T &x, unsigned int bitpos,
return zext_hwi (res, width);
}
+/* Return the minimum precision needed to store X with sign SGN. */
+template <typename T>
+inline unsigned int
+wi::min_precision (const T &x, signop sgn)
+{
+ if (sgn == SIGNED)
+ return get_precision (x) - clrsb (x);
+ else
+ return get_precision (x) - clz (x);
+}
+
template<typename T>
void
gt_ggc_mx (generic_wide_int <T> *)