// This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. #include "rust-builtins.h" namespace Rust { namespace Compile { static const int builtin_const = 1 << 0; static const int builtin_noreturn = 1 << 1; static const int builtin_novops = 1 << 2; BuiltinsContext & BuiltinsContext::get () { static BuiltinsContext instance; return instance; } bool BuiltinsContext::lookup_simple_builtin (const std::string &name, tree *builtin) { auto it = rust_intrinsic_to_gcc_builtin.find (name); if (it == rust_intrinsic_to_gcc_builtin.end ()) return false; return lookup_gcc_builtin (it->second, builtin); } BuiltinsContext::BuiltinsContext () { setup (); } void BuiltinsContext::setup_overflow_fns () { tree overflow_type = build_varargs_function_type_list (boolean_type_node, NULL_TREE); define_builtin ("add_overflow", BUILT_IN_ADD_OVERFLOW, "__builtin_add_overflow", "add_overflow", overflow_type, 0); define_builtin ("sub_overflow", BUILT_IN_SUB_OVERFLOW, "__builtin_sub_overflow", "sub_overflow", overflow_type, 0); define_builtin ("mul_overflow", BUILT_IN_MUL_OVERFLOW, "__builtin_mul_overflow", "mul_overflow", overflow_type, 0); } void BuiltinsContext::setup_math_fns () { tree fn_type_f32_to_f32 = build_function_type_list (float_type_node, float_type_node, NULL_TREE); tree fn_type_f64_to_f64 = build_function_type_list (double_type_node, double_type_node, NULL_TREE); tree fn_type_f32_f32_to_f32 = build_function_type_list (float_type_node, float_type_node, float_type_node, NULL_TREE); tree fn_type_f64_f64_to_f64 = build_function_type_list (double_type_node, double_type_node, double_type_node, NULL_TREE); tree fn_type_f32_i32_to_f32 = build_function_type_list (float_type_node, float_type_node, integer_type_node, NULL_TREE); tree fn_type_f64_i32_to_f64 = build_function_type_list (double_type_node, double_type_node, integer_type_node, NULL_TREE); define_builtin ("sqrtf32", BUILT_IN_SQRTF, "__builtin_sqrtf", "sqrtf", fn_type_f32_to_f32, builtin_const); define_builtin ("sqrtf64", BUILT_IN_SQRT, "__builtin_sqrt", "sqrt", fn_type_f64_to_f64, builtin_const); define_builtin ("powif32", BUILT_IN_POWIF, "__builtin_powif", "powif", fn_type_f32_i32_to_f32, builtin_const); define_builtin ("powif64", BUILT_IN_POWI, "__builtin_powi", "powi", fn_type_f64_i32_to_f64, builtin_const); define_builtin ("sinf32", BUILT_IN_SINF, "__builtin_sinf", "sinf", fn_type_f32_to_f32, builtin_const); define_builtin ("sinf64", BUILT_IN_SIN, "__builtin_sin", "sin", fn_type_f64_to_f64, builtin_const); define_builtin ("cosf32", BUILT_IN_COSF, "__builtin_cosf", "cosf", fn_type_f32_to_f32, builtin_const); define_builtin ("cosf64", BUILT_IN_COS, "__builtin_cos", "cos", fn_type_f64_to_f64, builtin_const); define_builtin ("powf32", BUILT_IN_POWF, "__builtin_powf", "powf", fn_type_f32_f32_to_f32, builtin_const); define_builtin ("powf64", BUILT_IN_POW, "__builtin_pow", "pow", fn_type_f64_f64_to_f64, builtin_const); define_builtin ("expf32", BUILT_IN_EXPF, "__builtin_expf", "expf", fn_type_f32_to_f32, builtin_const); define_builtin ("expf64", BUILT_IN_EXP, "__builtin_exp", "exp", fn_type_f64_to_f64, builtin_const); define_builtin ("exp2f32", BUILT_IN_EXP2F, "__builtin_exp2f", "exp2f", fn_type_f32_to_f32, builtin_const); define_builtin ("exp2f64", BUILT_IN_EXP2, "__builtin_exp2", "exp2", fn_type_f64_to_f64, builtin_const); define_builtin ("logf32", BUILT_IN_LOGF, "__builtin_logf", "logf", fn_type_f32_to_f32, builtin_const); define_builtin ("logf64", BUILT_IN_LOG, "__builtin_log", "log", fn_type_f64_to_f64, builtin_const); define_builtin ("log10f32", BUILT_IN_LOG10F, "__builtin_log10f", "log10f", fn_type_f32_to_f32, builtin_const); define_builtin ("log10f64", BUILT_IN_LOG10, "__builtin_log10", "log10", fn_type_f64_to_f64, builtin_const); define_builtin ("log2f32", BUILT_IN_LOG2F, "__builtin_log2f", "log2f", fn_type_f32_to_f32, builtin_const); define_builtin ("log2f64", BUILT_IN_LOG2, "__builtin_log2", "log2", fn_type_f64_to_f64, builtin_const); define_builtin ("fmaf32", BUILT_IN_FMAF, "__builtin_fmaf", "fmaf", fn_type_f32_f32_to_f32, builtin_const); define_builtin ("fmaf64", BUILT_IN_FMA, "__builtin_fma", "fma", fn_type_f64_f64_to_f64, builtin_const); define_builtin ("fabsf32", BUILT_IN_FABSF, "__builtin_fabsf", "fabsf", fn_type_f32_to_f32, builtin_const); define_builtin ("fabsf64", BUILT_IN_FABS, "__builtin_fabs", "fabs", fn_type_f64_to_f64, builtin_const); define_builtin ("minnumf32", BUILT_IN_FMINF, "__builtin_fminf", "fminf", fn_type_f32_f32_to_f32, builtin_const); define_builtin ("minnumf64", BUILT_IN_FMIN, "__builtin_fmin", "fmin", fn_type_f64_f64_to_f64, builtin_const); define_builtin ("maxnumf32", BUILT_IN_FMAXF, "__builtin_fmaxf", "fmaxf", fn_type_f32_f32_to_f32, builtin_const); define_builtin ("maxnumf64", BUILT_IN_FMAX, "__builtin_fmax", "fmax", fn_type_f64_f64_to_f64, builtin_const); define_builtin ("copysignf32", BUILT_IN_COPYSIGNF, "__builtin_copysignf", "copysignf", fn_type_f32_f32_to_f32, builtin_const); define_builtin ("copysignf64", BUILT_IN_COPYSIGN, "__builtin_copysign", "copysign", fn_type_f64_f64_to_f64, builtin_const); define_builtin ("floorf32", BUILT_IN_FLOORF, "__builtin_floorf", "floorf", fn_type_f32_to_f32, builtin_const); define_builtin ("floorf64", BUILT_IN_FLOOR, "__builtin_floor", "floor", fn_type_f64_to_f64, builtin_const); define_builtin ("ceilf32", BUILT_IN_CEILF, "__builtin_ceilf", "ceilf", fn_type_f32_to_f32, builtin_const); define_builtin ("ceilf64", BUILT_IN_CEIL, "__builtin_ceil", "ceil", fn_type_f64_to_f64, builtin_const); define_builtin ("truncf32", BUILT_IN_TRUNCF, "__builtin_truncf", "truncf", fn_type_f32_to_f32, builtin_const); define_builtin ("truncf64", BUILT_IN_TRUNC, "__builtin_trunc", "trunc", fn_type_f64_to_f64, builtin_const); define_builtin ("rintf32", BUILT_IN_RINTF, "__builtin_rintf", "rintf", fn_type_f32_to_f32, builtin_const); define_builtin ("rintf64", BUILT_IN_RINT, "__builtin_rint", "rint", fn_type_f64_to_f64, builtin_const); define_builtin ("nearbyintf32", BUILT_IN_NEARBYINTF, "__builtin_nearbyintf", "nearbyintf", fn_type_f32_to_f32, builtin_const); define_builtin ("nearbyintf64", BUILT_IN_NEARBYINT, "__builtin_nearbyint", "nearbyint", fn_type_f64_to_f64, builtin_const); define_builtin ("roundf32", BUILT_IN_ROUNDF, "__builtin_roundf", "roundf", fn_type_f32_to_f32, builtin_const); define_builtin ("roundf64", BUILT_IN_ROUND, "__builtin_round", "round", fn_type_f64_to_f64, builtin_const); } void BuiltinsContext::setup_atomic_fns () { auto atomic_store_type = build_varargs_function_type_list (void_type_node, NULL_TREE); auto atomic_load_type = [] (tree ret_type_node) { return build_function_type_list (ret_type_node, ptr_type_node, // const_ptr_type_node? integer_type_node, NULL_TREE); }; // FIXME: These should be the definition for the generic version of the // atomic_store builtins, but I cannot get them to work properly. Revisit // later. define_builtin ("atomic_store", BUILT_IN_ATOMIC_STORE, // "__atomic_store", NULL, // atomic_store_type, 0); // define_builtin ("atomic_store_n", BUILT_IN_ATOMIC_STORE_N, // "__atomic_store_n", // NULL, atomic_store_type, 0); define_builtin ("atomic_store_1", BUILT_IN_ATOMIC_STORE_1, "__atomic_store_1", NULL, atomic_store_type, 0); define_builtin ("atomic_store_2", BUILT_IN_ATOMIC_STORE_2, "__atomic_store_2", NULL, atomic_store_type, 0); define_builtin ("atomic_store_4", BUILT_IN_ATOMIC_STORE_4, "__atomic_store_4", NULL, atomic_store_type, 0); define_builtin ("atomic_store_8", BUILT_IN_ATOMIC_STORE_8, "__atomic_store_8", NULL, atomic_store_type, 0); define_builtin ("atomic_store_16", BUILT_IN_ATOMIC_STORE_16, "__atomic_store_16", NULL, atomic_store_type, 0); define_builtin ("atomic_load_1", BUILT_IN_ATOMIC_LOAD_1, "__atomic_load_1", NULL, atomic_load_type (integer_type_node), 0); define_builtin ("atomic_load_2", BUILT_IN_ATOMIC_LOAD_2, "__atomic_load_2", NULL, atomic_load_type (integer_type_node), 0); define_builtin ("atomic_load_4", BUILT_IN_ATOMIC_LOAD_4, "__atomic_load_4", NULL, atomic_load_type (integer_type_node), 0); define_builtin ("atomic_load_8", BUILT_IN_ATOMIC_LOAD_8, "__atomic_load_8", NULL, atomic_load_type (integer_type_node), 0); } void BuiltinsContext::setup () { setup_math_fns (); setup_overflow_fns (); setup_atomic_fns (); define_builtin ("unreachable", BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL, build_function_type (void_type_node, void_list_node), builtin_const | builtin_noreturn); define_builtin ("abort", BUILT_IN_ABORT, "__builtin_abort", "abort", build_function_type (void_type_node, void_list_node), builtin_const | builtin_noreturn); define_builtin ("breakpoint", BUILT_IN_TRAP, "__builtin_trap", "breakpoint", build_function_type (void_type_node, void_list_node), builtin_const | builtin_noreturn); define_builtin ("memcpy", BUILT_IN_MEMCPY, "__builtin_memcpy", "memcpy", build_function_type_list (build_pointer_type (void_type_node), build_pointer_type (void_type_node), build_pointer_type (void_type_node), size_type_node, NULL_TREE), 0); define_builtin ("prefetch", BUILT_IN_PREFETCH, "__builtin_prefetch", "prefetch", build_varargs_function_type_list ( build_pointer_type (const_ptr_type_node), NULL_TREE), builtin_const); } static void handle_flags (tree decl, int flags) { if (flags & builtin_const) TREE_READONLY (decl) = 1; if (flags & builtin_noreturn) TREE_READONLY (decl) = 1; if (flags & builtin_novops) DECL_IS_NOVOPS (decl) = 1; } void BuiltinsContext::define_builtin (const std::string rust_name, built_in_function bcode, const char *name, const char *libname, tree fntype, int flags) { tree decl = add_builtin_function (name, fntype, bcode, BUILT_IN_NORMAL, libname, NULL_TREE); handle_flags (decl, flags); set_builtin_decl (bcode, decl, true); this->builtin_functions_[name] = decl; if (libname != NULL) { decl = add_builtin_function (libname, fntype, bcode, BUILT_IN_NORMAL, NULL, NULL_TREE); handle_flags (decl, flags); this->builtin_functions_[libname] = decl; } rust_intrinsic_to_gcc_builtin[rust_name] = name; } bool BuiltinsContext::lookup_gcc_builtin (const std::string &name, tree *builtin) { auto it = builtin_functions_.find (name); if (it == builtin_functions_.end ()) return false; *builtin = it->second; return true; } } // namespace Compile } // namespace Rust