From f580a969d7fbab634949805c8b7e49f4e6273a7f Mon Sep 17 00:00:00 2001 From: Steve Ellcey Date: Thu, 29 Jun 2017 18:20:14 +0000 Subject: [PATCH] ccmp.c (ccmp_tree_comparison_p): New function. 2017-06-29 Steve Ellcey * ccmp.c (ccmp_tree_comparison_p): New function. (ccmp_candidate_p): Update to use above function. (get_compare_parts): New function. (expand_ccmp_next): Update to use new functions. (expand_ccmp_expr_1): Take tree arg instead of gimple, update to use new functions. (expand_ccmp_expr): Pass tree instead of gimple to expand_ccmp_expr_1, take mode as argument. * ccmp.h (expand_ccmp_expr): Add mode as argument. * expr.c (expand_expr_real_1): Pass mode as argument. From-SVN: r249805 --- gcc/ChangeLog | 13 ++++ gcc/ccmp.c | 168 ++++++++++++++++++++++++++++---------------------- gcc/ccmp.h | 2 +- gcc/expr.c | 2 +- 4 files changed, 111 insertions(+), 74 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dac1d7af9a0..079c674a7ce 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2017-06-29 Steve Ellcey + + * ccmp.c (ccmp_tree_comparison_p): New function. + (ccmp_candidate_p): Update to use above function. + (get_compare_parts): New function. + (expand_ccmp_next): Update to use new functions. + (expand_ccmp_expr_1): Take tree arg instead of gimple, update to use + new functions. + (expand_ccmp_expr): Pass tree instead of gimple to expand_ccmp_expr_1, + take mode as argument. + * ccmp.h (expand_ccmp_expr): Add mode as argument. + * expr.c (expand_expr_real_1): Pass mode as argument. + 2017-06-29 Segher Boessenkool * combine.c (combine_instructions): Print insns to dump_file, together diff --git a/gcc/ccmp.c b/gcc/ccmp.c index 92ca133d842..4fa3ebdc422 100644 --- a/gcc/ccmp.c +++ b/gcc/ccmp.c @@ -38,6 +38,29 @@ along with GCC; see the file COPYING3. If not see #include "ccmp.h" #include "predict.h" +/* Check whether T is a simple boolean variable or a SSA name + set by a comparison operator in the same basic block. */ +static bool +ccmp_tree_comparison_p (tree t, basic_block bb) +{ + gimple *g = get_gimple_for_ssa_name (t); + tree_code tcode; + + /* If we have a boolean variable allow it and generate a compare + to zero reg when expanding. */ + if (!g) + return (TREE_CODE (TREE_TYPE (t)) == BOOLEAN_TYPE); + + /* Check to see if SSA name is set by a comparison operator in + the same basic block. */ + if (!is_gimple_assign (g)) + return false; + if (bb != gimple_bb (g)) + return false; + tcode = gimple_assign_rhs_code (g); + return TREE_CODE_CLASS (tcode) == tcc_comparison; +} + /* The following functions expand conditional compare (CCMP) instructions. Here is a short description about the over all algorithm: * ccmp_candidate_p is used to identify the CCMP candidate @@ -71,49 +94,69 @@ along with GCC; see the file COPYING3. If not see static bool ccmp_candidate_p (gimple *g) { - tree rhs = gimple_assign_rhs_to_tree (g); + tree rhs; tree lhs, op0, op1; gimple *gs0, *gs1; - tree_code tcode, tcode0, tcode1; - tcode = TREE_CODE (rhs); + tree_code tcode; + basic_block bb; + + if (!g) + return false; + rhs = gimple_assign_rhs_to_tree (g); + tcode = TREE_CODE (rhs); if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR) return false; lhs = gimple_assign_lhs (g); op0 = TREE_OPERAND (rhs, 0); op1 = TREE_OPERAND (rhs, 1); + bb = gimple_bb (g); if ((TREE_CODE (op0) != SSA_NAME) || (TREE_CODE (op1) != SSA_NAME) || !has_single_use (lhs)) return false; - gs0 = get_gimple_for_ssa_name (op0); - gs1 = get_gimple_for_ssa_name (op1); - if (!gs0 || !gs1 || !is_gimple_assign (gs0) || !is_gimple_assign (gs1) - /* g, gs0 and gs1 must be in the same basic block, since current stage - is out-of-ssa. We can not guarantee the correctness when forwording - the gs0 and gs1 into g whithout DATAFLOW analysis. */ - || gimple_bb (gs0) != gimple_bb (gs1) - || gimple_bb (gs0) != gimple_bb (g)) - return false; + gs0 = get_gimple_for_ssa_name (op0); /* gs0 may be NULL */ + gs1 = get_gimple_for_ssa_name (op1); /* gs1 may be NULL */ - tcode0 = gimple_assign_rhs_code (gs0); - tcode1 = gimple_assign_rhs_code (gs1); - if (TREE_CODE_CLASS (tcode0) == tcc_comparison - && TREE_CODE_CLASS (tcode1) == tcc_comparison) + if (ccmp_tree_comparison_p (op0, bb) && ccmp_tree_comparison_p (op1, bb)) return true; - if (TREE_CODE_CLASS (tcode0) == tcc_comparison - && ccmp_candidate_p (gs1)) + if (ccmp_tree_comparison_p (op0, bb) && ccmp_candidate_p (gs1)) return true; - else if (TREE_CODE_CLASS (tcode1) == tcc_comparison - && ccmp_candidate_p (gs0)) + if (ccmp_tree_comparison_p (op1, bb) && ccmp_candidate_p (gs0)) return true; /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since - there is no way to set the CC flag. */ + there is no way to set and maintain the CC flag on both sides of + the logical operator at the same time. */ return false; } +/* Extract the comparison we want to do from the tree. */ +void +get_compare_parts (tree t, int *up, rtx_code *rcode, + tree *rhs1, tree *rhs2) +{ + tree_code code; + gimple *g = get_gimple_for_ssa_name (t); + if (g) + { + *up = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g))); + code = gimple_assign_rhs_code (g); + *rcode = get_rtx_code (code, *up); + *rhs1 = gimple_assign_rhs1 (g); + *rhs2 = gimple_assign_rhs2 (g); + } + else + { + /* If g is not a comparison operator create a compare to zero. */ + *up = 1; + *rcode = NE; + *rhs1 = t; + *rhs2 = build_zero_cst (TREE_TYPE (t)); + } +} + /* PREV is a comparison with the CC register which represents the result of the previous CMP or CCMP. The function expands the next compare based on G which is ANDed/ORed with the previous @@ -121,20 +164,16 @@ ccmp_candidate_p (gimple *g) PREP_SEQ returns all insns to prepare opearands for compare. GEN_SEQ returns all compare insns. */ static rtx -expand_ccmp_next (gimple *g, tree_code code, rtx prev, +expand_ccmp_next (tree op, tree_code code, rtx prev, rtx_insn **prep_seq, rtx_insn **gen_seq) { rtx_code rcode; - int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g))); - - gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR); - - rcode = get_rtx_code (gimple_assign_rhs_code (g), unsignedp); + int unsignedp; + tree rhs1, rhs2; + get_compare_parts(op, &unsignedp, &rcode, &rhs1, &rhs2); return targetm.gen_ccmp_next (prep_seq, gen_seq, prev, rcode, - gimple_assign_rhs1 (g), - gimple_assign_rhs2 (g), - get_rtx_code (code, 0)); + rhs1, rhs2, get_rtx_code (code, 0)); } /* Expand conditional compare gimple G. A typical CCMP sequence is like: @@ -153,39 +192,42 @@ expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq) { tree exp = gimple_assign_rhs_to_tree (g); tree_code code = TREE_CODE (exp); - gimple *gs0 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 0)); - gimple *gs1 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 1)); + basic_block bb = gimple_bb (g); + + tree op0 = TREE_OPERAND (exp, 0); + tree op1 = TREE_OPERAND (exp, 1); + gimple *gs0 = get_gimple_for_ssa_name (op0); + gimple *gs1 = get_gimple_for_ssa_name (op1); rtx tmp; - tree_code code0 = gimple_assign_rhs_code (gs0); - tree_code code1 = gimple_assign_rhs_code (gs1); gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR); - gcc_assert (gs0 && gs1 && is_gimple_assign (gs0) && is_gimple_assign (gs1)); - if (TREE_CODE_CLASS (code0) == tcc_comparison) + if (ccmp_tree_comparison_p (op0, bb)) { - if (TREE_CODE_CLASS (code1) == tcc_comparison) + if (ccmp_tree_comparison_p (op1, bb)) { int unsignedp0, unsignedp1; rtx_code rcode0, rcode1; + tree logical_op0_rhs1, logical_op0_rhs2; + tree logical_op1_rhs1, logical_op1_rhs2; int speed_p = optimize_insn_for_speed_p (); + rtx tmp2 = NULL_RTX, ret = NULL_RTX, ret2 = NULL_RTX; unsigned cost1 = MAX_COST; unsigned cost2 = MAX_COST; - unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0))); - unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1))); - rcode0 = get_rtx_code (code0, unsignedp0); - rcode1 = get_rtx_code (code1, unsignedp1); + get_compare_parts (op0, &unsignedp0, &rcode0, + &logical_op0_rhs1, &logical_op0_rhs2); + + get_compare_parts (op1, &unsignedp1, &rcode1, + &logical_op1_rhs1, &logical_op1_rhs2); rtx_insn *prep_seq_1, *gen_seq_1; tmp = targetm.gen_ccmp_first (&prep_seq_1, &gen_seq_1, rcode0, - gimple_assign_rhs1 (gs0), - gimple_assign_rhs2 (gs0)); - + logical_op0_rhs1, logical_op0_rhs2); if (tmp != NULL) { - ret = expand_ccmp_next (gs1, code, tmp, &prep_seq_1, &gen_seq_1); + ret = expand_ccmp_next (op1, code, tmp, &prep_seq_1, &gen_seq_1); cost1 = seq_cost (prep_seq_1, speed_p); cost1 += seq_cost (gen_seq_1, speed_p); } @@ -197,27 +239,22 @@ expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq) rtx_insn *prep_seq_2, *gen_seq_2; if (tmp == NULL || cost1 < COSTS_N_INSNS (25)) tmp2 = targetm.gen_ccmp_first (&prep_seq_2, &gen_seq_2, rcode1, - gimple_assign_rhs1 (gs1), - gimple_assign_rhs2 (gs1)); - + logical_op1_rhs1, logical_op1_rhs2); if (!tmp && !tmp2) return NULL_RTX; - if (tmp2 != NULL) { - ret2 = expand_ccmp_next (gs0, code, tmp2, &prep_seq_2, + ret2 = expand_ccmp_next (op0, code, tmp2, &prep_seq_2, &gen_seq_2); cost2 = seq_cost (prep_seq_2, speed_p); cost2 += seq_cost (gen_seq_2, speed_p); } - if (cost2 < cost1) { *prep_seq = prep_seq_2; *gen_seq = gen_seq_2; return ret2; } - *prep_seq = prep_seq_1; *gen_seq = gen_seq_1; return ret; @@ -227,28 +264,18 @@ expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq) tmp = expand_ccmp_expr_1 (gs1, prep_seq, gen_seq); if (!tmp) return NULL_RTX; - - return expand_ccmp_next (gs0, code, tmp, prep_seq, gen_seq); + return expand_ccmp_next (op0, code, tmp, prep_seq, gen_seq); } } else { gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR); - - if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) == tcc_comparison) - { - tmp = expand_ccmp_expr_1 (gs0, prep_seq, gen_seq); - if (!tmp) - return NULL_RTX; - - return expand_ccmp_next (gs1, code, tmp, prep_seq, gen_seq); - } - else - { - gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR - || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR); - } + gcc_assert (ccmp_tree_comparison_p (op1, bb)); + tmp = expand_ccmp_expr_1 (gs0, prep_seq, gen_seq); + if (!tmp) + return NULL_RTX; + return expand_ccmp_next (op1, code, tmp, prep_seq, gen_seq); } return NULL_RTX; @@ -258,7 +285,7 @@ expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq) Return NULL_RTX if G is not a legal candidate or expand fail. Otherwise return the target. */ rtx -expand_ccmp_expr (gimple *g) +expand_ccmp_expr (gimple *g, machine_mode mode) { rtx_insn *last; rtx tmp; @@ -275,7 +302,6 @@ expand_ccmp_expr (gimple *g) { insn_code icode; machine_mode cc_mode = CCmode; - tree lhs = gimple_assign_lhs (g); rtx_code cmp_code = GET_CODE (tmp); #ifdef SELECT_CC_MODE @@ -284,7 +310,6 @@ expand_ccmp_expr (gimple *g) icode = optab_handler (cstore_optab, cc_mode); if (icode != CODE_FOR_nothing) { - machine_mode mode = TYPE_MODE (TREE_TYPE (lhs)); rtx target = gen_reg_rtx (mode); emit_insn (prep_seq); @@ -300,4 +325,3 @@ expand_ccmp_expr (gimple *g) delete_insns_since (last); return NULL_RTX; } - diff --git a/gcc/ccmp.h b/gcc/ccmp.h index bc1aafbc65e..93d10491eb9 100644 --- a/gcc/ccmp.h +++ b/gcc/ccmp.h @@ -20,6 +20,6 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_CCMP_H #define GCC_CCMP_H -extern rtx expand_ccmp_expr (gimple *); +extern rtx expand_ccmp_expr (gimple *, machine_mode); #endif /* GCC_CCMP_H */ diff --git a/gcc/expr.c b/gcc/expr.c index 753f5efde6c..0a52a3d7209 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -9776,7 +9776,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, if (targetm.gen_ccmp_first) { gcc_checking_assert (targetm.gen_ccmp_next != NULL); - r = expand_ccmp_expr (g); + r = expand_ccmp_expr (g, mode); if (r) break; } -- 2.30.2