* lib/ubsan-dg.exp (check_effective_target_fsanitize_undefined):
[official-gcc.git] / gcc / ccmp.c
blob9c239e2b5a84613be025f11ea5defe54b353e1fd
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
9 version.
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
14 for more details.
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/>. */
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "tm.h"
24 #include "rtl.h"
25 #include "tm_p.h"
26 #include "tree.h"
27 #include "stringpool.h"
28 #include "stor-layout.h"
29 #include "regs.h"
30 #include "expr.h"
31 #include "insn-codes.h"
32 #include "optabs.h"
33 #include "tree-iterator.h"
34 #include "predict.h"
35 #include "dominance.h"
36 #include "cfg.h"
37 #include "basic-block.h"
38 #include "tree-ssa-alias.h"
39 #include "internal-fn.h"
40 #include "gimple-expr.h"
41 #include "is-a.h"
42 #include "gimple.h"
43 #include "gimple-ssa.h"
44 #include "tree-ssanames.h"
45 #include "target.h"
46 #include "common/common-target.h"
47 #include "df.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"
53 #include "expmed.h"
54 #include "ccmp.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
61 to expand CCMP.
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
65 CCMP instructions.
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
71 general register. */
73 /* Check whether G is a potential conditional compare candidate. */
74 static bool
75 ccmp_candidate_p (gimple g)
77 tree rhs = gimple_assign_rhs_to_tree (g);
78 tree lhs, op0, op1;
79 gimple gs0, gs1;
80 enum tree_code tcode, tcode0, tcode1;
81 tcode = TREE_CODE (rhs);
83 if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR)
84 return false;
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))
92 return false;
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))
102 return false;
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)))))
108 return false;
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)
114 return true;
115 if (TREE_CODE_CLASS (tcode0) == tcc_comparison
116 && ccmp_candidate_p (gs1))
117 return true;
118 else if (TREE_CODE_CLASS (tcode1) == tcc_comparison
119 && ccmp_candidate_p (gs0))
120 return true;
121 /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since
122 there is no way to set the CC flag. */
123 return false;
126 /* Check whether EXP is used in a GIMPLE_COND statement or not. */
127 static bool
128 used_in_cond_stmt_p (tree exp)
130 bool expand_cond = false;
131 imm_use_iterator ui;
132 gimple use_stmt;
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))
138 expand_cond = true;
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)
145 expand_cond = true;
148 return expand_cond;
151 /* Expand conditional compare gimple G. A typical CCMP sequence is like:
153 CC0 = CMP (a, b);
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. */
160 static rtx
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));
167 rtx tmp;
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);
197 if (!tmp)
198 return NULL_RTX;
200 return targetm.gen_ccmp_next (tmp, rcode1, op2, op3,
201 get_rtx_code (code, 0));
203 else
205 rtx op0, op1;
206 enum rtx_code rcode;
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);
221 if (tmp)
222 return targetm.gen_ccmp_next (tmp, rcode, op0, op1,
223 get_rtx_code (code, 0));
226 else
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)
233 rtx op0, op1;
234 enum rtx_code rcode;
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);
245 if (tmp)
246 return targetm.gen_ccmp_next (tmp, rcode, op0, op1,
247 get_rtx_code (code, 0));
249 else
251 gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR
252 || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR);
256 return NULL_RTX;
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)
265 rtx_insn *last;
266 rtx tmp;
268 if (!ccmp_candidate_p (g))
269 return NULL_RTX;
271 last = get_last_insn ();
272 tmp = expand_ccmp_expr_1 (g);
274 if (tmp)
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))
283 return tmp;
285 #ifdef SELECT_CC_MODE
286 cc_mode = SELECT_CC_MODE (NE, tmp, const0_rtx);
287 #endif
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);
298 if (tmp)
299 return tmp;
302 /* Clean up. */
303 delete_insns_since (last);
304 return NULL_RTX;