From 2358ff9116d8167e4b0d2f70a9d61e4e8ca5168e Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 20 Oct 2005 14:14:30 +0200 Subject: [PATCH] re PR rtl-optimization/23585 (mem_fun* code fine with -O1, bus error with -O2) PR rtl-optimization/23585 * rtlanal.c (rtx_addr_can_trap_p_1): New predicate extracted from... (rtx_addr_can_trap_p): ... here. Invoke rtx_addr_can_trap_p_1. (may_trap_p_1): New predicate extracted from... (may_trap_p): ... here. Invoke may_trap_p_1. (may_trap_or_fault_p): New predicate. * rtl.h (may_trap_or_fault_p): Declare it. * reorg.c (steal_delay_list_from_target): Use may_trap_or_fault_p instead of may_trap_p. (steal_delay_list_from_fallthrough): Likewise. (fill_simple_delay_slots): Likewise. (fill_slots_from_thread): Likewise. * function.c (pad_to_arg_alignment): Rework comment about SPARC_STACK_BOUNDARY_HACK. * config/sparc/sparc.h: Likewise. From-SVN: r105671 --- gcc/ChangeLog | 18 ++++ gcc/config/sparc/sparc.h | 6 +- gcc/function.c | 7 +- gcc/reorg.c | 10 +- gcc/rtl.h | 1 + gcc/rtlanal.c | 134 ++++++++++++++++++++---- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/opt/delay-slot-1.C | 111 ++++++++++++++++++++ 8 files changed, 258 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/g++.dg/opt/delay-slot-1.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index feb6a71ab21f..e5de23f84213 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2005-10-20 Eric Botcazou + + PR rtl-optimization/23585 + * rtlanal.c (rtx_addr_can_trap_p_1): New predicate extracted from... + (rtx_addr_can_trap_p): ... here. Invoke rtx_addr_can_trap_p_1. + (may_trap_p_1): New predicate extracted from... + (may_trap_p): ... here. Invoke may_trap_p_1. + (may_trap_or_fault_p): New predicate. + * rtl.h (may_trap_or_fault_p): Declare it. + * reorg.c (steal_delay_list_from_target): Use may_trap_or_fault_p + instead of may_trap_p. + (steal_delay_list_from_fallthrough): Likewise. + (fill_simple_delay_slots): Likewise. + (fill_slots_from_thread): Likewise. + * function.c (pad_to_arg_alignment): Rework comment about + SPARC_STACK_BOUNDARY_HACK. + * config/sparc/sparc.h: Likewise. + 2005-10-19 Adrian Straetling * config/s390/s390.c (s390_expand_insv): New. diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index bb81dcc2208f..a72cc90910b6 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -624,11 +624,9 @@ if (TARGET_ARCH64 \ /* Boundary (in *bits*) on which stack pointer should be aligned. */ /* FIXME, this is wrong when TARGET_ARCH64 and TARGET_STACK_BIAS, because - then sp+2047 is 128-bit aligned so sp is really only byte-aligned. */ + then %sp+2047 is 128-bit aligned so %sp is really only byte-aligned. */ #define STACK_BOUNDARY (TARGET_ARCH64 ? 128 : 64) -/* Temporary hack until the FIXME above is fixed. This macro is used - only in pad_to_arg_alignment in function.c; see the comment there - for details about what it does. */ +/* Temporary hack until the FIXME above is fixed. */ #define SPARC_STACK_BOUNDARY_HACK (TARGET_ARCH64 && TARGET_STACK_BIAS) /* ALIGN FRAMES on double word boundaries */ diff --git a/gcc/function.c b/gcc/function.c index 7cff2a0d1dc6..941021edc667 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -3370,10 +3370,9 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary, HOST_WIDE_INT sp_offset = STACK_POINTER_OFFSET; #ifdef SPARC_STACK_BOUNDARY_HACK - /* The sparc port has a bug. It sometimes claims a STACK_BOUNDARY - higher than the real alignment of %sp. However, when it does this, - the alignment of %sp+STACK_POINTER_OFFSET will be STACK_BOUNDARY. - This is a temporary hack while the sparc port is fixed. */ + /* ??? The SPARC port may claim a STACK_BOUNDARY higher than + the real alignment of %sp. However, when it does this, the + alignment of %sp+STACK_POINTER_OFFSET is STACK_BOUNDARY. */ if (SPARC_STACK_BOUNDARY_HACK) sp_offset = 0; #endif diff --git a/gcc/reorg.c b/gcc/reorg.c index 8b9d7efccfbf..46154f1fd3a7 100644 --- a/gcc/reorg.c +++ b/gcc/reorg.c @@ -1337,7 +1337,7 @@ steal_delay_list_from_target (rtx insn, rtx condition, rtx seq, if (! must_annul && ((condition == const_true_rtx || (! insn_sets_resource_p (trial, other_needed, 0) - && ! may_trap_p (PATTERN (trial))))) + && ! may_trap_or_fault_p (PATTERN (trial))))) ? eligible_for_delay (insn, total_slots_filled, trial, flags) : (must_annul || (delay_list == NULL && new_delay_list == NULL)) && (must_annul = 1, @@ -1431,7 +1431,7 @@ steal_delay_list_from_fallthrough (rtx insn, rtx condition, rtx seq, if (! must_annul && ((condition == const_true_rtx || (! insn_sets_resource_p (trial, other_needed, 0) - && ! may_trap_p (PATTERN (trial))))) + && ! may_trap_or_fault_p (PATTERN (trial))))) ? eligible_for_delay (insn, *pslots_filled, trial, flags) : (must_annul || delay_list == NULL) && (must_annul = 1, check_annul_list_true_false (1, delay_list) @@ -2323,7 +2323,7 @@ fill_simple_delay_slots (int non_jumps_p) #ifdef HAVE_cc0 && ! (reg_mentioned_p (cc0_rtx, pat) && ! sets_cc0_p (pat)) #endif - && ! (maybe_never && may_trap_p (pat)) + && ! (maybe_never && may_trap_or_fault_p (pat)) && (trial = try_split (pat, trial, 0)) && eligible_for_delay (insn, slots_filled, trial, flags) && ! can_throw_internal(trial)) @@ -2376,7 +2376,7 @@ fill_simple_delay_slots (int non_jumps_p) #ifdef HAVE_cc0 && ! reg_mentioned_p (cc0_rtx, PATTERN (next_trial)) #endif - && ! (maybe_never && may_trap_p (PATTERN (next_trial))) + && ! (maybe_never && may_trap_or_fault_p (PATTERN (next_trial))) && (next_trial = try_split (PATTERN (next_trial), next_trial, 0)) && eligible_for_delay (insn, slots_filled, next_trial, flags) && ! can_throw_internal (trial)) @@ -2656,7 +2656,7 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, if (!must_annul && (condition == const_true_rtx || (! insn_sets_resource_p (trial, &opposite_needed, 1) - && ! may_trap_p (pat)))) + && ! may_trap_or_fault_p (pat)))) { old_trial = trial; trial = try_split (pat, trial, 0); diff --git a/gcc/rtl.h b/gcc/rtl.h index 6de76e288f3b..ceb23941b88f 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1611,6 +1611,7 @@ extern int side_effects_p (rtx); extern int volatile_refs_p (rtx); extern int volatile_insn_p (rtx); extern int may_trap_p (rtx); +extern int may_trap_or_fault_p (rtx); extern int inequality_comparisons_p (rtx); extern rtx replace_rtx (rtx, rtx, rtx); extern rtx replace_regs (rtx, rtx *, unsigned int, int); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 9064b009a9bc..594b2e47f643 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -223,10 +223,13 @@ rtx_varies_p (rtx x, int for_alias) return 0; } -/* Return 0 if the use of X as an address in a MEM can cause a trap. */ +/* Return nonzero if the use of X as an address in a MEM can cause a trap. + MODE is the mode of the MEM (not that of X) and UNALIGNED_MEMS controls + whether nonzero is returned for unaligned memory accesses on strict + alignment machines. */ -int -rtx_addr_can_trap_p (rtx x) +static int +rtx_addr_can_trap_p_1 (rtx x, enum machine_mode mode, bool unaligned_mems) { enum rtx_code code = GET_CODE (x); @@ -252,27 +255,52 @@ rtx_addr_can_trap_p (rtx x) return 1; case CONST: - return rtx_addr_can_trap_p (XEXP (x, 0)); + return rtx_addr_can_trap_p_1 (XEXP (x, 0), mode, unaligned_mems); case PLUS: - /* An address is assumed not to trap if it is an address that can't - trap plus a constant integer or it is the pic register plus a - constant. */ - return ! ((! rtx_addr_can_trap_p (XEXP (x, 0)) - && GET_CODE (XEXP (x, 1)) == CONST_INT) - || (XEXP (x, 0) == pic_offset_table_rtx - && CONSTANT_P (XEXP (x, 1)))); + /* An address is assumed not to trap if: + - it is an address that can't trap plus a constant integer, + with the proper remainder modulo the mode size if we are + considering unaligned memory references. */ + if (!rtx_addr_can_trap_p_1 (XEXP (x, 0), mode, unaligned_mems) + && GET_CODE (XEXP (x, 1)) == CONST_INT) + { + HOST_WIDE_INT offset; + + if (!STRICT_ALIGNMENT || !unaligned_mems) + return 0; + + offset = INTVAL (XEXP (x, 1)); + +#ifdef SPARC_STACK_BOUNDARY_HACK + /* ??? The SPARC port may claim a STACK_BOUNDARY higher than + the real alignment of %sp. However, when it does this, the + alignment of %sp+STACK_POINTER_OFFSET is STACK_BOUNDARY. */ + if (SPARC_STACK_BOUNDARY_HACK + && (XEXP (x, 0) == stack_pointer_rtx + || XEXP (x, 0) == hard_frame_pointer_rtx)) + offset -= STACK_POINTER_OFFSET; +#endif + + return offset % GET_MODE_SIZE (mode) != 0; + } + + /* - or it is the pic register plus a constant. */ + if (XEXP (x, 0) == pic_offset_table_rtx && CONSTANT_P (XEXP (x, 1))) + return 0; + + return 1; case LO_SUM: case PRE_MODIFY: - return rtx_addr_can_trap_p (XEXP (x, 1)); + return rtx_addr_can_trap_p_1 (XEXP (x, 1), mode, unaligned_mems); case PRE_DEC: case PRE_INC: case POST_DEC: case POST_INC: case POST_MODIFY: - return rtx_addr_can_trap_p (XEXP (x, 0)); + return rtx_addr_can_trap_p_1 (XEXP (x, 0), mode, unaligned_mems); default: break; @@ -282,6 +310,14 @@ rtx_addr_can_trap_p (rtx x) return 1; } +/* Return nonzero if the use of X as an address in a MEM can cause a trap. */ + +int +rtx_addr_can_trap_p (rtx x) +{ + return rtx_addr_can_trap_p_1 (x, VOIDmode, false); +} + /* Return true if X is an address that is known to not be zero. */ bool @@ -2065,10 +2101,12 @@ side_effects_p (rtx x) return 0; } -/* Return nonzero if evaluating rtx X might cause a trap. */ +/* Return nonzero if evaluating rtx X might cause a trap. UNALIGNED_MEMS + controls whether nonzero is returned for unaligned memory accesses on + strict alignment machines. */ -int -may_trap_p (rtx x) +static int +may_trap_p_1 (rtx x, bool unaligned_mems) { int i; enum rtx_code code; @@ -2102,9 +2140,11 @@ may_trap_p (rtx x) /* Memory ref can trap unless it's a static var or a stack slot. */ case MEM: - if (MEM_NOTRAP_P (x)) + if (MEM_NOTRAP_P (x) + && (!STRICT_ALIGNMENT || !unaligned_mems)) return 0; - return rtx_addr_can_trap_p (XEXP (x, 0)); + return + rtx_addr_can_trap_p_1 (XEXP (x, 0), GET_MODE (x), unaligned_mems); /* Division by a non-constant might trap. */ case DIV: @@ -2180,19 +2220,73 @@ may_trap_p (rtx x) { if (fmt[i] == 'e') { - if (may_trap_p (XEXP (x, i))) + if (may_trap_p_1 (XEXP (x, i), unaligned_mems)) return 1; } else if (fmt[i] == 'E') { int j; for (j = 0; j < XVECLEN (x, i); j++) - if (may_trap_p (XVECEXP (x, i, j))) + if (may_trap_p_1 (XVECEXP (x, i, j), unaligned_mems)) return 1; } } return 0; } + +/* Return nonzero if evaluating rtx X might cause a trap. */ + +int +may_trap_p (rtx x) +{ + return may_trap_p_1 (x, false); +} + +/* Same as above, but additionally return non-zero if evaluating rtx X might + cause a fault. We define a fault for the purpose of this function as a + erroneous execution condition that cannot be encountered during the normal + execution of a valid program; the typical example is an unaligned memory + access on a strict alignment machine. The compiler guarantees that it + doesn't generate code that will fault from a valid program, but this + guarantee doesn't mean anything for individual instructions. Consider + the following example: + + struct S { int d; union { char *cp; int *ip; }; }; + + int foo(struct S *s) + { + if (s->d == 1) + return *s->ip; + else + return *s->cp; + } + + on a strict alignment machine. In a valid program, foo will never be + invoked on a structure for which d is equal to 1 and the underlying + unique field of the union not aligned on a 4-byte boundary, but the + expression *s->ip might cause a fault if considered individually. + + At the RTL level, potentially problematic expressions will almost always + verify may_trap_p; for example, the above dereference can be emitted as + (mem:SI (reg:P)) and this expression is may_trap_p for a generic register. + However, suppose that foo is inlined in a caller that causes s->cp to + point to a local character variable and guarantees that s->d is not set + to 1; foo may have been effectively translated into pseudo-RTL as: + + if ((reg:SI) == 1) + (set (reg:SI) (mem:SI (%fp - 7))) + else + (set (reg:QI) (mem:QI (%fp - 7))) + + Now (mem:SI (%fp - 7)) is considered as not may_trap_p since it is a + memory reference to a stack slot, but it will certainly cause a fault + on a strict alignment machine. */ + +int +may_trap_or_fault_p (rtx x) +{ + return may_trap_p_1 (x, true); +} /* Return nonzero if X contains a comparison that is not either EQ or NE, i.e., an inequality. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7a536a72c187..82e1f048e183 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2005-10-20 Eric Botcazou + + * g++.dg/opt/delay-slot-1.C: New test. + 2005-10-20 Erik Edelmann PR fortran/21625 diff --git a/gcc/testsuite/g++.dg/opt/delay-slot-1.C b/gcc/testsuite/g++.dg/opt/delay-slot-1.C new file mode 100644 index 000000000000..e180e48105e1 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/delay-slot-1.C @@ -0,0 +1,111 @@ +/* PR rtl-optimization/23585 */ +/* Testcase by Matti Rintala */ + +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +template +class const_mem_fun_t +{ +public: + explicit + const_mem_fun_t(_Ret (_Tp::*__pf)() const) + : _M_f(__pf) {} + + _Ret + operator()(const _Tp* __p) const + { return (__p->*_M_f)(); } +private: + _Ret (_Tp::*_M_f)() const; +}; + +template +class const_mem_fun_ref_t +{ +public: + explicit + const_mem_fun_ref_t(_Ret (_Tp::*__pf)() const) + : _M_f(__pf) {} + + _Ret + operator()(const _Tp& __r) const + { return (__r.*_M_f)(); } +private: + _Ret (_Tp::*_M_f)() const; +}; + +template +class const_mem_fun1_t +{ +public: + explicit + const_mem_fun1_t(_Ret (_Tp::*__pf)(_Arg) const) + : _M_f(__pf) {} + + _Ret + operator()(const _Tp* __p, _Arg __x) const + { return (__p->*_M_f)(__x); } +private: + _Ret (_Tp::*_M_f)(_Arg) const; +}; + + +template +class const_mem_fun1_ref_t +{ +public: + explicit + const_mem_fun1_ref_t(_Ret (_Tp::*__pf)(_Arg) const) + : _M_f(__pf) {} + + _Ret + operator()(const _Tp& __r, _Arg __x) const + { return (__r.*_M_f)(__x); } +private: + _Ret (_Tp::*_M_f)(_Arg) const; +}; + +template +inline const_mem_fun_t<_Ret, _Tp> +mem_fun(_Ret (_Tp::*__f)() const) +{ return const_mem_fun_t<_Ret, _Tp>(__f); } + +template +inline const_mem_fun_ref_t<_Ret, _Tp> +mem_fun_ref(_Ret (_Tp::*__f)() const) +{ return const_mem_fun_ref_t<_Ret, _Tp>(__f); } + +template +inline const_mem_fun1_t<_Ret, _Tp, _Arg> +mem_fun(_Ret (_Tp::*__f)(_Arg) const) +{ return const_mem_fun1_t<_Ret, _Tp, _Arg>(__f); } + +template +inline const_mem_fun1_ref_t<_Ret, _Tp, _Arg> +mem_fun_ref(_Ret (_Tp::*__f)(_Arg) const) +{ return const_mem_fun1_ref_t<_Ret, _Tp, _Arg>(__f); } + +class Class { +public: + void vf0c() const; + void vf1c(const int&) const; +}; + +int main() +{ + Class obj; + const Class& objc = obj; + + mem_fun(&Class::vf0c)(&objc); + mem_fun(&Class::vf1c)(&objc, 1); + + mem_fun_ref(&Class::vf0c)(objc); + mem_fun_ref(&Class::vf1c)(objc, 1); + return 0; +} + +void Class::vf0c() const +{} + +void Class::vf1c(const int&) const +{}