diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 57 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr30778.c | 34 |
4 files changed, 82 insertions, 23 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 031c067..6aa21b5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2007-02-24 Uros Bizjak <ubizjak@gmail.com> + Jan Hubicka <jh@suse.cz> + + PR target/30778 + * i386.c (counter_mode): New function. + (expand_set_or_movmem_via_loop): Use it. + (expand_movmem_epilogue): Likewise; fix pasto. + (ix86_expand_movmem): Do emit guard even for constant counts. + (ix86_expand_setmem): Likewise. + 2007-02-25 Nick Clifton <nickc@redhat.com> * config/frv/frv.h (ASM_OUTPUT_CASE_LABEL): Delete. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index db07441..5a4e1d5 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -13314,6 +13314,21 @@ scale_counter (rtx countreg, int scale) return sc; } +/* Return mode for the memcpy/memset loop counter. Preffer SImode over DImode + for constant loop counts. */ + +static enum machine_mode +counter_mode (rtx count_exp) +{ + if (GET_MODE (count_exp) != VOIDmode) + return GET_MODE (count_exp); + if (GET_CODE (count_exp) != CONST_INT) + return Pmode; + if (TARGET_64BIT && (INTVAL (count_exp) & ~0xffffffff)) + return DImode; + return SImode; +} + /* When SRCPTR is non-NULL, output simple loop to move memory pointer to SRCPTR to DESTPTR via chunks of MODE unrolled UNROLL times, overall size is COUNT specified in bytes. When SRCPTR is NULL, output the @@ -13330,7 +13345,7 @@ expand_set_or_movmem_via_loop (rtx destmem, rtx srcmem, int expected_size) { rtx out_label, top_label, iter, tmp; - enum machine_mode iter_mode; + enum machine_mode iter_mode = counter_mode (count); rtx piece_size = GEN_INT (GET_MODE_SIZE (mode) * unroll); rtx piece_size_mask = GEN_INT (~((GET_MODE_SIZE (mode) * unroll) - 1)); rtx size; @@ -13338,10 +13353,6 @@ expand_set_or_movmem_via_loop (rtx destmem, rtx srcmem, rtx y_addr; int i; - iter_mode = GET_MODE (count); - if (iter_mode == VOIDmode) - iter_mode = word_mode; - top_label = gen_label_rtx (); out_label = gen_label_rtx (); iter = gen_reg_rtx (iter_mode); @@ -13555,8 +13566,8 @@ expand_movmem_epilogue (rtx destmem, rtx srcmem, emit_strmov (destmem, srcmem, destptr, srcptr, DImode, offset); else { - emit_strmov (destmem, srcmem, destptr, srcptr, DImode, offset); - emit_strmov (destmem, srcmem, destptr, srcptr, DImode, offset + 4); + emit_strmov (destmem, srcmem, destptr, srcptr, SImode, offset); + emit_strmov (destmem, srcmem, destptr, srcptr, SImode, offset + 4); } offset += 8; } @@ -13673,8 +13684,8 @@ expand_setmem_epilogue_via_loop (rtx destmem, rtx destptr, rtx value, rtx count, int max_size) { count = - expand_simple_binop (GET_MODE (count), AND, count, GEN_INT (max_size - 1), - count, 1, OPTAB_DIRECT); + expand_simple_binop (counter_mode (count), AND, count, + GEN_INT (max_size - 1), count, 1, OPTAB_DIRECT); expand_set_or_movmem_via_loop (destmem, NULL, destptr, NULL, gen_lowpart (QImode, value), count, QImode, 1, max_size / 2); @@ -14134,11 +14145,9 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp, gcc_assert (desired_align >= 1 && align >= 1); /* Ensure that alignment prologue won't copy past end of block. */ - if ((size_needed > 1 || (desired_align > 1 && desired_align > align)) - && !count) + if (size_needed > 1 || (desired_align > 1 && desired_align > align)) { epilogue_size_needed = MAX (size_needed - 1, desired_align - align); - /* Epilogue always copies COUNT_EXP & EPILOGUE_SIZE_NEEDED bytes. Make sure it is power of 2. */ epilogue_size_needed = smallest_pow2_greater_than (epilogue_size_needed); @@ -14146,8 +14155,10 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp, label = gen_label_rtx (); emit_cmp_and_jump_insns (count_exp, GEN_INT (epilogue_size_needed), - LTU, 0, GET_MODE (count_exp), 1, label); - if (expected_size == -1 || expected_size < epilogue_size_needed) + LTU, 0, counter_mode (count_exp), 1, label); + if (GET_CODE (count_exp) == CONST_INT) + ; + else if (expected_size == -1 || expected_size < epilogue_size_needed) predict_jump (REG_BR_PROB_BASE * 60 / 100); else predict_jump (REG_BR_PROB_BASE * 20 / 100); @@ -14247,7 +14258,7 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp, if (size_needed < epilogue_size_needed) { tmp = - expand_simple_binop (GET_MODE (count_exp), AND, count_exp, + expand_simple_binop (counter_mode (count_exp), AND, count_exp, GEN_INT (size_needed - 1), count_exp, 1, OPTAB_DIRECT); if (tmp != count_exp) @@ -14403,7 +14414,7 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp, return 0; gcc_assert (alg != no_stringop); if (!count) - count_exp = copy_to_mode_reg (GET_MODE (count_exp), count_exp); + count_exp = copy_to_mode_reg (counter_mode (count_exp), count_exp); destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0)); switch (alg) { @@ -14446,11 +14457,9 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp, promoted_val = promote_duplicated_reg_to_size (val_exp, size_needed, desired_align, align); /* Ensure that alignment prologue won't copy past end of block. */ - if ((size_needed > 1 || (desired_align > 1 && desired_align > align)) - && !count) + if (size_needed > 1 || (desired_align > 1 && desired_align > align)) { epilogue_size_needed = MAX (size_needed - 1, desired_align - align); - /* Epilogue always copies COUNT_EXP & EPILOGUE_SIZE_NEEDED bytes. Make sure it is power of 2. */ epilogue_size_needed = smallest_pow2_greater_than (epilogue_size_needed); @@ -14464,8 +14473,10 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp, label = gen_label_rtx (); emit_cmp_and_jump_insns (count_exp, GEN_INT (epilogue_size_needed), - LTU, 0, GET_MODE (count_exp), 1, label); - if (expected_size == -1 || expected_size <= epilogue_size_needed) + LTU, 0, counter_mode (count_exp), 1, label); + if (GET_CODE (count_exp) == CONST_INT) + ; + else if (expected_size == -1 || expected_size <= epilogue_size_needed) predict_jump (REG_BR_PROB_BASE * 60 / 100); else predict_jump (REG_BR_PROB_BASE * 20 / 100); @@ -14475,7 +14486,7 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp, rtx hot_label = gen_label_rtx (); jump_around_label = gen_label_rtx (); emit_cmp_and_jump_insns (count_exp, GEN_INT (dynamic_check - 1), - LEU, 0, GET_MODE (count_exp), 1, hot_label); + LEU, 0, counter_mode (count_exp), 1, hot_label); predict_jump (REG_BR_PROB_BASE * 90 / 100); set_storage_via_libcall (dst, count_exp, val_exp, false); emit_jump (jump_around_label); @@ -14558,7 +14569,7 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp, if (size_needed < desired_align - align) { tmp = - expand_simple_binop (GET_MODE (count_exp), AND, count_exp, + expand_simple_binop (counter_mode (count_exp), AND, count_exp, GEN_INT (size_needed - 1), count_exp, 1, OPTAB_DIRECT); size_needed = desired_align - align + 1; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2e9bce6..c2e1df8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2007-02-24 Jan Hubicka <jh@suse.cz> + + * gcc.c-torture/execute/pr30778.c: New testcase. + 2007-02-24 Jerry DeLisle <jvdelisle@gcc.gnu.org> PR libgfortran/30918 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr30778.c b/gcc/testsuite/gcc.c-torture/execute/pr30778.c new file mode 100644 index 0000000..1b05189 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr30778.c @@ -0,0 +1,34 @@ +extern void *memset (void *, int, unsigned long); +extern void abort (void); + +struct reg_stat { + void *last_death; + void *last_set; + void *last_set_value; + int last_set_label; + char last_set_sign_bit_copies; + int last_set_mode : 8; + char last_set_invalid; + char sign_bit_copies; + long nonzero_bits; +}; + +static struct reg_stat *reg_stat; + +void __attribute__((noinline)) +init_reg_last (void) +{ + memset (reg_stat, 0, __builtin_offsetof (struct reg_stat, sign_bit_copies)); +} + +int main (void) +{ + struct reg_stat r; + + reg_stat = &r; + r.nonzero_bits = -1; + init_reg_last (); + if (r.nonzero_bits != -1) + abort (); + return 0; +} |