xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/ccmp.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* Conditional compare related functions
2*8feb0f0bSmrg    Copyright (C) 2014-2020 Free Software Foundation, Inc.
31debfc3dSmrg 
41debfc3dSmrg This file is part of GCC.
51debfc3dSmrg 
61debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
71debfc3dSmrg the terms of the GNU General Public License as published by the Free
81debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
91debfc3dSmrg version.
101debfc3dSmrg 
111debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
121debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
131debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141debfc3dSmrg for more details.
151debfc3dSmrg 
161debfc3dSmrg You should have received a copy of the GNU General Public License
171debfc3dSmrg along with GCC; see the file COPYING3.  If not see
181debfc3dSmrg <http://www.gnu.org/licenses/>.  */
191debfc3dSmrg 
201debfc3dSmrg #include "config.h"
211debfc3dSmrg #include "system.h"
221debfc3dSmrg #include "coretypes.h"
231debfc3dSmrg #include "backend.h"
241debfc3dSmrg #include "target.h"
251debfc3dSmrg #include "rtl.h"
261debfc3dSmrg #include "tree.h"
271debfc3dSmrg #include "gimple.h"
281debfc3dSmrg #include "memmodel.h"
291debfc3dSmrg #include "tm_p.h"
301debfc3dSmrg #include "ssa.h"
311debfc3dSmrg #include "expmed.h"
321debfc3dSmrg #include "optabs.h"
331debfc3dSmrg #include "emit-rtl.h"
341debfc3dSmrg #include "stor-layout.h"
351debfc3dSmrg #include "tree-ssa-live.h"
361debfc3dSmrg #include "tree-outof-ssa.h"
371debfc3dSmrg #include "cfgexpand.h"
381debfc3dSmrg #include "ccmp.h"
391debfc3dSmrg #include "predict.h"
401debfc3dSmrg 
41a2dc1f3fSmrg /* Check whether T is a simple boolean variable or a SSA name
42a2dc1f3fSmrg    set by a comparison operator in the same basic block.  */
43a2dc1f3fSmrg static bool
ccmp_tree_comparison_p(tree t,basic_block bb)44a2dc1f3fSmrg ccmp_tree_comparison_p (tree t, basic_block bb)
45a2dc1f3fSmrg {
46a2dc1f3fSmrg   gimple *g = get_gimple_for_ssa_name (t);
47a2dc1f3fSmrg   tree_code tcode;
48a2dc1f3fSmrg 
49a2dc1f3fSmrg   /* If we have a boolean variable allow it and generate a compare
50a2dc1f3fSmrg      to zero reg when expanding.  */
51a2dc1f3fSmrg   if (!g)
52a2dc1f3fSmrg     return (TREE_CODE (TREE_TYPE (t)) == BOOLEAN_TYPE);
53a2dc1f3fSmrg 
54a2dc1f3fSmrg   /* Check to see if SSA name is set by a comparison operator in
55a2dc1f3fSmrg      the same basic block.  */
56a2dc1f3fSmrg   if (!is_gimple_assign (g))
57a2dc1f3fSmrg     return false;
58a2dc1f3fSmrg   if (bb != gimple_bb (g))
59a2dc1f3fSmrg     return false;
60a2dc1f3fSmrg   tcode = gimple_assign_rhs_code (g);
61a2dc1f3fSmrg   return TREE_CODE_CLASS (tcode) == tcc_comparison;
62a2dc1f3fSmrg }
63a2dc1f3fSmrg 
641debfc3dSmrg /* The following functions expand conditional compare (CCMP) instructions.
651debfc3dSmrg    Here is a short description about the over all algorithm:
661debfc3dSmrg      * ccmp_candidate_p is used to identify the CCMP candidate
671debfc3dSmrg 
681debfc3dSmrg      * expand_ccmp_expr is the main entry, which calls expand_ccmp_expr_1
691debfc3dSmrg        to expand CCMP.
701debfc3dSmrg 
711debfc3dSmrg      * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP.
721debfc3dSmrg        It calls two target hooks gen_ccmp_first and gen_ccmp_next to generate
731debfc3dSmrg        CCMP instructions.
741debfc3dSmrg 	 - gen_ccmp_first expands the first compare in CCMP.
751debfc3dSmrg 	 - gen_ccmp_next expands the following compares.
761debfc3dSmrg 
771debfc3dSmrg        Both hooks return a comparison with the CC register that is equivalent
781debfc3dSmrg        to the value of the gimple comparison.  This is used by the next CCMP
791debfc3dSmrg        and in the final conditional store.
801debfc3dSmrg 
811debfc3dSmrg      * We use cstorecc4 pattern to convert the CCmode intermediate to
821debfc3dSmrg        the integer mode result that expand_normal is expecting.
831debfc3dSmrg 
841debfc3dSmrg    Since the operands of the later compares might clobber CC reg, we do not
851debfc3dSmrg    emit the insns during expand.  We keep the insn sequences in two seq
861debfc3dSmrg 
871debfc3dSmrg      * prep_seq, which includes all the insns to prepare the operands.
881debfc3dSmrg      * gen_seq, which includes all the compare and conditional compares.
891debfc3dSmrg 
901debfc3dSmrg    If all checks OK in expand_ccmp_expr, it emits insns in prep_seq, then
911debfc3dSmrg    insns in gen_seq.  */
921debfc3dSmrg 
931debfc3dSmrg /* Check whether G is a potential conditional compare candidate.  */
941debfc3dSmrg static bool
ccmp_candidate_p(gimple * g)951debfc3dSmrg ccmp_candidate_p (gimple *g)
961debfc3dSmrg {
971debfc3dSmrg   tree lhs, op0, op1;
981debfc3dSmrg   gimple *gs0, *gs1;
99a2dc1f3fSmrg   tree_code tcode;
100a2dc1f3fSmrg   basic_block bb;
1011debfc3dSmrg 
102a2dc1f3fSmrg   if (!g)
103a2dc1f3fSmrg     return false;
104a2dc1f3fSmrg 
105c0a68be4Smrg   tcode = gimple_assign_rhs_code (g);
1061debfc3dSmrg   if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR)
1071debfc3dSmrg     return false;
1081debfc3dSmrg 
1091debfc3dSmrg   lhs = gimple_assign_lhs (g);
110c0a68be4Smrg   op0 = gimple_assign_rhs1 (g);
111c0a68be4Smrg   op1 = gimple_assign_rhs2 (g);
1121debfc3dSmrg   if ((TREE_CODE (op0) != SSA_NAME) || (TREE_CODE (op1) != SSA_NAME)
1131debfc3dSmrg       || !has_single_use (lhs))
1141debfc3dSmrg     return false;
1151debfc3dSmrg 
116c0a68be4Smrg   bb = gimple_bb (g);
117a2dc1f3fSmrg   gs0 = get_gimple_for_ssa_name (op0); /* gs0 may be NULL */
118a2dc1f3fSmrg   gs1 = get_gimple_for_ssa_name (op1); /* gs1 may be NULL */
1191debfc3dSmrg 
120a2dc1f3fSmrg   if (ccmp_tree_comparison_p (op0, bb) && ccmp_tree_comparison_p (op1, bb))
1211debfc3dSmrg     return true;
122a2dc1f3fSmrg   if (ccmp_tree_comparison_p (op0, bb) && ccmp_candidate_p (gs1))
1231debfc3dSmrg     return true;
124a2dc1f3fSmrg   if (ccmp_tree_comparison_p (op1, bb) && ccmp_candidate_p (gs0))
1251debfc3dSmrg     return true;
1261debfc3dSmrg   /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since
127a2dc1f3fSmrg      there is no way to set and maintain the CC flag on both sides of
128a2dc1f3fSmrg      the logical operator at the same time.  */
1291debfc3dSmrg   return false;
1301debfc3dSmrg }
1311debfc3dSmrg 
132a2dc1f3fSmrg /* Extract the comparison we want to do from the tree.  */
133a2dc1f3fSmrg void
get_compare_parts(tree t,int * up,rtx_code * rcode,tree * rhs1,tree * rhs2)134a2dc1f3fSmrg get_compare_parts (tree t, int *up, rtx_code *rcode,
135a2dc1f3fSmrg 		   tree *rhs1, tree *rhs2)
136a2dc1f3fSmrg {
137a2dc1f3fSmrg   tree_code code;
138a2dc1f3fSmrg   gimple *g = get_gimple_for_ssa_name (t);
139a2dc1f3fSmrg   if (g)
140a2dc1f3fSmrg     {
141a2dc1f3fSmrg       *up = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g)));
142a2dc1f3fSmrg       code = gimple_assign_rhs_code (g);
143a2dc1f3fSmrg       *rcode = get_rtx_code (code, *up);
144a2dc1f3fSmrg       *rhs1 = gimple_assign_rhs1 (g);
145a2dc1f3fSmrg       *rhs2 = gimple_assign_rhs2 (g);
146a2dc1f3fSmrg     }
147a2dc1f3fSmrg   else
148a2dc1f3fSmrg     {
149a2dc1f3fSmrg       /* If g is not a comparison operator create a compare to zero.  */
150a2dc1f3fSmrg       *up = 1;
151a2dc1f3fSmrg       *rcode = NE;
152a2dc1f3fSmrg       *rhs1 = t;
153a2dc1f3fSmrg       *rhs2 = build_zero_cst (TREE_TYPE (t));
154a2dc1f3fSmrg     }
155a2dc1f3fSmrg }
156a2dc1f3fSmrg 
1571debfc3dSmrg /* PREV is a comparison with the CC register which represents the
1581debfc3dSmrg    result of the previous CMP or CCMP.  The function expands the
1591debfc3dSmrg    next compare based on G which is ANDed/ORed with the previous
1601debfc3dSmrg    compare depending on CODE.
1611debfc3dSmrg    PREP_SEQ returns all insns to prepare opearands for compare.
1621debfc3dSmrg    GEN_SEQ returns all compare insns.  */
1631debfc3dSmrg static rtx
expand_ccmp_next(tree op,tree_code code,rtx prev,rtx_insn ** prep_seq,rtx_insn ** gen_seq)164a2dc1f3fSmrg expand_ccmp_next (tree op, tree_code code, rtx prev,
1651debfc3dSmrg 		  rtx_insn **prep_seq, rtx_insn **gen_seq)
1661debfc3dSmrg {
1671debfc3dSmrg   rtx_code rcode;
168a2dc1f3fSmrg   int unsignedp;
169a2dc1f3fSmrg   tree rhs1, rhs2;
1701debfc3dSmrg 
171a2dc1f3fSmrg   get_compare_parts(op, &unsignedp, &rcode, &rhs1, &rhs2);
1721debfc3dSmrg   return targetm.gen_ccmp_next (prep_seq, gen_seq, prev, rcode,
173a2dc1f3fSmrg 				rhs1, rhs2, get_rtx_code (code, 0));
1741debfc3dSmrg }
1751debfc3dSmrg 
1761debfc3dSmrg /* Expand conditional compare gimple G.  A typical CCMP sequence is like:
1771debfc3dSmrg 
1781debfc3dSmrg      CC0 = CMP (a, b);
1791debfc3dSmrg      CC1 = CCMP (NE (CC0, 0), CMP (e, f));
1801debfc3dSmrg      ...
1811debfc3dSmrg      CCn = CCMP (NE (CCn-1, 0), CMP (...));
1821debfc3dSmrg 
1831debfc3dSmrg    hook gen_ccmp_first is used to expand the first compare.
1841debfc3dSmrg    hook gen_ccmp_next is used to expand the following CCMP.
1851debfc3dSmrg    PREP_SEQ returns all insns to prepare opearand.
1861debfc3dSmrg    GEN_SEQ returns all compare insns.  */
1871debfc3dSmrg static rtx
expand_ccmp_expr_1(gimple * g,rtx_insn ** prep_seq,rtx_insn ** gen_seq)1881debfc3dSmrg expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq)
1891debfc3dSmrg {
190*8feb0f0bSmrg   tree_code code = gimple_assign_rhs_code (g);
191a2dc1f3fSmrg   basic_block bb = gimple_bb (g);
192a2dc1f3fSmrg 
193*8feb0f0bSmrg   tree op0 = gimple_assign_rhs1 (g);
194*8feb0f0bSmrg   tree op1 = gimple_assign_rhs2 (g);
195a2dc1f3fSmrg   gimple *gs0 = get_gimple_for_ssa_name (op0);
196a2dc1f3fSmrg   gimple *gs1 = get_gimple_for_ssa_name (op1);
1971debfc3dSmrg   rtx tmp;
1981debfc3dSmrg 
1991debfc3dSmrg   gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR);
2001debfc3dSmrg 
201a2dc1f3fSmrg   if (ccmp_tree_comparison_p (op0, bb))
2021debfc3dSmrg     {
203a2dc1f3fSmrg       if (ccmp_tree_comparison_p (op1, bb))
2041debfc3dSmrg 	{
2051debfc3dSmrg 	  int unsignedp0, unsignedp1;
2061debfc3dSmrg 	  rtx_code rcode0, rcode1;
207a2dc1f3fSmrg 	  tree logical_op0_rhs1, logical_op0_rhs2;
208a2dc1f3fSmrg 	  tree logical_op1_rhs1, logical_op1_rhs2;
2091debfc3dSmrg 	  int speed_p = optimize_insn_for_speed_p ();
210a2dc1f3fSmrg 
2111debfc3dSmrg 	  rtx tmp2 = NULL_RTX, ret = NULL_RTX, ret2 = NULL_RTX;
2121debfc3dSmrg 	  unsigned cost1 = MAX_COST;
2131debfc3dSmrg 	  unsigned cost2 = MAX_COST;
2141debfc3dSmrg 
215a2dc1f3fSmrg 	  get_compare_parts (op0, &unsignedp0, &rcode0,
216a2dc1f3fSmrg 			     &logical_op0_rhs1, &logical_op0_rhs2);
217a2dc1f3fSmrg 
218a2dc1f3fSmrg 	  get_compare_parts (op1, &unsignedp1, &rcode1,
219a2dc1f3fSmrg 			     &logical_op1_rhs1, &logical_op1_rhs2);
2201debfc3dSmrg 
2211debfc3dSmrg 	  rtx_insn *prep_seq_1, *gen_seq_1;
2221debfc3dSmrg 	  tmp = targetm.gen_ccmp_first (&prep_seq_1, &gen_seq_1, rcode0,
223a2dc1f3fSmrg 					logical_op0_rhs1, logical_op0_rhs2);
2241debfc3dSmrg 	  if (tmp != NULL)
2251debfc3dSmrg 	    {
226a2dc1f3fSmrg 	      ret = expand_ccmp_next (op1, code, tmp, &prep_seq_1, &gen_seq_1);
2271debfc3dSmrg 	      cost1 = seq_cost (prep_seq_1, speed_p);
2281debfc3dSmrg 	      cost1 += seq_cost (gen_seq_1, speed_p);
2291debfc3dSmrg 	    }
2301debfc3dSmrg 
2311debfc3dSmrg 	  /* FIXME: Temporary workaround for PR69619.
2321debfc3dSmrg 	     Avoid exponential compile time due to expanding gs0 and gs1 twice.
2331debfc3dSmrg 	     If gs0 and gs1 are complex, the cost will be high, so avoid
2341debfc3dSmrg 	     reevaluation if above an arbitrary threshold.  */
2351debfc3dSmrg 	  rtx_insn *prep_seq_2, *gen_seq_2;
2361debfc3dSmrg 	  if (tmp == NULL || cost1 < COSTS_N_INSNS (25))
2371debfc3dSmrg 	    tmp2 = targetm.gen_ccmp_first (&prep_seq_2, &gen_seq_2, rcode1,
238a2dc1f3fSmrg 					   logical_op1_rhs1, logical_op1_rhs2);
2391debfc3dSmrg 	  if (!tmp && !tmp2)
2401debfc3dSmrg 	    return NULL_RTX;
2411debfc3dSmrg 	  if (tmp2 != NULL)
2421debfc3dSmrg 	    {
243a2dc1f3fSmrg 	      ret2 = expand_ccmp_next (op0, code, tmp2, &prep_seq_2,
2441debfc3dSmrg 				       &gen_seq_2);
2451debfc3dSmrg 	      cost2 = seq_cost (prep_seq_2, speed_p);
2461debfc3dSmrg 	      cost2 += seq_cost (gen_seq_2, speed_p);
2471debfc3dSmrg 	    }
2481debfc3dSmrg 	  if (cost2 < cost1)
2491debfc3dSmrg 	    {
2501debfc3dSmrg 	      *prep_seq = prep_seq_2;
2511debfc3dSmrg 	      *gen_seq = gen_seq_2;
2521debfc3dSmrg 	      return ret2;
2531debfc3dSmrg 	    }
2541debfc3dSmrg 	  *prep_seq = prep_seq_1;
2551debfc3dSmrg 	  *gen_seq = gen_seq_1;
2561debfc3dSmrg 	  return ret;
2571debfc3dSmrg 	}
2581debfc3dSmrg       else
2591debfc3dSmrg 	{
2601debfc3dSmrg 	  tmp = expand_ccmp_expr_1 (gs1, prep_seq, gen_seq);
2611debfc3dSmrg 	  if (!tmp)
2621debfc3dSmrg 	    return NULL_RTX;
263a2dc1f3fSmrg 	  return expand_ccmp_next (op0, code, tmp, prep_seq, gen_seq);
2641debfc3dSmrg 	}
2651debfc3dSmrg     }
2661debfc3dSmrg   else
2671debfc3dSmrg     {
2681debfc3dSmrg       gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR
2691debfc3dSmrg                   || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR);
270a2dc1f3fSmrg       gcc_assert (ccmp_tree_comparison_p (op1, bb));
2711debfc3dSmrg       tmp = expand_ccmp_expr_1 (gs0, prep_seq, gen_seq);
2721debfc3dSmrg       if (!tmp)
2731debfc3dSmrg 	return NULL_RTX;
274a2dc1f3fSmrg       return expand_ccmp_next (op1, code, tmp, prep_seq, gen_seq);
2751debfc3dSmrg     }
2761debfc3dSmrg 
2771debfc3dSmrg   return NULL_RTX;
2781debfc3dSmrg }
2791debfc3dSmrg 
2801debfc3dSmrg /* Main entry to expand conditional compare statement G.
2811debfc3dSmrg    Return NULL_RTX if G is not a legal candidate or expand fail.
2821debfc3dSmrg    Otherwise return the target.  */
2831debfc3dSmrg rtx
expand_ccmp_expr(gimple * g,machine_mode mode)284a2dc1f3fSmrg expand_ccmp_expr (gimple *g, machine_mode mode)
2851debfc3dSmrg {
2861debfc3dSmrg   rtx_insn *last;
2871debfc3dSmrg   rtx tmp;
2881debfc3dSmrg 
2891debfc3dSmrg   if (!ccmp_candidate_p (g))
2901debfc3dSmrg     return NULL_RTX;
2911debfc3dSmrg 
2921debfc3dSmrg   last = get_last_insn ();
2931debfc3dSmrg 
2941debfc3dSmrg   rtx_insn *prep_seq = NULL, *gen_seq = NULL;
2951debfc3dSmrg   tmp = expand_ccmp_expr_1 (g, &prep_seq, &gen_seq);
2961debfc3dSmrg 
2971debfc3dSmrg   if (tmp)
2981debfc3dSmrg     {
2991debfc3dSmrg       insn_code icode;
3001debfc3dSmrg       machine_mode cc_mode = CCmode;
3011debfc3dSmrg       rtx_code cmp_code = GET_CODE (tmp);
3021debfc3dSmrg 
3031debfc3dSmrg #ifdef SELECT_CC_MODE
3041debfc3dSmrg       cc_mode = SELECT_CC_MODE (cmp_code, XEXP (tmp, 0), const0_rtx);
3051debfc3dSmrg #endif
3061debfc3dSmrg       icode = optab_handler (cstore_optab, cc_mode);
3071debfc3dSmrg       if (icode != CODE_FOR_nothing)
3081debfc3dSmrg 	{
3091debfc3dSmrg 	  rtx target = gen_reg_rtx (mode);
3101debfc3dSmrg 
3111debfc3dSmrg 	  emit_insn (prep_seq);
3121debfc3dSmrg 	  emit_insn (gen_seq);
3131debfc3dSmrg 
3141debfc3dSmrg 	  tmp = emit_cstore (target, icode, cmp_code, cc_mode, cc_mode,
3151debfc3dSmrg 			     0, XEXP (tmp, 0), const0_rtx, 1, mode);
3161debfc3dSmrg 	  if (tmp)
3171debfc3dSmrg 	    return tmp;
3181debfc3dSmrg 	}
3191debfc3dSmrg     }
3201debfc3dSmrg   /* Clean up.  */
3211debfc3dSmrg   delete_insns_since (last);
3221debfc3dSmrg   return NULL_RTX;
3231debfc3dSmrg }
324