Hi, Before r207231, we generate:
;; basic block 12, loop depth 0 ;; Invalid sum of incoming frequencies 8210, should be 4809 ;; pred: 4 ;; 13 ;; 5 ;; 6 ;; 7 ;; 10 ;; 11 _33 = _setjmp (&float_error); if (_33 != 0) goto <bb 13>; else goto <bb 9>; ;; succ: 13 ;; 9 ;; basic block 13, loop depth 0 ;; pred: 12 copy_node (arg1_7(D)); goto <bb 9>; ;; succ: 12 ;; 9 ;; basic block 14, loop depth 0 ;; pred: 5 ;; 11 ;; 7 ;; 9 ;; 3 ;; 6 ;; 4 # _2 = PHI <t_26(5), arg2_11(D)(11), t_28(7), 0B(9), t_15(D)(3), _19(6), t_23(4)> <L21>: return _2; ;; succ: EXIT } After r207231, we have ;; basic block 12, loop depth 0 ;; pred: 11 ;; 13 _34 = _setjmp (&float_error); if (_34 != 0) goto <bb 14>; else goto <bb 9>; ;; succ: 14 ;; 9 ;; basic block 13, loop depth 0 ;; pred: 4 ;; 14 ;; 5 ;; 6 ;; 7 ;; 10 ABNORMAL_DISPATCHER (0); ;; succ: 12 ;; basic block 14, loop depth 0 ;; pred: 12 copy_node (arg1_8(D)); goto <bb 9>; ;; succ: 9 ;; 13 ;; basic block 15, loop depth 0 ;; pred: 5 ;; 11 ;; 7 ;; 9 ;; 3 ;; 6 ;; 4 # _2 = PHI <t_27(5), arg2_12(D)(11), t_29(7), 0B(9), t_16(D)(3), _20(6), t_24(4)> <L21>: return _2; ;; succ: EXIT } basic block 13 only contains ABNORMAL_DISPATCHER (0); which is an internal function and will be expanded to empty block: ;; Generating RTL for gimple basic block 13 ;; ABNORMAL_DISPATCHER (0); (nil) compute_bb_predicates goes into an infinite loop due to ;; basic block 13, loop depth 0 ;; pred: 4 ;; 14 ;; 5 ;; 6 ;; 7 ;; 10 ABNORMAL_DISPATCHER (0); ;; succ: 12 This patch changes compute_bb_predicates to skip basic blocks containing IFN_ABNORMAL_DISPATCHER and updates estimate_function_body_sizes to use Use false predicate if aux is NULL. Tested on Linux/x86-64 with: --enable-languages=c,c++,fortran,java,lto,objc,ada,obj-c++,go and make check RUNTESTFLAGS="--target_board='unix{-m32,}'". OK for trunk? Thanks. H.J. -- gcc/ 2014-02-02 H.J. Lu <hongjiu...@intel.com> PR middle-end/60013 * basic-block.h (bb_has_abnormal_dispatcher): New prototype. * ipa-inline-analysis.c (compute_bb_predicates): Skip basic block containing IFN_ABNORMAL_DISPATCHER when computing predicate. (estimate_function_body_sizes): Use false predicate if aux is NULL. * tree-cfg.c (bb_has_abnormal_dispatcher): New functiom. gcc/testsuite/ 2014-02-02 H.J. Lu <hongjiu...@intel.com> PR middle-end/60013 * gcc.dg/torture/pr60013.c: New test. diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 82729b4..4cb0238 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -942,6 +942,9 @@ extern void default_rtl_profile (void); typedef struct gcov_working_set_info gcov_working_set_t; extern gcov_working_set_t *find_working_set (unsigned pct_times_10); +/* In tree-cfg.c. */ +extern bool bb_has_abnormal_dispatcher (basic_block bb); + /* Check tha probability is sane. */ static inline void diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index ffb8264..dc3ebe1 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -1860,21 +1860,24 @@ compute_bb_predicates (struct cgraph_node *node, struct predicate p = false_predicate (); edge e; edge_iterator ei; - FOR_EACH_EDGE (e, ei, bb->preds) - { - if (e->src->aux) - { - struct predicate this_bb_predicate - = *(struct predicate *) e->src->aux; - if (e->aux) - this_bb_predicate - = and_predicates (summary->conds, &this_bb_predicate, - (struct predicate *) e->aux); - p = or_predicates (summary->conds, &p, &this_bb_predicate); - if (true_predicate_p (&p)) - break; - } - } + if (!bb_has_abnormal_dispatcher (bb)) + FOR_EACH_EDGE (e, ei, bb->preds) + { + if (e->src->aux) + { + struct predicate this_bb_predicate + = *(struct predicate *) e->src->aux; + if (e->aux) + this_bb_predicate + = and_predicates (summary->conds, + &this_bb_predicate, + (struct predicate *) e->aux); + p = or_predicates (summary->conds, &p, + &this_bb_predicate); + if (true_predicate_p (&p)) + break; + } + } if (false_predicate_p (&p)) gcc_assert (!bb->aux); else @@ -2703,7 +2706,10 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) for (i = 0; i < loop->num_nodes; i++) { gimple_stmt_iterator gsi; - bb_predicate = *(struct predicate *) body[i]->aux; + if (body[i]->aux) + bb_predicate = *(struct predicate *) body[i]->aux; + else + bb_predicate = false_predicate (); for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi)) { diff --git a/gcc/testsuite/gcc.dg/torture/pr60013.c b/gcc/testsuite/gcc.dg/torture/pr60013.c new file mode 100644 index 0000000..e9d7c4e --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr60013.c @@ -0,0 +1,102 @@ +/* { dg-do compile } */ + +#include <setjmp.h> + +enum tree_code { + INTEGER_CST, + REAL_CST, + CEIL_MOD_EXPR, + FLOOR_MOD_EXPR, + EXACT_DIV_EXPR, + CEIL_DIV_EXPR, + FLOOR_DIV_EXPR, + PLUS_EXPR, + BIT_IOR_EXPR +}; +typedef union tree_node *tree; +struct tree_common +{ + unsigned int code : 8; + unsigned unsigned_flag : 1; +}; +struct tree_int_cst +{ + char common[sizeof (struct tree_common)]; + int int_cst_low; + int int_cst_high; +}; +struct tree_real_cst +{ + char common[sizeof (struct tree_common)]; + double real_cst; +}; +union tree_node +{ + struct tree_common common; + struct tree_int_cst int_cst; + struct tree_real_cst real_cst; +}; +extern tree build_int_2_wide (int, int); +extern tree size_int (unsigned int); +extern tree copy_node (tree); +extern int target_isnan (double); +static jmp_buf float_error; +int +add_double (l1, h1, l2, h2, lv, hv) + int l1, h1, l2, h2; + int *lv, *hv; +{ + int l, h; + l = l1 + l2; + h = h1 + h2 + ((unsigned int) l < l1); + *lv = l; + *hv = h; + return ((~((h1) ^ (h2)) & ((h1) ^ (h))) < 0); +} +tree +const_binop (code, arg1, arg2, notrunc) + enum tree_code code; + register tree arg1, arg2; + int notrunc; +{ + if (((enum tree_code) (arg1)->common.code) == INTEGER_CST) + { + register int int1l = ((arg1)->int_cst.int_cst_low); + register int int1h = ((arg1)->int_cst.int_cst_high); + int int2l = ((arg2)->int_cst.int_cst_low); + int int2h = ((arg2)->int_cst.int_cst_high); + int low, hi; + register tree t; + int overflow = 0; + switch (code) + { + case BIT_IOR_EXPR: + t = build_int_2_wide ((int) (int1l | int2l), (int) (int1h | int2h)); + break; + case PLUS_EXPR: + overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi); + t = build_int_2_wide ((int) (low), (int) (hi)); + break; + case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + return size_int (int1l / int2l); + case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR: + t = build_int_2_wide ((int) (low), (int) (hi)); + break; + default: + break; + } + return t; + } + if (((enum tree_code) (arg1)->common.code) == REAL_CST) + { + tree t; + double d2; + d2 = ((arg2)->real_cst.real_cst); + if ((target_isnan (d2))) + return arg2; + else if (_setjmp (float_error)) + t = copy_node (arg1); + } + return 0; +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index dfc9b7b..f1075fd 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -599,6 +599,25 @@ get_abnormal_succ_dispatcher (basic_block bb) return NULL; } +/* Return TRUE if basic block BB contains IFN_ABNORMAL_DISPATCHER + internal call, otherwise return FALSE. */ + +bool +bb_has_abnormal_dispatcher (basic_block bb) +{ + gimple_stmt_iterator gsi; + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple g = gsi_stmt (gsi); + if (g + && is_gimple_call (g) + && gimple_call_internal_p (g) + && gimple_call_internal_fn (g) == IFN_ABNORMAL_DISPATCHER) + return true; + } + return false; +} + /* Helper function for make_edges. Create a basic block with with ABNORMAL_DISPATCHER internal call in it if needed, and create abnormal edges from BBS to it and from it to FOR_BB