File: | build/gcc/ccmp.cc |
Warning: | line 250, column 18 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Conditional compare related functions | |||
2 | Copyright (C) 2014-2023 Free Software Foundation, Inc. | |||
3 | ||||
4 | This file is part of GCC. | |||
5 | ||||
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. | |||
10 | ||||
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. | |||
15 | ||||
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/>. */ | |||
19 | ||||
20 | #include "config.h" | |||
21 | #include "system.h" | |||
22 | #include "coretypes.h" | |||
23 | #include "backend.h" | |||
24 | #include "target.h" | |||
25 | #include "rtl.h" | |||
26 | #include "tree.h" | |||
27 | #include "gimple.h" | |||
28 | #include "memmodel.h" | |||
29 | #include "tm_p.h" | |||
30 | #include "ssa.h" | |||
31 | #include "expmed.h" | |||
32 | #include "optabs.h" | |||
33 | #include "emit-rtl.h" | |||
34 | #include "stor-layout.h" | |||
35 | #include "tree-ssa-live.h" | |||
36 | #include "tree-outof-ssa.h" | |||
37 | #include "cfgexpand.h" | |||
38 | #include "ccmp.h" | |||
39 | #include "predict.h" | |||
40 | ||||
41 | /* Check whether T is a simple boolean variable or a SSA name | |||
42 | set by a comparison operator in the same basic block. */ | |||
43 | static bool | |||
44 | ccmp_tree_comparison_p (tree t, basic_block bb) | |||
45 | { | |||
46 | gimple *g = get_gimple_for_ssa_name (t); | |||
47 | tree_code tcode; | |||
48 | ||||
49 | /* If we have a boolean variable allow it and generate a compare | |||
50 | to zero reg when expanding. */ | |||
51 | if (!g) | |||
52 | return (TREE_CODE (TREE_TYPE (t))((enum tree_code) (((contains_struct_check ((t), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ccmp.cc" , 52, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE); | |||
53 | ||||
54 | /* Check to see if SSA name is set by a comparison operator in | |||
55 | the same basic block. */ | |||
56 | if (!is_gimple_assign (g)) | |||
57 | return false; | |||
58 | if (bb != gimple_bb (g)) | |||
59 | return false; | |||
60 | tcode = gimple_assign_rhs_code (g); | |||
61 | return TREE_CODE_CLASS (tcode)tree_code_type_tmpl <0>::tree_code_type[(int) (tcode)] == tcc_comparison; | |||
62 | } | |||
63 | ||||
64 | /* The following functions expand conditional compare (CCMP) instructions. | |||
65 | Here is a short description about the over all algorithm: | |||
66 | * ccmp_candidate_p is used to identify the CCMP candidate | |||
67 | ||||
68 | * expand_ccmp_expr is the main entry, which calls expand_ccmp_expr_1 | |||
69 | to expand CCMP. | |||
70 | ||||
71 | * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP. | |||
72 | It calls two target hooks gen_ccmp_first and gen_ccmp_next to generate | |||
73 | CCMP instructions. | |||
74 | - gen_ccmp_first expands the first compare in CCMP. | |||
75 | - gen_ccmp_next expands the following compares. | |||
76 | ||||
77 | Both hooks return a comparison with the CC register that is equivalent | |||
78 | to the value of the gimple comparison. This is used by the next CCMP | |||
79 | and in the final conditional store. | |||
80 | ||||
81 | * We use cstorecc4 pattern to convert the CCmode intermediate to | |||
82 | the integer mode result that expand_normal is expecting. | |||
83 | ||||
84 | Since the operands of the later compares might clobber CC reg, we do not | |||
85 | emit the insns during expand. We keep the insn sequences in two seq | |||
86 | ||||
87 | * prep_seq, which includes all the insns to prepare the operands. | |||
88 | * gen_seq, which includes all the compare and conditional compares. | |||
89 | ||||
90 | If all checks OK in expand_ccmp_expr, it emits insns in prep_seq, then | |||
91 | insns in gen_seq. */ | |||
92 | ||||
93 | /* Check whether G is a potential conditional compare candidate. */ | |||
94 | static bool | |||
95 | ccmp_candidate_p (gimple *g) | |||
96 | { | |||
97 | tree lhs, op0, op1; | |||
98 | gimple *gs0, *gs1; | |||
99 | tree_code tcode; | |||
100 | basic_block bb; | |||
101 | ||||
102 | if (!g) | |||
103 | return false; | |||
104 | ||||
105 | tcode = gimple_assign_rhs_code (g); | |||
106 | if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR) | |||
107 | return false; | |||
108 | ||||
109 | lhs = gimple_assign_lhs (g); | |||
110 | op0 = gimple_assign_rhs1 (g); | |||
111 | op1 = gimple_assign_rhs2 (g); | |||
112 | if ((TREE_CODE (op0)((enum tree_code) (op0)->base.code) != SSA_NAME) || (TREE_CODE (op1)((enum tree_code) (op1)->base.code) != SSA_NAME) | |||
113 | || !has_single_use (lhs)) | |||
114 | return false; | |||
115 | ||||
116 | bb = gimple_bb (g); | |||
117 | gs0 = get_gimple_for_ssa_name (op0); /* gs0 may be NULL */ | |||
118 | gs1 = get_gimple_for_ssa_name (op1); /* gs1 may be NULL */ | |||
119 | ||||
120 | if (ccmp_tree_comparison_p (op0, bb) && ccmp_tree_comparison_p (op1, bb)) | |||
121 | return true; | |||
122 | if (ccmp_tree_comparison_p (op0, bb) && ccmp_candidate_p (gs1)) | |||
123 | return true; | |||
124 | if (ccmp_tree_comparison_p (op1, bb) && ccmp_candidate_p (gs0)) | |||
125 | return true; | |||
126 | /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since | |||
127 | there is no way to set and maintain the CC flag on both sides of | |||
128 | the logical operator at the same time. */ | |||
129 | return false; | |||
130 | } | |||
131 | ||||
132 | /* Extract the comparison we want to do from the tree. */ | |||
133 | void | |||
134 | get_compare_parts (tree t, int *up, rtx_code *rcode, | |||
135 | tree *rhs1, tree *rhs2) | |||
136 | { | |||
137 | tree_code code; | |||
138 | gimple *g = get_gimple_for_ssa_name (t); | |||
139 | if (g) | |||
140 | { | |||
141 | *up = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g)))((tree_class_check ((((contains_struct_check ((gimple_assign_rhs1 (g)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ccmp.cc" , 141, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ccmp.cc" , 141, __FUNCTION__))->base.u.bits.unsigned_flag); | |||
142 | code = gimple_assign_rhs_code (g); | |||
143 | *rcode = get_rtx_code (code, *up); | |||
144 | *rhs1 = gimple_assign_rhs1 (g); | |||
145 | *rhs2 = gimple_assign_rhs2 (g); | |||
146 | } | |||
147 | else | |||
148 | { | |||
149 | /* If g is not a comparison operator create a compare to zero. */ | |||
150 | *up = 1; | |||
151 | *rcode = NE; | |||
152 | *rhs1 = t; | |||
153 | *rhs2 = build_zero_cst (TREE_TYPE (t)((contains_struct_check ((t), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ccmp.cc" , 153, __FUNCTION__))->typed.type)); | |||
154 | } | |||
155 | } | |||
156 | ||||
157 | /* PREV is a comparison with the CC register which represents the | |||
158 | result of the previous CMP or CCMP. The function expands the | |||
159 | next compare based on G which is ANDed/ORed with the previous | |||
160 | compare depending on CODE. | |||
161 | PREP_SEQ returns all insns to prepare opearands for compare. | |||
162 | GEN_SEQ returns all compare insns. */ | |||
163 | static rtx | |||
164 | expand_ccmp_next (tree op, tree_code code, rtx prev, | |||
165 | rtx_insn **prep_seq, rtx_insn **gen_seq) | |||
166 | { | |||
167 | rtx_code rcode; | |||
168 | int unsignedp; | |||
169 | tree rhs1, rhs2; | |||
170 | ||||
171 | get_compare_parts(op, &unsignedp, &rcode, &rhs1, &rhs2); | |||
172 | return targetm.gen_ccmp_next (prep_seq, gen_seq, prev, rcode, | |||
173 | rhs1, rhs2, get_rtx_code (code, 0)); | |||
174 | } | |||
175 | ||||
176 | /* Expand conditional compare gimple G. A typical CCMP sequence is like: | |||
177 | ||||
178 | CC0 = CMP (a, b); | |||
179 | CC1 = CCMP (NE (CC0, 0), CMP (e, f)); | |||
180 | ... | |||
181 | CCn = CCMP (NE (CCn-1, 0), CMP (...)); | |||
182 | ||||
183 | hook gen_ccmp_first is used to expand the first compare. | |||
184 | hook gen_ccmp_next is used to expand the following CCMP. | |||
185 | PREP_SEQ returns all insns to prepare opearand. | |||
186 | GEN_SEQ returns all compare insns. */ | |||
187 | static rtx | |||
188 | expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq) | |||
189 | { | |||
190 | tree_code code = gimple_assign_rhs_code (g); | |||
191 | basic_block bb = gimple_bb (g); | |||
192 | ||||
193 | tree op0 = gimple_assign_rhs1 (g); | |||
194 | tree op1 = gimple_assign_rhs2 (g); | |||
195 | gimple *gs0 = get_gimple_for_ssa_name (op0); | |||
196 | gimple *gs1 = get_gimple_for_ssa_name (op1); | |||
197 | rtx tmp; | |||
198 | ||||
199 | gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)((void)(!(code == BIT_AND_EXPR || code == BIT_IOR_EXPR) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ccmp.cc" , 199, __FUNCTION__), 0 : 0)); | |||
200 | ||||
201 | if (ccmp_tree_comparison_p (op0, bb)) | |||
202 | { | |||
203 | if (ccmp_tree_comparison_p (op1, bb)) | |||
204 | { | |||
205 | int unsignedp0, unsignedp1; | |||
206 | rtx_code rcode0, rcode1; | |||
207 | tree logical_op0_rhs1, logical_op0_rhs2; | |||
208 | tree logical_op1_rhs1, logical_op1_rhs2; | |||
209 | int speed_p = optimize_insn_for_speed_p (); | |||
210 | ||||
211 | rtx tmp2 = NULL_RTX(rtx) 0, ret = NULL_RTX(rtx) 0, ret2 = NULL_RTX(rtx) 0; | |||
212 | unsigned cost1 = MAX_COST2147483647; | |||
213 | unsigned cost2 = MAX_COST2147483647; | |||
214 | ||||
215 | get_compare_parts (op0, &unsignedp0, &rcode0, | |||
216 | &logical_op0_rhs1, &logical_op0_rhs2); | |||
217 | ||||
218 | get_compare_parts (op1, &unsignedp1, &rcode1, | |||
219 | &logical_op1_rhs1, &logical_op1_rhs2); | |||
220 | ||||
221 | rtx_insn *prep_seq_1, *gen_seq_1; | |||
222 | tmp = targetm.gen_ccmp_first (&prep_seq_1, &gen_seq_1, rcode0, | |||
223 | logical_op0_rhs1, logical_op0_rhs2); | |||
224 | if (tmp != NULLnullptr) | |||
225 | { | |||
226 | ret = expand_ccmp_next (op1, code, tmp, &prep_seq_1, &gen_seq_1); | |||
227 | cost1 = seq_cost (prep_seq_1, speed_p); | |||
228 | cost1 += seq_cost (gen_seq_1, speed_p); | |||
229 | } | |||
230 | ||||
231 | /* FIXME: Temporary workaround for PR69619. | |||
232 | Avoid exponential compile time due to expanding gs0 and gs1 twice. | |||
233 | If gs0 and gs1 are complex, the cost will be high, so avoid | |||
234 | reevaluation if above an arbitrary threshold. */ | |||
235 | rtx_insn *prep_seq_2, *gen_seq_2; | |||
236 | if (tmp == NULLnullptr || cost1 < COSTS_N_INSNS (25)((25) * 4)) | |||
237 | tmp2 = targetm.gen_ccmp_first (&prep_seq_2, &gen_seq_2, rcode1, | |||
238 | logical_op1_rhs1, logical_op1_rhs2); | |||
239 | if (!tmp
| |||
240 | return NULL_RTX(rtx) 0; | |||
241 | if (tmp2 != NULLnullptr) | |||
242 | { | |||
243 | ret2 = expand_ccmp_next (op0, code, tmp2, &prep_seq_2, | |||
244 | &gen_seq_2); | |||
245 | cost2 = seq_cost (prep_seq_2, speed_p); | |||
246 | cost2 += seq_cost (gen_seq_2, speed_p); | |||
247 | } | |||
248 | if (cost2 < cost1) | |||
249 | { | |||
250 | *prep_seq = prep_seq_2; | |||
| ||||
251 | *gen_seq = gen_seq_2; | |||
252 | return ret2; | |||
253 | } | |||
254 | *prep_seq = prep_seq_1; | |||
255 | *gen_seq = gen_seq_1; | |||
256 | return ret; | |||
257 | } | |||
258 | else | |||
259 | { | |||
260 | tmp = expand_ccmp_expr_1 (gs1, prep_seq, gen_seq); | |||
261 | if (!tmp) | |||
262 | return NULL_RTX(rtx) 0; | |||
263 | return expand_ccmp_next (op0, code, tmp, prep_seq, gen_seq); | |||
264 | } | |||
265 | } | |||
266 | else | |||
267 | { | |||
268 | gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR((void)(!(gimple_assign_rhs_code (gs0) == BIT_AND_EXPR || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ccmp.cc" , 269, __FUNCTION__), 0 : 0)) | |||
269 | || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR)((void)(!(gimple_assign_rhs_code (gs0) == BIT_AND_EXPR || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ccmp.cc" , 269, __FUNCTION__), 0 : 0)); | |||
270 | gcc_assert (ccmp_tree_comparison_p (op1, bb))((void)(!(ccmp_tree_comparison_p (op1, bb)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ccmp.cc" , 270, __FUNCTION__), 0 : 0)); | |||
271 | tmp = expand_ccmp_expr_1 (gs0, prep_seq, gen_seq); | |||
272 | if (!tmp) | |||
273 | return NULL_RTX(rtx) 0; | |||
274 | return expand_ccmp_next (op1, code, tmp, prep_seq, gen_seq); | |||
275 | } | |||
276 | } | |||
277 | ||||
278 | /* Main entry to expand conditional compare statement G. | |||
279 | Return NULL_RTX if G is not a legal candidate or expand fail. | |||
280 | Otherwise return the target. */ | |||
281 | rtx | |||
282 | expand_ccmp_expr (gimple *g, machine_mode mode) | |||
283 | { | |||
284 | rtx_insn *last; | |||
285 | rtx tmp; | |||
286 | ||||
287 | if (!ccmp_candidate_p (g)) | |||
| ||||
288 | return NULL_RTX(rtx) 0; | |||
289 | ||||
290 | last = get_last_insn (); | |||
291 | ||||
292 | rtx_insn *prep_seq = NULLnullptr, *gen_seq = NULLnullptr; | |||
293 | tmp = expand_ccmp_expr_1 (g, &prep_seq, &gen_seq); | |||
294 | ||||
295 | if (tmp) | |||
296 | { | |||
297 | insn_code icode; | |||
298 | machine_mode cc_mode = CCmode((void) 0, E_CCmode); | |||
299 | rtx_code cmp_code = GET_CODE (tmp)((enum rtx_code) (tmp)->code); | |||
300 | ||||
301 | #ifdef SELECT_CC_MODE | |||
302 | cc_mode = SELECT_CC_MODE (cmp_code, XEXP (tmp, 0), const0_rtx)ix86_cc_mode ((cmp_code), ((((tmp)->u.fld[0]).rt_rtx)), (( const_int_rtx[64]))); | |||
303 | #endif | |||
304 | icode = optab_handler (cstore_optab, cc_mode); | |||
305 | if (icode != CODE_FOR_nothing) | |||
306 | { | |||
307 | rtx target = gen_reg_rtx (mode); | |||
308 | ||||
309 | emit_insn (prep_seq); | |||
310 | emit_insn (gen_seq); | |||
311 | ||||
312 | tmp = emit_cstore (target, icode, cmp_code, cc_mode, cc_mode, | |||
313 | 0, XEXP (tmp, 0)(((tmp)->u.fld[0]).rt_rtx), const0_rtx(const_int_rtx[64]), 1, mode); | |||
314 | if (tmp) | |||
315 | return tmp; | |||
316 | } | |||
317 | } | |||
318 | /* Clean up. */ | |||
319 | delete_insns_since (last); | |||
320 | return NULL_RTX(rtx) 0; | |||
321 | } |