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 26647334 : BuiltinsContext::get ()
30 : {
31 26647334 : static BuiltinsContext instance;
32 :
33 26647334 : if (instance.setup_state == SetupState::UNINITIALIZED)
34 5117 : instance.setup ();
35 :
36 26647334 : return instance;
37 : }
38 :
39 : bool
40 11243 : BuiltinsContext::lookup_simple_builtin (const std::string &name, tree *builtin)
41 : {
42 11243 : auto *to_search = &name;
43 :
44 11243 : auto it = rust_intrinsic_to_gcc_builtin.find (name);
45 11243 : if (it != rust_intrinsic_to_gcc_builtin.end ())
46 449 : to_search = &it->second;
47 :
48 11243 : return lookup_gcc_builtin (*to_search, builtin);
49 : }
50 :
51 : LlvmBuiltinMappingResult
52 5 : BuiltinsContext::map_llvm_to_gcc_builtin (const std::string &name,
53 : tree *resolved,
54 : LlvmBuiltinAdapter *adapter)
55 : {
56 5 : rust_assert (resolved != nullptr);
57 :
58 5 : auto mapping = llvm_to_gcc_builtin.find (name);
59 5 : if (mapping == llvm_to_gcc_builtin.end ())
60 : return LlvmBuiltinMappingResult::NOT_MAPPED;
61 :
62 5 : *resolved = NULL_TREE;
63 5 : if (!lookup_gcc_builtin (mapping->second.gcc_name, resolved))
64 : return LlvmBuiltinMappingResult::TARGET_UNAVAILABLE;
65 :
66 5 : *adapter = mapping->second.adapter;
67 5 : return LlvmBuiltinMappingResult::RESOLVED;
68 : }
69 :
70 5117 : BuiltinsContext::BuiltinsContext () : setup_state (SetupState::UNINITIALIZED) {}
71 :
72 : /**
73 : * Define a function type according to `builtin-types.def`
74 : *
75 : * *Heavily* inspired by the D frontend's `def_fn_type` function
76 : */
77 : void
78 2604553 : BuiltinsContext::define_function_type (Type def_idx, Type ret_idx,
79 : bool is_variadic, size_t n, ...)
80 : {
81 2604553 : va_list list;
82 2604553 : va_start (list, n);
83 :
84 2604553 : auto args = std::vector<tree> ();
85 :
86 8350944 : for (size_t i = 0; i < n; i++)
87 : {
88 : // The argument is an enum Type, but it's promoted to int when passed
89 : // though '...'.
90 5746391 : auto arg_idx = va_arg (list, int);
91 5746391 : auto arg_type = builtin_types[arg_idx];
92 :
93 5746391 : args.emplace_back (arg_type);
94 : }
95 :
96 2604553 : auto return_type = builtin_types[ret_idx];
97 2604553 : if (return_type == error_mark_node)
98 : {
99 : // Mark the builtin as not available.
100 66521 : builtin_types[def_idx] = error_mark_node;
101 66521 : va_end (list);
102 66521 : return;
103 : }
104 :
105 2538032 : auto fn_type = NULL_TREE;
106 2538032 : if (is_variadic)
107 153510 : fn_type = build_varargs_function_type_array (return_type, n, args.data ());
108 : else
109 2384522 : fn_type = build_function_type_array (return_type, n, args.data ());
110 :
111 2538032 : builtin_types[def_idx] = fn_type;
112 2538032 : va_end (list);
113 2604553 : }
114 :
115 : // Taken directly from the D frontend
116 : static void
117 5117 : build_c_type_nodes (void)
118 : {
119 5117 : string_type_node = build_pointer_type (char_type_node);
120 5117 : const_string_type_node = build_pointer_type (
121 : build_qualified_type (char_type_node, TYPE_QUAL_CONST));
122 :
123 5117 : if (strcmp (UINTMAX_TYPE, "unsigned int") == 0)
124 : {
125 0 : intmax_type_node = integer_type_node;
126 0 : uintmax_type_node = unsigned_type_node;
127 : }
128 5117 : else if (strcmp (UINTMAX_TYPE, "long unsigned int") == 0)
129 : {
130 5117 : intmax_type_node = long_integer_type_node;
131 5117 : uintmax_type_node = long_unsigned_type_node;
132 : }
133 0 : else if (strcmp (UINTMAX_TYPE, "long long unsigned int") == 0)
134 : {
135 0 : intmax_type_node = long_long_integer_type_node;
136 0 : uintmax_type_node = long_long_unsigned_type_node;
137 : }
138 : else
139 0 : gcc_unreachable ();
140 :
141 5117 : signed_size_type_node = signed_type_for (size_type_node);
142 5117 : wint_type_node = unsigned_type_node;
143 5117 : pid_type_node = integer_type_node;
144 5117 : }
145 :
146 : /**
147 : * Define all builtin types in the `builtin_types` array
148 : */
149 : void
150 5117 : BuiltinsContext::define_builtin_types ()
151 : {
152 : // This is taken directly from the D frontend's handling of builtins
153 5117 : auto va_list_ref_type_node = build_reference_type (va_list_type_node);
154 5117 : auto va_list_arg_type_node = va_list_type_node;
155 :
156 5117 : build_c_type_nodes ();
157 :
158 5117 : auto builtin_type_for_size = [] (int size, bool unsignedp) {
159 25585 : tree type = lang_hooks.types.type_for_size (size, unsignedp);
160 25585 : return type ? type : error_mark_node;
161 : };
162 :
163 : #define DEF_PRIMITIVE_TYPE(ENUM, VALUE) builtin_types[ENUM] = VALUE;
164 : #define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
165 : define_function_type (ENUM, RETURN, 0, 0);
166 : #define DEF_FUNCTION_TYPE_1(ENUM, RETURN, A1) \
167 : define_function_type (ENUM, RETURN, 0, 1, A1);
168 : #define DEF_FUNCTION_TYPE_2(ENUM, RETURN, A1, A2) \
169 : define_function_type (ENUM, RETURN, 0, 2, A1, A2);
170 : #define DEF_FUNCTION_TYPE_3(ENUM, RETURN, A1, A2, A3) \
171 : define_function_type (ENUM, RETURN, 0, 3, A1, A2, A3);
172 : #define DEF_FUNCTION_TYPE_4(ENUM, RETURN, A1, A2, A3, A4) \
173 : define_function_type (ENUM, RETURN, 0, 4, A1, A2, A3, A4);
174 : #define DEF_FUNCTION_TYPE_5(ENUM, RETURN, A1, A2, A3, A4, A5) \
175 : define_function_type (ENUM, RETURN, 0, 5, A1, A2, A3, A4, A5);
176 : #define DEF_FUNCTION_TYPE_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \
177 : define_function_type (ENUM, RETURN, 0, 6, A1, A2, A3, A4, A5, A6);
178 : #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \
179 : define_function_type (ENUM, RETURN, 0, 7, A1, A2, A3, A4, A5, A6, A7);
180 : #define DEF_FUNCTION_TYPE_8(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8) \
181 : define_function_type (ENUM, RETURN, 0, 8, A1, A2, A3, A4, A5, A6, A7, A8);
182 : #define DEF_FUNCTION_TYPE_9(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9) \
183 : define_function_type (ENUM, RETURN, 0, 9, A1, A2, A3, A4, A5, A6, A7, A8, A9);
184 : #define DEF_FUNCTION_TYPE_10(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \
185 : A10) \
186 : define_function_type (ENUM, RETURN, 0, 10, A1, A2, A3, A4, A5, A6, A7, A8, \
187 : A9, A10);
188 : #define DEF_FUNCTION_TYPE_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \
189 : A10, A11) \
190 : define_function_type (ENUM, RETURN, 0, 11, A1, A2, A3, A4, A5, A6, A7, A8, \
191 : A9, A10, A11);
192 : #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
193 : define_function_type (ENUM, RETURN, 1, 0);
194 : #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, A1) \
195 : define_function_type (ENUM, RETURN, 1, 1, A1);
196 : #define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, A1, A2) \
197 : define_function_type (ENUM, RETURN, 1, 2, A1, A2);
198 : #define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, A1, A2, A3) \
199 : define_function_type (ENUM, RETURN, 1, 3, A1, A2, A3);
200 : #define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, A1, A2, A3, A4) \
201 : define_function_type (ENUM, RETURN, 1, 4, A1, A2, A3, A4);
202 : #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, A1, A2, A3, A4, A5) \
203 : define_function_type (ENUM, RETURN, 1, 5, A1, A2, A3, A4, A5);
204 : #define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \
205 : define_function_type (ENUM, RETURN, 1, 6, A1, A2, A3, A4, A5, A6);
206 : #define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \
207 : define_function_type (ENUM, RETURN, 1, 7, A1, A2, A3, A4, A5, A6, A7);
208 : #define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, \
209 : A9, A10, A11) \
210 : define_function_type (ENUM, RETURN, 1, 11, A1, A2, A3, A4, A5, A6, A7, A8, \
211 : A9, A10, A11);
212 : #define DEF_POINTER_TYPE(ENUM, TYPE) \
213 : builtin_types[ENUM] = build_pointer_type (builtin_types[TYPE]);
214 :
215 : #include "builtin-types.def"
216 :
217 : #undef DEF_PRIMITIVE_TYPE
218 : #undef DEF_FUNCTION_TYPE_1
219 : #undef DEF_FUNCTION_TYPE_2
220 : #undef DEF_FUNCTION_TYPE_3
221 : #undef DEF_FUNCTION_TYPE_4
222 : #undef DEF_FUNCTION_TYPE_5
223 : #undef DEF_FUNCTION_TYPE_6
224 : #undef DEF_FUNCTION_TYPE_7
225 : #undef DEF_FUNCTION_TYPE_8
226 : #undef DEF_FUNCTION_TYPE_9
227 : #undef DEF_FUNCTION_TYPE_10
228 : #undef DEF_FUNCTION_TYPE_11
229 : #undef DEF_FUNCTION_TYPE_VAR_0
230 : #undef DEF_FUNCTION_TYPE_VAR_1
231 : #undef DEF_FUNCTION_TYPE_VAR_2
232 : #undef DEF_FUNCTION_TYPE_VAR_3
233 : #undef DEF_FUNCTION_TYPE_VAR_4
234 : #undef DEF_FUNCTION_TYPE_VAR_5
235 : #undef DEF_FUNCTION_TYPE_VAR_6
236 : #undef DEF_FUNCTION_TYPE_VAR_7
237 : #undef DEF_FUNCTION_TYPE_VAR_11
238 : #undef DEF_POINTER_TYPE
239 :
240 5117 : builtin_types[Type::BT_LAST] = NULL_TREE;
241 5117 : }
242 :
243 : /**
244 : * Define all builtin attributes in the `builtin_types` array
245 : */
246 : void
247 5117 : BuiltinsContext::define_builtin_attributes ()
248 :
249 : {
250 5117 : auto *built_in_attributes = builtin_attributes;
251 :
252 : #define DEF_ATTR_NULL_TREE(ENUM) built_in_attributes[(int) ENUM] = NULL_TREE;
253 : #define DEF_ATTR_INT(ENUM, VALUE) \
254 : built_in_attributes[ENUM] = build_int_cst (integer_type_node, VALUE);
255 : #define DEF_ATTR_STRING(ENUM, VALUE) \
256 : built_in_attributes[ENUM] = build_string (strlen (VALUE), VALUE);
257 : #define DEF_ATTR_IDENT(ENUM, STRING) \
258 : built_in_attributes[ENUM] = get_identifier (STRING);
259 : #define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
260 : built_in_attributes[ENUM] \
261 : = tree_cons (built_in_attributes[PURPOSE], built_in_attributes[VALUE], \
262 : built_in_attributes[CHAIN]);
263 : #include "builtin-attrs.def"
264 : #undef DEF_ATTR_NULL_TREE
265 : #undef DEF_ATTR_INT
266 : #undef DEF_ATTR_STRING
267 : #undef DEF_ATTR_IDENT
268 : #undef DEF_ATTR_TREE_LIST
269 5117 : }
270 :
271 : /**
272 : * Define all builtin functions during the first initialization of the
273 : * `BuiltinsContext`.
274 : */
275 : void
276 5117 : BuiltinsContext::define_builtins ()
277 : {
278 5117 : auto *built_in_attributes = builtin_attributes;
279 7706202 : auto build_builtin = [this] (built_in_function fn_code, const char *fn_name,
280 : built_in_class fn_class, tree fn_type, bool both,
281 : bool fallback, tree attributes, bool implicit) {
282 7701085 : if (fn_type == error_mark_node)
283 7701085 : return;
284 :
285 7286608 : static auto to_skip = strlen ("__builtin_");
286 :
287 7286608 : auto libname = fn_name + to_skip;
288 9451099 : auto decl = add_builtin_function (fn_name, fn_type, fn_code, fn_class,
289 7286608 : fallback ? libname : NULL, attributes);
290 :
291 7286608 : set_builtin_decl (fn_code, decl, implicit);
292 :
293 7286608 : builtin_functions.insert ({std::string (fn_name), decl});
294 5117 : };
295 :
296 : #define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \
297 : NONANSI_P, ATTRS, IMPLICIT, COND) \
298 : if (NAME && COND) \
299 : build_builtin (ENUM, NAME, CLASS, builtin_types[TYPE], BOTH_P, FALLBACK_P, \
300 : built_in_attributes[ATTRS], IMPLICIT);
301 : #include "builtins.def"
302 : #undef DEF_BUILTIN
303 5117 : }
304 :
305 : /**
306 : * Register direct mappings between Rust functions and GCC builtins
307 : */
308 : void
309 5117 : BuiltinsContext::register_rust_mappings ()
310 : {
311 5117 : rust_intrinsic_to_gcc_builtin = {
312 : {Values::Intrinsics::UNREACHABLE, "__builtin_unreachable"},
313 : {Values::Intrinsics::ABORT, "__builtin_abort"},
314 :
315 : // Math intrinsics
316 : {Values::Intrinsics::SQRTF32, "__builtin_sqrtf"},
317 : {Values::Intrinsics::SQRTF64, "__builtin_sqrt"},
318 :
319 : {Values::Intrinsics::SINF32, "__builtin_sinf"},
320 : {Values::Intrinsics::SINF64, "__builtin_sin"},
321 :
322 : {Values::Intrinsics::COSF32, "__builtin_cosf"},
323 : {Values::Intrinsics::COSF64, "__builtin_cos"},
324 :
325 : {Values::Intrinsics::POWF32, "__builtin_powf"},
326 : {Values::Intrinsics::POWF64, "__builtin_pow"},
327 :
328 : {Values::Intrinsics::POWIF32, "__builtin_powif"},
329 : {Values::Intrinsics::POWIF64, "__builtin_powi"},
330 :
331 : {Values::Intrinsics::EXPF32, "__builtin_expf"},
332 : {Values::Intrinsics::EXPF64, "__builtin_exp"},
333 :
334 : {Values::Intrinsics::EXP2F32, "__builtin_exp2f"},
335 : {Values::Intrinsics::EXP2F64, "__builtin_exp2"},
336 :
337 : {Values::Intrinsics::LOGF32, "__builtin_logf"},
338 : {Values::Intrinsics::LOGF64, "__builtin_log"},
339 :
340 : {Values::Intrinsics::LOG10F32, "__builtin_log10f"},
341 : {Values::Intrinsics::LOG10F64, "__builtin_log10"},
342 :
343 : {Values::Intrinsics::LOG2F32, "__builtin_log2f"},
344 : {Values::Intrinsics::LOG2F64, "__builtin_log2"},
345 :
346 : {Values::Intrinsics::FMAF32, "__builtin_fmaf"},
347 : {Values::Intrinsics::FMAF64, "__builtin_fma"},
348 :
349 : {Values::Intrinsics::FABSF32, "__builtin_fabsf"},
350 : {Values::Intrinsics::FABSF64, "__builtin_fabs"},
351 :
352 : {Values::Intrinsics::MINNUMF32, "__builtin_fminf"},
353 : {Values::Intrinsics::MINNUMF64, "__builtin_fmin"},
354 :
355 : {Values::Intrinsics::MAXNUMF32, "__builtin_fmaxf"},
356 : {Values::Intrinsics::MAXNUMF64, "__builtin_fmax"},
357 :
358 : {Values::Intrinsics::COPYSIGNF32, "__builtin_copysignf"},
359 : {Values::Intrinsics::COPYSIGNF64, "__builtin_copysign"},
360 :
361 : {Values::Intrinsics::FLOORF32, "__builtin_floorf"},
362 : {Values::Intrinsics::FLOORF64, "__builtin_floor"},
363 :
364 : {Values::Intrinsics::CEILF32, "__builtin_ceilf"},
365 : {Values::Intrinsics::CEILF64, "__builtin_ceil"},
366 :
367 : {Values::Intrinsics::TRUNCF32, "__builtin_truncf"},
368 : {Values::Intrinsics::TRUNCF64, "__builtin_trunc"},
369 :
370 : {Values::Intrinsics::RINTF32, "__builtin_rintf"},
371 : {Values::Intrinsics::RINTF64, "__builtin_rint"},
372 :
373 : {Values::Intrinsics::NEARBYINTF32, "__builtin_nearbyintf"},
374 : {Values::Intrinsics::NEARBYINTF64, "__builtin_nearbyint"},
375 :
376 : {Values::Intrinsics::ROUNDF32, "__builtin_roundf"},
377 : {Values::Intrinsics::ROUNDF64, "__builtin_round"},
378 230265 : };
379 5117 : }
380 :
381 : void
382 5117 : BuiltinsContext::register_llvm_to_gcc_builtin ()
383 : {
384 5117 : llvm_to_gcc_builtin = {
385 5117 : {"llvm.x86.rdrand.16",
386 5117 : {"__builtin_ia32_rdrand16_step",
387 : LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
388 10234 : {"llvm.x86.rdrand.32",
389 5117 : {"__builtin_ia32_rdrand32_step",
390 : LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
391 10234 : {"llvm.x86.rdrand.64",
392 5117 : {"__builtin_ia32_rdrand64_step",
393 : LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
394 10234 : {"llvm.x86.rdseed.16",
395 5117 : {"__builtin_ia32_rdseed_hi_step",
396 : LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
397 10234 : {"llvm.x86.rdseed.32",
398 5117 : {"__builtin_ia32_rdseed_si_step",
399 : LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
400 10234 : {"llvm.x86.rdseed.64",
401 5117 : {"__builtin_ia32_rdseed_di_step",
402 : LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
403 :
404 10234 : {"llvm.x86.addcarry.32",
405 5117 : {"__builtin_ia32_addcarryx_u32",
406 : LlvmBuiltinAdapter::OUTPUT_POINTER_STATUS_VALUE}},
407 10234 : {"llvm.x86.addcarryx.u32",
408 5117 : {"__builtin_ia32_addcarryx_u32", LlvmBuiltinAdapter::FORWARD_ARGUMENTS}},
409 10234 : {"llvm.x86.subborrow.32",
410 5117 : {"__builtin_ia32_sbb_u32",
411 : LlvmBuiltinAdapter::OUTPUT_POINTER_STATUS_VALUE}},
412 10234 : {"llvm.x86.addcarry.64",
413 5117 : {"__builtin_ia32_addcarryx_u64",
414 : LlvmBuiltinAdapter::OUTPUT_POINTER_STATUS_VALUE}},
415 10234 : {"llvm.x86.addcarryx.u64",
416 5117 : {"__builtin_ia32_addcarryx_u64", LlvmBuiltinAdapter::FORWARD_ARGUMENTS}},
417 10234 : {"llvm.x86.subborrow.64",
418 5117 : {"__builtin_ia32_sbb_u64",
419 : LlvmBuiltinAdapter::OUTPUT_POINTER_STATUS_VALUE}},
420 :
421 10234 : {"llvm.x86.vcvtph2ps.128",
422 5117 : {"__builtin_ia32_vcvtph2ps", LlvmBuiltinAdapter::FORWARD_ARGUMENTS}},
423 10234 : {"llvm.x86.vcvtph2ps.256",
424 5117 : {"__builtin_ia32_vcvtph2ps256", LlvmBuiltinAdapter::FORWARD_ARGUMENTS}},
425 10234 : {"llvm.x86.vcvtps2ph.128",
426 5117 : {"__builtin_ia32_vcvtps2ph", LlvmBuiltinAdapter::FORWARD_ARGUMENTS}},
427 10234 : {"llvm.x86.vcvtps2ph.256",
428 5117 : {"__builtin_ia32_vcvtps2ph256", LlvmBuiltinAdapter::FORWARD_ARGUMENTS}},
429 245616 : };
430 5117 : }
431 :
432 : void
433 26633985 : BuiltinsContext::register_builtin (tree decl)
434 : {
435 26633985 : rust_assert (TREE_CODE (decl) == FUNCTION_DECL);
436 26633985 : rust_assert (DECL_NAME (decl));
437 :
438 26633985 : const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
439 26633985 : builtin_functions.insert ({std::string (name), decl});
440 26633985 : }
441 :
442 : void
443 5117 : BuiltinsContext::setup ()
444 : {
445 5117 : rust_assert (setup_state == SetupState::UNINITIALIZED);
446 5117 : setup_state = SetupState::INITIALIZING;
447 :
448 5117 : define_builtin_types ();
449 5117 : define_builtin_attributes ();
450 5117 : define_builtins ();
451 :
452 5117 : targetm.init_builtins ();
453 :
454 5117 : register_rust_mappings ();
455 5117 : register_llvm_to_gcc_builtin ();
456 :
457 5117 : setup_state = SetupState::READY;
458 5117 : }
459 :
460 : bool
461 11248 : BuiltinsContext::lookup_gcc_builtin (const std::string &name, tree *builtin)
462 : {
463 11248 : auto it = builtin_functions.find (name);
464 11248 : if (it == builtin_functions.end ())
465 : return false;
466 :
467 7914 : *builtin = it->second;
468 7914 : return true;
469 : }
470 :
471 : } // namespace Compile
472 : } // namespace Rust
|