From f06cd23dc761a7769f8bdca26a42db59b71dec54 Mon Sep 17 00:00:00 2001 From: Zhenqiang Chen Date: Mon, 17 Nov 2014 06:03:07 +0000 Subject: [PATCH] Makefile.in: Add ccmp.o. 2014-11-17 Zhenqiang Chen * Makefile.in: Add ccmp.o. * ccmp.c: New file. * ccmp.h: New file. * expr.c: include "ccmp.h" (expand_cond_expr_using_cmove): Handle VOIDmode. (expand_expr_real_1): Try to expand ccmp. From-SVN: r217641 --- gcc/ChangeLog | 9 ++ gcc/Makefile.in | 1 + gcc/ccmp.c | 306 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/ccmp.h | 25 ++++ gcc/expr.c | 14 ++- 5 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 gcc/ccmp.c create mode 100644 gcc/ccmp.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 16b3e35b5fa..c5da3318e8c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2014-11-17 Zhenqiang Chen + + * Makefile.in: Add ccmp.o. + * ccmp.c: New file. + * ccmp.h: New file. + * expr.c: include "ccmp.h" + (expand_cond_expr_using_cmove): Handle VOIDmode. + (expand_expr_real_1): Try to expand ccmp. + 2014-11-17 Zhenqiang Chen * cfgexpand.c (expand_gimple_cond): Check ccmp. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 32f307282c2..49f94e751b3 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1174,6 +1174,7 @@ OBJS = \ builtins.o \ caller-save.o \ calls.o \ + ccmp.o \ cfg.o \ cfganal.o \ cfgbuild.o \ diff --git a/gcc/ccmp.c b/gcc/ccmp.c new file mode 100644 index 00000000000..9c239e2b5a8 --- /dev/null +++ b/gcc/ccmp.c @@ -0,0 +1,306 @@ +/* Conditional compare related functions + Copyright (C) 2014-2014 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "tm_p.h" +#include "tree.h" +#include "stringpool.h" +#include "stor-layout.h" +#include "regs.h" +#include "expr.h" +#include "insn-codes.h" +#include "optabs.h" +#include "tree-iterator.h" +#include "predict.h" +#include "dominance.h" +#include "cfg.h" +#include "basic-block.h" +#include "tree-ssa-alias.h" +#include "internal-fn.h" +#include "gimple-expr.h" +#include "is-a.h" +#include "gimple.h" +#include "gimple-ssa.h" +#include "tree-ssanames.h" +#include "target.h" +#include "common/common-target.h" +#include "df.h" +#include "tree-ssa-live.h" +#include "tree-outof-ssa.h" +#include "cfgexpand.h" +#include "tree-phinodes.h" +#include "ssa-iterators.h" +#include "expmed.h" +#include "ccmp.h" + +/* 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 + + * expand_ccmp_expr is the main entry, which calls expand_ccmp_expr_1 + to expand CCMP. + + * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP. + It calls two target hooks gen_ccmp_first and gen_ccmp_next to generate + CCMP instructions. + - gen_ccmp_first expands the first compare in CCMP. + - gen_ccmp_next expands the following compares. + + * If the final result is not used in a COND_EXPR (checked by function + used_in_cond_stmt_p), it calls cstorecc4 pattern to store the CC to a + general register. */ + +/* Check whether G is a potential conditional compare candidate. */ +static bool +ccmp_candidate_p (gimple g) +{ + tree rhs = gimple_assign_rhs_to_tree (g); + tree lhs, op0, op1; + gimple gs0, gs1; + enum tree_code tcode, tcode0, tcode1; + 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); + + 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; + + if (!(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0))) + || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0)))) + || !(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))) + || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))))) + return false; + + 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) + return true; + if (TREE_CODE_CLASS (tcode0) == tcc_comparison + && ccmp_candidate_p (gs1)) + return true; + else if (TREE_CODE_CLASS (tcode1) == tcc_comparison + && 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. */ + return false; +} + +/* Check whether EXP is used in a GIMPLE_COND statement or not. */ +static bool +used_in_cond_stmt_p (tree exp) +{ + bool expand_cond = false; + imm_use_iterator ui; + gimple use_stmt; + FOR_EACH_IMM_USE_STMT (use_stmt, ui, exp) + if (gimple_code (use_stmt) == GIMPLE_COND) + { + tree op1 = gimple_cond_rhs (use_stmt); + if (integer_zerop (op1)) + expand_cond = true; + BREAK_FROM_IMM_USE_STMT (ui); + } + else if (gimple_code (use_stmt) == GIMPLE_ASSIGN + && gimple_expr_code (use_stmt) == COND_EXPR) + { + if (gimple_assign_rhs1 (use_stmt) == exp) + expand_cond = true; + } + + return expand_cond; +} + +/* Expand conditional compare gimple G. A typical CCMP sequence is like: + + CC0 = CMP (a, b); + CC1 = CCMP (NE (CC0, 0), CMP (e, f)); + ... + CCn = CCMP (NE (CCn-1, 0), CMP (...)); + + hook gen_ccmp_first is used to expand the first compare. + hook gen_ccmp_next is used to expand the following CCMP. */ +static rtx +expand_ccmp_expr_1 (gimple g) +{ + tree exp = gimple_assign_rhs_to_tree (g); + enum 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)); + rtx tmp; + enum tree_code code0 = gimple_assign_rhs_code (gs0); + enum 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 (TREE_CODE_CLASS (code1) == tcc_comparison) + { + int unsignedp0, unsignedp1; + enum rtx_code rcode0, rcode1; + rtx op0, op1, op2, op3, tmp; + + unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0))); + rcode0 = get_rtx_code (code0, unsignedp0); + unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1))); + rcode1 = get_rtx_code (code1, unsignedp1); + + expand_operands (gimple_assign_rhs1 (gs0), + gimple_assign_rhs2 (gs0), + NULL_RTX, &op0, &op1, EXPAND_NORMAL); + + /* Since the operands of GS1 might clobber CC reg, we expand the + operands of GS1 before GEN_CCMP_FIRST. */ + expand_operands (gimple_assign_rhs1 (gs1), + gimple_assign_rhs2 (gs1), + NULL_RTX, &op2, &op3, EXPAND_NORMAL); + tmp = targetm.gen_ccmp_first (rcode0, op0, op1); + if (!tmp) + return NULL_RTX; + + return targetm.gen_ccmp_next (tmp, rcode1, op2, op3, + get_rtx_code (code, 0)); + } + else + { + rtx op0, op1; + enum rtx_code rcode; + int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0))); + + rcode = get_rtx_code (gimple_assign_rhs_code (gs0), unsignedp); + + /* Hoist the preparation operations above the entire + conditional compare sequence. */ + expand_operands (gimple_assign_rhs1 (gs0), + gimple_assign_rhs2 (gs0), + NULL_RTX, &op0, &op1, EXPAND_NORMAL); + + gcc_assert (code1 == BIT_AND_EXPR || code1 == BIT_IOR_EXPR); + + /* Note: We swap the order to make the recursive function work. */ + tmp = expand_ccmp_expr_1 (gs1); + if (tmp) + return targetm.gen_ccmp_next (tmp, rcode, op0, op1, + get_rtx_code (code, 0)); + } + } + 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) + { + rtx op0, op1; + enum rtx_code rcode; + int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1))); + + rcode = get_rtx_code (gimple_assign_rhs_code (gs1), unsignedp); + + /* Hoist the preparation operations above the entire + conditional compare sequence. */ + expand_operands (gimple_assign_rhs1 (gs1), + gimple_assign_rhs2 (gs1), + NULL_RTX, &op0, &op1, EXPAND_NORMAL); + tmp = expand_ccmp_expr_1 (gs0); + if (tmp) + return targetm.gen_ccmp_next (tmp, rcode, op0, op1, + get_rtx_code (code, 0)); + } + else + { + gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR + || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR); + } + } + + return NULL_RTX; +} + +/* Main entry to expand conditional compare statement G. + Return NULL_RTX if G is not a legal candidate or expand fail. + Otherwise return the target. */ +rtx +expand_ccmp_expr (gimple g) +{ + rtx_insn *last; + rtx tmp; + + if (!ccmp_candidate_p (g)) + return NULL_RTX; + + last = get_last_insn (); + tmp = expand_ccmp_expr_1 (g); + + if (tmp) + { + enum insn_code icode; + enum machine_mode cc_mode = CCmode; + + tree lhs = gimple_assign_lhs (g); + /* TMP should be CC. If it is used in a GIMPLE_COND, just return it. + Note: Target needs to define "cbranchcc4". */ + if (used_in_cond_stmt_p (lhs)) + return tmp; + +#ifdef SELECT_CC_MODE + cc_mode = SELECT_CC_MODE (NE, tmp, const0_rtx); +#endif + /* If TMP is not used in a GIMPLE_COND, store it with a csctorecc4_optab. + Note: Target needs to define "cstorecc4". */ + icode = optab_handler (cstore_optab, cc_mode); + if (icode != CODE_FOR_nothing) + { + tree lhs = gimple_assign_lhs (g); + enum machine_mode mode = TYPE_MODE (TREE_TYPE (lhs)); + rtx target = gen_reg_rtx (mode); + tmp = emit_cstore (target, icode, NE, cc_mode, cc_mode, + 0, tmp, const0_rtx, 1, mode); + if (tmp) + return tmp; + } + } + /* Clean up. */ + delete_insns_since (last); + return NULL_RTX; +} + diff --git a/gcc/ccmp.h b/gcc/ccmp.h new file mode 100644 index 00000000000..6144dbbb35d --- /dev/null +++ b/gcc/ccmp.h @@ -0,0 +1,25 @@ +/* Conditional comapre related functions. + Copyright (C) 2014-2014 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_CCMP_H +#define GCC_CCMP_H + +extern rtx expand_ccmp_expr (gimple); + +#endif /* GCC_CCMP_H */ diff --git a/gcc/expr.c b/gcc/expr.c index 7b1cb29043e..093f544a993 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "tree-chkp.h" #include "rtl-chkp.h" +#include "ccmp.h" #ifndef STACK_PUSH_CODE #ifdef STACK_GROWS_DOWNWARD @@ -8062,7 +8063,9 @@ expand_cond_expr_using_cmove (tree treeop0 ATTRIBUTE_UNUSED, op00 = expand_normal (treeop0); op01 = const0_rtx; comparison_code = NE; - comparison_mode = TYPE_MODE (TREE_TYPE (treeop0)); + comparison_mode = GET_MODE (op00); + if (comparison_mode == VOIDmode) + comparison_mode = TYPE_MODE (TREE_TYPE (treeop0)); } if (GET_MODE (op1) != mode) @@ -9504,6 +9507,15 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, /* Fallthru */ case GIMPLE_BINARY_RHS: ops.op1 = gimple_assign_rhs2 (g); + + /* Try to expand conditonal compare. */ + if (targetm.gen_ccmp_first) + { + gcc_checking_assert (targetm.gen_ccmp_next != NULL); + r = expand_ccmp_expr (g); + if (r) + break; + } /* Fallthru */ case GIMPLE_UNARY_RHS: ops.op0 = gimple_assign_rhs1 (g); -- 2.30.2