// 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
// .
#include "rust-diagnostics.h"
#include "rust-system.h"
#include "rust-builtins.h"
#include "target.h"
#include "stringpool.h"
namespace Rust {
namespace Compile {
BuiltinsContext &
BuiltinsContext::get ()
{
static BuiltinsContext instance;
return instance;
}
bool
BuiltinsContext::lookup_simple_builtin (const std::string &name, tree *builtin)
{
auto *to_search = &name;
auto it = rust_intrinsic_to_gcc_builtin.find (name);
if (it != rust_intrinsic_to_gcc_builtin.end ())
to_search = &it->second;
return lookup_gcc_builtin (*to_search, builtin);
}
BuiltinsContext::BuiltinsContext () { setup (); }
/**
* Define a function type according to `builtin-types.def`
*
* *Heavily* inspired by the D frontend's `def_fn_type` function
*/
void
BuiltinsContext::define_function_type (Type def_idx, Type ret_idx,
bool is_variadic, size_t n, ...)
{
va_list list;
va_start (list, n);
auto args = std::vector ();
for (size_t i = 0; i < n; i++)
{
// The argument is an enum Type, but it's promoted to int when passed
// though '...'.
auto arg_idx = va_arg (list, int);
auto arg_type = builtin_types[arg_idx];
args.emplace_back (arg_type);
}
auto return_type = builtin_types[ret_idx];
if (return_type == error_mark_node)
{
// Mark the builtin as not available.
builtin_types[def_idx] = error_mark_node;
va_end (list);
return;
}
auto fn_type = NULL_TREE;
if (is_variadic)
fn_type = build_varargs_function_type_array (return_type, n, args.data ());
else
fn_type = build_function_type_array (return_type, n, args.data ());
builtin_types[def_idx] = fn_type;
va_end (list);
}
// Taken directly from the D frontend
static void
build_c_type_nodes (void)
{
string_type_node = build_pointer_type (char_type_node);
const_string_type_node = build_pointer_type (
build_qualified_type (char_type_node, TYPE_QUAL_CONST));
if (strcmp (UINTMAX_TYPE, "unsigned int") == 0)
{
intmax_type_node = integer_type_node;
uintmax_type_node = unsigned_type_node;
}
else if (strcmp (UINTMAX_TYPE, "long unsigned int") == 0)
{
intmax_type_node = long_integer_type_node;
uintmax_type_node = long_unsigned_type_node;
}
else if (strcmp (UINTMAX_TYPE, "long long unsigned int") == 0)
{
intmax_type_node = long_long_integer_type_node;
uintmax_type_node = long_long_unsigned_type_node;
}
else
gcc_unreachable ();
signed_size_type_node = signed_type_for (size_type_node);
wint_type_node = unsigned_type_node;
pid_type_node = integer_type_node;
}
/**
* Define all builtin types in the `builtin_types` array
*/
void
BuiltinsContext::define_builtin_types ()
{
// This is taken directly from the D frontend's handling of builtins
auto va_list_ref_type_node = build_reference_type (va_list_type_node);
auto va_list_arg_type_node = va_list_type_node;
build_c_type_nodes ();
auto builtin_type_for_size = [] (int size, bool unsignedp) {
tree type = lang_hooks.types.type_for_size (size, unsignedp);
return type ? type : error_mark_node;
};
#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) builtin_types[ENUM] = VALUE;
#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
define_function_type (ENUM, RETURN, 0, 0);
#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, A1) \
define_function_type (ENUM, RETURN, 0, 1, A1);
#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, A1, A2) \
define_function_type (ENUM, RETURN, 0, 2, A1, A2);
#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, A1, A2, A3) \
define_function_type (ENUM, RETURN, 0, 3, A1, A2, A3);
#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, A1, A2, A3, A4) \
define_function_type (ENUM, RETURN, 0, 4, A1, A2, A3, A4);
#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, A1, A2, A3, A4, A5) \
define_function_type (ENUM, RETURN, 0, 5, A1, A2, A3, A4, A5);
#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \
define_function_type (ENUM, RETURN, 0, 6, A1, A2, A3, A4, A5, A6);
#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \
define_function_type (ENUM, RETURN, 0, 7, A1, A2, A3, A4, A5, A6, A7);
#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8) \
define_function_type (ENUM, RETURN, 0, 8, A1, A2, A3, A4, A5, A6, A7, A8);
#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9) \
define_function_type (ENUM, RETURN, 0, 9, A1, A2, A3, A4, A5, A6, A7, A8, A9);
#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \
A10) \
define_function_type (ENUM, RETURN, 0, 10, A1, A2, A3, A4, A5, A6, A7, A8, \
A9, A10);
#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \
A10, A11) \
define_function_type (ENUM, RETURN, 0, 11, A1, A2, A3, A4, A5, A6, A7, A8, \
A9, A10, A11);
#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
define_function_type (ENUM, RETURN, 1, 0);
#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, A1) \
define_function_type (ENUM, RETURN, 1, 1, A1);
#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, A1, A2) \
define_function_type (ENUM, RETURN, 1, 2, A1, A2);
#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, A1, A2, A3) \
define_function_type (ENUM, RETURN, 1, 3, A1, A2, A3);
#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, A1, A2, A3, A4) \
define_function_type (ENUM, RETURN, 1, 4, A1, A2, A3, A4);
#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, A1, A2, A3, A4, A5) \
define_function_type (ENUM, RETURN, 1, 5, A1, A2, A3, A4, A5);
#define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \
define_function_type (ENUM, RETURN, 1, 6, A1, A2, A3, A4, A5, A6);
#define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \
define_function_type (ENUM, RETURN, 1, 7, A1, A2, A3, A4, A5, A6, A7);
#define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, \
A9, A10, A11) \
define_function_type (ENUM, RETURN, 1, 11, A1, A2, A3, A4, A5, A6, A7, A8, \
A9, A10, A11);
#define DEF_POINTER_TYPE(ENUM, TYPE) \
builtin_types[ENUM] = build_pointer_type (builtin_types[TYPE]);
#include "builtin-types.def"
#undef DEF_PRIMITIVE_TYPE
#undef DEF_FUNCTION_TYPE_1
#undef DEF_FUNCTION_TYPE_2
#undef DEF_FUNCTION_TYPE_3
#undef DEF_FUNCTION_TYPE_4
#undef DEF_FUNCTION_TYPE_5
#undef DEF_FUNCTION_TYPE_6
#undef DEF_FUNCTION_TYPE_7
#undef DEF_FUNCTION_TYPE_8
#undef DEF_FUNCTION_TYPE_9
#undef DEF_FUNCTION_TYPE_10
#undef DEF_FUNCTION_TYPE_11
#undef DEF_FUNCTION_TYPE_VAR_0
#undef DEF_FUNCTION_TYPE_VAR_1
#undef DEF_FUNCTION_TYPE_VAR_2
#undef DEF_FUNCTION_TYPE_VAR_3
#undef DEF_FUNCTION_TYPE_VAR_4
#undef DEF_FUNCTION_TYPE_VAR_5
#undef DEF_FUNCTION_TYPE_VAR_6
#undef DEF_FUNCTION_TYPE_VAR_7
#undef DEF_FUNCTION_TYPE_VAR_11
#undef DEF_POINTER_TYPE
builtin_types[Type::BT_LAST] = NULL_TREE;
}
/**
* Define all builtin attributes in the `builtin_types` array
*/
void
BuiltinsContext::define_builtin_attributes ()
{
auto *built_in_attributes = builtin_attributes;
#define DEF_ATTR_NULL_TREE(ENUM) built_in_attributes[(int) ENUM] = NULL_TREE;
#define DEF_ATTR_INT(ENUM, VALUE) \
built_in_attributes[ENUM] = build_int_cst (NULL_TREE, VALUE);
#define DEF_ATTR_STRING(ENUM, VALUE) \
built_in_attributes[ENUM] = build_string (strlen (VALUE), VALUE);
#define DEF_ATTR_IDENT(ENUM, STRING) \
built_in_attributes[ENUM] = get_identifier (STRING);
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
built_in_attributes[ENUM] \
= tree_cons (built_in_attributes[PURPOSE], built_in_attributes[VALUE], \
built_in_attributes[CHAIN]);
#include "builtin-attrs.def"
#undef DEF_ATTR_NULL_TREE
#undef DEF_ATTR_INT
#undef DEF_ATTR_STRING
#undef DEF_ATTR_IDENT
#undef DEF_ATTR_TREE_LIST
}
/**
* Define all builtin functions during the first initialization of the
* `BuiltinsContext`.
*/
void
BuiltinsContext::define_builtins ()
{
auto *built_in_attributes = builtin_attributes;
auto build_builtin = [this] (built_in_function fn_code, const char *fn_name,
built_in_class fn_class, tree fn_type, bool both,
bool fallback, tree attributes, bool implicit) {
if (fn_type == error_mark_node)
return;
static auto to_skip = strlen ("__builtin_");
auto libname = fn_name + to_skip;
auto decl = add_builtin_function (fn_name, fn_type, fn_code, fn_class,
fallback ? libname : NULL, attributes);
set_builtin_decl (fn_code, decl, implicit);
builtin_functions.insert ({std::string (fn_name), decl});
};
#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \
NONANSI_P, ATTRS, IMPLICIT, COND) \
if (NAME && COND) \
build_builtin (ENUM, NAME, CLASS, builtin_types[TYPE], BOTH_P, FALLBACK_P, \
built_in_attributes[ATTRS], IMPLICIT);
#include "builtins.def"
#undef DEF_BUILTIN
}
/**
* Register direct mappings between Rust functions and GCC builtins
*/
void
BuiltinsContext::register_rust_mappings ()
{
rust_intrinsic_to_gcc_builtin = {
{"unreachable", "__builtin_unreachable"},
{"abort", "__builtin_abort"},
// Math intrinsics
{"sqrtf32", "__builtin_sqrtf"},
{"sqrtf64", "__builtin_sqrt"},
{"sinf32", "__builtin_sinf"},
{"sinf64", "__builtin_sin"},
{"cosf32", "__builtin_cosf"},
{"cosf64", "__builtin_cos"},
{"powf32", "__builtin_powf"},
{"powf64", "__builtin_pow"},
{"powif32", "__builtin_powif"},
{"powif64", "__builtin_powi"},
{"expf32", "__builtin_expf"},
{"expf64", "__builtin_exp"},
{"exp2f32", "__builtin_exp2f"},
{"exp2f64", "__builtin_exp2"},
{"logf32", "__builtin_logf"},
{"logf64", "__builtin_log"},
{"log10f32", "__builtin_log10f"},
{"log10f64", "__builtin_log10"},
{"log2f32", "__builtin_log2f"},
{"log2f64", "__builtin_log2"},
{"fmaf32", "__builtin_fmaf"},
{"fmaf64", "__builtin_fma"},
{"fabsf32", "__builtin_fabsf"},
{"fabsf64", "__builtin_fabs"},
{"minnumf32", "__builtin_fminf"},
{"minnumf64", "__builtin_fmin"},
{"maxnumf32", "__builtin_fmaxf"},
{"maxnumf64", "__builtin_fmax"},
{"copysignf32", "__builtin_copysignf"},
{"copysignf64", "__builtin_copysign"},
{"floorf32", "__builtin_floorf"},
{"floorf64", "__builtin_floor"},
{"ceilf32", "__builtin_ceilf"},
{"ceilf64", "__builtin_ceil"},
{"truncf32", "__builtin_truncf"},
{"truncf64", "__builtin_trunc"},
{"rintf32", "__builtin_rintf"},
{"rintf64", "__builtin_rint"},
{"nearbyintf32", "__builtin_nearbyintf"},
{"nearbyintf64", "__builtin_nearbyint"},
{"roundf32", "__builtin_roundf"},
{"roundf64", "__builtin_round"},
};
}
void
BuiltinsContext::setup ()
{
define_builtin_types ();
define_builtin_attributes ();
define_builtins ();
register_rust_mappings ();
}
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