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 <[email protected]>
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 <[email protected]>
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