Line data Source code
1 : // This file is part of GCC.
2 :
3 : // GCC is free software; you can redistribute it and/or modify it under
4 : // the terms of the GNU General Public License as published by the Free
5 : // Software Foundation; either version 3, or (at your option) any later
6 : // version.
7 :
8 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
9 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 : // for more details.
12 :
13 : // You should have received a copy of the GNU General Public License
14 : // along with GCC; see the file COPYING3. If not see
15 : // <http://www.gnu.org/licenses/>.
16 :
17 : #include "rust-diagnostics.h"
18 : #include "rust-system.h"
19 : #include "rust-builtins.h"
20 :
21 : #include "target.h"
22 : #include "stringpool.h"
23 : #include "rust-intrinsic-values.h"
24 :
25 : namespace Rust {
26 : namespace Compile {
27 :
28 : BuiltinsContext &
29 7434 : BuiltinsContext::get ()
30 : {
31 7434 : static BuiltinsContext instance;
32 7434 : return instance;
33 : }
34 :
35 : bool
36 10189 : BuiltinsContext::lookup_simple_builtin (const std::string &name, tree *builtin)
37 : {
38 10189 : auto *to_search = &name;
39 :
40 10189 : auto it = rust_intrinsic_to_gcc_builtin.find (name);
41 10189 : if (it != rust_intrinsic_to_gcc_builtin.end ())
42 449 : to_search = &it->second;
43 :
44 10189 : return lookup_gcc_builtin (*to_search, builtin);
45 : }
46 :
47 1527 : BuiltinsContext::BuiltinsContext () { setup (); }
48 :
49 : /**
50 : * Define a function type according to `builtin-types.def`
51 : *
52 : * *Heavily* inspired by the D frontend's `def_fn_type` function
53 : */
54 : void
55 774189 : BuiltinsContext::define_function_type (Type def_idx, Type ret_idx,
56 : bool is_variadic, size_t n, ...)
57 : {
58 774189 : va_list list;
59 774189 : va_start (list, n);
60 :
61 774189 : auto args = std::vector<tree> ();
62 :
63 2482902 : for (size_t i = 0; i < n; i++)
64 : {
65 : // The argument is an enum Type, but it's promoted to int when passed
66 : // though '...'.
67 1708713 : auto arg_idx = va_arg (list, int);
68 1708713 : auto arg_type = builtin_types[arg_idx];
69 :
70 1708713 : args.emplace_back (arg_type);
71 : }
72 :
73 774189 : auto return_type = builtin_types[ret_idx];
74 774189 : if (return_type == error_mark_node)
75 : {
76 : // Mark the builtin as not available.
77 19851 : builtin_types[def_idx] = error_mark_node;
78 19851 : va_end (list);
79 19851 : return;
80 : }
81 :
82 754338 : auto fn_type = NULL_TREE;
83 754338 : if (is_variadic)
84 45810 : fn_type = build_varargs_function_type_array (return_type, n, args.data ());
85 : else
86 708528 : fn_type = build_function_type_array (return_type, n, args.data ());
87 :
88 754338 : builtin_types[def_idx] = fn_type;
89 754338 : va_end (list);
90 774189 : }
91 :
92 : // Taken directly from the D frontend
93 : static void
94 1527 : build_c_type_nodes (void)
95 : {
96 1527 : string_type_node = build_pointer_type (char_type_node);
97 1527 : const_string_type_node = build_pointer_type (
98 : build_qualified_type (char_type_node, TYPE_QUAL_CONST));
99 :
100 1527 : if (strcmp (UINTMAX_TYPE, "unsigned int") == 0)
101 : {
102 0 : intmax_type_node = integer_type_node;
103 0 : uintmax_type_node = unsigned_type_node;
104 : }
105 1527 : else if (strcmp (UINTMAX_TYPE, "long unsigned int") == 0)
106 : {
107 1527 : intmax_type_node = long_integer_type_node;
108 1527 : uintmax_type_node = long_unsigned_type_node;
109 : }
110 0 : else if (strcmp (UINTMAX_TYPE, "long long unsigned int") == 0)
111 : {
112 0 : intmax_type_node = long_long_integer_type_node;
113 0 : uintmax_type_node = long_long_unsigned_type_node;
114 : }
115 : else
116 0 : gcc_unreachable ();
117 :
118 1527 : signed_size_type_node = signed_type_for (size_type_node);
119 1527 : wint_type_node = unsigned_type_node;
120 1527 : pid_type_node = integer_type_node;
121 1527 : }
122 :
123 : /**
124 : * Define all builtin types in the `builtin_types` array
125 : */
126 : void
127 1527 : BuiltinsContext::define_builtin_types ()
128 : {
129 : // This is taken directly from the D frontend's handling of builtins
130 1527 : auto va_list_ref_type_node = build_reference_type (va_list_type_node);
131 1527 : auto va_list_arg_type_node = va_list_type_node;
132 :
133 1527 : build_c_type_nodes ();
134 :
135 1527 : auto builtin_type_for_size = [] (int size, bool unsignedp) {
136 7635 : tree type = lang_hooks.types.type_for_size (size, unsignedp);
137 7635 : return type ? type : error_mark_node;
138 : };
139 :
140 : #define DEF_PRIMITIVE_TYPE(ENUM, VALUE) builtin_types[ENUM] = VALUE;
141 : #define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
142 : define_function_type (ENUM, RETURN, 0, 0);
143 : #define DEF_FUNCTION_TYPE_1(ENUM, RETURN, A1) \
144 : define_function_type (ENUM, RETURN, 0, 1, A1);
145 : #define DEF_FUNCTION_TYPE_2(ENUM, RETURN, A1, A2) \
146 : define_function_type (ENUM, RETURN, 0, 2, A1, A2);
147 : #define DEF_FUNCTION_TYPE_3(ENUM, RETURN, A1, A2, A3) \
148 : define_function_type (ENUM, RETURN, 0, 3, A1, A2, A3);
149 : #define DEF_FUNCTION_TYPE_4(ENUM, RETURN, A1, A2, A3, A4) \
150 : define_function_type (ENUM, RETURN, 0, 4, A1, A2, A3, A4);
151 : #define DEF_FUNCTION_TYPE_5(ENUM, RETURN, A1, A2, A3, A4, A5) \
152 : define_function_type (ENUM, RETURN, 0, 5, A1, A2, A3, A4, A5);
153 : #define DEF_FUNCTION_TYPE_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \
154 : define_function_type (ENUM, RETURN, 0, 6, A1, A2, A3, A4, A5, A6);
155 : #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \
156 : define_function_type (ENUM, RETURN, 0, 7, A1, A2, A3, A4, A5, A6, A7);
157 : #define DEF_FUNCTION_TYPE_8(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8) \
158 : define_function_type (ENUM, RETURN, 0, 8, A1, A2, A3, A4, A5, A6, A7, A8);
159 : #define DEF_FUNCTION_TYPE_9(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9) \
160 : define_function_type (ENUM, RETURN, 0, 9, A1, A2, A3, A4, A5, A6, A7, A8, A9);
161 : #define DEF_FUNCTION_TYPE_10(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \
162 : A10) \
163 : define_function_type (ENUM, RETURN, 0, 10, A1, A2, A3, A4, A5, A6, A7, A8, \
164 : A9, A10);
165 : #define DEF_FUNCTION_TYPE_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \
166 : A10, A11) \
167 : define_function_type (ENUM, RETURN, 0, 11, A1, A2, A3, A4, A5, A6, A7, A8, \
168 : A9, A10, A11);
169 : #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
170 : define_function_type (ENUM, RETURN, 1, 0);
171 : #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, A1) \
172 : define_function_type (ENUM, RETURN, 1, 1, A1);
173 : #define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, A1, A2) \
174 : define_function_type (ENUM, RETURN, 1, 2, A1, A2);
175 : #define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, A1, A2, A3) \
176 : define_function_type (ENUM, RETURN, 1, 3, A1, A2, A3);
177 : #define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, A1, A2, A3, A4) \
178 : define_function_type (ENUM, RETURN, 1, 4, A1, A2, A3, A4);
179 : #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, A1, A2, A3, A4, A5) \
180 : define_function_type (ENUM, RETURN, 1, 5, A1, A2, A3, A4, A5);
181 : #define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \
182 : define_function_type (ENUM, RETURN, 1, 6, A1, A2, A3, A4, A5, A6);
183 : #define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \
184 : define_function_type (ENUM, RETURN, 1, 7, A1, A2, A3, A4, A5, A6, A7);
185 : #define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, \
186 : A9, A10, A11) \
187 : define_function_type (ENUM, RETURN, 1, 11, A1, A2, A3, A4, A5, A6, A7, A8, \
188 : A9, A10, A11);
189 : #define DEF_POINTER_TYPE(ENUM, TYPE) \
190 : builtin_types[ENUM] = build_pointer_type (builtin_types[TYPE]);
191 :
192 : #include "builtin-types.def"
193 :
194 : #undef DEF_PRIMITIVE_TYPE
195 : #undef DEF_FUNCTION_TYPE_1
196 : #undef DEF_FUNCTION_TYPE_2
197 : #undef DEF_FUNCTION_TYPE_3
198 : #undef DEF_FUNCTION_TYPE_4
199 : #undef DEF_FUNCTION_TYPE_5
200 : #undef DEF_FUNCTION_TYPE_6
201 : #undef DEF_FUNCTION_TYPE_7
202 : #undef DEF_FUNCTION_TYPE_8
203 : #undef DEF_FUNCTION_TYPE_9
204 : #undef DEF_FUNCTION_TYPE_10
205 : #undef DEF_FUNCTION_TYPE_11
206 : #undef DEF_FUNCTION_TYPE_VAR_0
207 : #undef DEF_FUNCTION_TYPE_VAR_1
208 : #undef DEF_FUNCTION_TYPE_VAR_2
209 : #undef DEF_FUNCTION_TYPE_VAR_3
210 : #undef DEF_FUNCTION_TYPE_VAR_4
211 : #undef DEF_FUNCTION_TYPE_VAR_5
212 : #undef DEF_FUNCTION_TYPE_VAR_6
213 : #undef DEF_FUNCTION_TYPE_VAR_7
214 : #undef DEF_FUNCTION_TYPE_VAR_11
215 : #undef DEF_POINTER_TYPE
216 :
217 1527 : builtin_types[Type::BT_LAST] = NULL_TREE;
218 1527 : }
219 :
220 : /**
221 : * Define all builtin attributes in the `builtin_types` array
222 : */
223 : void
224 1527 : BuiltinsContext::define_builtin_attributes ()
225 :
226 : {
227 1527 : auto *built_in_attributes = builtin_attributes;
228 :
229 : #define DEF_ATTR_NULL_TREE(ENUM) built_in_attributes[(int) ENUM] = NULL_TREE;
230 : #define DEF_ATTR_INT(ENUM, VALUE) \
231 : built_in_attributes[ENUM] = build_int_cst (NULL_TREE, VALUE);
232 : #define DEF_ATTR_STRING(ENUM, VALUE) \
233 : built_in_attributes[ENUM] = build_string (strlen (VALUE), VALUE);
234 : #define DEF_ATTR_IDENT(ENUM, STRING) \
235 : built_in_attributes[ENUM] = get_identifier (STRING);
236 : #define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
237 : built_in_attributes[ENUM] \
238 : = tree_cons (built_in_attributes[PURPOSE], built_in_attributes[VALUE], \
239 : built_in_attributes[CHAIN]);
240 : #include "builtin-attrs.def"
241 : #undef DEF_ATTR_NULL_TREE
242 : #undef DEF_ATTR_INT
243 : #undef DEF_ATTR_STRING
244 : #undef DEF_ATTR_IDENT
245 : #undef DEF_ATTR_TREE_LIST
246 1527 : }
247 :
248 : /**
249 : * Define all builtin functions during the first initialization of the
250 : * `BuiltinsContext`.
251 : */
252 : void
253 1527 : BuiltinsContext::define_builtins ()
254 : {
255 1527 : auto *built_in_attributes = builtin_attributes;
256 2299662 : auto build_builtin = [this] (built_in_function fn_code, const char *fn_name,
257 : built_in_class fn_class, tree fn_type, bool both,
258 : bool fallback, tree attributes, bool implicit) {
259 2298135 : if (fn_type == error_mark_node)
260 2298135 : return;
261 :
262 2174448 : static auto to_skip = strlen ("__builtin_");
263 :
264 2174448 : auto libname = fn_name + to_skip;
265 2820369 : auto decl = add_builtin_function (fn_name, fn_type, fn_code, fn_class,
266 2174448 : fallback ? libname : NULL, attributes);
267 :
268 2174448 : set_builtin_decl (fn_code, decl, implicit);
269 :
270 2174448 : builtin_functions.insert ({std::string (fn_name), decl});
271 1527 : };
272 :
273 : #define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \
274 : NONANSI_P, ATTRS, IMPLICIT, COND) \
275 : if (NAME && COND) \
276 : build_builtin (ENUM, NAME, CLASS, builtin_types[TYPE], BOTH_P, FALLBACK_P, \
277 : built_in_attributes[ATTRS], IMPLICIT);
278 : #include "builtins.def"
279 : #undef DEF_BUILTIN
280 1527 : }
281 :
282 : /**
283 : * Register direct mappings between Rust functions and GCC builtins
284 : */
285 : void
286 1527 : BuiltinsContext::register_rust_mappings ()
287 : {
288 1527 : rust_intrinsic_to_gcc_builtin = {
289 : {Values::Intrinsics::UNREACHABLE, "__builtin_unreachable"},
290 : {Values::Intrinsics::ABORT, "__builtin_abort"},
291 :
292 : // Math intrinsics
293 : {Values::Intrinsics::SQRTF32, "__builtin_sqrtf"},
294 : {Values::Intrinsics::SQRTF64, "__builtin_sqrt"},
295 :
296 : {Values::Intrinsics::SINF32, "__builtin_sinf"},
297 : {Values::Intrinsics::SINF64, "__builtin_sin"},
298 :
299 : {Values::Intrinsics::COSF32, "__builtin_cosf"},
300 : {Values::Intrinsics::COSF64, "__builtin_cos"},
301 :
302 : {Values::Intrinsics::POWF32, "__builtin_powf"},
303 : {Values::Intrinsics::POWF64, "__builtin_pow"},
304 :
305 : {Values::Intrinsics::POWIF32, "__builtin_powif"},
306 : {Values::Intrinsics::POWIF64, "__builtin_powi"},
307 :
308 : {Values::Intrinsics::EXPF32, "__builtin_expf"},
309 : {Values::Intrinsics::EXPF64, "__builtin_exp"},
310 :
311 : {Values::Intrinsics::EXP2F32, "__builtin_exp2f"},
312 : {Values::Intrinsics::EXP2F64, "__builtin_exp2"},
313 :
314 : {Values::Intrinsics::LOGF32, "__builtin_logf"},
315 : {Values::Intrinsics::LOGF64, "__builtin_log"},
316 :
317 : {Values::Intrinsics::LOG10F32, "__builtin_log10f"},
318 : {Values::Intrinsics::LOG10F64, "__builtin_log10"},
319 :
320 : {Values::Intrinsics::LOG2F32, "__builtin_log2f"},
321 : {Values::Intrinsics::LOG2F64, "__builtin_log2"},
322 :
323 : {Values::Intrinsics::FMAF32, "__builtin_fmaf"},
324 : {Values::Intrinsics::FMAF64, "__builtin_fma"},
325 :
326 : {Values::Intrinsics::FABSF32, "__builtin_fabsf"},
327 : {Values::Intrinsics::FABSF64, "__builtin_fabs"},
328 :
329 : {Values::Intrinsics::MINNUMF32, "__builtin_fminf"},
330 : {Values::Intrinsics::MINNUMF64, "__builtin_fmin"},
331 :
332 : {Values::Intrinsics::MAXNUMF32, "__builtin_fmaxf"},
333 : {Values::Intrinsics::MAXNUMF64, "__builtin_fmax"},
334 :
335 : {Values::Intrinsics::COPYSIGNF32, "__builtin_copysignf"},
336 : {Values::Intrinsics::COPYSIGNF64, "__builtin_copysign"},
337 :
338 : {Values::Intrinsics::FLOORF32, "__builtin_floorf"},
339 : {Values::Intrinsics::FLOORF64, "__builtin_floor"},
340 :
341 : {Values::Intrinsics::CEILF32, "__builtin_ceilf"},
342 : {Values::Intrinsics::CEILF64, "__builtin_ceil"},
343 :
344 : {Values::Intrinsics::TRUNCF32, "__builtin_truncf"},
345 : {Values::Intrinsics::TRUNCF64, "__builtin_trunc"},
346 :
347 : {Values::Intrinsics::RINTF32, "__builtin_rintf"},
348 : {Values::Intrinsics::RINTF64, "__builtin_rint"},
349 :
350 : {Values::Intrinsics::NEARBYINTF32, "__builtin_nearbyintf"},
351 : {Values::Intrinsics::NEARBYINTF64, "__builtin_nearbyint"},
352 :
353 : {Values::Intrinsics::ROUNDF32, "__builtin_roundf"},
354 : {Values::Intrinsics::ROUNDF64, "__builtin_round"},
355 68715 : };
356 1527 : }
357 :
358 : void
359 1527 : BuiltinsContext::setup ()
360 : {
361 1527 : define_builtin_types ();
362 1527 : define_builtin_attributes ();
363 1527 : define_builtins ();
364 :
365 1527 : register_rust_mappings ();
366 1527 : }
367 :
368 : bool
369 10189 : BuiltinsContext::lookup_gcc_builtin (const std::string &name, tree *builtin)
370 : {
371 10189 : auto it = builtin_functions.find (name);
372 10189 : if (it == builtin_functions.end ())
373 : return false;
374 :
375 7268 : *builtin = it->second;
376 7268 : return true;
377 : }
378 :
379 : } // namespace Compile
380 : } // namespace Rust
|