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