aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2013-02-21 21:29:29 +0000
committerJakub Jelinek <jakub@redhat.com>2013-02-21 21:29:29 +0000
commiteef22c0466d8cb7ca475b0f7f245da8706a04d38 (patch)
treed1030e594d863fd4319e656fd16f5fbba7cd2f74
parentfb4c40c2eab1caeb53be6db59af49ee27272a296 (diff)
PR middle-end/56420
* expmed.c (EXACT_POWER_OF_2_OR_ZERO_P): Do subtraction in uhwi, to avoid signed wrapping. (expand_mult): Handle properly multiplication by ((dword_type) -1) << (BITS_PER_WORD - 1). Improve multiplication by ((dword_type) 1) << (BITS_PER_WORD - 1). Avoid undefined behavior in the compiler if coeff is HOST_WIDE_INT_MIN. (expand_divmod): Don't make ext_op1 static, change it's type to uhwi. Avoid undefined behavior in -INTVAL (op1). * gcc.dg/torture/pr56420.c: New test. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@196215 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/expmed.c35
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr56420.c37
4 files changed, 77 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5cd6c358562..c2b35d3538c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,15 @@
2013-02-21 Jakub Jelinek <jakub@redhat.com>
+ PR middle-end/56420
+ * expmed.c (EXACT_POWER_OF_2_OR_ZERO_P): Do subtraction in uhwi, to
+ avoid signed wrapping.
+ (expand_mult): Handle properly multiplication by
+ ((dword_type) -1) << (BITS_PER_WORD - 1). Improve multiplication by
+ ((dword_type) 1) << (BITS_PER_WORD - 1). Avoid undefined behavior
+ in the compiler if coeff is HOST_WIDE_INT_MIN.
+ (expand_divmod): Don't make ext_op1 static, change it's type to
+ uhwi. Avoid undefined behavior in -INTVAL (op1).
+
PR rtl-optimization/50339
* lower-subreg.h (struct lower_subreg_choices): Add splitting_ashiftrt
field.
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 954a360c7b2..d66c6e667fb 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -64,7 +64,8 @@ static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
/* Test whether a value is zero of a power of two. */
-#define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
+#define EXACT_POWER_OF_2_OR_ZERO_P(x) \
+ (((x) & ((x) - (unsigned HOST_WIDE_INT) 1)) == 0)
struct init_expmed_rtl
{
@@ -3079,7 +3080,10 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
/* If we are multiplying in DImode, it may still be a win
to try to work with shifts and adds. */
if (CONST_DOUBLE_HIGH (scalar_op1) == 0
- && CONST_DOUBLE_LOW (scalar_op1) > 0)
+ && (CONST_DOUBLE_LOW (scalar_op1) > 0
+ || (CONST_DOUBLE_LOW (scalar_op1) < 0
+ && EXACT_POWER_OF_2_OR_ZERO_P
+ (CONST_DOUBLE_LOW (scalar_op1)))))
{
coeff = CONST_DOUBLE_LOW (scalar_op1);
is_neg = false;
@@ -3109,7 +3113,8 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
use synth_mult. */
/* Special case powers of two. */
- if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
+ if (EXACT_POWER_OF_2_OR_ZERO_P (coeff)
+ && !(is_neg && mode_bitsize > HOST_BITS_PER_WIDE_INT))
return expand_shift (LSHIFT_EXPR, mode, op0,
floor_log2 (coeff), target, unsignedp);
@@ -3124,13 +3129,24 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
result is interpreted as an unsigned coefficient.
Exclude cost of op0 from max_cost to match the cost
calculation of the synth_mult. */
+ coeff = -(unsigned HOST_WIDE_INT) coeff;
max_cost = (set_src_cost (gen_rtx_MULT (mode, fake_reg, op1), speed)
- neg_cost(speed, mode));
- if (max_cost > 0
- && choose_mult_variant (mode, -coeff, &algorithm,
- &variant, max_cost))
+ if (max_cost <= 0)
+ goto skip_synth;
+
+ /* Special case powers of two. */
+ if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
+ {
+ rtx temp = expand_shift (LSHIFT_EXPR, mode, op0,
+ floor_log2 (coeff), target, unsignedp);
+ return expand_unop (mode, neg_optab, temp, target, 0);
+ }
+
+ if (choose_mult_variant (mode, coeff, &algorithm, &variant,
+ max_cost))
{
- rtx temp = expand_mult_const (mode, op0, -coeff, NULL_RTX,
+ rtx temp = expand_mult_const (mode, op0, coeff, NULL_RTX,
&algorithm, variant);
return expand_unop (mode, neg_optab, temp, target, 0);
}
@@ -3813,13 +3829,12 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
int op1_is_constant, op1_is_pow2 = 0;
int max_cost, extra_cost;
static HOST_WIDE_INT last_div_const = 0;
- static HOST_WIDE_INT ext_op1;
bool speed = optimize_insn_for_speed_p ();
op1_is_constant = CONST_INT_P (op1);
if (op1_is_constant)
{
- ext_op1 = INTVAL (op1);
+ unsigned HOST_WIDE_INT ext_op1 = UINTVAL (op1);
if (unsignedp)
ext_op1 &= GET_MODE_MASK (mode);
op1_is_pow2 = ((EXACT_POWER_OF_2_OR_ZERO_P (ext_op1)
@@ -3967,7 +3982,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
op1_is_pow2 = (op1_is_constant
&& ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
|| (! unsignedp
- && EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1)))))) ;
+ && EXACT_POWER_OF_2_OR_ZERO_P (-UINTVAL (op1))))));
}
/* If one of the operands is a volatile MEM, copy it into a register. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5bffe4317bd..7df8623d288 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2013-02-21 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/56420
+ * gcc.dg/torture/pr56420.c: New test.
+
2013-02-20 Aldy Hernandez <aldyh@redhat.com>
PR middle-end/56108
diff --git a/gcc/testsuite/gcc.dg/torture/pr56420.c b/gcc/testsuite/gcc.dg/torture/pr56420.c
new file mode 100644
index 00000000000..6fa1a803dd6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr56420.c
@@ -0,0 +1,37 @@
+/* PR middle-end/56420 */
+/* { dg-do run { target int128 } } */
+
+extern void abort (void);
+
+__attribute__((noinline, noclone)) __uint128_t
+foo (__uint128_t x)
+{
+ return x * (((__uint128_t) -1) << 63);
+}
+
+__attribute__((noinline, noclone)) __uint128_t
+bar (__uint128_t x)
+{
+ return x * (((__uint128_t) 1) << 63);
+}
+
+__attribute__((noinline, noclone)) __uint128_t
+baz (__uint128_t x)
+{
+ return x * -(((__uint128_t) 1) << 62);
+}
+
+int
+main ()
+{
+ if (foo (1) != (((__uint128_t) -1) << 63)
+ || foo (8) != (((__uint128_t) -1) << 66))
+ abort ();
+ if (bar (1) != (((__uint128_t) 1) << 63)
+ || bar (8) != (((__uint128_t) 1) << 66))
+ abort ();
+ if (baz (1) != -(((__uint128_t) 1) << 62)
+ || baz (8) != ((-(((__uint128_t) 1) << 62)) << 3))
+ abort ();
+ return 0;
+}