Hi! I've committed following backports from trunk to 4.7 branch, after bootstrapping/regtesting it on x86_64-linux and i686-linux.
Jakub
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-11-13 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/54127 * cfgrtl.c (force_nonfallthru_and_redirect): When redirecting asm goto labels from BB_HEAD (e->dest) to target bb, decrement LABEL_NUSES of BB_HEAD (e->dest) and increment LABEL_NUSES of BB_HEAD (target) appropriately and adjust JUMP_LABEL and/or REG_LABEL_TARGET and REG_LABEL_OPERAND. * gcc.dg/torture/pr54127.c: New test. --- gcc/cfgrtl.c (revision 193469) +++ gcc/cfgrtl.c (revision 193470) @@ -1424,14 +1424,46 @@ force_nonfallthru_and_redirect (edge e, && (note = extract_asm_operands (PATTERN (BB_END (e->src))))) { int i, n = ASM_OPERANDS_LABEL_LENGTH (note); + bool adjust_jump_target = false; for (i = 0; i < n; ++i) { if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest)) - XEXP (ASM_OPERANDS_LABEL (note, i), 0) = block_label (target); + { + LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))--; + XEXP (ASM_OPERANDS_LABEL (note, i), 0) = block_label (target); + LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))++; + adjust_jump_target = true; + } if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (target)) asm_goto_edge = true; } + if (adjust_jump_target) + { + rtx insn = BB_END (e->src), note; + rtx old_label = BB_HEAD (e->dest); + rtx new_label = BB_HEAD (target); + + if (JUMP_LABEL (insn) == old_label) + { + JUMP_LABEL (insn) = new_label; + note = find_reg_note (insn, REG_LABEL_TARGET, new_label); + if (note) + remove_note (insn, note); + } + else + { + note = find_reg_note (insn, REG_LABEL_TARGET, old_label); + if (note) + remove_note (insn, note); + if (JUMP_LABEL (insn) != new_label + && !find_reg_note (insn, REG_LABEL_TARGET, new_label)) + add_reg_note (insn, REG_LABEL_TARGET, new_label); + } + while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label)) + != NULL_RTX) + XEXP (note, 0) = new_label; + } } if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags || asm_goto_edge) --- gcc/testsuite/gcc.dg/torture/pr54127.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr54127.c (revision 193470) @@ -0,0 +1,16 @@ +/* PR rtl-optimization/54127 */ +/* { dg-do compile } */ + +extern void foo (void) __attribute__ ((__noreturn__)); + +void +bar (int x) +{ + if (x < 0) + foo (); + if (x == 0) + return; + __asm goto ("# %l[lab] %l[lab2]" : : : : lab, lab2); +lab:; +lab2:; +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-11-17 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/55236 * fold-const.c (make_range_step) <case NEGATE_EXPR>: For -fwrapv and signed ARG0_TYPE, force low and high to be non-NULL. * gcc.dg/pr55236.c: New test. --- gcc/fold-const.c (revision 193590) +++ gcc/fold-const.c (revision 193591) @@ -3880,6 +3880,17 @@ make_range_step (location_t loc, enum tr return arg0; case NEGATE_EXPR: + /* If flag_wrapv and ARG0_TYPE is signed, make sure + low and high are non-NULL, then normalize will DTRT. */ + if (!TYPE_UNSIGNED (arg0_type) + && !TYPE_OVERFLOW_UNDEFINED (arg0_type)) + { + if (low == NULL_TREE) + low = TYPE_MIN_VALUE (arg0_type); + if (high == NULL_TREE) + high = TYPE_MAX_VALUE (arg0_type); + } + /* (-x) IN [a,b] -> x in [-b, -a] */ n_low = range_binop (MINUS_EXPR, exp_type, build_int_cst (exp_type, 0), --- gcc/testsuite/gcc.dg/pr55236.c (revision 0) +++ gcc/testsuite/gcc.dg/pr55236.c (revision 193591) @@ -0,0 +1,31 @@ +/* PR tree-optimization/55236 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fwrapv" } */ + +extern void abort (); + +__attribute__((noinline, noclone)) void +foo (int i) +{ + if (i > 0) + abort (); + i = -i; + if (i < 0) + return; + abort (); +} + +__attribute__((noinline, noclone)) void +bar (int i) +{ + if (i > 0 || (-i) >= 0) + abort (); +} + +int +main () +{ + foo (-__INT_MAX__ - 1); + bar (-__INT_MAX__ - 1); + return 0; +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-11-20 Jakub Jelinek <ja...@redhat.com> PR middle-end/55094 * builtins.c (expand_builtin_trap): Add REG_ARGS_SIZE note on the trap insn for !ACCUMULATE_OUTGOING_ARGS. * cfgcleanup.c (outgoing_edges_match): Don't look at debug insns on the first old_insns_match_p call. For !ACCUMULATE_OUTGOING_ARGS fail if the last real insn doesn't have REG_ARGS_SIZE note. * gcc.dg/pr55094.c: New test. --- gcc/builtins.c (revision 193648) +++ gcc/builtins.c (revision 193649) @@ -4666,7 +4666,14 @@ expand_builtin_trap (void) { #ifdef HAVE_trap if (HAVE_trap) - emit_insn (gen_trap ()); + { + rtx insn = emit_insn (gen_trap ()); + /* For trap insns when not accumulating outgoing args force + REG_ARGS_SIZE note to prevent crossjumping of calls with + different args sizes. */ + if (!ACCUMULATE_OUTGOING_ARGS) + add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta)); + } else #endif emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0); --- gcc/cfgcleanup.c (revision 193648) +++ gcc/cfgcleanup.c (revision 193649) @@ -1487,6 +1487,8 @@ outgoing_edges_match (int mode, basic_bl edge fallthru1 = 0, fallthru2 = 0; edge e1, e2; edge_iterator ei; + rtx last1, last2; + bool nonfakeedges; /* If we performed shrink-wrapping, edges to the EXIT_BLOCK_PTR can only be distinguished for JUMP_INSNs. The two paths may differ in @@ -1695,9 +1697,15 @@ outgoing_edges_match (int mode, basic_bl } } + last1 = BB_END (bb1); + last2 = BB_END (bb2); + if (DEBUG_INSN_P (last1)) + last1 = prev_nondebug_insn (last1); + if (DEBUG_INSN_P (last2)) + last2 = prev_nondebug_insn (last2); /* First ensure that the instructions match. There may be many outgoing edges so this test is generally cheaper. */ - if (old_insns_match_p (mode, BB_END (bb1), BB_END (bb2)) != dir_both) + if (old_insns_match_p (mode, last1, last2) != dir_both) return false; /* Search the outgoing edges, ensure that the counts do match, find possible @@ -1706,10 +1714,14 @@ outgoing_edges_match (int mode, basic_bl if (EDGE_COUNT (bb1->succs) != EDGE_COUNT (bb2->succs)) return false; + nonfakeedges = false; FOR_EACH_EDGE (e1, ei, bb1->succs) { e2 = EDGE_SUCC (bb2, ei.index); + if ((e1->flags & EDGE_FAKE) == 0) + nonfakeedges = true; + if (e1->flags & EDGE_EH) nehedges1++; @@ -1727,6 +1739,18 @@ outgoing_edges_match (int mode, basic_bl || (fallthru1 != 0) != (fallthru2 != 0)) return false; + /* If !ACCUMULATE_OUTGOING_ARGS, bb1 (and bb2) have no successors + and the last real insn doesn't have REG_ARGS_SIZE note, don't + attempt to optimize, as the two basic blocks might have different + REG_ARGS_SIZE depths. For noreturn calls and unconditional + traps there should be REG_ARG_SIZE notes, they could be missing + for __builtin_unreachable () uses though. */ + if (!nonfakeedges + && !ACCUMULATE_OUTGOING_ARGS + && (!INSN_P (last1) + || !find_reg_note (last1, REG_ARGS_SIZE, NULL))) + return false; + /* fallthru edges must be forwarded to the same destination. */ if (fallthru1) { --- gcc/testsuite/gcc.dg/pr55094.c (revision 0) +++ gcc/testsuite/gcc.dg/pr55094.c (revision 193649) @@ -0,0 +1,45 @@ +/* PR middle-end/55094 */ +/* { dg-do compile } */ +/* { dg-options "-fcompare-debug -Os" } */ +/* { dg-additional-options "-fomit-frame-pointer -fno-asynchronous-unwind-tables -mpreferred-stack-boundary=2" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */ + +extern int fn (long); +int v; + +int +foo (int x, long *y) +{ + if (x) + { + fn (y[0]); + __builtin_trap (); + } + __builtin_trap (); +} + +int +bar (int x, long *y) +{ + if (x) + { + fn (y[0]); + v = 1; + __builtin_unreachable (); + } + v = 1; + __builtin_unreachable (); +} + +int +baz (int x, long *y) +{ + if (x) + { + fn (y[0]); + v = 1; + __builtin_unreachable (); + } + v = 1; + int w = 1; + __builtin_unreachable (); +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-11-23 Jakub Jelinek <ja...@redhat.com> PR c++/54046 * Makefile.in (gimple-low.o): Depend on langhooks.h. * gimple-low.c: Include langhooks.c. (block_may_fallthru): Handle TARGET_EXPR and ERROR_MARK, by default call lang_hooks.block_may_fallthru. * langhooks.h (struct lang_hooks): Add block_may_fallthru langhook. * langhooks-def.h (LANG_HOOKS_BLOCK_MAY_FALLTHRU): Define. (LANG_HOOKS_INITIALIZER): Use it. * cp-objcp-common.h (LANG_HOOKS_BLOCK_MAY_FALLTHRU): Redefine. * cp-objcp-common.c (cxx_block_may_fallthru): New function. * cp-tree.h (cxx_block_may_fallthru): New prototype. * g++.dg/warn/Wreturn-type-8.C: New test. --- gcc/cp/cp-objcp-common.c (revision 193761) +++ gcc/cp/cp-objcp-common.c (revision 193762) @@ -227,6 +227,25 @@ init_shadowed_var_for_decl (void) tree_decl_map_eq, 0); } +/* Return true if stmt can fall thru. Used by block_may_fallthru + default case. */ + +bool +cxx_block_may_fallthru (const_tree stmt) +{ + switch (TREE_CODE (stmt)) + { + case EXPR_STMT: + return block_may_fallthru (EXPR_STMT_EXPR (stmt)); + + case THROW_EXPR: + return false; + + default: + return true; + } +} + void cp_common_init_ts (void) { --- gcc/cp/cp-objcp-common.h (revision 193761) +++ gcc/cp/cp-objcp-common.h (revision 193762) @@ -94,6 +94,8 @@ extern void cp_common_init_ts (void); #define LANG_HOOKS_TYPE_HASH_EQ cxx_type_hash_eq #undef LANG_HOOKS_MISSING_NORETURN_OK_P #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p +#undef LANG_HOOKS_BLOCK_MAY_FALLTHRU +#define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE --- gcc/cp/cp-tree.h (revision 193761) +++ gcc/cp/cp-tree.h (revision 193762) @@ -6019,6 +6019,7 @@ extern bool cp_var_mod_type_p (tree, t extern void cxx_initialize_diagnostics (diagnostic_context *); extern int cxx_types_compatible_p (tree, tree); extern void init_shadowed_var_for_decl (void); +extern bool cxx_block_may_fallthru (const_tree); /* in cp-gimplify.c */ extern int cp_gimplify_expr (tree *, gimple_seq *, --- gcc/gimple-low.c (revision 193761) +++ gcc/gimple-low.c (revision 193762) @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. #include "function.h" #include "diagnostic-core.h" #include "tree-pass.h" +#include "langhooks.h" /* The differences between High GIMPLE and Low GIMPLE are the following: @@ -739,8 +740,14 @@ block_may_fallthru (const_tree block) case CLEANUP_POINT_EXPR: return block_may_fallthru (TREE_OPERAND (stmt, 0)); - default: + case TARGET_EXPR: + return block_may_fallthru (TREE_OPERAND (stmt, 1)); + + case ERROR_MARK: return true; + + default: + return lang_hooks.block_may_fallthru (stmt); } } --- gcc/langhooks.h (revision 193761) +++ gcc/langhooks.h (revision 193762) @@ -456,6 +456,10 @@ struct lang_hooks FUNCTION_DECL for `std::terminate'. */ tree (*eh_protect_cleanup_actions) (void); + /* Return true if a stmt can fallthru. Used by block_may_fallthru + to possibly handle language trees. */ + bool (*block_may_fallthru) (const_tree); + /* True if this language uses __cxa_end_cleanup when the ARM EABI is enabled. */ bool eh_use_cxa_end_cleanup; --- gcc/Makefile.in (revision 193761) +++ gcc/Makefile.in (revision 193762) @@ -2596,7 +2596,7 @@ gimple-low.o : gimple-low.c $(CONFIG_H) $(DIAGNOSTIC_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h \ $(LANGHOOKS_DEF_H) $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ $(EXCEPT_H) $(FLAGS_H) $(RTL_H) $(FUNCTION_H) $(EXPR_H) $(TREE_PASS_H) \ - $(HASHTAB_H) $(DIAGNOSTIC_CORE_H) tree-iterator.h + $(HASHTAB_H) $(DIAGNOSTIC_CORE_H) tree-iterator.h langhooks.h omp-low.o : omp-low.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(RTL_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h $(DIAGNOSTIC_CORE_H) \ $(TREE_FLOW_H) $(TIMEVAR_H) $(FLAGS_H) $(EXPR_H) $(DIAGNOSTIC_CORE_H) \ --- gcc/langhooks-def.h (revision 193761) +++ gcc/langhooks-def.h (revision 193762) @@ -115,6 +115,7 @@ extern void lhd_omp_firstprivatize_type_ #define LANG_HOOKS_EH_PERSONALITY lhd_gcc_personality #define LANG_HOOKS_EH_RUNTIME_TYPE lhd_pass_through_t #define LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS NULL +#define LANG_HOOKS_BLOCK_MAY_FALLTHRU hook_bool_const_tree_true #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP false #define LANG_HOOKS_DEEP_UNSHARING false @@ -300,6 +301,7 @@ extern void lhd_end_section (void); LANG_HOOKS_EH_PERSONALITY, \ LANG_HOOKS_EH_RUNTIME_TYPE, \ LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS, \ + LANG_HOOKS_BLOCK_MAY_FALLTHRU, \ LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \ LANG_HOOKS_DEEP_UNSHARING \ } --- gcc/testsuite/g++.dg/warn/Wreturn-type-8.C (revision 0) +++ gcc/testsuite/g++.dg/warn/Wreturn-type-8.C (revision 193762) @@ -0,0 +1,90 @@ +// PR c++/54046 +// { dg-do compile } +// { dg-options "-O0 -Wall -Wno-unused" } + +void foo (void) __attribute__((noreturn)); + +struct A +{ + ~A () {} +}; + +bool +check1 (int x) +{ + A z; + switch (x) + { + case 0: + return false; + default: + throw "X"; + break; + } +} + +bool +check2 (int x) +{ + A z; + switch (x) + { + case 0: + return false; + default: + foo (); + break; + } +} + +bool +check3 (int x) +{ + switch (x) + { + case 0: + return false; + default: + throw "X"; + break; + } +} + +bool +check4 (int x) +{ + switch (x) + { + case 0: + return false; + default: + foo (); + break; + } +} + +bool +check5 (int x) +{ + A z; + switch (x) + { + case 0: + return false; + default: + throw "X"; + } +} + +bool +check6 (int x) +{ + A z; + switch (x) + { + case 0: + return false; + default: + foo (); + } +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-12-01 Jakub Jelinek <ja...@redhat.com> PR c++/55542 * pt.c (make_ith_pack_parameter_name): Return NULL if name is NULL. (tsubst_decl): Call make_ith_pack_parameter_name even if DECL_NAME is NULL. * g++.dg/cpp0x/vt-55542.C: New test. --- gcc/cp/pt.c (revision 194009) +++ gcc/cp/pt.c (revision 194010) @@ -2905,6 +2905,8 @@ make_ith_pack_parameter_name (tree name, char* newname; int newname_len; + if (name == NULL_TREE) + return name; snprintf (numbuf, NUMBUF_LEN, "%i", i); newname_len = IDENTIFIER_LENGTH (name) + strlen (numbuf) + 2; @@ -10261,10 +10263,9 @@ tsubst_decl (tree t, tree args, tsubst_f /* Get the Ith type. */ type = TREE_VEC_ELT (expanded_types, i); - if (DECL_NAME (r)) - /* Rename the parameter to include the index. */ - DECL_NAME (r) = - make_ith_pack_parameter_name (DECL_NAME (r), i); + /* Rename the parameter to include the index. */ + DECL_NAME (r) + = make_ith_pack_parameter_name (DECL_NAME (r), i); } else if (!type) /* We're dealing with a normal parameter. */ --- gcc/testsuite/g++.dg/cpp0x/vt-55542.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/vt-55542.C (revision 194010) @@ -0,0 +1,22 @@ +// PR c++/55542 +// { dg-options "-std=c++11" } + +template <typename ... P> +struct B +{ + template <typename O> + B (O *o, void (O::*f) (P ... p)) {} +}; +class C +{ + void foo (void *, int); + template <typename ... A> + void bar (A ... a); + B <void *> c; + B <void *, int> d; + C (int) : c (this, &C::bar), d (this, &C::foo) {} +}; +template <typename ... A> +void C::bar (A ...) +{ +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-12-13 Jakub Jelinek <ja...@redhat.com> PR c++/55652 * typeck2.c (merge_exception_specifiers): Don't call operand_equal_p if noex is NULL. * g++.dg/cpp0x/noexcept19.C: New test. 2012-12-06 Jakub Jelinek <ja...@redhat.com> PR c++/54207 * except.c (build_noexcept_spec): Avoid direct comparison with boolean_true_node or boolean_false_node, instead use operand_equal_p and/or INTEGER_CST check. * pt.c (tsubst_exception_specification): Likewise. * typeck2.c (merge_exception_specifiers): Likewise. * g++.dg/cpp0x/noexcept18.C: New test. --- gcc/cp/except.c (revision 194262) +++ gcc/cp/except.c (revision 194263) @@ -1316,15 +1316,21 @@ build_noexcept_spec (tree expr, int comp LOOKUP_NORMAL); expr = cxx_constant_value (expr); } - if (expr == boolean_true_node) - return noexcept_true_spec; - else if (expr == boolean_false_node) - return noexcept_false_spec; + if (TREE_CODE (expr) == INTEGER_CST) + { + if (operand_equal_p (expr, boolean_true_node, 0)) + return noexcept_true_spec; + else + { + gcc_checking_assert (operand_equal_p (expr, boolean_false_node, 0)); + return noexcept_false_spec; + } + } else if (expr == error_mark_node) return error_mark_node; else { - gcc_assert (processing_template_decl || expr == error_mark_node + gcc_assert (processing_template_decl || TREE_CODE (expr) == DEFERRED_NOEXCEPT); return build_tree_list (expr, NULL_TREE); } --- gcc/cp/typeck2.c (revision 194262) +++ gcc/cp/typeck2.c (revision 194263) @@ -1871,7 +1871,7 @@ merge_exception_specifiers (tree list, t /* If ADD is a deferred noexcept, we must have been called from process_subob_fn. For implicitly declared functions, we build up a list of functions to consider at instantiation time. */ - if (noex == boolean_true_node) + if (noex && operand_equal_p (noex, boolean_true_node, 0)) noex = NULL_TREE; gcc_assert (fn && (!noex || is_overloaded_fn (noex))); noex = build_overload (fn, noex); --- gcc/cp/pt.c (revision 194262) +++ gcc/cp/pt.c (revision 194263) @@ -10844,7 +10844,7 @@ tsubst_exception_specification (tree fnt { /* A noexcept-specifier. */ tree expr = TREE_PURPOSE (specs); - if (expr == boolean_true_node || expr == boolean_false_node) + if (TREE_CODE (expr) == INTEGER_CST) new_specs = expr; else if (defer_ok) { --- gcc/testsuite/g++.dg/cpp0x/noexcept18.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/noexcept18.C (revision 194263) @@ -0,0 +1,11 @@ +// PR c++/54207 +// { dg-do compile } +// { dg-options "-std=c++11" } + +typedef bool B; +constexpr B foo () { return true; } + +void +bar () noexcept (foo ()) +{ +} --- gcc/testsuite/g++.dg/cpp0x/noexcept19.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/noexcept19.C (revision 194479) @@ -0,0 +1,29 @@ +// PR c++/55652 +// { dg-do compile } +// { dg-options "-std=c++11" } + +template <typename T> +struct A +{ + static const bool a = false; +}; + +template <typename X, typename Y = A <X>> +struct B +{ + B () noexcept (A <Y>::a) {} +}; + +template <typename X, typename Y> +struct C +{ + X x; + Y y; +}; + +struct D +{ + D () throw (int); +}; + +C <D, B <D>> c;
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-03 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/55838 * loop-iv.c (iv_number_of_iterations): Call lowpart_subreg on iv0.step, iv1.step and step. * gcc.dg/pr55838.c: New test. --- gcc/loop-iv.c (revision 194836) +++ gcc/loop-iv.c (revision 194837) @@ -2406,6 +2406,9 @@ iv_number_of_iterations (struct loop *lo iv1.step = const0_rtx; } + iv0.step = lowpart_subreg (mode, iv0.step, comp_mode); + iv1.step = lowpart_subreg (mode, iv1.step, comp_mode); + /* This is either infinite loop or the one that ends immediately, depending on initial values. Unswitching should remove this kind of conditions. */ if (iv0.step == const0_rtx && iv1.step == const0_rtx) @@ -2516,6 +2519,7 @@ iv_number_of_iterations (struct loop *lo step = simplify_gen_unary (NEG, comp_mode, iv1.step, comp_mode); else step = iv0.step; + step = lowpart_subreg (mode, step, comp_mode); delta = simplify_gen_binary (MINUS, comp_mode, iv1.base, iv0.base); delta = lowpart_subreg (mode, delta, comp_mode); delta = simplify_gen_binary (UMOD, mode, delta, step); --- gcc/testsuite/gcc.dg/pr55838.c (revision 0) +++ gcc/testsuite/gcc.dg/pr55838.c (revision 194837) @@ -0,0 +1,13 @@ +/* PR rtl-optimization/55838 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -funroll-loops" } */ + +int a; +unsigned char c; + +void +f (void) +{ + while (c++ < 2) + c = a += 129; +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-10 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/55921 * tree-complex.c (expand_complex_asm): New function. (expand_complex_operations_1): Call it for GIMPLE_ASM. * gcc.c-torture/compile/pr55921.c: New test. --- gcc/tree-complex.c (revision 195079) +++ gcc/tree-complex.c (revision 195080) @@ -1391,6 +1391,36 @@ expand_complex_comparison (gimple_stmt_i update_stmt (stmt); } +/* Expand inline asm that sets some complex SSA_NAMEs. */ + +static void +expand_complex_asm (gimple_stmt_iterator *gsi) +{ + gimple stmt = gsi_stmt (*gsi); + unsigned int i; + + for (i = 0; i < gimple_asm_noutputs (stmt); ++i) + { + tree link = gimple_asm_output_op (stmt, i); + tree op = TREE_VALUE (link); + if (TREE_CODE (op) == SSA_NAME + && TREE_CODE (TREE_TYPE (op)) == COMPLEX_TYPE) + { + tree type = TREE_TYPE (op); + tree inner_type = TREE_TYPE (type); + tree r = build1 (REALPART_EXPR, inner_type, op); + tree i = build1 (IMAGPART_EXPR, inner_type, op); + gimple_seq list = set_component_ssa_name (op, false, r); + + if (list) + gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); + + list = set_component_ssa_name (op, true, i); + if (list) + gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); + } + } +} /* Process one statement. If we identify a complex operation, expand it. */ @@ -1403,6 +1433,12 @@ expand_complex_operations_1 (gimple_stmt complex_lattice_t al, bl; enum tree_code code; + if (gimple_code (stmt) == GIMPLE_ASM) + { + expand_complex_asm (gsi); + return; + } + lhs = gimple_get_lhs (stmt); if (!lhs && gimple_code (stmt) != GIMPLE_COND) return; --- gcc/testsuite/gcc.c-torture/compile/pr55921.c (revision 0) +++ gcc/testsuite/gcc.c-torture/compile/pr55921.c (revision 195080) @@ -0,0 +1,22 @@ +/* PR tree-optimization/55921 */ +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ + +typedef union +{ + _Complex float cf; + long long ll; +} ucf; + +void +foo (ucf *in, ucf *out, _Complex float r) +{ + int i; + ucf ucf1; + _Complex float cf; + + ucf1.ll = in[i].ll; + __asm ("" : "=r" (cf) : "0" (ucf1.ll)); + cf *= r; + __asm ("" : "=r" (ucf1.ll) : "0" (cf)); + out[i].ll = ucf1.ll; +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-15 Jakub Jelinek <ja...@redhat.com> PR target/55940 * function.c (thread_prologue_and_epilogue_insns): Always add crtl->drap_reg to set_up_by_prologue.set, even if stack_realign_drap is false. * gcc.dg/pr55940.c: New test. --- gcc/function.c (revision 195219) +++ gcc/function.c (revision 195220) @@ -6029,7 +6029,7 @@ thread_prologue_and_epilogue_insns (void if (pic_offset_table_rtx) add_to_hard_reg_set (&set_up_by_prologue.set, Pmode, PIC_OFFSET_TABLE_REGNUM); - if (stack_realign_drap && crtl->drap_reg) + if (crtl->drap_reg) add_to_hard_reg_set (&set_up_by_prologue.set, GET_MODE (crtl->drap_reg), REGNO (crtl->drap_reg)); --- gcc/testsuite/gcc.dg/pr55940.c (revision 0) +++ gcc/testsuite/gcc.dg/pr55940.c (revision 195220) @@ -0,0 +1,54 @@ +/* PR target/55940 */ +/* { dg-do run } */ +/* { dg-options "-Os" } */ +/* { dg-additional-options "-mpreferred-stack-boundary=2" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */ + +struct S { int s; unsigned long t; }; + +__attribute__ ((noinline, noclone)) unsigned long long +bar (struct S *x, unsigned long y) +{ + asm volatile ("" : : "r" (x), "r" (y) : "memory"); + return x->s + y; +} + +__attribute__ ((noinline, noclone)) unsigned long long +foo (struct S *x, unsigned long y) +{ + unsigned long a; + if (__builtin_expect (((__UINTPTR_TYPE__) (x) + 0x1000U < 0x2000U), 0)) + return ~0ULL; + if (__builtin_expect (x->s <= 0 || x->s > 9, 0)) + return ~0ULL; + a = x->t >> 12; + if (y == a) + return ~0ULL; + if (x->s == 3) + return x->t + y * 4096; + return bar (x, y); +} + +int va, vb, vc, vd; + +int +main () +{ + struct S s; + asm volatile ("" : : : "memory"); + int a = va, b = vb, c = vc, d = vd; + asm volatile ("" : : : "memory"); + int i; + for (i = 0; i < 64; i++) + if (foo ((struct S *) 0, 0) != ~0ULL) + __builtin_abort (); + s.s = 3; + s.t = 2 << 12; + if (foo (&s, 2) != ~0ULL) + __builtin_abort (); + if (foo (&s, 3) != (2 << 12) + 3 * 4096) + __builtin_abort (); + asm volatile ("" : : : "memory"); + va = a; vb = b; vc = c; vd = d; + asm volatile ("" : : : "memory"); + return 0; +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-18 Jakub Jelinek <ja...@redhat.com> PR middle-end/56015 * expr.c (expand_expr_real_2) <case COMPLEX_EXPR>: Handle the case where writing real complex part of target modifies op1. * gfortran.dg/pr56015.f90: New test. --- gcc/expr.c (revision 195300) +++ gcc/expr.c (revision 195301) @@ -8860,6 +8860,54 @@ expand_expr_real_2 (sepops ops, rtx targ if (!target) target = gen_reg_rtx (TYPE_MODE (type)); + else + /* If target overlaps with op1, then either we need to force + op1 into a pseudo (if target also overlaps with op0), + or write the complex parts in reverse order. */ + switch (GET_CODE (target)) + { + case CONCAT: + if (reg_overlap_mentioned_p (XEXP (target, 0), op1)) + { + if (reg_overlap_mentioned_p (XEXP (target, 1), op0)) + { + complex_expr_force_op1: + temp = gen_reg_rtx (GET_MODE_INNER (GET_MODE (target))); + emit_move_insn (temp, op1); + op1 = temp; + break; + } + complex_expr_swap_order: + /* Move the imaginary (op1) and real (op0) parts to their + location. */ + write_complex_part (target, op1, true); + write_complex_part (target, op0, false); + + return target; + } + break; + case MEM: + temp = adjust_address_nv (target, + GET_MODE_INNER (GET_MODE (target)), 0); + if (reg_overlap_mentioned_p (temp, op1)) + { + enum machine_mode imode = GET_MODE_INNER (GET_MODE (target)); + temp = adjust_address_nv (target, imode, + GET_MODE_SIZE (imode)); + if (reg_overlap_mentioned_p (temp, op0)) + goto complex_expr_force_op1; + goto complex_expr_swap_order; + } + break; + default: + if (reg_overlap_mentioned_p (target, op1)) + { + if (reg_overlap_mentioned_p (target, op0)) + goto complex_expr_force_op1; + goto complex_expr_swap_order; + } + break; + } /* Move the real (op0) and imaginary (op1) parts to their location. */ write_complex_part (target, op0, false); --- gcc/testsuite/gfortran.dg/pr56015.f90 (revision 0) +++ gcc/testsuite/gfortran.dg/pr56015.f90 (revision 195301) @@ -0,0 +1,16 @@ +! PR middle-end/56015 +! { dg-do run } +! { dg-options "-Ofast -fno-inline" } + +program pr56015 + implicit none + complex*16 p(10) + p(:) = (0.1d0, 0.2d0) + p(:) = (0.0d0, 1.0d0) * p(:) + call foo (p) +contains + subroutine foo (p) + complex*16 p(10) + if (any (p .ne. (-0.2d0, 0.1d0))) call abort + end subroutine +end program pr56015
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-21 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/56051 * fold-const.c (fold_binary_loc): Don't fold X < (cast) (1 << Y) into (X >> Y) != 0 if cast is either a narrowing conversion, or widening conversion from signed to unsigned. * gcc.c-torture/execute/pr56051.c: New test. --- gcc/fold-const.c (revision 195342) +++ gcc/fold-const.c (revision 195343) @@ -13449,10 +13449,22 @@ fold_binary_loc (location_t loc, TREE_OPERAND (arg1, 1)), build_int_cst (TREE_TYPE (arg0), 0)); + /* Similarly for X < (cast) (1 << Y). But cast can't be narrowing, + otherwise Y might be >= # of bits in X's type and thus e.g. + (unsigned char) (1 << Y) for Y 15 might be 0. + If the cast is widening, then 1 << Y should have unsigned type, + otherwise if Y is number of bits in the signed shift type minus 1, + we can't optimize this. E.g. (unsigned long long) (1 << Y) for Y + 31 might be 0xffffffff80000000. */ if ((code == LT_EXPR || code == GE_EXPR) && TYPE_UNSIGNED (TREE_TYPE (arg0)) && CONVERT_EXPR_P (arg1) && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR + && (TYPE_PRECISION (TREE_TYPE (arg1)) + >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0)))) + && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg1, 0))) + || (TYPE_PRECISION (TREE_TYPE (arg1)) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0))))) && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0))) { tem = build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0, --- gcc/testsuite/gcc.c-torture/execute/pr56051.c (revision 0) +++ gcc/testsuite/gcc.c-torture/execute/pr56051.c (revision 195343) @@ -0,0 +1,32 @@ +/* PR tree-optimization/56051 */ + +extern void abort (void); + +int +main () +{ + unsigned char x1[1] = { 0 }; + unsigned int s1 = __CHAR_BIT__; + int a1 = x1[0] < (unsigned char) (1 << s1); + unsigned char y1 = (unsigned char) (1 << s1); + int b1 = x1[0] < y1; + if (a1 != b1) + abort (); +#if __SIZEOF_LONG_LONG__ > __SIZEOF_INT__ + unsigned long long x2[1] = { 2ULL << (sizeof (int) * __CHAR_BIT__) }; + unsigned int s2 = sizeof (int) * __CHAR_BIT__ - 1; + int a2 = x2[0] >= (unsigned long long) (1 << s2); + unsigned long long y2 = 1 << s2; + int b2 = x2[0] >= y2; + if (a2 != b2) + abort (); + unsigned long long x3[1] = { 2ULL << (sizeof (int) * __CHAR_BIT__) }; + unsigned int s3 = sizeof (int) * __CHAR_BIT__ - 1; + int a3 = x3[0] >= (unsigned long long) (1U << s3); + unsigned long long y3 = 1U << s3; + int b3 = x3[0] >= y3; + if (a3 != b3) + abort (); +#endif + return 0; +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-22 Jakub Jelinek <ja...@redhat.com> PR libquadmath/56072 * libquadmath.texi (M_PI_2q, M_PI_4q): Fix up description. --- libquadmath/libquadmath.texi (revision 195359) +++ libquadmath/libquadmath.texi (revision 195360) @@ -123,8 +123,8 @@ The following mathematical constants of @item @code{M_LN2q}: natural logarithm of 2 @item @code{M_LN10q}: natural logarithm of 10 @item @code{M_PIq}: pi -@item @code{M_PI_2q}: two pi -@item @code{M_PI_4q}: four pi +@item @code{M_PI_2q}: pi divided by two +@item @code{M_PI_4q}: pi divided by four @item @code{M_1_PIq}: one over pi @item @code{M_2_PIq}: one over two pi @item @code{M_2_SQRTPIq}: two over square root of pi
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-23 Jakub Jelinek <ja...@redhat.com> PR target/49069 * config/arm/arm.md (cbranchdi4, cstoredi4): Use s_register_operand instead of cmpdi_operand for first comparison operand. Don't assert that comparison operands aren't both constants. * gcc.dg/pr49069.c: New test. --- gcc/config/arm/arm.md (revision 195397) +++ gcc/config/arm/arm.md (revision 195398) @@ -6904,7 +6904,7 @@ (define_expand "cbranchdi4" [(set (pc) (if_then_else (match_operator 0 "expandable_comparison_operator" - [(match_operand:DI 1 "cmpdi_operand" "") + [(match_operand:DI 1 "s_register_operand" "") (match_operand:DI 2 "cmpdi_operand" "")]) (label_ref (match_operand 3 "" "")) (pc)))] @@ -6913,10 +6913,6 @@ rtx swap = NULL_RTX; enum rtx_code code = GET_CODE (operands[0]); - /* We should not have two constants. */ - gcc_assert (GET_MODE (operands[1]) == DImode - || GET_MODE (operands[2]) == DImode); - /* Flip unimplemented DImode comparisons to a form that arm_gen_compare_reg can handle. */ switch (code) @@ -7917,17 +7913,13 @@ (define_expand "cstoredi4" [(set (match_operand:SI 0 "s_register_operand" "") (match_operator:SI 1 "expandable_comparison_operator" - [(match_operand:DI 2 "cmpdi_operand" "") + [(match_operand:DI 2 "s_register_operand" "") (match_operand:DI 3 "cmpdi_operand" "")]))] "TARGET_32BIT" "{ rtx swap = NULL_RTX; enum rtx_code code = GET_CODE (operands[1]); - /* We should not have two constants. */ - gcc_assert (GET_MODE (operands[2]) == DImode - || GET_MODE (operands[3]) == DImode); - /* Flip unimplemented DImode comparisons to a form that arm_gen_compare_reg can handle. */ switch (code) --- gcc/testsuite/gcc.dg/pr49069.c (revision 0) +++ gcc/testsuite/gcc.dg/pr49069.c (revision 195398) @@ -0,0 +1,15 @@ +/* PR target/49069 */ +/* { dg-do compile } */ +/* { dg-options "-Os -fno-tree-forwprop -Wno-div-by-zero" } */ + +int a; +const unsigned long long b[1] = { 1ULL }; +extern void bar (int); + +void +foo (void) +{ + for (a = 0; a == 1; a = 2) + ; + bar (b[0] == (a == 0 ? a : a / 0)); +}
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-23 Jakub Jelinek <ja...@redhat.com> PR fortran/56052 * trans-decl.c (gfc_get_symbol_decl): Set DECL_ARTIFICIAL and DECL_IGNORED_P on select_type_temporary and don't set DECL_BY_REFERENCE. * gfortran.dg/gomp/pr56052.f90: New test. --- gcc/fortran/trans-decl.c (revision 195398) +++ gcc/fortran/trans-decl.c (revision 195399) @@ -1397,6 +1397,12 @@ gfc_get_symbol_decl (gfc_symbol * sym) DECL_IGNORED_P (decl) = 1; } + if (sym->attr.select_type_temporary) + { + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + } + if (sym->attr.dimension || sym->attr.codimension) { /* Create variables to hold the non-constant bits of array info. */ @@ -1496,7 +1502,8 @@ gfc_get_symbol_decl (gfc_symbol * sym) && POINTER_TYPE_P (TREE_TYPE (decl)) && !sym->attr.pointer && !sym->attr.allocatable - && !sym->attr.proc_pointer) + && !sym->attr.proc_pointer + && !sym->attr.select_type_temporary) DECL_BY_REFERENCE (decl) = 1; if (sym->attr.vtab --- gcc/testsuite/gfortran.dg/gomp/pr56052.f90 (revision 0) +++ gcc/testsuite/gfortran.dg/gomp/pr56052.f90 (revision 195399) @@ -0,0 +1,16 @@ +! PR fortran/56052 +! { dg-do compile } +! { dg-options "-fopenmp" } + +subroutine middle(args) + type args_t + end type + type, extends(args_t) :: scan_args_t + end type + class(args_t),intent(inout) :: args + !$omp single + select type (args) + type is (scan_args_t) + end select + !$omp end single +end subroutine middle
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-25 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/56098 * tree-ssa-phiopt.c (nt_init_block): Don't call add_or_mark_expr for stmts with volatile ops. (cond_store_replacement): Don't optimize if assign has volatile ops. (cond_if_else_store_replacement_1): Don't optimize if either then_assign or else_assign have volatile ops. * gcc.dg/pr56098-1.c: New test. --- gcc/tree-ssa-phiopt.c (revision 195474) +++ gcc/tree-ssa-phiopt.c (revision 195475) @@ -1342,7 +1342,7 @@ nt_init_block (struct dom_walk_data *dat { gimple stmt = gsi_stmt (gsi); - if (gimple_assign_single_p (stmt)) + if (gimple_assign_single_p (stmt) && !gimple_has_volatile_ops (stmt)) { add_or_mark_expr (bb, gimple_assign_lhs (stmt), nontrap_set, true); add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), nontrap_set, false); @@ -1419,7 +1419,8 @@ cond_store_replacement (basic_block midd /* Check if middle_bb contains of only one store. */ if (!assign - || !gimple_assign_single_p (assign)) + || !gimple_assign_single_p (assign) + || gimple_has_volatile_ops (assign)) return false; locus = gimple_location (assign); @@ -1490,9 +1491,11 @@ cond_if_else_store_replacement_1 (basic_ if (then_assign == NULL || !gimple_assign_single_p (then_assign) || gimple_clobber_p (then_assign) + || gimple_has_volatile_ops (then_assign) || else_assign == NULL || !gimple_assign_single_p (else_assign) - || gimple_clobber_p (else_assign)) + || gimple_clobber_p (else_assign) + || gimple_has_volatile_ops (else_assign)) return false; lhs = gimple_assign_lhs (then_assign); --- gcc/testsuite/gcc.dg/pr56098-1.c (revision 0) +++ gcc/testsuite/gcc.dg/pr56098-1.c (revision 195475) @@ -0,0 +1,16 @@ +/* PR tree-optimization/56098 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +volatile int *p; + +void +foo (int x) +{ + *p = 1; + if (x) + *p = 2; +} + +/* { dg-final { scan-tree-dump-not "=\[^\n\r]*\\*p" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */
2013-02-01 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-28 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/56125 * tree-ssa-math-opts.c (gimple_expand_builtin_pow): Don't optimize pow(x,c) into sqrt(x) * powi(x, n/2) or 1.0 / (sqrt(x) * powi(x, abs(n/2))) if c is an integer or when optimizing for size. Don't optimize pow(x,c) into powi(x, n/3) * powi(cbrt(x), n%3) or 1.0 / (powi(x, abs(n)/3) * powi(cbrt(x), abs(n)%3)) if 2c is an integer. * gcc.dg/pr56125.c: New test. --- gcc/tree-ssa-math-opts.c (revision 195506) +++ gcc/tree-ssa-math-opts.c (revision 195507) @@ -1113,7 +1113,7 @@ gimple_expand_builtin_pow (gimple_stmt_i tree type, sqrtfn, cbrtfn, sqrt_arg0, sqrt_sqrt, result, cbrt_x, powi_cbrt_x; tree target = NULL_TREE; enum machine_mode mode; - bool hw_sqrt_exists; + bool hw_sqrt_exists, c_is_int, c2_is_int; /* If the exponent isn't a constant, there's nothing of interest to be done. */ @@ -1125,8 +1125,9 @@ gimple_expand_builtin_pow (gimple_stmt_i c = TREE_REAL_CST (arg1); n = real_to_integer (&c); real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0); + c_is_int = real_identical (&c, &cint); - if (real_identical (&c, &cint) + if (c_is_int && ((n >= -1 && n <= 2) || (flag_unsafe_math_optimizations && optimize_insn_for_speed_p () @@ -1224,7 +1225,8 @@ gimple_expand_builtin_pow (gimple_stmt_i return build_and_insert_call (gsi, loc, &target, cbrtfn, sqrt_arg0); } - /* Optimize pow(x,c), where n = 2c for some nonzero integer n, into + /* Optimize pow(x,c), where n = 2c for some nonzero integer n + and c not an integer, into sqrt(x) * powi(x, n/2), n > 0; 1.0 / (sqrt(x) * powi(x, abs(n/2))), n < 0. @@ -1233,10 +1235,13 @@ gimple_expand_builtin_pow (gimple_stmt_i real_arithmetic (&c2, MULT_EXPR, &c, &dconst2); n = real_to_integer (&c2); real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0); + c2_is_int = real_identical (&c2, &cint); if (flag_unsafe_math_optimizations && sqrtfn - && real_identical (&c2, &cint)) + && c2_is_int + && !c_is_int + && optimize_function_for_speed_p (cfun)) { tree powi_x_ndiv2 = NULL_TREE; @@ -1289,6 +1294,7 @@ gimple_expand_builtin_pow (gimple_stmt_i && cbrtfn && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode)) && real_identical (&c2, &c) + && !c2_is_int && optimize_function_for_speed_p (cfun) && powi_cost (n / 3) <= POWI_MAX_MULTS) { --- gcc/testsuite/gcc.dg/pr56125.c (revision 0) +++ gcc/testsuite/gcc.dg/pr56125.c (revision 195507) @@ -0,0 +1,21 @@ +/* PR tree-optimization/56125 */ +/* { dg-do run } */ +/* { dg-options "-O2 -ffast-math" } */ + +extern void abort (void); +extern double fabs (double); + +__attribute__((cold)) double +foo (double x, double n) +{ + double u = x / (n * n); + return u; +} + +int +main () +{ + if (fabs (foo (29, 2) - 7.25) > 0.001) + abort (); + return 0; +}