]>
Commit | Line | Data |
---|---|---|
502d63b6 ML |
1 | /* Schedule GIMPLE vector statements. |
2 | Copyright (C) 2020 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 | |
7 | under the terms of the GNU General Public License as published by the | |
8 | Free Software Foundation; either version 3, or (at your option) any | |
9 | later version. | |
10 | ||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT | |
12 | ANY 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 "rtl.h" | |
25 | #include "tree.h" | |
26 | #include "gimple.h" | |
27 | #include "tree-pass.h" | |
28 | #include "ssa.h" | |
29 | #include "expmed.h" | |
30 | #include "optabs-tree.h" | |
31 | #include "tree-eh.h" | |
32 | #include "gimple-iterator.h" | |
33 | #include "gimplify-me.h" | |
34 | #include "gimplify.h" | |
35 | #include "tree-cfg.h" | |
a8d8caca ML |
36 | #include "bitmap.h" |
37 | #include "tree-ssa-dce.h" | |
502d63b6 ML |
38 | |
39 | /* Expand all VEC_COND_EXPR gimple assignments into calls to internal | |
40 | function based on type of selected expansion. */ | |
41 | ||
42 | static gimple * | |
43 | gimple_expand_vec_cond_expr (gimple_stmt_iterator *gsi, | |
44 | hash_map<tree, unsigned int> *vec_cond_ssa_name_uses) | |
45 | { | |
46 | tree lhs, op0a = NULL_TREE, op0b = NULL_TREE; | |
47 | enum tree_code code; | |
48 | enum tree_code tcode; | |
49 | machine_mode cmp_op_mode; | |
50 | bool unsignedp; | |
51 | enum insn_code icode; | |
52 | imm_use_iterator imm_iter; | |
53 | ||
54 | /* Only consider code == GIMPLE_ASSIGN. */ | |
55 | gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi)); | |
56 | if (!stmt) | |
57 | return NULL; | |
58 | ||
59 | code = gimple_assign_rhs_code (stmt); | |
60 | if (code != VEC_COND_EXPR) | |
61 | return NULL; | |
62 | ||
63 | tree op0 = gimple_assign_rhs1 (stmt); | |
64 | tree op1 = gimple_assign_rhs2 (stmt); | |
65 | tree op2 = gimple_assign_rhs3 (stmt); | |
66 | lhs = gimple_assign_lhs (stmt); | |
67 | machine_mode mode = TYPE_MODE (TREE_TYPE (lhs)); | |
68 | ||
69 | gcc_assert (!COMPARISON_CLASS_P (op0)); | |
70 | if (TREE_CODE (op0) == SSA_NAME) | |
71 | { | |
72 | unsigned int used_vec_cond_exprs = 0; | |
73 | unsigned int *slot = vec_cond_ssa_name_uses->get (op0); | |
74 | if (slot) | |
75 | used_vec_cond_exprs = *slot; | |
76 | else | |
77 | { | |
78 | gimple *use_stmt; | |
79 | FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, op0) | |
80 | { | |
81 | gassign *assign = dyn_cast<gassign *> (use_stmt); | |
82 | if (assign != NULL | |
83 | && gimple_assign_rhs_code (assign) == VEC_COND_EXPR | |
84 | && gimple_assign_rhs1 (assign) == op0) | |
85 | used_vec_cond_exprs++; | |
86 | } | |
87 | vec_cond_ssa_name_uses->put (op0, used_vec_cond_exprs); | |
88 | } | |
89 | ||
90 | gassign *def_stmt = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (op0)); | |
91 | if (def_stmt) | |
92 | { | |
93 | tcode = gimple_assign_rhs_code (def_stmt); | |
94 | op0a = gimple_assign_rhs1 (def_stmt); | |
95 | op0b = gimple_assign_rhs2 (def_stmt); | |
96 | ||
97 | tree op0a_type = TREE_TYPE (op0a); | |
98 | if (used_vec_cond_exprs >= 2 | |
99 | && (get_vcond_mask_icode (mode, TYPE_MODE (op0a_type)) | |
100 | != CODE_FOR_nothing) | |
101 | && expand_vec_cmp_expr_p (op0a_type, TREE_TYPE (lhs), tcode)) | |
102 | { | |
103 | /* Keep the SSA name and use vcond_mask. */ | |
104 | tcode = TREE_CODE (op0); | |
105 | } | |
106 | } | |
107 | else | |
108 | tcode = TREE_CODE (op0); | |
109 | } | |
110 | else | |
111 | tcode = TREE_CODE (op0); | |
112 | ||
113 | if (TREE_CODE_CLASS (tcode) != tcc_comparison) | |
114 | { | |
115 | gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0))); | |
116 | if (get_vcond_mask_icode (mode, TYPE_MODE (TREE_TYPE (op0))) | |
117 | != CODE_FOR_nothing) | |
118 | return gimple_build_call_internal (IFN_VCOND_MASK, 3, op0, op1, op2); | |
119 | /* Fake op0 < 0. */ | |
120 | else | |
121 | { | |
122 | gcc_assert (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (op0))) | |
123 | == MODE_VECTOR_INT); | |
124 | op0a = op0; | |
125 | op0b = build_zero_cst (TREE_TYPE (op0)); | |
126 | tcode = LT_EXPR; | |
127 | } | |
128 | } | |
129 | cmp_op_mode = TYPE_MODE (TREE_TYPE (op0a)); | |
130 | unsignedp = TYPE_UNSIGNED (TREE_TYPE (op0a)); | |
131 | ||
132 | ||
133 | gcc_assert (known_eq (GET_MODE_SIZE (mode), GET_MODE_SIZE (cmp_op_mode)) | |
134 | && known_eq (GET_MODE_NUNITS (mode), | |
135 | GET_MODE_NUNITS (cmp_op_mode))); | |
136 | ||
137 | icode = get_vcond_icode (mode, cmp_op_mode, unsignedp); | |
138 | if (icode == CODE_FOR_nothing) | |
139 | { | |
140 | if (tcode == LT_EXPR | |
141 | && op0a == op0 | |
142 | && TREE_CODE (op0) == VECTOR_CST) | |
143 | { | |
144 | /* A VEC_COND_EXPR condition could be folded from EQ_EXPR/NE_EXPR | |
145 | into a constant when only get_vcond_eq_icode is supported. | |
146 | Verify < 0 and != 0 behave the same and change it to NE_EXPR. */ | |
147 | unsigned HOST_WIDE_INT nelts; | |
148 | if (!VECTOR_CST_NELTS (op0).is_constant (&nelts)) | |
149 | { | |
150 | if (VECTOR_CST_STEPPED_P (op0)) | |
151 | gcc_unreachable (); | |
152 | nelts = vector_cst_encoded_nelts (op0); | |
153 | } | |
154 | for (unsigned int i = 0; i < nelts; ++i) | |
155 | if (tree_int_cst_sgn (vector_cst_elt (op0, i)) == 1) | |
156 | gcc_unreachable (); | |
157 | tcode = NE_EXPR; | |
158 | } | |
159 | if (tcode == EQ_EXPR || tcode == NE_EXPR) | |
160 | { | |
161 | tree tcode_tree = build_int_cst (integer_type_node, tcode); | |
162 | return gimple_build_call_internal (IFN_VCONDEQ, 5, op0a, op0b, op1, | |
163 | op2, tcode_tree); | |
164 | } | |
165 | } | |
166 | ||
167 | gcc_assert (icode != CODE_FOR_nothing); | |
168 | tree tcode_tree = build_int_cst (integer_type_node, tcode); | |
169 | return gimple_build_call_internal (unsignedp ? IFN_VCONDU : IFN_VCOND, | |
170 | 5, op0a, op0b, op1, op2, tcode_tree); | |
171 | } | |
172 | ||
173 | ||
174 | ||
175 | /* Iterate all gimple statements and try to expand | |
176 | VEC_COND_EXPR assignments. */ | |
177 | ||
178 | static unsigned int | |
179 | gimple_expand_vec_cond_exprs (void) | |
180 | { | |
181 | gimple_stmt_iterator gsi; | |
182 | basic_block bb; | |
502d63b6 | 183 | hash_map<tree, unsigned int> vec_cond_ssa_name_uses; |
a8d8caca | 184 | auto_bitmap dce_ssa_names; |
502d63b6 ML |
185 | |
186 | FOR_EACH_BB_FN (bb, cfun) | |
187 | { | |
188 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |
189 | { | |
190 | gimple *g = gimple_expand_vec_cond_expr (&gsi, | |
191 | &vec_cond_ssa_name_uses); | |
192 | if (g != NULL) | |
193 | { | |
194 | tree lhs = gimple_assign_lhs (gsi_stmt (gsi)); | |
195 | gimple_set_lhs (g, lhs); | |
196 | gsi_replace (&gsi, g, false); | |
197 | } | |
198 | } | |
199 | } | |
200 | ||
a8d8caca ML |
201 | for (hash_map<tree, unsigned int>::iterator it = vec_cond_ssa_name_uses.begin (); |
202 | it != vec_cond_ssa_name_uses.end (); ++it) | |
203 | bitmap_set_bit (dce_ssa_names, SSA_NAME_VERSION ((*it).first)); | |
204 | ||
205 | simple_dce_from_worklist (dce_ssa_names); | |
206 | ||
207 | return 0; | |
502d63b6 ML |
208 | } |
209 | ||
210 | namespace { | |
211 | ||
212 | const pass_data pass_data_gimple_isel = | |
213 | { | |
214 | GIMPLE_PASS, /* type */ | |
215 | "isel", /* name */ | |
216 | OPTGROUP_VEC, /* optinfo_flags */ | |
217 | TV_NONE, /* tv_id */ | |
218 | PROP_cfg, /* properties_required */ | |
219 | 0, /* properties_provided */ | |
220 | 0, /* properties_destroyed */ | |
221 | 0, /* todo_flags_start */ | |
222 | TODO_update_ssa, /* todo_flags_finish */ | |
223 | }; | |
224 | ||
225 | class pass_gimple_isel : public gimple_opt_pass | |
226 | { | |
227 | public: | |
228 | pass_gimple_isel (gcc::context *ctxt) | |
229 | : gimple_opt_pass (pass_data_gimple_isel, ctxt) | |
230 | {} | |
231 | ||
232 | /* opt_pass methods: */ | |
233 | virtual bool gate (function *) | |
234 | { | |
235 | return true; | |
236 | } | |
237 | ||
238 | virtual unsigned int execute (function *) | |
239 | { | |
240 | return gimple_expand_vec_cond_exprs (); | |
241 | } | |
242 | ||
243 | }; // class pass_gimple_isel | |
244 | ||
245 | } // anon namespace | |
246 | ||
247 | gimple_opt_pass * | |
248 | make_pass_gimple_isel (gcc::context *ctxt) | |
249 | { | |
250 | return new pass_gimple_isel (ctxt); | |
251 | } | |
252 |