]>
Commit | Line | Data |
---|---|---|
07f32359 | 1 | /* Language specific subroutines used for code generation on IBM S/390 |
2 | and zSeries | |
3 | Copyright (C) 2015 Free Software Foundation, Inc. | |
4 | ||
5 | Contributed by Andreas Krebbel (Andreas.Krebbel@de.ibm.com). | |
6 | ||
7 | This file is part of GCC. | |
8 | ||
9 | GCC is free software; you can redistribute it and/or modify it | |
10 | under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 3, or (at your option) | |
12 | any later version. | |
13 | ||
14 | GCC is distributed in the hope that it will be useful, but WITHOUT | |
15 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
16 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
17 | License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with GCC; see the file COPYING3. If not see | |
21 | <http://www.gnu.org/licenses/>. | |
22 | ||
23 | Based on gcc/config/rs6000/rs6000-c.c. | |
24 | ||
25 | In GCC terms this file belongs to the frontend. It will be | |
26 | compiled with -DIN_GCC_FRONTEND. With that rtl.h cannot be | |
27 | included anymore - a mechanism supposed to avoid adding frontend - | |
28 | backend dependencies. */ | |
29 | ||
30 | #include "config.h" | |
31 | #include "system.h" | |
32 | #include "coretypes.h" | |
33 | #include "tm.h" | |
34 | #include "cpplib.h" | |
07f32359 | 35 | #include "alias.h" |
36 | #include "symtab.h" | |
07f32359 | 37 | #include "tree.h" |
38 | #include "fold-const.h" | |
39 | #include "stringpool.h" | |
40 | #include "c-family/c-common.h" | |
41 | #include "c-family/c-pragma.h" | |
42 | #include "diagnostic-core.h" | |
43 | #include "tm_p.h" | |
44 | #include "target.h" | |
45 | #include "langhooks.h" | |
46 | #include "tree-pretty-print.h" | |
47 | #include "c/c-tree.h" | |
48 | ||
49 | #include "s390-builtins.h" | |
50 | ||
51 | static GTY(()) tree __vector_keyword; | |
52 | static GTY(()) tree vector_keyword; | |
53 | static GTY(()) tree __bool_keyword; | |
54 | static GTY(()) tree bool_keyword; | |
55 | static GTY(()) tree _Bool_keyword; | |
56 | ||
57 | ||
58 | /* Generate an array holding all the descriptions of variants of | |
59 | overloaded builtins defined with OB_DEF_VAR in | |
60 | s390-builtins.def. */ | |
61 | static enum s390_builtin_ov_type_index | |
62 | type_for_overloaded_builtin_var[S390_OVERLOADED_BUILTIN_VAR_MAX + 1] = | |
63 | { | |
64 | #undef B_DEF | |
65 | #undef OB_DEF | |
66 | #undef OB_DEF_VAR | |
67 | #define B_DEF(...) | |
68 | #define OB_DEF(...) | |
69 | #define OB_DEF_VAR(NAME, PATTERN, FLAGS, FNTYPE) FNTYPE, | |
70 | #include "s390-builtins.def" | |
71 | BT_OV_MAX | |
72 | }; | |
73 | ||
74 | ||
75 | /* Generate an array indexed by an overloaded builtin index returning | |
76 | the first index in desc_for_overloaded_builtin_var where the | |
77 | variants for the builtin can be found. */ | |
78 | static enum s390_overloaded_builtin_vars | |
79 | desc_start_for_overloaded_builtin[S390_OVERLOADED_BUILTIN_MAX + 1] = | |
80 | { | |
81 | #undef B_DEF | |
82 | #undef OB_DEF | |
83 | #undef OB_DEF_VAR | |
84 | #define B_DEF(...) | |
85 | #define OB_DEF(NAME, FIRST_VAR_NAME, LAST_VAR_NAME, FNTYPE) \ | |
86 | S390_OVERLOADED_BUILTIN_VAR_##FIRST_VAR_NAME, | |
87 | #define OB_DEF_VAR(...) | |
88 | #include "s390-builtins.def" | |
89 | S390_OVERLOADED_BUILTIN_VAR_MAX | |
90 | }; | |
91 | ||
92 | /* Generate an array indexed by an overloaded builtin index returning | |
93 | the last index in desc_for_overloaded_builtin_var where the | |
94 | variants for the builtin can be found. */ | |
95 | static enum s390_overloaded_builtin_vars | |
96 | desc_end_for_overloaded_builtin[S390_OVERLOADED_BUILTIN_MAX + 1] = | |
97 | { | |
98 | #undef B_DEF | |
99 | #undef OB_DEF | |
100 | #undef OB_DEF_VAR | |
101 | #define B_DEF(...) | |
102 | #define OB_DEF(NAME, FIRST_VAR_NAME, LAST_VAR_NAME, FNTYPE) \ | |
103 | S390_OVERLOADED_BUILTIN_VAR_##LAST_VAR_NAME, | |
104 | #define OB_DEF_VAR(...) | |
105 | #include "s390-builtins.def" | |
106 | S390_OVERLOADED_BUILTIN_VAR_MAX | |
107 | }; | |
108 | ||
109 | static enum s390_builtin_type_index | |
110 | s390_builtin_ov_types[BT_OV_MAX][MAX_OV_OPERANDS] = | |
111 | { | |
112 | #undef DEF_TYPE | |
113 | #undef DEF_POINTER_TYPE | |
114 | #undef DEF_DISTINCT_TYPE | |
115 | #undef DEF_VECTOR_TYPE | |
116 | #undef DEF_OPAQUE_VECTOR_TYPE | |
117 | #undef DEF_FN_TYPE | |
118 | #undef DEF_OV_TYPE | |
119 | #define DEF_TYPE(...) | |
120 | #define DEF_POINTER_TYPE(...) | |
121 | #define DEF_DISTINCT_TYPE(...) | |
122 | #define DEF_VECTOR_TYPE(...) | |
123 | #define DEF_OPAQUE_VECTOR_TYPE(...) | |
124 | #define DEF_FN_TYPE(...) | |
125 | #define DEF_OV_TYPE(INDEX, args...) { args }, | |
126 | #include "s390-builtin-types.def" | |
127 | }; | |
128 | ||
129 | static const enum s390_builtins bt_for_overloaded_builtin_var[S390_OVERLOADED_BUILTIN_VAR_MAX] = { | |
130 | #undef B_DEF | |
131 | #undef OB_DEF | |
132 | #undef OB_DEF_VAR | |
133 | #define B_DEF(...) | |
134 | #define OB_DEF(...) | |
135 | #define OB_DEF_VAR(NAME, BT, ...) S390_BUILTIN_##BT, | |
136 | ||
137 | #include "s390-builtins.def" | |
138 | }; | |
139 | ||
140 | /* In addition to calling fold_convert for EXPR of type TYPE, also | |
141 | call c_fully_fold to remove any C_MAYBE_CONST_EXPRs that could be | |
142 | hiding there (PR47197). */ | |
143 | tree | |
144 | fully_fold_convert (tree type, tree expr) | |
145 | { | |
146 | tree result = fold_convert (type, expr); | |
147 | bool maybe_const = true; | |
148 | ||
149 | if (!c_dialect_cxx ()) | |
150 | result = c_fully_fold (result, false, &maybe_const); | |
151 | ||
152 | return result; | |
153 | } | |
154 | ||
155 | /* Unify the different variants to the same nodes in order to keep the | |
156 | code working with it simple. */ | |
157 | static cpp_hashnode * | |
158 | s390_categorize_keyword (const cpp_token *tok) | |
159 | { | |
160 | if (tok->type == CPP_NAME) | |
161 | { | |
162 | cpp_hashnode *ident = tok->val.node.node; | |
163 | ||
164 | if (ident == C_CPP_HASHNODE (vector_keyword)) | |
165 | return C_CPP_HASHNODE (__vector_keyword); | |
166 | ||
167 | if (ident == C_CPP_HASHNODE (bool_keyword)) | |
168 | return C_CPP_HASHNODE (__bool_keyword); | |
169 | ||
170 | if (ident == C_CPP_HASHNODE (_Bool_keyword)) | |
171 | return C_CPP_HASHNODE (__bool_keyword); | |
172 | return ident; | |
173 | } | |
174 | ||
175 | return 0; | |
176 | } | |
177 | ||
178 | ||
179 | /* Called to decide whether a conditional macro should be expanded. | |
180 | Since we have exactly one such macro (i.e, 'vector'), we do not | |
181 | need to examine the 'tok' parameter. */ | |
182 | ||
183 | static cpp_hashnode * | |
184 | s390_macro_to_expand (cpp_reader *pfile, const cpp_token *tok) | |
185 | { | |
186 | cpp_hashnode *expand_this = tok->val.node.node; | |
187 | cpp_hashnode *ident; | |
188 | static bool expand_bool_p = false; | |
189 | int idx = 0; | |
190 | enum rid rid_code; | |
191 | ||
192 | /* The vector keyword is only expanded if the machine actually | |
193 | provides hardware support. */ | |
194 | if (!TARGET_ZVECTOR) | |
195 | return NULL; | |
196 | ||
197 | ident = s390_categorize_keyword (tok); | |
198 | ||
199 | /* Triggered when we picked a different variant in | |
200 | s390_categorize_keyword. */ | |
201 | if (ident != expand_this) | |
202 | expand_this = NULL; | |
203 | ||
204 | /* The vector keyword has been found already and we remembered to | |
205 | expand the next bool. */ | |
206 | if (expand_bool_p && ident == C_CPP_HASHNODE (__bool_keyword)) | |
207 | { | |
208 | expand_bool_p = false; | |
209 | return ident; | |
210 | } | |
211 | ||
212 | if (ident != C_CPP_HASHNODE (__vector_keyword)) | |
213 | return expand_this; | |
214 | ||
215 | do | |
216 | tok = cpp_peek_token (pfile, idx++); | |
217 | while (tok->type == CPP_PADDING); | |
218 | ident = s390_categorize_keyword (tok); | |
219 | ||
220 | if (!ident) | |
221 | return expand_this; | |
222 | ||
223 | /* vector bool - remember to expand the next bool. */ | |
224 | if (ident == C_CPP_HASHNODE (__bool_keyword)) | |
225 | { | |
226 | expand_bool_p = true; | |
227 | return C_CPP_HASHNODE (__vector_keyword); | |
228 | } | |
229 | ||
230 | /* The boost libraries have code with Iterator::vector vector in it. | |
231 | If we allow the normal handling, this module will be called | |
232 | recursively, and the vector will be skipped.; */ | |
233 | if (ident == C_CPP_HASHNODE (__vector_keyword)) | |
234 | return expand_this; | |
235 | ||
236 | rid_code = (enum rid)(ident->rid_code); | |
237 | ||
238 | if (ident->type == NT_MACRO) | |
239 | { | |
240 | /* Now actually fetch the tokens we "peeked" before and do a | |
241 | lookahead for the next. */ | |
242 | do | |
243 | (void) cpp_get_token (pfile); | |
244 | while (--idx > 0); | |
245 | do | |
246 | tok = cpp_peek_token (pfile, idx++); | |
247 | while (tok->type == CPP_PADDING); | |
248 | ident = s390_categorize_keyword (tok); | |
249 | ||
250 | if (ident == C_CPP_HASHNODE (__bool_keyword)) | |
251 | { | |
252 | expand_bool_p = true; | |
253 | return C_CPP_HASHNODE (__vector_keyword); | |
254 | } | |
255 | else if (ident) | |
256 | rid_code = (enum rid)(ident->rid_code); | |
257 | } | |
258 | ||
259 | /* vector keyword followed by type identifier: vector unsigned, | |
260 | vector long, ... | |
261 | Types consisting of more than one identifier are not supported by | |
262 | zvector e.g. long long, long double, unsigned long int. */ | |
263 | if (rid_code == RID_UNSIGNED || rid_code == RID_LONG | |
264 | || rid_code == RID_SHORT || rid_code == RID_SIGNED | |
265 | || rid_code == RID_INT || rid_code == RID_CHAR | |
266 | || rid_code == RID_DOUBLE) | |
267 | { | |
268 | expand_this = C_CPP_HASHNODE (__vector_keyword); | |
269 | /* If the next keyword is bool, it will need to be expanded as | |
270 | well. */ | |
271 | do | |
272 | tok = cpp_peek_token (pfile, idx++); | |
273 | while (tok->type == CPP_PADDING); | |
274 | ident = s390_categorize_keyword (tok); | |
275 | ||
276 | /* __vector long __bool a; */ | |
277 | if (ident == C_CPP_HASHNODE (__bool_keyword)) | |
278 | expand_bool_p = true; | |
279 | else | |
280 | { | |
281 | /* Triggered with: __vector long long __bool a; */ | |
282 | do | |
283 | tok = cpp_peek_token (pfile, idx++); | |
284 | while (tok->type == CPP_PADDING); | |
285 | ident = s390_categorize_keyword (tok); | |
286 | ||
287 | if (ident == C_CPP_HASHNODE (__bool_keyword)) | |
288 | expand_bool_p = true; | |
289 | } | |
290 | } | |
291 | ||
292 | return expand_this; | |
293 | } | |
294 | ||
295 | /* Define platform dependent macros. */ | |
296 | void | |
297 | s390_cpu_cpp_builtins (cpp_reader *pfile) | |
298 | { | |
299 | cpp_assert (pfile, "cpu=s390"); | |
300 | cpp_assert (pfile, "machine=s390"); | |
301 | cpp_define (pfile, "__s390__"); | |
302 | if (TARGET_ZARCH) | |
303 | cpp_define (pfile, "__zarch__"); | |
304 | if (TARGET_64BIT) | |
305 | cpp_define (pfile, "__s390x__"); | |
306 | if (TARGET_LONG_DOUBLE_128) | |
307 | cpp_define (pfile, "__LONG_DOUBLE_128__"); | |
308 | if (TARGET_HTM) | |
309 | cpp_define (pfile, "__HTM__"); | |
310 | if (TARGET_ZVECTOR) | |
311 | { | |
312 | cpp_define (pfile, "__VEC__=10301"); | |
313 | cpp_define (pfile, "__vector=__attribute__((vector_size(16)))"); | |
314 | cpp_define (pfile, "__bool=__attribute__((s390_vector_bool)) unsigned"); | |
315 | ||
316 | if (!flag_iso) | |
317 | { | |
318 | cpp_define (pfile, "__VECTOR_KEYWORD_SUPPORTED__"); | |
319 | cpp_define (pfile, "vector=vector"); | |
320 | cpp_define (pfile, "bool=bool"); | |
321 | ||
322 | __vector_keyword = get_identifier ("__vector"); | |
323 | C_CPP_HASHNODE (__vector_keyword)->flags |= NODE_CONDITIONAL; | |
324 | ||
325 | vector_keyword = get_identifier ("vector"); | |
326 | C_CPP_HASHNODE (vector_keyword)->flags |= NODE_CONDITIONAL; | |
327 | ||
328 | __bool_keyword = get_identifier ("__bool"); | |
329 | C_CPP_HASHNODE (__bool_keyword)->flags |= NODE_CONDITIONAL; | |
330 | ||
331 | bool_keyword = get_identifier ("bool"); | |
332 | C_CPP_HASHNODE (bool_keyword)->flags |= NODE_CONDITIONAL; | |
333 | ||
334 | _Bool_keyword = get_identifier ("_Bool"); | |
335 | C_CPP_HASHNODE (_Bool_keyword)->flags |= NODE_CONDITIONAL; | |
336 | ||
337 | /* Enable context-sensitive macros. */ | |
338 | cpp_get_callbacks (pfile)->macro_to_expand = s390_macro_to_expand; | |
339 | } | |
340 | } | |
341 | } | |
342 | ||
343 | /* Expand builtins which can directly be mapped to tree expressions. | |
344 | LOC - location information | |
345 | FCODE - function code of the builtin | |
346 | ARGLIST - value supposed to be passed as arguments | |
347 | RETURN-TYPE - expected return type of the builtin */ | |
348 | static tree | |
349 | s390_expand_overloaded_builtin (location_t loc, | |
350 | unsigned fcode, | |
351 | vec<tree, va_gc> *arglist, | |
352 | tree return_type) | |
353 | { | |
354 | switch (fcode) | |
355 | { | |
356 | case S390_OVERLOADED_BUILTIN_s390_vec_step: | |
357 | if (TREE_CODE (TREE_TYPE ((*arglist)[0])) != VECTOR_TYPE) | |
358 | { | |
359 | error_at (loc, "Builtin vec_step can only be used on vector types."); | |
360 | return error_mark_node; | |
361 | } | |
362 | return build_int_cst (NULL_TREE, | |
363 | TYPE_VECTOR_SUBPARTS (TREE_TYPE ((*arglist)[0]))); | |
364 | case S390_OVERLOADED_BUILTIN_s390_vec_xld2: | |
365 | case S390_OVERLOADED_BUILTIN_s390_vec_xlw4: | |
366 | return build2 (MEM_REF, return_type, | |
367 | fold_build_pointer_plus ((*arglist)[1], (*arglist)[0]), | |
368 | build_int_cst (TREE_TYPE ((*arglist)[1]), 0)); | |
369 | case S390_OVERLOADED_BUILTIN_s390_vec_xstd2: | |
370 | case S390_OVERLOADED_BUILTIN_s390_vec_xstw4: | |
371 | return build2 (MODIFY_EXPR, TREE_TYPE((*arglist)[0]), | |
372 | build1 (INDIRECT_REF, TREE_TYPE((*arglist)[0]), | |
373 | fold_build_pointer_plus ((*arglist)[2], (*arglist)[1])), | |
374 | (*arglist)[0]); | |
375 | case S390_OVERLOADED_BUILTIN_s390_vec_load_pair: | |
376 | return build_constructor_va (return_type, 2, | |
377 | NULL_TREE, (*arglist)[0], | |
378 | NULL_TREE, (*arglist)[1]); | |
379 | default: | |
380 | gcc_unreachable (); | |
381 | } | |
382 | } | |
383 | ||
384 | /* invert result */ | |
385 | #define __VSTRING_FLAG_IN 8 | |
386 | /* result type */ | |
387 | #define __VSTRING_FLAG_RT 4 | |
388 | /* zero search */ | |
389 | #define __VSTRING_FLAG_ZS 2 | |
390 | /* set condition code */ | |
391 | #define __VSTRING_FLAG_CS 1 | |
392 | ||
393 | /* Return the flags value to be used for string low-level builtins | |
394 | when expanded from overloaded builtin OB_FCODE. */ | |
395 | static unsigned int | |
396 | s390_get_vstring_flags (int ob_fcode) | |
397 | { | |
398 | unsigned int flags = 0; | |
399 | ||
400 | switch (ob_fcode) | |
401 | { | |
402 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_idx: | |
403 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx: | |
404 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne: | |
405 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_idx_cc: | |
406 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx_cc: | |
407 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_cc: | |
408 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_idx: | |
409 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx: | |
410 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg: | |
411 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_idx_cc: | |
412 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx_cc: | |
413 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_cc: | |
414 | flags |= __VSTRING_FLAG_IN; | |
415 | break; | |
416 | default: | |
417 | break; | |
418 | } | |
419 | switch (ob_fcode) | |
420 | { | |
421 | ||
422 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_idx: | |
423 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_idx: | |
424 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_or_0_idx: | |
425 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx: | |
426 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_idx_cc: | |
427 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_idx_cc: | |
428 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_or_0_idx_cc: | |
429 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx_cc: | |
430 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_idx: | |
431 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_idx: | |
432 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_or_0_idx: | |
433 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx: | |
434 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_idx_cc: | |
435 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_idx_cc: | |
436 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_or_0_idx_cc: | |
437 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx_cc: | |
438 | flags |= __VSTRING_FLAG_RT; | |
439 | break; | |
440 | default: | |
441 | break; | |
442 | } | |
443 | switch (ob_fcode) | |
444 | { | |
445 | ||
446 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_or_0_idx: | |
447 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx: | |
448 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_or_0_idx_cc: | |
449 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx_cc: | |
450 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_or_0_idx: | |
451 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx: | |
452 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_or_0_idx_cc: | |
453 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx_cc: | |
454 | flags |= __VSTRING_FLAG_ZS; | |
455 | break; | |
456 | default: | |
457 | break; | |
458 | } | |
459 | switch (ob_fcode) | |
460 | { | |
461 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_idx_cc: | |
462 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_idx_cc: | |
463 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_or_0_idx_cc: | |
464 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx_cc: | |
465 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_cc: | |
466 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_cc: | |
467 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_idx_cc: | |
468 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_idx_cc: | |
469 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_or_0_idx_cc: | |
470 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx_cc: | |
471 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_cc: | |
472 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_cc: | |
473 | flags |= __VSTRING_FLAG_CS; | |
474 | break; | |
475 | default: | |
476 | break; | |
477 | } | |
478 | return flags; | |
479 | } | |
480 | #undef __VSTRING_FLAG_IN | |
481 | #undef __VSTRING_FLAG_RT | |
482 | #undef __VSTRING_FLAG_ZS | |
483 | #undef __VSTRING_FLAG_CS | |
484 | ||
485 | /* For several overloaded builtins the argument lists do not match | |
486 | exactly the signature of a low-level builtin. This function | |
487 | adjusts the argument list ARGLIST for the overloaded builtin | |
488 | OB_FCODE to the signature of the low-level builtin given by | |
489 | DECL. */ | |
490 | static void | |
491 | s390_adjust_builtin_arglist (unsigned int ob_fcode, tree decl, | |
492 | vec<tree, va_gc> **arglist) | |
493 | { | |
494 | tree arg_chain; | |
495 | int src_arg_index, dest_arg_index; | |
496 | vec<tree, va_gc> *folded_args = NULL; | |
497 | ||
498 | /* We at most add one more operand to the list. */ | |
499 | vec_alloc (folded_args, (*arglist)->allocated () + 1); | |
500 | for (arg_chain = TYPE_ARG_TYPES (TREE_TYPE (decl)), | |
501 | src_arg_index = 0, dest_arg_index = 0; | |
502 | !VOID_TYPE_P (TREE_VALUE (arg_chain)); | |
503 | arg_chain = TREE_CHAIN (arg_chain), dest_arg_index++) | |
504 | { | |
505 | bool arg_assigned_p = false; | |
506 | switch (ob_fcode) | |
507 | { | |
508 | /* For all these the low level builtin needs an additional flags parameter. */ | |
509 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_idx: | |
510 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_idx: | |
511 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_or_0_idx: | |
512 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx: | |
513 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq: | |
514 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne: | |
515 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_idx_cc: | |
516 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_idx_cc: | |
517 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_or_0_idx_cc: | |
518 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx_cc: | |
519 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_cc: | |
520 | case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_cc: | |
521 | if (dest_arg_index == 2) | |
522 | { | |
523 | folded_args->quick_push (build_int_cst (integer_type_node, | |
524 | s390_get_vstring_flags (ob_fcode))); | |
525 | arg_assigned_p = true; | |
526 | } | |
527 | break; | |
528 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_idx: | |
529 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_idx: | |
530 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_or_0_idx: | |
531 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx: | |
532 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg: | |
533 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg: | |
534 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_idx_cc: | |
535 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_idx_cc: | |
536 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_or_0_idx_cc: | |
537 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx_cc: | |
538 | case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_cc: | |
539 | case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_cc: | |
540 | if (dest_arg_index == 3) | |
541 | { | |
542 | folded_args->quick_push (build_int_cst (integer_type_node, | |
543 | s390_get_vstring_flags (ob_fcode))); | |
544 | arg_assigned_p = true; | |
545 | } | |
546 | break; | |
547 | case S390_OVERLOADED_BUILTIN_s390_vec_sel: | |
548 | case S390_OVERLOADED_BUILTIN_s390_vec_insert: | |
549 | case S390_OVERLOADED_BUILTIN_s390_vec_load_len: | |
550 | /* Swap the first to arguments. It is better to do it here | |
551 | instead of the header file to avoid operand checking | |
552 | throwing error messages for a weird operand index. */ | |
553 | if (dest_arg_index < 2) | |
554 | { | |
555 | folded_args->quick_push (fully_fold_convert (TREE_VALUE (arg_chain), | |
556 | (**arglist)[1 - dest_arg_index])); | |
557 | src_arg_index++; | |
558 | arg_assigned_p = true; | |
559 | } | |
560 | break; | |
561 | case S390_OVERLOADED_BUILTIN_s390_vec_store_len: | |
562 | if (dest_arg_index == 1 || dest_arg_index == 2) | |
563 | { | |
564 | folded_args->quick_push (fully_fold_convert (TREE_VALUE (arg_chain), | |
565 | (**arglist)[3 - dest_arg_index])); | |
566 | src_arg_index++; | |
567 | arg_assigned_p = true; | |
568 | } | |
569 | break; | |
570 | ||
571 | case S390_OVERLOADED_BUILTIN_s390_vec_load_bndry: | |
572 | { | |
573 | int code; | |
574 | ||
575 | if (dest_arg_index == 1) | |
576 | { | |
577 | switch (tree_to_uhwi ((**arglist)[src_arg_index])) | |
578 | { | |
579 | case 64: code = 0; break; | |
580 | case 128: code = 1; break; | |
581 | case 256: code = 2; break; | |
582 | case 512: code = 3; break; | |
583 | case 1024: code = 4; break; | |
584 | case 2048: code = 5; break; | |
585 | case 4096: code = 6; break; | |
586 | default: | |
587 | error ("valid values for builtin %qF argument %d are 64, " | |
588 | "128, 256, 512, 1024, 2048, and 4096", decl, | |
589 | src_arg_index + 1); | |
590 | return; | |
591 | } | |
592 | folded_args->quick_push (build_int_cst (integer_type_node, | |
593 | code)); | |
594 | src_arg_index++; | |
595 | arg_assigned_p = true; | |
596 | } | |
597 | } | |
598 | break; | |
599 | case S390_OVERLOADED_BUILTIN_s390_vec_rl_mask: | |
600 | /* Duplicate the first src arg. */ | |
601 | if (dest_arg_index == 0) | |
602 | { | |
603 | folded_args->quick_push (fully_fold_convert (TREE_VALUE (arg_chain), | |
604 | (**arglist)[src_arg_index])); | |
605 | arg_assigned_p = true; | |
606 | } | |
607 | break; | |
608 | default: | |
609 | break; | |
610 | } | |
611 | if (!arg_assigned_p) | |
612 | { | |
613 | folded_args->quick_push (fully_fold_convert (TREE_VALUE (arg_chain), | |
614 | (**arglist)[src_arg_index])); | |
615 | src_arg_index++; | |
616 | } | |
617 | } | |
618 | *arglist = folded_args; | |
619 | } | |
620 | ||
621 | /* Check whether the arguments in ARGLIST match the function type | |
622 | DEF_TYPE. Return the number of argument types which required | |
623 | conversion/promotion in order to make it match. | |
624 | 0 stands for a perfect match - all operand types match without changes | |
625 | INT_MAX stands for a mismatch. */ | |
626 | static int | |
627 | s390_fn_types_compatible (enum s390_builtin_ov_type_index typeindex, | |
628 | vec<tree, va_gc> *arglist) | |
629 | { | |
630 | unsigned int i; | |
631 | int match_type = 0; | |
632 | ||
633 | for (i = 0; i < vec_safe_length (arglist); i++) | |
634 | { | |
635 | tree b_arg_type = s390_builtin_types[s390_builtin_ov_types[typeindex][i + 1]]; | |
636 | tree in_arg = (*arglist)[i]; | |
637 | tree in_type = TREE_TYPE (in_arg); | |
638 | ||
639 | if (TREE_CODE (b_arg_type) == VECTOR_TYPE) | |
640 | { | |
641 | /* Vector types have to match precisely. */ | |
642 | if (b_arg_type != in_type | |
643 | && TYPE_MAIN_VARIANT (b_arg_type) != TYPE_MAIN_VARIANT (in_type)) | |
644 | goto mismatch; | |
645 | } | |
646 | ||
647 | if (lang_hooks.types_compatible_p (in_type, b_arg_type)) | |
648 | continue; | |
649 | ||
650 | if (lang_hooks.types_compatible_p ( | |
651 | lang_hooks.types.type_promotes_to (in_type), | |
652 | lang_hooks.types.type_promotes_to (b_arg_type))) | |
653 | { | |
654 | match_type++; | |
655 | continue; | |
656 | } | |
657 | ||
658 | /* In this stage the C++ frontend would go ahead trying to find | |
659 | implicit conversion chains for the argument to match the | |
660 | target type. We will mimic this here only for our limited | |
661 | subset of argument types. */ | |
662 | if (TREE_CODE (b_arg_type) == INTEGER_TYPE | |
663 | && TREE_CODE (in_type) == INTEGER_TYPE) | |
664 | { | |
665 | match_type++; | |
666 | continue; | |
667 | } | |
668 | ||
669 | /* If the incoming pointer argument has more qualifiers than the | |
670 | argument type it can still be an imperfect match. */ | |
671 | if (POINTER_TYPE_P (b_arg_type) && POINTER_TYPE_P (in_type) | |
672 | && !(TYPE_QUALS (TREE_TYPE (in_type)) | |
673 | & ~TYPE_QUALS (TREE_TYPE (b_arg_type))) | |
674 | && (TYPE_QUALS (TREE_TYPE (b_arg_type)) | |
675 | & ~TYPE_QUALS (TREE_TYPE (in_type)))) | |
676 | { | |
677 | tree qual_in_type = | |
678 | build_qualified_type (TREE_TYPE (in_type), | |
679 | TYPE_QUALS (TREE_TYPE (b_arg_type))); | |
680 | ||
681 | if (lang_hooks.types_compatible_p (qual_in_type, | |
682 | TREE_TYPE (b_arg_type))) | |
683 | { | |
684 | match_type++; | |
685 | continue; | |
686 | } | |
687 | } | |
688 | ||
689 | mismatch: | |
690 | if (TARGET_DEBUG_ARG) | |
691 | fprintf (stderr, " mismatch in operand: %d\n", i + 1); | |
692 | return INT_MAX; | |
693 | } | |
694 | ||
695 | return match_type; | |
696 | } | |
697 | ||
698 | /* Return the number of elements in the vector arguments of FNDECL in | |
699 | case all it matches for all vector arguments, -1 otherwise. */ | |
700 | static int | |
701 | s390_vec_n_elem (tree fndecl) | |
702 | { | |
703 | tree b_arg_chain; | |
704 | int n_elem = -1; | |
705 | ||
706 | if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) == VECTOR_TYPE) | |
707 | n_elem = TYPE_VECTOR_SUBPARTS (TREE_TYPE (TREE_TYPE ((fndecl)))); | |
708 | ||
709 | for (b_arg_chain = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); | |
710 | !VOID_TYPE_P (TREE_VALUE (b_arg_chain)); | |
711 | b_arg_chain = TREE_CHAIN (b_arg_chain)) | |
712 | { | |
713 | int tmp_n_elem; | |
714 | if (TREE_CODE (TREE_VALUE (b_arg_chain)) != VECTOR_TYPE) | |
715 | continue; | |
716 | tmp_n_elem = TYPE_VECTOR_SUBPARTS (TREE_VALUE (b_arg_chain)); | |
717 | if (n_elem != -1 && n_elem != tmp_n_elem) | |
718 | return -1; | |
719 | n_elem = tmp_n_elem; | |
720 | } | |
721 | return n_elem; | |
722 | } | |
723 | ||
724 | ||
725 | /* Return a tree expression for a call to the overloaded builtin | |
726 | function OB_FNDECL at LOC with arguments PASSED_ARGLIST. */ | |
727 | tree | |
728 | s390_resolve_overloaded_builtin (location_t loc, | |
729 | tree ob_fndecl, | |
730 | void *passed_arglist) | |
731 | { | |
732 | vec<tree, va_gc> *arglist = static_cast<vec<tree, va_gc> *> (passed_arglist); | |
733 | unsigned int in_args_num = vec_safe_length (arglist); | |
734 | unsigned int ob_args_num = 0; | |
735 | unsigned int ob_fcode = DECL_FUNCTION_CODE (ob_fndecl); | |
736 | enum s390_overloaded_builtin_vars bindex; | |
737 | unsigned int i; | |
738 | int last_match_type = INT_MAX; | |
739 | int last_match_index = -1; | |
740 | unsigned int all_op_flags; | |
741 | int num_matches = 0; | |
742 | tree target_builtin_decl, b_arg_chain, return_type; | |
743 | enum s390_builtin_ov_type_index last_match_fntype_index; | |
744 | ||
745 | if (TARGET_DEBUG_ARG) | |
746 | fprintf (stderr, | |
747 | "s390_resolve_overloaded_builtin, code = %4d, %s - %s overloaded\n", | |
748 | (int)ob_fcode, IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)), | |
749 | ob_fcode < S390_BUILTIN_MAX ? "not" : ""); | |
750 | ||
751 | /* 0...S390_BUILTIN_MAX-1 is for non-overloaded builtins. */ | |
752 | if (ob_fcode < S390_BUILTIN_MAX) | |
753 | { | |
754 | if (flags_for_builtin(ob_fcode) & B_INT) | |
755 | { | |
756 | error_at (loc, | |
757 | "Builtin %qF is for GCC internal use only.", | |
758 | ob_fndecl); | |
759 | return error_mark_node; | |
760 | } | |
761 | return NULL_TREE; | |
762 | } | |
763 | ||
764 | ob_fcode -= S390_BUILTIN_MAX; | |
765 | ||
766 | for (b_arg_chain = TYPE_ARG_TYPES (TREE_TYPE (ob_fndecl)); | |
767 | !VOID_TYPE_P (TREE_VALUE (b_arg_chain)); | |
768 | b_arg_chain = TREE_CHAIN (b_arg_chain)) | |
769 | ob_args_num++; | |
770 | ||
771 | if (ob_args_num != in_args_num) | |
772 | { | |
773 | error_at (loc, | |
774 | "Mismatch in number of arguments for builtin %qF. " | |
775 | "Expected: %d got %d", ob_fndecl, | |
776 | ob_args_num, in_args_num); | |
777 | return error_mark_node; | |
778 | } | |
779 | ||
780 | for (i = 0; i < in_args_num; i++) | |
781 | if ((*arglist)[i] == error_mark_node) | |
782 | return error_mark_node; | |
783 | ||
784 | /* Overloaded builtins without any variants are directly expanded here. */ | |
785 | if (desc_start_for_overloaded_builtin[ob_fcode] == | |
786 | S390_OVERLOADED_BUILTIN_VAR_MAX) | |
787 | return s390_expand_overloaded_builtin (loc, ob_fcode, arglist, NULL_TREE); | |
788 | ||
789 | for (bindex = desc_start_for_overloaded_builtin[ob_fcode]; | |
790 | bindex <= desc_end_for_overloaded_builtin[ob_fcode]; | |
791 | bindex = (enum s390_overloaded_builtin_vars)((int)bindex + 1)) | |
792 | { | |
793 | int match_type; | |
794 | enum s390_builtin_ov_type_index type_index = | |
795 | type_for_overloaded_builtin_var[bindex]; | |
796 | ||
797 | if (TARGET_DEBUG_ARG) | |
798 | fprintf (stderr, "checking variant number: %d", (int)bindex); | |
799 | ||
800 | match_type = s390_fn_types_compatible (type_index, arglist); | |
801 | ||
802 | if (match_type == INT_MAX) | |
803 | continue; | |
804 | ||
805 | if (TARGET_DEBUG_ARG) | |
806 | fprintf (stderr, | |
807 | " %s match score: %d\n", match_type == 0 ? "perfect" : "imperfect", | |
808 | match_type); | |
809 | ||
810 | if (match_type < last_match_type) | |
811 | { | |
812 | num_matches = 1; | |
813 | last_match_type = match_type; | |
814 | last_match_fntype_index = type_index; | |
815 | last_match_index = bindex; | |
816 | } | |
817 | else if (match_type == last_match_type) | |
818 | num_matches++; | |
819 | } | |
820 | ||
821 | if (last_match_type == INT_MAX) | |
822 | { | |
823 | error_at (loc, "invalid parameter combination for intrinsic"); | |
824 | return error_mark_node; | |
825 | } | |
826 | else if (num_matches > 1) | |
827 | { | |
828 | error_at (loc, "ambiguous overload for intrinsic: %s\n", | |
829 | IDENTIFIER_POINTER (DECL_NAME (ob_fndecl))); | |
830 | return error_mark_node; | |
831 | } | |
832 | ||
833 | if (bt_for_overloaded_builtin_var[last_match_index] == S390_BUILTIN_MAX) | |
834 | target_builtin_decl = ob_fndecl; | |
835 | else | |
836 | target_builtin_decl = s390_builtin_decls[bt_for_overloaded_builtin_var[last_match_index]]; | |
837 | ||
838 | all_op_flags = flags_overloaded_builtin_var[last_match_index]; | |
839 | return_type = s390_builtin_types[s390_builtin_ov_types[last_match_fntype_index][0]]; | |
840 | ||
841 | /* Check for the operand flags in the overloaded builtin variant. */ | |
842 | for (i = 0; i < ob_args_num; i++) | |
843 | { | |
844 | unsigned int op_flags = all_op_flags & ((1 << O_SHIFT) - 1); | |
845 | tree arg = (*arglist)[i]; | |
846 | tree type = s390_builtin_types[s390_builtin_ov_types[last_match_fntype_index][i + 1]]; | |
847 | ||
848 | all_op_flags = all_op_flags >> O_SHIFT; | |
849 | ||
850 | if (op_flags == O_ELEM) | |
851 | { | |
852 | int n_elem = s390_vec_n_elem (target_builtin_decl); | |
853 | gcc_assert (n_elem > 0); | |
854 | gcc_assert (type == integer_type_node); | |
855 | (*arglist)[i] = build2 (BIT_AND_EXPR, integer_type_node, | |
856 | fold_convert (integer_type_node, arg), | |
857 | build_int_cst (NULL_TREE, n_elem - 1)); | |
858 | } | |
859 | ||
860 | if (TREE_CODE (arg) != INTEGER_CST || !O_IMM_P (op_flags)) | |
861 | continue; | |
862 | ||
863 | if ((TYPE_UNSIGNED (type) | |
864 | && !int_fits_type_p (arg, c_common_unsigned_type (type))) | |
865 | || (!TYPE_UNSIGNED (type) | |
866 | && !int_fits_type_p (arg, c_common_signed_type (type)))) | |
867 | { | |
868 | error("constant argument %d for builtin %qF is out " | |
869 | "of range for target type", | |
870 | i + 1, target_builtin_decl); | |
871 | return error_mark_node; | |
872 | } | |
873 | ||
874 | if (TREE_CODE (arg) == INTEGER_CST | |
875 | && !s390_const_operand_ok (arg, i + 1, op_flags, target_builtin_decl)) | |
876 | return error_mark_node; | |
877 | } | |
878 | ||
879 | /* Handle builtins we expand directly - without mapping it to a low | |
880 | level builtin. */ | |
881 | if (bt_for_overloaded_builtin_var[last_match_index] == S390_BUILTIN_MAX) | |
882 | return s390_expand_overloaded_builtin (loc, ob_fcode, arglist, return_type); | |
883 | ||
884 | s390_adjust_builtin_arglist (ob_fcode, target_builtin_decl, &arglist); | |
885 | ||
886 | if (VOID_TYPE_P (return_type)) | |
887 | return build_function_call_vec (loc, vNULL, target_builtin_decl, | |
888 | arglist, NULL); | |
889 | else | |
890 | return fully_fold_convert (return_type, | |
891 | build_function_call_vec (loc, vNULL, target_builtin_decl, | |
892 | arglist, NULL)); | |
893 | } | |
894 | ||
895 | /* This is used to define the REGISTER_TARGET_PRAGMAS macro in s390.h. */ | |
896 | void | |
897 | s390_register_target_pragmas (void) | |
898 | { | |
899 | targetm.resolve_overloaded_builtin = s390_resolve_overloaded_builtin; | |
900 | } |