1 /* Conditional compare related functions
2 Copyright (C) 2014-2014 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
22 #include "coretypes.h"
27 #include "stringpool.h"
28 #include "stor-layout.h"
31 #include "insn-codes.h"
33 #include "tree-iterator.h"
35 #include "dominance.h"
37 #include "basic-block.h"
38 #include "tree-ssa-alias.h"
39 #include "internal-fn.h"
40 #include "gimple-expr.h"
43 #include "gimple-ssa.h"
44 #include "tree-ssanames.h"
46 #include "common/common-target.h"
48 #include "tree-ssa-live.h"
49 #include "tree-outof-ssa.h"
50 #include "cfgexpand.h"
51 #include "tree-phinodes.h"
52 #include "ssa-iterators.h"
56 /* The following functions expand conditional compare (CCMP) instructions.
57 Here is a short description about the over all algorithm:
58 * ccmp_candidate_p is used to identify the CCMP candidate
60 * expand_ccmp_expr is the main entry, which calls expand_ccmp_expr_1
63 * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP.
64 It calls two target hooks gen_ccmp_first and gen_ccmp_next to generate
66 - gen_ccmp_first expands the first compare in CCMP.
67 - gen_ccmp_next expands the following compares.
69 * If the final result is not used in a COND_EXPR (checked by function
70 used_in_cond_stmt_p), it calls cstorecc4 pattern to store the CC to a
73 /* Check whether G is a potential conditional compare candidate. */
75 ccmp_candidate_p (gimple g
)
77 tree rhs
= gimple_assign_rhs_to_tree (g
);
80 enum tree_code tcode
, tcode0
, tcode1
;
81 tcode
= TREE_CODE (rhs
);
83 if (tcode
!= BIT_AND_EXPR
&& tcode
!= BIT_IOR_EXPR
)
86 lhs
= gimple_assign_lhs (g
);
87 op0
= TREE_OPERAND (rhs
, 0);
88 op1
= TREE_OPERAND (rhs
, 1);
90 if ((TREE_CODE (op0
) != SSA_NAME
) || (TREE_CODE (op1
) != SSA_NAME
)
91 || !has_single_use (lhs
))
94 gs0
= get_gimple_for_ssa_name (op0
);
95 gs1
= get_gimple_for_ssa_name (op1
);
96 if (!gs0
|| !gs1
|| !is_gimple_assign (gs0
) || !is_gimple_assign (gs1
)
97 /* g, gs0 and gs1 must be in the same basic block, since current stage
98 is out-of-ssa. We can not guarantee the correctness when forwording
99 the gs0 and gs1 into g whithout DATAFLOW analysis. */
100 || gimple_bb (gs0
) != gimple_bb (gs1
)
101 || gimple_bb (gs0
) != gimple_bb (g
))
104 if (!(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0
)))
105 || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0
))))
106 || !(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1
)))
107 || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1
)))))
110 tcode0
= gimple_assign_rhs_code (gs0
);
111 tcode1
= gimple_assign_rhs_code (gs1
);
112 if (TREE_CODE_CLASS (tcode0
) == tcc_comparison
113 && TREE_CODE_CLASS (tcode1
) == tcc_comparison
)
115 if (TREE_CODE_CLASS (tcode0
) == tcc_comparison
116 && ccmp_candidate_p (gs1
))
118 else if (TREE_CODE_CLASS (tcode1
) == tcc_comparison
119 && ccmp_candidate_p (gs0
))
121 /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since
122 there is no way to set the CC flag. */
126 /* Check whether EXP is used in a GIMPLE_COND statement or not. */
128 used_in_cond_stmt_p (tree exp
)
130 bool expand_cond
= false;
133 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, exp
)
134 if (gimple_code (use_stmt
) == GIMPLE_COND
)
136 tree op1
= gimple_cond_rhs (use_stmt
);
137 if (integer_zerop (op1
))
139 BREAK_FROM_IMM_USE_STMT (ui
);
141 else if (gimple_code (use_stmt
) == GIMPLE_ASSIGN
142 && gimple_expr_code (use_stmt
) == COND_EXPR
)
144 if (gimple_assign_rhs1 (use_stmt
) == exp
)
151 /* Expand conditional compare gimple G. A typical CCMP sequence is like:
154 CC1 = CCMP (NE (CC0, 0), CMP (e, f));
156 CCn = CCMP (NE (CCn-1, 0), CMP (...));
158 hook gen_ccmp_first is used to expand the first compare.
159 hook gen_ccmp_next is used to expand the following CCMP. */
161 expand_ccmp_expr_1 (gimple g
)
163 tree exp
= gimple_assign_rhs_to_tree (g
);
164 enum tree_code code
= TREE_CODE (exp
);
165 gimple gs0
= get_gimple_for_ssa_name (TREE_OPERAND (exp
, 0));
166 gimple gs1
= get_gimple_for_ssa_name (TREE_OPERAND (exp
, 1));
168 enum tree_code code0
= gimple_assign_rhs_code (gs0
);
169 enum tree_code code1
= gimple_assign_rhs_code (gs1
);
171 gcc_assert (code
== BIT_AND_EXPR
|| code
== BIT_IOR_EXPR
);
172 gcc_assert (gs0
&& gs1
&& is_gimple_assign (gs0
) && is_gimple_assign (gs1
));
174 if (TREE_CODE_CLASS (code0
) == tcc_comparison
)
176 if (TREE_CODE_CLASS (code1
) == tcc_comparison
)
178 int unsignedp0
, unsignedp1
;
179 enum rtx_code rcode0
, rcode1
;
180 rtx op0
, op1
, op2
, op3
, tmp
;
182 unsignedp0
= TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0
)));
183 rcode0
= get_rtx_code (code0
, unsignedp0
);
184 unsignedp1
= TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1
)));
185 rcode1
= get_rtx_code (code1
, unsignedp1
);
187 expand_operands (gimple_assign_rhs1 (gs0
),
188 gimple_assign_rhs2 (gs0
),
189 NULL_RTX
, &op0
, &op1
, EXPAND_NORMAL
);
191 /* Since the operands of GS1 might clobber CC reg, we expand the
192 operands of GS1 before GEN_CCMP_FIRST. */
193 expand_operands (gimple_assign_rhs1 (gs1
),
194 gimple_assign_rhs2 (gs1
),
195 NULL_RTX
, &op2
, &op3
, EXPAND_NORMAL
);
196 tmp
= targetm
.gen_ccmp_first (rcode0
, op0
, op1
);
200 return targetm
.gen_ccmp_next (tmp
, rcode1
, op2
, op3
,
201 get_rtx_code (code
, 0));
207 int unsignedp
= TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0
)));
209 rcode
= get_rtx_code (gimple_assign_rhs_code (gs0
), unsignedp
);
211 /* Hoist the preparation operations above the entire
212 conditional compare sequence. */
213 expand_operands (gimple_assign_rhs1 (gs0
),
214 gimple_assign_rhs2 (gs0
),
215 NULL_RTX
, &op0
, &op1
, EXPAND_NORMAL
);
217 gcc_assert (code1
== BIT_AND_EXPR
|| code1
== BIT_IOR_EXPR
);
219 /* Note: We swap the order to make the recursive function work. */
220 tmp
= expand_ccmp_expr_1 (gs1
);
222 return targetm
.gen_ccmp_next (tmp
, rcode
, op0
, op1
,
223 get_rtx_code (code
, 0));
228 gcc_assert (gimple_assign_rhs_code (gs0
) == BIT_AND_EXPR
229 || gimple_assign_rhs_code (gs0
) == BIT_IOR_EXPR
);
231 if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1
)) == tcc_comparison
)
235 int unsignedp
= TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1
)));
237 rcode
= get_rtx_code (gimple_assign_rhs_code (gs1
), unsignedp
);
239 /* Hoist the preparation operations above the entire
240 conditional compare sequence. */
241 expand_operands (gimple_assign_rhs1 (gs1
),
242 gimple_assign_rhs2 (gs1
),
243 NULL_RTX
, &op0
, &op1
, EXPAND_NORMAL
);
244 tmp
= expand_ccmp_expr_1 (gs0
);
246 return targetm
.gen_ccmp_next (tmp
, rcode
, op0
, op1
,
247 get_rtx_code (code
, 0));
251 gcc_assert (gimple_assign_rhs_code (gs1
) == BIT_AND_EXPR
252 || gimple_assign_rhs_code (gs1
) == BIT_IOR_EXPR
);
259 /* Main entry to expand conditional compare statement G.
260 Return NULL_RTX if G is not a legal candidate or expand fail.
261 Otherwise return the target. */
263 expand_ccmp_expr (gimple g
)
268 if (!ccmp_candidate_p (g
))
271 last
= get_last_insn ();
272 tmp
= expand_ccmp_expr_1 (g
);
276 enum insn_code icode
;
277 enum machine_mode cc_mode
= CCmode
;
279 tree lhs
= gimple_assign_lhs (g
);
280 /* TMP should be CC. If it is used in a GIMPLE_COND, just return it.
281 Note: Target needs to define "cbranchcc4". */
282 if (used_in_cond_stmt_p (lhs
))
285 #ifdef SELECT_CC_MODE
286 cc_mode
= SELECT_CC_MODE (NE
, tmp
, const0_rtx
);
288 /* If TMP is not used in a GIMPLE_COND, store it with a csctorecc4_optab.
289 Note: Target needs to define "cstorecc4". */
290 icode
= optab_handler (cstore_optab
, cc_mode
);
291 if (icode
!= CODE_FOR_nothing
)
293 tree lhs
= gimple_assign_lhs (g
);
294 enum machine_mode mode
= TYPE_MODE (TREE_TYPE (lhs
));
295 rtx target
= gen_reg_rtx (mode
);
296 tmp
= emit_cstore (target
, icode
, NE
, cc_mode
, cc_mode
,
297 0, tmp
, const0_rtx
, 1, mode
);
303 delete_insns_since (last
);