/* Select the personality routine to be used for exception handling, or issue an error if we need two different ones in the same translation unit. ??? At present DECL_FUNCTION_PERSONALITY is set via LANG_HOOKS_EH_PERSONALITY. Should it be done here instead? */ void choose_personality_routine (enum languages lang) { static enum { chose_none, chose_cpp, chose_java, gave_error } state; switch (state) { case gave_error: return; case chose_cpp: if (lang != lang_cplusplus) goto give_error; return; case chose_java: if (lang != lang_java) goto give_error; return; case chose_none: ; /* Proceed to language selection. */ } switch (lang) { case lang_cplusplus: state = chose_cpp; break; case lang_java: state = chose_java; terminate_node = builtin_decl_explicit (BUILT_IN_ABORT); pragma_java_exceptions = true; break; default: gcc_unreachable (); } return; give_error: error ("mixing C++ and Java catches in a single translation unit"); state = gave_error; }
/* Call malloc to allocate size bytes of memory, with special conditions: + if size == 0, return a malloced area of size 1, + if malloc returns NULL, issue a runtime error. */ tree gfc_call_malloc (stmtblock_t * block, tree type, tree size) { tree tmp, msg, malloc_result, null_result, res, malloc_tree; stmtblock_t block2; size = gfc_evaluate_now (size, block); if (TREE_TYPE (size) != TREE_TYPE (size_type_node)) size = fold_convert (size_type_node, size); /* Create a variable to hold the result. */ res = gfc_create_var (prvoid_type_node, NULL); /* Call malloc. */ gfc_start_block (&block2); size = fold_build2_loc (input_location, MAX_EXPR, size_type_node, size, build_int_cst (size_type_node, 1)); malloc_tree = builtin_decl_explicit (BUILT_IN_MALLOC); gfc_add_modify (&block2, res, fold_convert (prvoid_type_node, build_call_expr_loc (input_location, malloc_tree, 1, size))); /* Optionally check whether malloc was successful. */ if (gfc_option.rtcheck & GFC_RTCHECK_MEM) { null_result = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, res, build_int_cst (pvoid_type_node, 0)); msg = gfc_build_addr_expr (pchar_type_node, gfc_build_localized_cstring_const ("Memory allocation failed")); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, null_result, build_call_expr_loc (input_location, gfor_fndecl_os_error, 1, msg), build_empty_stmt (input_location)); gfc_add_expr_to_block (&block2, tmp); } malloc_result = gfc_finish_block (&block2); gfc_add_expr_to_block (block, malloc_result); if (type != NULL) res = fold_convert (type, res); return res; }
tree ubsan_instrument_division (location_t loc, tree op0, tree op1) { tree t, tt; tree type = TREE_TYPE (op0); /* At this point both operands should have the same type, because they are already converted to RESULT_TYPE. Use TYPE_MAIN_VARIANT since typedefs can confuse us. */ gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (op0)) == TYPE_MAIN_VARIANT (TREE_TYPE (op1))); /* TODO: REAL_TYPE is not supported yet. */ if (TREE_CODE (type) != INTEGER_TYPE) return NULL_TREE; t = fold_build2 (EQ_EXPR, boolean_type_node, op1, build_int_cst (type, 0)); /* We check INT_MIN / -1 only for signed types. */ if (!TYPE_UNSIGNED (type)) { tree x; tt = fold_build2 (EQ_EXPR, boolean_type_node, op1, build_int_cst (type, -1)); x = fold_build2 (EQ_EXPR, boolean_type_node, op0, TYPE_MIN_VALUE (type)); x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt); t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x); } /* If the condition was folded to 0, no need to instrument this expression. */ if (integer_zerop (t)) return NULL_TREE; /* In case we have a SAVE_EXPR in a conditional context, we need to make sure it gets evaluated before the condition. */ t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), op0, t); tree data = ubsan_create_data ("__ubsan_overflow_data", loc, ubsan_type_descriptor (type), NULL_TREE); data = build_fold_addr_expr_loc (loc, data); tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW); tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0), ubsan_encode_value (op1)); t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node); return t; }
/* Allocate memory, using an optional status argument. This function follows the following pseudo-code: void * allocate (size_t size, integer_type stat) { void *newmem; if (stat requested) stat = 0; newmem = malloc (MAX (size, 1)); if (newmem == NULL) { if (stat) *stat = LIBERROR_ALLOCATION; else runtime_error ("Allocation would exceed memory limit"); } return newmem; } */ void gfc_allocate_using_malloc (stmtblock_t * block, tree pointer, tree size, tree status) { tree tmp, on_error, error_cond; tree status_type = status ? TREE_TYPE (status) : NULL_TREE; /* Evaluate size only once, and make sure it has the right type. */ size = gfc_evaluate_now (size, block); if (TREE_TYPE (size) != TREE_TYPE (size_type_node)) size = fold_convert (size_type_node, size); /* If successful and stat= is given, set status to 0. */ if (status != NULL_TREE) gfc_add_expr_to_block (block, fold_build2_loc (input_location, MODIFY_EXPR, status_type, status, build_int_cst (status_type, 0))); /* The allocation itself. */ gfc_add_modify (block, pointer, fold_convert (TREE_TYPE (pointer), build_call_expr_loc (input_location, builtin_decl_explicit (BUILT_IN_MALLOC), 1, fold_build2_loc (input_location, MAX_EXPR, size_type_node, size, build_int_cst (size_type_node, 1))))); /* What to do in case of error. */ if (status != NULL_TREE) on_error = fold_build2_loc (input_location, MODIFY_EXPR, status_type, status, build_int_cst (status_type, LIBERROR_ALLOCATION)); else on_error = build_call_expr_loc (input_location, gfor_fndecl_os_error, 1, gfc_build_addr_expr (pchar_type_node, gfc_build_localized_cstring_const ("Allocation would exceed memory limit"))); error_cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, pointer, build_int_cst (prvoid_type_node, 0)); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, gfc_unlikely (error_cond), on_error, build_empty_stmt (input_location)); gfc_add_expr_to_block (block, tmp); }
/* Reallocate MEM so it has SIZE bytes of data. This behaves like the following pseudo-code: void * internal_realloc (void *mem, size_t size) { res = realloc (mem, size); if (!res && size != 0) _gfortran_os_error ("Allocation would exceed memory limit"); if (size == 0) return NULL; return res; } */ tree gfc_call_realloc (stmtblock_t * block, tree mem, tree size) { tree msg, res, nonzero, zero, null_result, tmp; tree type = TREE_TYPE (mem); size = gfc_evaluate_now (size, block); if (TREE_TYPE (size) != TREE_TYPE (size_type_node)) size = fold_convert (size_type_node, size); /* Create a variable to hold the result. */ res = gfc_create_var (type, NULL); /* Call realloc and check the result. */ tmp = build_call_expr_loc (input_location, builtin_decl_explicit (BUILT_IN_REALLOC), 2, fold_convert (pvoid_type_node, mem), size); gfc_add_modify (block, res, fold_convert (type, tmp)); null_result = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, res, build_int_cst (pvoid_type_node, 0)); nonzero = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, size, build_int_cst (size_type_node, 0)); null_result = fold_build2_loc (input_location, TRUTH_AND_EXPR, boolean_type_node, null_result, nonzero); msg = gfc_build_addr_expr (pchar_type_node, gfc_build_localized_cstring_const ("Allocation would exceed memory limit")); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, null_result, build_call_expr_loc (input_location, gfor_fndecl_os_error, 1, msg), build_empty_stmt (input_location)); gfc_add_expr_to_block (block, tmp); /* if (size == 0) then the result is NULL. */ tmp = fold_build2_loc (input_location, MODIFY_EXPR, type, res, build_int_cst (type, 0)); zero = fold_build1_loc (input_location, TRUTH_NOT_EXPR, boolean_type_node, nonzero); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, zero, tmp, build_empty_stmt (input_location)); gfc_add_expr_to_block (block, tmp); return res; }
void gimple_gen_edge_profiler (int edgeno, edge e) { tree ref, one; gimple stmt1, stmt2, stmt3; /* We share one temporary variable declaration per function. This gets re-set in tree_profiling. */ if (gcov_type_tmp_var == NULL_TREE) gcov_type_tmp_var = create_tmp_reg (gcov_type_node, "PROF_edge_counter"); if (PROFILE_GEN_EDGE_ATOMIC) ref = tree_coverage_counter_addr (GCOV_COUNTER_ARCS, edgeno); else ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); one = build_int_cst (gcov_type_node, 1); if (PROFILE_GEN_EDGE_ATOMIC) { /* __atomic_fetch_add (&counter, 1, MEMMODEL_RELAXED); */ stmt3 = gimple_build_call (builtin_decl_explicit ( GCOV_TYPE_ATOMIC_FETCH_ADD), 3, ref, one, build_int_cst (integer_type_node, MEMMODEL_RELAXED)); find_referenced_vars_in (stmt3); } else { stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); gimple_assign_set_lhs (stmt1, make_ssa_name (gcov_type_tmp_var, stmt1)); find_referenced_vars_in (stmt1); stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, gcov_type_tmp_var, gimple_assign_lhs (stmt1), one); gimple_assign_set_lhs (stmt2, make_ssa_name (gcov_type_tmp_var, stmt2)); stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); gsi_insert_on_edge (e, stmt1); gsi_insert_on_edge (e, stmt2); } gsi_insert_on_edge (e, stmt3); }
static tree compareAndSwapInt_builtin (tree method_return_type ATTRIBUTE_UNUSED, tree orig_call) { enum machine_mode mode = TYPE_MODE (int_type_node); if (can_compare_and_swap_p (mode, flag_use_atomic_builtins)) { tree addr, stmt; enum built_in_function fncode = BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4; UNMARSHAL5 (orig_call); (void) value_type; /* Avoid set but not used warning. */ addr = build_addr_sum (int_type_node, obj_arg, offset_arg); stmt = build_call_expr (builtin_decl_explicit (fncode), 3, addr, expected_arg, value_arg); return build_check_this (stmt, this_arg); } return NULL_TREE; }
/* Free a given variable, if it's not NULL. */ tree gfc_call_free (tree var) { stmtblock_t block; tree tmp, cond, call; if (TREE_TYPE (var) != TREE_TYPE (pvoid_type_node)) var = fold_convert (pvoid_type_node, var); gfc_start_block (&block); var = gfc_evaluate_now (var, &block); cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, var, build_int_cst (pvoid_type_node, 0)); call = build_call_expr_loc (input_location, builtin_decl_explicit (BUILT_IN_FREE), 1, var); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond, call, build_empty_stmt (input_location)); gfc_add_expr_to_block (&block, tmp); return gfc_finish_block (&block); }
static tree putVolatile_builtin (tree method_return_type ATTRIBUTE_UNUSED, tree orig_call) { tree addr, stmt, modify_stmt; UNMARSHAL4 (orig_call); addr = build_addr_sum (value_type, obj_arg, offset_arg); addr = fold_convert (build_pointer_type (build_type_variant (value_type, 0, 1)), addr); stmt = build_call_expr (builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE), 0); modify_stmt = fold_build2 (MODIFY_EXPR, value_type, build_java_indirect_ref (value_type, addr, flag_check_references), value_arg); stmt = build2 (COMPOUND_EXPR, TREE_TYPE (modify_stmt), stmt, modify_stmt); return build_check_this (stmt, this_arg); }
static tree compareAndSwapObject_builtin (tree method_return_type ATTRIBUTE_UNUSED, tree orig_call) { enum machine_mode mode = TYPE_MODE (ptr_type_node); if (can_compare_and_swap_p (mode, flag_use_atomic_builtins)) { tree addr, stmt; enum built_in_function builtin; UNMARSHAL5 (orig_call); builtin = (POINTER_SIZE == 32 ? BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4 : BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8); addr = build_addr_sum (value_type, obj_arg, offset_arg); stmt = build_call_expr (builtin_decl_explicit (builtin), 3, addr, expected_arg, value_arg); return build_check_this (stmt, this_arg); } return NULL_TREE; }
/* If the call matches a builtin, return the appropriate builtin expression instead. */ tree check_for_builtin (tree method, tree call) { if (optimize && TREE_CODE (call) == CALL_EXPR) { int i; tree method_class = DECL_NAME (TYPE_NAME (DECL_CONTEXT (method))); tree method_name = DECL_NAME (method); tree method_return_type = TREE_TYPE (TREE_TYPE (method)); for (i = 0; java_builtins[i].builtin_code != END_BUILTINS; ++i) { if (method_class == java_builtins[i].class_name.t && method_name == java_builtins[i].method_name.t) { tree fn; if (java_builtins[i].creator != NULL) { tree result = (*java_builtins[i].creator) (method_return_type, call); return result == NULL_TREE ? call : result; } /* Builtin functions emit a direct call which is incompatible with the BC-ABI. */ if (flag_indirect_dispatch) return call; fn = builtin_decl_explicit (java_builtins[i].builtin_code); if (fn == NULL_TREE) return call; return java_build_function_call_expr (fn, call); } } } return call; }
tree streamer_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in) { enum built_in_class fclass; enum built_in_function fcode; const char *asmname; tree result; fclass = streamer_read_enum (ib, built_in_class, BUILT_IN_LAST); gcc_assert (fclass == BUILT_IN_NORMAL || fclass == BUILT_IN_MD); fcode = (enum built_in_function) streamer_read_uhwi (ib); if (fclass == BUILT_IN_NORMAL) { if (fcode >= END_BUILTINS) fatal_error ("machine independent builtin code out of range"); result = builtin_decl_explicit (fcode); gcc_assert (result); } else if (fclass == BUILT_IN_MD) { result = targetm.builtin_decl (fcode, true); if (!result || result == error_mark_node) fatal_error ("target specific builtin not available"); } else gcc_unreachable (); asmname = streamer_read_string (data_in, ib); if (asmname) set_builtin_user_assembler_name (result, asmname); streamer_tree_cache_append (data_in->reader_cache, result); return result; }
+#include "cfgbuild.h" +#include "cfgcleanup.h" +#include "debug.h" +#include "internal-fn.h" +#include "gimple-fold.h" +#include "tree-eh.h" +#include "gimplify.h" +#include "cgraph.h" +#include "alloc-pool.h" +#include "lto-streamer.h" +#include "lto-section-names.h" + +static void +netbsd_patch_builtin (enum built_in_function fncode) +{ + tree fn = builtin_decl_explicit (fncode); + tree sym; + char *newname; + + if (!fn) + return; + + sym = DECL_ASSEMBLER_NAME (fn); + newname = ACONCAT (("__c99_", IDENTIFIER_POINTER (sym), NULL)); + + set_user_assembler_name (fn, newname); + + fn = builtin_decl_implicit (fncode); + if (fn) + set_user_assembler_name (fn, newname); +}
tree ubsan_instrument_shift (location_t loc, enum tree_code code, tree op0, tree op1) { tree t, tt = NULL_TREE; tree type0 = TREE_TYPE (op0); tree type1 = TREE_TYPE (op1); tree op1_utype = unsigned_type_for (type1); HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0); tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1); t = fold_convert_loc (loc, op1_utype, op1); t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1); /* For signed x << y, in C99/C11, the following: (unsigned) x >> (uprecm1 - y) if non-zero, is undefined. */ if (code == LSHIFT_EXPR && !TYPE_UNSIGNED (type0) && flag_isoc99) { tree x = fold_build2 (MINUS_EXPR, unsigned_type_node, uprecm1, fold_convert (op1_utype, op1)); tt = fold_convert_loc (loc, unsigned_type_for (type0), op0); tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x); tt = fold_build2 (NE_EXPR, boolean_type_node, tt, build_int_cst (TREE_TYPE (tt), 0)); } /* For signed x << y, in C++11 and later, the following: x < 0 || ((unsigned) x >> (uprecm1 - y)) if > 1, is undefined. */ if (code == LSHIFT_EXPR && !TYPE_UNSIGNED (TREE_TYPE (op0)) && (cxx_dialect >= cxx11)) { tree x = fold_build2 (MINUS_EXPR, unsigned_type_node, uprecm1, fold_convert (op1_utype, op1)); tt = fold_convert_loc (loc, unsigned_type_for (type0), op0); tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x); tt = fold_build2 (GT_EXPR, boolean_type_node, tt, build_int_cst (TREE_TYPE (tt), 1)); x = fold_build2 (LT_EXPR, boolean_type_node, op0, build_int_cst (type0, 0)); tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt); } /* If the condition was folded to 0, no need to instrument this expression. */ if (integer_zerop (t) && (tt == NULL_TREE || integer_zerop (tt))) return NULL_TREE; /* In case we have a SAVE_EXPR in a conditional context, we need to make sure it gets evaluated before the condition. If the OP0 is an instrumented array reference, mark it as having side effects so it's not folded away. */ if (flag_sanitize & SANITIZE_BOUNDS) { tree xop0 = op0; while (CONVERT_EXPR_P (xop0)) xop0 = TREE_OPERAND (xop0, 0); if (TREE_CODE (xop0) == ARRAY_REF) { TREE_SIDE_EFFECTS (xop0) = 1; TREE_SIDE_EFFECTS (op0) = 1; } } t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), op0, t); t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt ? tt : integer_zero_node); if (flag_sanitize_undefined_trap_on_error) tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); else { tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc, ubsan_type_descriptor (type0), ubsan_type_descriptor (type1), NULL_TREE, NULL_TREE); data = build_fold_addr_expr_loc (loc, data); enum built_in_function bcode = (flag_sanitize_recover & SANITIZE_SHIFT) ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT; tt = builtin_decl_explicit (bcode); tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0), ubsan_encode_value (op1)); } t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node); return t; }
static void gfc_init_builtin_functions (void) { enum builtin_type { #define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME, #define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME, #define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, #define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) NAME, #define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9) NAME, #define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9, ARG10) NAME, #define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, #define DEF_FUNCTION_TYPE_VAR_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) NAME, #define DEF_FUNCTION_TYPE_VAR_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "types.def" #undef DEF_PRIMITIVE_TYPE #undef DEF_FUNCTION_TYPE_0 #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_6 #undef DEF_FUNCTION_TYPE_VAR_7 #undef DEF_POINTER_TYPE BT_LAST }; tree mfunc_float[6]; tree mfunc_double[6]; tree mfunc_longdouble[6]; tree mfunc_cfloat[6]; tree mfunc_cdouble[6]; tree mfunc_clongdouble[6]; tree func_cfloat_float, func_float_cfloat; tree func_cdouble_double, func_double_cdouble; tree func_clongdouble_longdouble, func_longdouble_clongdouble; tree func_float_floatp_floatp; tree func_double_doublep_doublep; tree func_longdouble_longdoublep_longdoublep; tree ftype, ptype; tree builtin_types[(int) BT_LAST + 1]; int attr; build_builtin_fntypes (mfunc_float, float_type_node); build_builtin_fntypes (mfunc_double, double_type_node); build_builtin_fntypes (mfunc_longdouble, long_double_type_node); build_builtin_fntypes (mfunc_cfloat, complex_float_type_node); build_builtin_fntypes (mfunc_cdouble, complex_double_type_node); build_builtin_fntypes (mfunc_clongdouble, complex_long_double_type_node); func_cfloat_float = build_function_type_list (float_type_node, complex_float_type_node, NULL_TREE); func_float_cfloat = build_function_type_list (complex_float_type_node, float_type_node, NULL_TREE); func_cdouble_double = build_function_type_list (double_type_node, complex_double_type_node, NULL_TREE); func_double_cdouble = build_function_type_list (complex_double_type_node, double_type_node, NULL_TREE); func_clongdouble_longdouble = build_function_type_list (long_double_type_node, complex_long_double_type_node, NULL_TREE); func_longdouble_clongdouble = build_function_type_list (complex_long_double_type_node, long_double_type_node, NULL_TREE); ptype = build_pointer_type (float_type_node); func_float_floatp_floatp = build_function_type_list (void_type_node, ptype, ptype, NULL_TREE); ptype = build_pointer_type (double_type_node); func_double_doublep_doublep = build_function_type_list (void_type_node, ptype, ptype, NULL_TREE); ptype = build_pointer_type (long_double_type_node); func_longdouble_longdoublep_longdoublep = build_function_type_list (void_type_node, ptype, ptype, NULL_TREE); /* Non-math builtins are defined manually, so they're not included here. */ #define OTHER_BUILTIN(ID,NAME,TYPE,CONST) #include "mathbuiltins.def" gfc_define_builtin ("__builtin_roundl", mfunc_longdouble[0], BUILT_IN_ROUNDL, "roundl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_round", mfunc_double[0], BUILT_IN_ROUND, "round", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_roundf", mfunc_float[0], BUILT_IN_ROUNDF, "roundf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_truncl", mfunc_longdouble[0], BUILT_IN_TRUNCL, "truncl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_trunc", mfunc_double[0], BUILT_IN_TRUNC, "trunc", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_truncf", mfunc_float[0], BUILT_IN_TRUNCF, "truncf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cabsl", func_clongdouble_longdouble, BUILT_IN_CABSL, "cabsl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cabs", func_cdouble_double, BUILT_IN_CABS, "cabs", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cabsf", func_cfloat_float, BUILT_IN_CABSF, "cabsf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_copysignl", mfunc_longdouble[1], BUILT_IN_COPYSIGNL, "copysignl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_copysign", mfunc_double[1], BUILT_IN_COPYSIGN, "copysign", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_copysignf", mfunc_float[1], BUILT_IN_COPYSIGNF, "copysignf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_nextafterl", mfunc_longdouble[1], BUILT_IN_NEXTAFTERL, "nextafterl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_nextafter", mfunc_double[1], BUILT_IN_NEXTAFTER, "nextafter", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_nextafterf", mfunc_float[1], BUILT_IN_NEXTAFTERF, "nextafterf", ATTR_CONST_NOTHROW_LEAF_LIST); /* Some built-ins depend on rounding mode. Depending on compilation options, they will be "pure" or "const". */ attr = flag_rounding_math ? ATTR_PURE_NOTHROW_LEAF_LIST : ATTR_CONST_NOTHROW_LEAF_LIST; gfc_define_builtin ("__builtin_rintl", mfunc_longdouble[0], BUILT_IN_RINTL, "rintl", attr); gfc_define_builtin ("__builtin_rint", mfunc_double[0], BUILT_IN_RINT, "rint", attr); gfc_define_builtin ("__builtin_rintf", mfunc_float[0], BUILT_IN_RINTF, "rintf", attr); gfc_define_builtin ("__builtin_remainderl", mfunc_longdouble[1], BUILT_IN_REMAINDERL, "remainderl", attr); gfc_define_builtin ("__builtin_remainder", mfunc_double[1], BUILT_IN_REMAINDER, "remainder", attr); gfc_define_builtin ("__builtin_remainderf", mfunc_float[1], BUILT_IN_REMAINDERF, "remainderf", attr); gfc_define_builtin ("__builtin_logbl", mfunc_longdouble[0], BUILT_IN_LOGBL, "logbl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_logb", mfunc_double[0], BUILT_IN_LOGB, "logb", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_logbf", mfunc_float[0], BUILT_IN_LOGBF, "logbf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_frexpl", mfunc_longdouble[4], BUILT_IN_FREXPL, "frexpl", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_frexp", mfunc_double[4], BUILT_IN_FREXP, "frexp", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_frexpf", mfunc_float[4], BUILT_IN_FREXPF, "frexpf", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fabsl", mfunc_longdouble[0], BUILT_IN_FABSL, "fabsl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fabs", mfunc_double[0], BUILT_IN_FABS, "fabs", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fabsf", mfunc_float[0], BUILT_IN_FABSF, "fabsf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_scalbnl", mfunc_longdouble[2], BUILT_IN_SCALBNL, "scalbnl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_scalbn", mfunc_double[2], BUILT_IN_SCALBN, "scalbn", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_scalbnf", mfunc_float[2], BUILT_IN_SCALBNF, "scalbnf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fmodl", mfunc_longdouble[1], BUILT_IN_FMODL, "fmodl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fmod", mfunc_double[1], BUILT_IN_FMOD, "fmod", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fmodf", mfunc_float[1], BUILT_IN_FMODF, "fmodf", ATTR_CONST_NOTHROW_LEAF_LIST); /* iround{f,,l}, lround{f,,l} and llround{f,,l} */ ftype = build_function_type_list (integer_type_node, float_type_node, NULL_TREE); gfc_define_builtin("__builtin_iroundf", ftype, BUILT_IN_IROUNDF, "iroundf", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_integer_type_node, float_type_node, NULL_TREE); gfc_define_builtin ("__builtin_lroundf", ftype, BUILT_IN_LROUNDF, "lroundf", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_long_integer_type_node, float_type_node, NULL_TREE); gfc_define_builtin ("__builtin_llroundf", ftype, BUILT_IN_LLROUNDF, "llroundf", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (integer_type_node, double_type_node, NULL_TREE); gfc_define_builtin("__builtin_iround", ftype, BUILT_IN_IROUND, "iround", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_integer_type_node, double_type_node, NULL_TREE); gfc_define_builtin ("__builtin_lround", ftype, BUILT_IN_LROUND, "lround", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_long_integer_type_node, double_type_node, NULL_TREE); gfc_define_builtin ("__builtin_llround", ftype, BUILT_IN_LLROUND, "llround", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (integer_type_node, long_double_type_node, NULL_TREE); gfc_define_builtin("__builtin_iroundl", ftype, BUILT_IN_IROUNDL, "iroundl", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_integer_type_node, long_double_type_node, NULL_TREE); gfc_define_builtin ("__builtin_lroundl", ftype, BUILT_IN_LROUNDL, "lroundl", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_long_integer_type_node, long_double_type_node, NULL_TREE); gfc_define_builtin ("__builtin_llroundl", ftype, BUILT_IN_LLROUNDL, "llroundl", ATTR_CONST_NOTHROW_LEAF_LIST); /* These are used to implement the ** operator. */ gfc_define_builtin ("__builtin_powl", mfunc_longdouble[1], BUILT_IN_POWL, "powl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_pow", mfunc_double[1], BUILT_IN_POW, "pow", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_powf", mfunc_float[1], BUILT_IN_POWF, "powf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cpowl", mfunc_clongdouble[1], BUILT_IN_CPOWL, "cpowl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cpow", mfunc_cdouble[1], BUILT_IN_CPOW, "cpow", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cpowf", mfunc_cfloat[1], BUILT_IN_CPOWF, "cpowf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_powil", mfunc_longdouble[2], BUILT_IN_POWIL, "powil", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_powi", mfunc_double[2], BUILT_IN_POWI, "powi", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_powif", mfunc_float[2], BUILT_IN_POWIF, "powif", ATTR_CONST_NOTHROW_LEAF_LIST); if (targetm.libc_has_function (function_c99_math_complex)) { gfc_define_builtin ("__builtin_cbrtl", mfunc_longdouble[0], BUILT_IN_CBRTL, "cbrtl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cbrt", mfunc_double[0], BUILT_IN_CBRT, "cbrt", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cbrtf", mfunc_float[0], BUILT_IN_CBRTF, "cbrtf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cexpil", func_longdouble_clongdouble, BUILT_IN_CEXPIL, "cexpil", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cexpi", func_double_cdouble, BUILT_IN_CEXPI, "cexpi", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cexpif", func_float_cfloat, BUILT_IN_CEXPIF, "cexpif", ATTR_CONST_NOTHROW_LEAF_LIST); } if (targetm.libc_has_function (function_sincos)) { gfc_define_builtin ("__builtin_sincosl", func_longdouble_longdoublep_longdoublep, BUILT_IN_SINCOSL, "sincosl", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_sincos", func_double_doublep_doublep, BUILT_IN_SINCOS, "sincos", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_sincosf", func_float_floatp_floatp, BUILT_IN_SINCOSF, "sincosf", ATTR_NOTHROW_LEAF_LIST); } /* For LEADZ, TRAILZ, POPCNT and POPPAR. */ ftype = build_function_type_list (integer_type_node, unsigned_type_node, NULL_TREE); gfc_define_builtin ("__builtin_clz", ftype, BUILT_IN_CLZ, "__builtin_clz", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_ctz", ftype, BUILT_IN_CTZ, "__builtin_ctz", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_parity", ftype, BUILT_IN_PARITY, "__builtin_parity", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_popcount", ftype, BUILT_IN_POPCOUNT, "__builtin_popcount", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (integer_type_node, long_unsigned_type_node, NULL_TREE); gfc_define_builtin ("__builtin_clzl", ftype, BUILT_IN_CLZL, "__builtin_clzl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_ctzl", ftype, BUILT_IN_CTZL, "__builtin_ctzl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_parityl", ftype, BUILT_IN_PARITYL, "__builtin_parityl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_popcountl", ftype, BUILT_IN_POPCOUNTL, "__builtin_popcountl", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (integer_type_node, long_long_unsigned_type_node, NULL_TREE); gfc_define_builtin ("__builtin_clzll", ftype, BUILT_IN_CLZLL, "__builtin_clzll", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_ctzll", ftype, BUILT_IN_CTZLL, "__builtin_ctzll", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_parityll", ftype, BUILT_IN_PARITYLL, "__builtin_parityll", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_popcountll", ftype, BUILT_IN_POPCOUNTLL, "__builtin_popcountll", ATTR_CONST_NOTHROW_LEAF_LIST); /* Other builtin functions we use. */ ftype = build_function_type_list (long_integer_type_node, long_integer_type_node, long_integer_type_node, NULL_TREE); gfc_define_builtin ("__builtin_expect", ftype, BUILT_IN_EXPECT, "__builtin_expect", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (void_type_node, pvoid_type_node, NULL_TREE); gfc_define_builtin ("__builtin_free", ftype, BUILT_IN_FREE, "free", ATTR_NOTHROW_LEAF_LIST); ftype = build_function_type_list (pvoid_type_node, size_type_node, NULL_TREE); gfc_define_builtin ("__builtin_malloc", ftype, BUILT_IN_MALLOC, "malloc", ATTR_NOTHROW_LEAF_MALLOC_LIST); ftype = build_function_type_list (pvoid_type_node, size_type_node, size_type_node, NULL_TREE); gfc_define_builtin ("__builtin_calloc", ftype, BUILT_IN_CALLOC, "calloc", ATTR_NOTHROW_LEAF_MALLOC_LIST); DECL_IS_MALLOC (builtin_decl_explicit (BUILT_IN_CALLOC)) = 1; ftype = build_function_type_list (pvoid_type_node, size_type_node, pvoid_type_node, NULL_TREE); gfc_define_builtin ("__builtin_realloc", ftype, BUILT_IN_REALLOC, "realloc", ATTR_NOTHROW_LEAF_LIST); /* Type-generic floating-point classification built-ins. */ ftype = build_function_type (integer_type_node, NULL_TREE); gfc_define_builtin ("__builtin_isfinite", ftype, BUILT_IN_ISFINITE, "__builtin_isfinite", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_isinf", ftype, BUILT_IN_ISINF, "__builtin_isinf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_isinf_sign", ftype, BUILT_IN_ISINF_SIGN, "__builtin_isinf_sign", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_isnan", ftype, BUILT_IN_ISNAN, "__builtin_isnan", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_isnormal", ftype, BUILT_IN_ISNORMAL, "__builtin_isnormal", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_signbit", ftype, BUILT_IN_SIGNBIT, "__builtin_signbit", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type (integer_type_node, NULL_TREE); gfc_define_builtin ("__builtin_isless", ftype, BUILT_IN_ISLESS, "__builtin_isless", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_islessequal", ftype, BUILT_IN_ISLESSEQUAL, "__builtin_islessequal", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_islessgreater", ftype, BUILT_IN_ISLESSGREATER, "__builtin_islessgreater", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_isgreater", ftype, BUILT_IN_ISGREATER, "__builtin_isgreater", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_isgreaterequal", ftype, BUILT_IN_ISGREATEREQUAL, "__builtin_isgreaterequal", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_isunordered", ftype, BUILT_IN_ISUNORDERED, "__builtin_isunordered", ATTR_CONST_NOTHROW_LEAF_LIST); #define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \ builtin_types[(int) ENUM] = VALUE; #define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ NULL_TREE); #define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ NULL_TREE); #define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ NULL_TREE); #define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ NULL_TREE); #define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ NULL_TREE); #define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ NULL_TREE); #define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ NULL_TREE); #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ NULL_TREE); #define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ builtin_types[(int) ARG8], \ NULL_TREE); #define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ builtin_types[(int) ARG8], \ builtin_types[(int) ARG9], \ NULL_TREE); #define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, \ ARG5, ARG6, ARG7, ARG8, ARG9, ARG10) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ builtin_types[(int) ARG8], \ builtin_types[(int) ARG9], \ builtin_types[(int) ARG10], \ NULL_TREE); #define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, \ ARG5, ARG6, ARG7, ARG8, ARG9, ARG10, ARG11)\ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ builtin_types[(int) ARG8], \ builtin_types[(int) ARG9], \ builtin_types[(int) ARG10], \ builtin_types[(int) ARG11], \ NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ NULL_TREE); #define DEF_POINTER_TYPE(ENUM, TYPE) \ builtin_types[(int) ENUM] \ = build_pointer_type (builtin_types[(int) TYPE]); #include "types.def" #undef DEF_PRIMITIVE_TYPE #undef DEF_FUNCTION_TYPE_0 #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_10 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 #undef DEF_FUNCTION_TYPE_VAR_6 #undef DEF_FUNCTION_TYPE_VAR_7 #undef DEF_POINTER_TYPE builtin_types[(int) BT_LAST] = NULL_TREE; /* Initialize synchronization builtins. */ #undef DEF_SYNC_BUILTIN #define DEF_SYNC_BUILTIN(code, name, type, attr) \ gfc_define_builtin (name, builtin_types[type], code, name, \ attr); #include "../sync-builtins.def" #undef DEF_SYNC_BUILTIN if (flag_openacc) { #undef DEF_GOACC_BUILTIN #define DEF_GOACC_BUILTIN(code, name, type, attr) \ gfc_define_builtin ("__builtin_" name, builtin_types[type], \ code, name, attr); #undef DEF_GOACC_BUILTIN_COMPILER #define DEF_GOACC_BUILTIN_COMPILER(code, name, type, attr) \ gfc_define_builtin (name, builtin_types[type], code, name, attr); #undef DEF_GOMP_BUILTIN #define DEF_GOMP_BUILTIN(code, name, type, attr) /* ignore */ #include "../omp-builtins.def" #undef DEF_GOACC_BUILTIN #undef DEF_GOACC_BUILTIN_COMPILER #undef DEF_GOMP_BUILTIN } if (flag_openmp || flag_openmp_simd || flag_tree_parallelize_loops) { #undef DEF_GOACC_BUILTIN #define DEF_GOACC_BUILTIN(code, name, type, attr) /* ignore */ #undef DEF_GOACC_BUILTIN_COMPILER #define DEF_GOACC_BUILTIN_COMPILER(code, name, type, attr) /* ignore */ #undef DEF_GOMP_BUILTIN #define DEF_GOMP_BUILTIN(code, name, type, attr) \ gfc_define_builtin ("__builtin_" name, builtin_types[type], \ code, name, attr); #include "../omp-builtins.def" #undef DEF_GOACC_BUILTIN #undef DEF_GOACC_BUILTIN_COMPILER #undef DEF_GOMP_BUILTIN } #ifdef ENABLE_HSA if (!flag_disable_hsa) { #undef DEF_HSA_BUILTIN #define DEF_HSA_BUILTIN(code, name, type, attr) \ gfc_define_builtin ("__builtin_" name, builtin_types[type], \ code, name, attr); #include "../hsa-builtins.def" } #endif gfc_define_builtin ("__builtin_trap", builtin_types[BT_FN_VOID], BUILT_IN_TRAP, NULL, ATTR_NOTHROW_LEAF_LIST); TREE_THIS_VOLATILE (builtin_decl_explicit (BUILT_IN_TRAP)) = 1; ftype = build_varargs_function_type_list (ptr_type_node, const_ptr_type_node, size_type_node, NULL_TREE); gfc_define_builtin ("__builtin_assume_aligned", ftype, BUILT_IN_ASSUME_ALIGNED, "__builtin_assume_aligned", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__emutls_get_address", builtin_types[BT_FN_PTR_PTR], BUILT_IN_EMUTLS_GET_ADDRESS, "__emutls_get_address", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__emutls_register_common", builtin_types[BT_FN_VOID_PTR_WORD_WORD_PTR], BUILT_IN_EMUTLS_REGISTER_COMMON, "__emutls_register_common", ATTR_NOTHROW_LEAF_LIST); build_common_builtin_nodes (); targetm.init_builtins (); }
tree gfc_deallocate_scalar_with_status (tree pointer, tree status, bool can_fail, gfc_expr* expr, gfc_typespec ts) { stmtblock_t null, non_null; tree cond, tmp, error; cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, pointer, build_int_cst (TREE_TYPE (pointer), 0)); /* When POINTER is NULL, we set STATUS to 1 if it's present, otherwise we emit a runtime error. */ gfc_start_block (&null); if (!can_fail) { tree varname; gcc_assert (expr && expr->expr_type == EXPR_VARIABLE && expr->symtree); varname = gfc_build_cstring_const (expr->symtree->name); varname = gfc_build_addr_expr (pchar_type_node, varname); error = gfc_trans_runtime_error (true, &expr->where, "Attempt to DEALLOCATE unallocated '%s'", varname); } else error = build_empty_stmt (input_location); if (status != NULL_TREE && !integer_zerop (status)) { tree status_type = TREE_TYPE (TREE_TYPE (status)); tree cond2; cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, status, build_int_cst (TREE_TYPE (status), 0)); tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, fold_build1_loc (input_location, INDIRECT_REF, status_type, status), build_int_cst (status_type, 1)); error = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond2, tmp, error); } gfc_add_expr_to_block (&null, error); /* When POINTER is not NULL, we free it. */ gfc_start_block (&non_null); /* Free allocatable components. */ if (ts.type == BT_DERIVED && ts.u.derived->attr.alloc_comp) { tmp = build_fold_indirect_ref_loc (input_location, pointer); tmp = gfc_deallocate_alloc_comp (ts.u.derived, tmp, 0); gfc_add_expr_to_block (&non_null, tmp); } else if (ts.type == BT_CLASS && ts.u.derived->components->ts.u.derived->attr.alloc_comp) { tmp = build_fold_indirect_ref_loc (input_location, pointer); tmp = gfc_deallocate_alloc_comp (ts.u.derived->components->ts.u.derived, tmp, 0); gfc_add_expr_to_block (&non_null, tmp); } tmp = build_call_expr_loc (input_location, builtin_decl_explicit (BUILT_IN_FREE), 1, fold_convert (pvoid_type_node, pointer)); gfc_add_expr_to_block (&non_null, tmp); if (status != NULL_TREE && !integer_zerop (status)) { /* We set STATUS to zero if it is present. */ tree status_type = TREE_TYPE (TREE_TYPE (status)); tree cond2; cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, status, build_int_cst (TREE_TYPE (status), 0)); tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, fold_build1_loc (input_location, INDIRECT_REF, status_type, status), build_int_cst (status_type, 0)); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond2, tmp, build_empty_stmt (input_location)); gfc_add_expr_to_block (&non_null, tmp); } return fold_build3_loc (input_location, COND_EXPR, void_type_node, cond, gfc_finish_block (&null), gfc_finish_block (&non_null)); }
tree ubsan_instrument_division (location_t loc, tree op0, tree op1) { tree t, tt; tree type = TREE_TYPE (op0); /* At this point both operands should have the same type, because they are already converted to RESULT_TYPE. Use TYPE_MAIN_VARIANT since typedefs can confuse us. */ gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (op0)) == TYPE_MAIN_VARIANT (TREE_TYPE (op1))); op0 = unshare_expr (op0); op1 = unshare_expr (op1); if (TREE_CODE (type) == INTEGER_TYPE && (flag_sanitize & SANITIZE_DIVIDE)) t = fold_build2 (EQ_EXPR, boolean_type_node, op1, build_int_cst (type, 0)); else if (TREE_CODE (type) == REAL_TYPE && (flag_sanitize & SANITIZE_FLOAT_DIVIDE)) t = fold_build2 (EQ_EXPR, boolean_type_node, op1, build_real (type, dconst0)); else return NULL_TREE; /* We check INT_MIN / -1 only for signed types. */ if (TREE_CODE (type) == INTEGER_TYPE && (flag_sanitize & SANITIZE_DIVIDE) && !TYPE_UNSIGNED (type)) { tree x; tt = fold_build2 (EQ_EXPR, boolean_type_node, unshare_expr (op1), build_int_cst (type, -1)); x = fold_build2 (EQ_EXPR, boolean_type_node, op0, TYPE_MIN_VALUE (type)); x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt); t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x); } /* If the condition was folded to 0, no need to instrument this expression. */ if (integer_zerop (t)) return NULL_TREE; /* In case we have a SAVE_EXPR in a conditional context, we need to make sure it gets evaluated before the condition. */ t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t); t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t); if (flag_sanitize_undefined_trap_on_error) tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); else { tree data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc, ubsan_type_descriptor (type), NULL_TREE, NULL_TREE); data = build_fold_addr_expr_loc (loc, data); enum built_in_function bcode = (flag_sanitize_recover & SANITIZE_DIVIDE) ? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW : BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT; tt = builtin_decl_explicit (bcode); op0 = unshare_expr (op0); op1 = unshare_expr (op1); tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0), ubsan_encode_value (op1)); } t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node); return t; }
tree ubsan_instrument_shift (location_t loc, enum tree_code code, tree op0, tree op1) { tree t, tt = NULL_TREE; tree type0 = TREE_TYPE (op0); tree type1 = TREE_TYPE (op1); if (!INTEGRAL_TYPE_P (type0)) return NULL_TREE; tree op1_utype = unsigned_type_for (type1); HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0); tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1); op0 = unshare_expr (op0); op1 = unshare_expr (op1); t = fold_convert_loc (loc, op1_utype, op1); t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1); /* If this is not a signed operation, don't perform overflow checks. Also punt on bit-fields. */ if (TYPE_OVERFLOW_WRAPS (type0) || GET_MODE_BITSIZE (TYPE_MODE (type0)) != TYPE_PRECISION (type0) || (flag_sanitize & SANITIZE_SHIFT_BASE) == 0) ; /* For signed x << y, in C99/C11, the following: (unsigned) x >> (uprecm1 - y) if non-zero, is undefined. */ else if (code == LSHIFT_EXPR && flag_isoc99 && cxx_dialect < cxx11) { tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1, fold_convert (op1_utype, unshare_expr (op1))); tt = fold_convert_loc (loc, unsigned_type_for (type0), op0); tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x); tt = fold_build2 (NE_EXPR, boolean_type_node, tt, build_int_cst (TREE_TYPE (tt), 0)); } /* For signed x << y, in C++11 and later, the following: x < 0 || ((unsigned) x >> (uprecm1 - y)) if > 1, is undefined. */ else if (code == LSHIFT_EXPR && cxx_dialect >= cxx11) { tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1, fold_convert (op1_utype, unshare_expr (op1))); tt = fold_convert_loc (loc, unsigned_type_for (type0), unshare_expr (op0)); tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x); tt = fold_build2 (GT_EXPR, boolean_type_node, tt, build_int_cst (TREE_TYPE (tt), 1)); x = fold_build2 (LT_EXPR, boolean_type_node, unshare_expr (op0), build_int_cst (type0, 0)); tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt); } /* If the condition was folded to 0, no need to instrument this expression. */ if (integer_zerop (t) && (tt == NULL_TREE || integer_zerop (tt))) return NULL_TREE; /* In case we have a SAVE_EXPR in a conditional context, we need to make sure it gets evaluated before the condition. */ t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t); enum sanitize_code recover_kind = SANITIZE_SHIFT_EXPONENT; tree else_t = void_node; if (tt) { if ((flag_sanitize & SANITIZE_SHIFT_EXPONENT) == 0) { t = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, t); t = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, t, tt); recover_kind = SANITIZE_SHIFT_BASE; } else { if (flag_sanitize_undefined_trap_on_error || ((!(flag_sanitize_recover & SANITIZE_SHIFT_EXPONENT)) == (!(flag_sanitize_recover & SANITIZE_SHIFT_BASE)))) t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt); else else_t = tt; } } if (flag_sanitize_undefined_trap_on_error) tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); else { tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc, ubsan_type_descriptor (type0), ubsan_type_descriptor (type1), NULL_TREE, NULL_TREE); data = build_fold_addr_expr_loc (loc, data); enum built_in_function bcode = (flag_sanitize_recover & recover_kind) ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT; tt = builtin_decl_explicit (bcode); op0 = unshare_expr (op0); op1 = unshare_expr (op1); tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0), ubsan_encode_value (op1)); if (else_t != void_node) { bcode = (flag_sanitize_recover & SANITIZE_SHIFT_BASE) ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT; tree else_tt = builtin_decl_explicit (bcode); op0 = unshare_expr (op0); op1 = unshare_expr (op1); else_tt = build_call_expr_loc (loc, else_tt, 3, data, ubsan_encode_value (op0), ubsan_encode_value (op1)); else_t = fold_build3 (COND_EXPR, void_type_node, else_t, else_tt, void_node); } } t = fold_build3 (COND_EXPR, void_type_node, t, tt, else_t); return t; }
static bool ortho_init (void) { tree n; input_location = BUILTINS_LOCATION; /* Create a global binding. Don't use push_binding, as neither a BLOCK nor a BIND_EXPR are needed. */ push_binding (GLOBAL_BINDING); build_common_tree_nodes (0, 0); n = build_decl (input_location, TYPE_DECL, get_identifier ("int"), integer_type_node); pushdecl (n); n = build_decl (input_location, TYPE_DECL, get_identifier ("char"), char_type_node); pushdecl (n); /* Create alloca builtin. */ { tree args_type = tree_cons (NULL_TREE, size_type_node, void_list_node); tree func_type = build_function_type (ptr_type_node, args_type); define_builtin ("__builtin_alloca", func_type, BUILT_IN_ALLOCA, NULL, 0); stack_alloc_function_ptr = build1 (ADDR_EXPR, build_pointer_type (func_type), builtin_decl_implicit (BUILT_IN_ALLOCA)); } { tree ptr_ftype = build_function_type (ptr_type_node, NULL_TREE); define_builtin ("__builtin_stack_save", ptr_ftype, BUILT_IN_STACK_SAVE, NULL, 0); } { tree ftype_ptr = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); define_builtin ("__builtin_stack_restore", ftype_ptr, BUILT_IN_STACK_RESTORE, NULL, 0); } { tree ftype_ptr = build_function_type_list (void_type_node, NULL_TREE); define_builtin ("__builtin_trap", ftype_ptr, BUILT_IN_TRAP, NULL, ECF_NOTHROW | ECF_LEAF); TREE_THIS_VOLATILE (builtin_decl_explicit (BUILT_IN_TRAP)) = 1; } { REAL_VALUE_TYPE v; REAL_VALUE_FROM_INT (v, 1, 0, DFmode); real_ldexp (&fp_const_p5, &v, -1); REAL_VALUE_FROM_INT (v, -1, -1, DFmode); real_ldexp (&fp_const_m_p5, &v, -1); REAL_VALUE_FROM_INT (fp_const_zero, 0, 0, DFmode); } build_common_builtin_nodes (); // FIXME: this MAY remove the need for creating the builtins above... // Evaluate tree.c / build_common_builtin_nodes (); for each in turn. return true; }
static void adjust_simduid_builtins (hash_table<simduid_to_vf> *htab) { basic_block bb; FOR_EACH_BB_FN (bb, cfun) { gimple_stmt_iterator i; for (i = gsi_start_bb (bb); !gsi_end_p (i); ) { unsigned int vf = 1; enum internal_fn ifn; gimple *stmt = gsi_stmt (i); tree t; if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt)) { gsi_next (&i); continue; } ifn = gimple_call_internal_fn (stmt); switch (ifn) { case IFN_GOMP_SIMD_LANE: case IFN_GOMP_SIMD_VF: case IFN_GOMP_SIMD_LAST_LANE: break; case IFN_GOMP_SIMD_ORDERED_START: case IFN_GOMP_SIMD_ORDERED_END: if (integer_onep (gimple_call_arg (stmt, 0))) { enum built_in_function bcode = (ifn == IFN_GOMP_SIMD_ORDERED_START ? BUILT_IN_GOMP_ORDERED_START : BUILT_IN_GOMP_ORDERED_END); gimple *g = gimple_build_call (builtin_decl_explicit (bcode), 0); tree vdef = gimple_vdef (stmt); gimple_set_vdef (g, vdef); SSA_NAME_DEF_STMT (vdef) = g; gimple_set_vuse (g, gimple_vuse (stmt)); gsi_replace (&i, g, true); continue; } gsi_remove (&i, true); unlink_stmt_vdef (stmt); continue; default: gsi_next (&i); continue; } tree arg = gimple_call_arg (stmt, 0); gcc_assert (arg != NULL_TREE); gcc_assert (TREE_CODE (arg) == SSA_NAME); simduid_to_vf *p = NULL, data; data.simduid = DECL_UID (SSA_NAME_VAR (arg)); /* Need to nullify loop safelen field since it's value is not valid after transformation. */ if (bb->loop_father && bb->loop_father->safelen > 0) bb->loop_father->safelen = 0; if (htab) { p = htab->find (&data); if (p) vf = p->vf; } switch (ifn) { case IFN_GOMP_SIMD_VF: t = build_int_cst (unsigned_type_node, vf); break; case IFN_GOMP_SIMD_LANE: t = build_int_cst (unsigned_type_node, 0); break; case IFN_GOMP_SIMD_LAST_LANE: t = gimple_call_arg (stmt, 1); break; default: gcc_unreachable (); } update_call_from_tree (&i, t); gsi_next (&i); } }
static void instrument_bool_enum_load (gimple_stmt_iterator *gsi) { gimple stmt = gsi_stmt (*gsi); tree rhs = gimple_assign_rhs1 (stmt); tree type = TREE_TYPE (rhs); tree minv = NULL_TREE, maxv = NULL_TREE; if (TREE_CODE (type) == BOOLEAN_TYPE && (flag_sanitize & SANITIZE_BOOL)) { minv = boolean_false_node; maxv = boolean_true_node; } else if (TREE_CODE (type) == ENUMERAL_TYPE && (flag_sanitize & SANITIZE_ENUM) && TREE_TYPE (type) != NULL_TREE && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE && (TYPE_PRECISION (TREE_TYPE (type)) < GET_MODE_PRECISION (TYPE_MODE (type)))) { minv = TYPE_MIN_VALUE (TREE_TYPE (type)); maxv = TYPE_MAX_VALUE (TREE_TYPE (type)); } else return; int modebitsize = GET_MODE_BITSIZE (TYPE_MODE (type)); HOST_WIDE_INT bitsize, bitpos; tree offset; enum machine_mode mode; int volatilep = 0, unsignedp = 0; tree base = get_inner_reference (rhs, &bitsize, &bitpos, &offset, &mode, &unsignedp, &volatilep, false); tree utype = build_nonstandard_integer_type (modebitsize, 1); if ((TREE_CODE (base) == VAR_DECL && DECL_HARD_REGISTER (base)) || (bitpos % modebitsize) != 0 || bitsize != modebitsize || GET_MODE_BITSIZE (TYPE_MODE (utype)) != modebitsize || TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME) return; location_t loc = gimple_location (stmt); tree ptype = build_pointer_type (TREE_TYPE (rhs)); tree atype = reference_alias_ptr_type (rhs); gimple g = gimple_build_assign (make_ssa_name (ptype, NULL), build_fold_addr_expr (rhs)); gimple_set_location (g, loc); gsi_insert_before (gsi, g, GSI_SAME_STMT); tree mem = build2 (MEM_REF, utype, gimple_assign_lhs (g), build_int_cst (atype, 0)); tree urhs = make_ssa_name (utype, NULL); g = gimple_build_assign (urhs, mem); gimple_set_location (g, loc); gsi_insert_before (gsi, g, GSI_SAME_STMT); minv = fold_convert (utype, minv); maxv = fold_convert (utype, maxv); if (!integer_zerop (minv)) { g = gimple_build_assign_with_ops (MINUS_EXPR, make_ssa_name (utype, NULL), urhs, minv); gimple_set_location (g, loc); gsi_insert_before (gsi, g, GSI_SAME_STMT); } gimple_stmt_iterator gsi2 = *gsi; basic_block then_bb, fallthru_bb; *gsi = create_cond_insert_point (gsi, true, false, true, &then_bb, &fallthru_bb); g = gimple_build_cond (GT_EXPR, gimple_assign_lhs (g), int_const_binop (MINUS_EXPR, maxv, minv), NULL_TREE, NULL_TREE); gimple_set_location (g, loc); gsi_insert_after (gsi, g, GSI_NEW_STMT); gimple_assign_set_rhs_with_ops (&gsi2, NOP_EXPR, urhs, NULL_TREE); update_stmt (stmt); gsi2 = gsi_after_labels (then_bb); if (flag_sanitize_undefined_trap_on_error) g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0); else { tree data = ubsan_create_data ("__ubsan_invalid_value_data", &loc, NULL, ubsan_type_descriptor (type), NULL_TREE); data = build_fold_addr_expr_loc (loc, data); enum built_in_function bcode = flag_sanitize_recover ? BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE : BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE_ABORT; tree fn = builtin_decl_explicit (bcode); tree val = force_gimple_operand_gsi (&gsi2, ubsan_encode_value (urhs), true, NULL_TREE, true, GSI_SAME_STMT); g = gimple_build_call (fn, 2, data, val); } gimple_set_location (g, loc); gsi_insert_before (&gsi2, g, GSI_SAME_STMT); }
/* User-deallocate; we emit the code directly from the front-end, and the logic is the same as the previous library function: void deallocate (void *pointer, GFC_INTEGER_4 * stat) { if (!pointer) { if (stat) *stat = 1; else runtime_error ("Attempt to DEALLOCATE unallocated memory."); } else { free (pointer); if (stat) *stat = 0; } } In this front-end version, status doesn't have to be GFC_INTEGER_4. Moreover, if CAN_FAIL is true, then we will not emit a runtime error, even when no status variable is passed to us (this is used for unconditional deallocation generated by the front-end at end of each procedure). If a runtime-message is possible, `expr' must point to the original expression being deallocated for its locus and variable name. For coarrays, "pointer" must be the array descriptor and not its "data" component. */ tree gfc_deallocate_with_status (tree pointer, tree status, tree errmsg, tree errlen, tree label_finish, bool can_fail, gfc_expr* expr, bool coarray) { stmtblock_t null, non_null; tree cond, tmp, error; tree status_type = NULL_TREE; tree caf_decl = NULL_TREE; if (coarray) { gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (pointer))); caf_decl = pointer; pointer = gfc_conv_descriptor_data_get (caf_decl); STRIP_NOPS (pointer); } cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, pointer, build_int_cst (TREE_TYPE (pointer), 0)); /* When POINTER is NULL, we set STATUS to 1 if it's present, otherwise we emit a runtime error. */ gfc_start_block (&null); if (!can_fail) { tree varname; gcc_assert (expr && expr->expr_type == EXPR_VARIABLE && expr->symtree); varname = gfc_build_cstring_const (expr->symtree->name); varname = gfc_build_addr_expr (pchar_type_node, varname); error = gfc_trans_runtime_error (true, &expr->where, "Attempt to DEALLOCATE unallocated '%s'", varname); } else error = build_empty_stmt (input_location); if (status != NULL_TREE && !integer_zerop (status)) { tree cond2; status_type = TREE_TYPE (TREE_TYPE (status)); cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, status, build_int_cst (TREE_TYPE (status), 0)); tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, fold_build1_loc (input_location, INDIRECT_REF, status_type, status), build_int_cst (status_type, 1)); error = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond2, tmp, error); } gfc_add_expr_to_block (&null, error); /* When POINTER is not NULL, we free it. */ gfc_start_block (&non_null); if (!coarray || gfc_option.coarray != GFC_FCOARRAY_LIB) { tmp = build_call_expr_loc (input_location, builtin_decl_explicit (BUILT_IN_FREE), 1, fold_convert (pvoid_type_node, pointer)); gfc_add_expr_to_block (&non_null, tmp); if (status != NULL_TREE && !integer_zerop (status)) { /* We set STATUS to zero if it is present. */ tree status_type = TREE_TYPE (TREE_TYPE (status)); tree cond2; cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, status, build_int_cst (TREE_TYPE (status), 0)); tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, fold_build1_loc (input_location, INDIRECT_REF, status_type, status), build_int_cst (status_type, 0)); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, gfc_unlikely (cond2), tmp, build_empty_stmt (input_location)); gfc_add_expr_to_block (&non_null, tmp); } } else { tree caf_type, token, cond2; tree pstat = null_pointer_node; if (errmsg == NULL_TREE) { gcc_assert (errlen == NULL_TREE); errmsg = null_pointer_node; errlen = build_zero_cst (integer_type_node); } else { gcc_assert (errlen != NULL_TREE); if (!POINTER_TYPE_P (TREE_TYPE (errmsg))) errmsg = gfc_build_addr_expr (NULL_TREE, errmsg); } caf_type = TREE_TYPE (caf_decl); if (status != NULL_TREE && !integer_zerop (status)) { gcc_assert (status_type == integer_type_node); pstat = status; } if (GFC_DESCRIPTOR_TYPE_P (caf_type) && GFC_TYPE_ARRAY_AKIND (caf_type) == GFC_ARRAY_ALLOCATABLE) token = gfc_conv_descriptor_token (caf_decl); else if (DECL_LANG_SPECIFIC (caf_decl) && GFC_DECL_TOKEN (caf_decl) != NULL_TREE) token = GFC_DECL_TOKEN (caf_decl); else { gcc_assert (GFC_ARRAY_TYPE_P (caf_type) && GFC_TYPE_ARRAY_CAF_TOKEN (caf_type) != NULL_TREE); token = GFC_TYPE_ARRAY_CAF_TOKEN (caf_type); } token = gfc_build_addr_expr (NULL_TREE, token); tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_deregister, 4, token, pstat, errmsg, errlen); gfc_add_expr_to_block (&non_null, tmp); if (status != NULL_TREE) { tree stat = build_fold_indirect_ref_loc (input_location, status); TREE_USED (label_finish) = 1; tmp = build1_v (GOTO_EXPR, label_finish); cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, stat, build_zero_cst (TREE_TYPE (stat))); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, gfc_unlikely (cond2), tmp, build_empty_stmt (input_location)); gfc_add_expr_to_block (&non_null, tmp); } } return fold_build3_loc (input_location, COND_EXPR, void_type_node, cond, gfc_finish_block (&null), gfc_finish_block (&non_null)); }
static void gfc_init_builtin_functions (void) { enum builtin_type { #define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME, #define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME, #define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, #define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "types.def" #undef DEF_PRIMITIVE_TYPE #undef DEF_FUNCTION_TYPE_0 #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_VAR_0 #undef DEF_POINTER_TYPE BT_LAST }; tree mfunc_float[6]; tree mfunc_double[6]; tree mfunc_longdouble[6]; tree mfunc_cfloat[6]; tree mfunc_cdouble[6]; tree mfunc_clongdouble[6]; tree func_cfloat_float, func_float_cfloat; tree func_cdouble_double, func_double_cdouble; tree func_clongdouble_longdouble, func_longdouble_clongdouble; tree func_float_floatp_floatp; tree func_double_doublep_doublep; tree func_longdouble_longdoublep_longdoublep; tree ftype, ptype; tree builtin_types[(int) BT_LAST + 1]; build_builtin_fntypes (mfunc_float, float_type_node); build_builtin_fntypes (mfunc_double, double_type_node); build_builtin_fntypes (mfunc_longdouble, long_double_type_node); build_builtin_fntypes (mfunc_cfloat, complex_float_type_node); build_builtin_fntypes (mfunc_cdouble, complex_double_type_node); build_builtin_fntypes (mfunc_clongdouble, complex_long_double_type_node); func_cfloat_float = build_function_type_list (float_type_node, complex_float_type_node, NULL_TREE); func_float_cfloat = build_function_type_list (complex_float_type_node, float_type_node, NULL_TREE); func_cdouble_double = build_function_type_list (double_type_node, complex_double_type_node, NULL_TREE); func_double_cdouble = build_function_type_list (complex_double_type_node, double_type_node, NULL_TREE); func_clongdouble_longdouble = build_function_type_list (long_double_type_node, complex_long_double_type_node, NULL_TREE); func_longdouble_clongdouble = build_function_type_list (complex_long_double_type_node, long_double_type_node, NULL_TREE); ptype = build_pointer_type (float_type_node); func_float_floatp_floatp = build_function_type_list (void_type_node, ptype, ptype, NULL_TREE); ptype = build_pointer_type (double_type_node); func_double_doublep_doublep = build_function_type_list (void_type_node, ptype, ptype, NULL_TREE); ptype = build_pointer_type (long_double_type_node); func_longdouble_longdoublep_longdoublep = build_function_type_list (void_type_node, ptype, ptype, NULL_TREE); /* Non-math builtins are defined manually, so they're not included here. */ #define OTHER_BUILTIN(ID,NAME,TYPE,CONST) #include "mathbuiltins.def" gfc_define_builtin ("__builtin_roundl", mfunc_longdouble[0], BUILT_IN_ROUNDL, "roundl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_round", mfunc_double[0], BUILT_IN_ROUND, "round", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_roundf", mfunc_float[0], BUILT_IN_ROUNDF, "roundf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_truncl", mfunc_longdouble[0], BUILT_IN_TRUNCL, "truncl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_trunc", mfunc_double[0], BUILT_IN_TRUNC, "trunc", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_truncf", mfunc_float[0], BUILT_IN_TRUNCF, "truncf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cabsl", func_clongdouble_longdouble, BUILT_IN_CABSL, "cabsl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cabs", func_cdouble_double, BUILT_IN_CABS, "cabs", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cabsf", func_cfloat_float, BUILT_IN_CABSF, "cabsf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_copysignl", mfunc_longdouble[1], BUILT_IN_COPYSIGNL, "copysignl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_copysign", mfunc_double[1], BUILT_IN_COPYSIGN, "copysign", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_copysignf", mfunc_float[1], BUILT_IN_COPYSIGNF, "copysignf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_nextafterl", mfunc_longdouble[1], BUILT_IN_NEXTAFTERL, "nextafterl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_nextafter", mfunc_double[1], BUILT_IN_NEXTAFTER, "nextafter", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_nextafterf", mfunc_float[1], BUILT_IN_NEXTAFTERF, "nextafterf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_frexpl", mfunc_longdouble[4], BUILT_IN_FREXPL, "frexpl", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_frexp", mfunc_double[4], BUILT_IN_FREXP, "frexp", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_frexpf", mfunc_float[4], BUILT_IN_FREXPF, "frexpf", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fabsl", mfunc_longdouble[0], BUILT_IN_FABSL, "fabsl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fabs", mfunc_double[0], BUILT_IN_FABS, "fabs", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fabsf", mfunc_float[0], BUILT_IN_FABSF, "fabsf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_scalbnl", mfunc_longdouble[5], BUILT_IN_SCALBNL, "scalbnl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_scalbn", mfunc_double[5], BUILT_IN_SCALBN, "scalbn", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_scalbnf", mfunc_float[5], BUILT_IN_SCALBNF, "scalbnf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fmodl", mfunc_longdouble[1], BUILT_IN_FMODL, "fmodl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fmod", mfunc_double[1], BUILT_IN_FMOD, "fmod", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fmodf", mfunc_float[1], BUILT_IN_FMODF, "fmodf", ATTR_CONST_NOTHROW_LEAF_LIST); /* iround{f,,l}, lround{f,,l} and llround{f,,l} */ ftype = build_function_type_list (integer_type_node, float_type_node, NULL_TREE); gfc_define_builtin("__builtin_iroundf", ftype, BUILT_IN_IROUNDF, "iroundf", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_integer_type_node, float_type_node, NULL_TREE); gfc_define_builtin ("__builtin_lroundf", ftype, BUILT_IN_LROUNDF, "lroundf", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_long_integer_type_node, float_type_node, NULL_TREE); gfc_define_builtin ("__builtin_llroundf", ftype, BUILT_IN_LLROUNDF, "llroundf", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (integer_type_node, double_type_node, NULL_TREE); gfc_define_builtin("__builtin_iround", ftype, BUILT_IN_IROUND, "iround", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_integer_type_node, double_type_node, NULL_TREE); gfc_define_builtin ("__builtin_lround", ftype, BUILT_IN_LROUND, "lround", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_long_integer_type_node, double_type_node, NULL_TREE); gfc_define_builtin ("__builtin_llround", ftype, BUILT_IN_LLROUND, "llround", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (integer_type_node, long_double_type_node, NULL_TREE); gfc_define_builtin("__builtin_iroundl", ftype, BUILT_IN_IROUNDL, "iroundl", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_integer_type_node, long_double_type_node, NULL_TREE); gfc_define_builtin ("__builtin_lroundl", ftype, BUILT_IN_LROUNDL, "lroundl", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (long_long_integer_type_node, long_double_type_node, NULL_TREE); gfc_define_builtin ("__builtin_llroundl", ftype, BUILT_IN_LLROUNDL, "llroundl", ATTR_CONST_NOTHROW_LEAF_LIST); /* These are used to implement the ** operator. */ gfc_define_builtin ("__builtin_powl", mfunc_longdouble[1], BUILT_IN_POWL, "powl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_pow", mfunc_double[1], BUILT_IN_POW, "pow", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_powf", mfunc_float[1], BUILT_IN_POWF, "powf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cpowl", mfunc_clongdouble[1], BUILT_IN_CPOWL, "cpowl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cpow", mfunc_cdouble[1], BUILT_IN_CPOW, "cpow", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cpowf", mfunc_cfloat[1], BUILT_IN_CPOWF, "cpowf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_powil", mfunc_longdouble[2], BUILT_IN_POWIL, "powil", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_powi", mfunc_double[2], BUILT_IN_POWI, "powi", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_powif", mfunc_float[2], BUILT_IN_POWIF, "powif", ATTR_CONST_NOTHROW_LEAF_LIST); if (targetm.libc_has_function (function_c99_math_complex)) { gfc_define_builtin ("__builtin_cbrtl", mfunc_longdouble[0], BUILT_IN_CBRTL, "cbrtl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cbrt", mfunc_double[0], BUILT_IN_CBRT, "cbrt", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cbrtf", mfunc_float[0], BUILT_IN_CBRTF, "cbrtf", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cexpil", func_longdouble_clongdouble, BUILT_IN_CEXPIL, "cexpil", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cexpi", func_double_cdouble, BUILT_IN_CEXPI, "cexpi", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_cexpif", func_float_cfloat, BUILT_IN_CEXPIF, "cexpif", ATTR_CONST_NOTHROW_LEAF_LIST); } if (targetm.libc_has_function (function_sincos)) { gfc_define_builtin ("__builtin_sincosl", func_longdouble_longdoublep_longdoublep, BUILT_IN_SINCOSL, "sincosl", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_sincos", func_double_doublep_doublep, BUILT_IN_SINCOS, "sincos", ATTR_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_sincosf", func_float_floatp_floatp, BUILT_IN_SINCOSF, "sincosf", ATTR_NOTHROW_LEAF_LIST); } /* For LEADZ, TRAILZ, POPCNT and POPPAR. */ ftype = build_function_type_list (integer_type_node, unsigned_type_node, NULL_TREE); gfc_define_builtin ("__builtin_clz", ftype, BUILT_IN_CLZ, "__builtin_clz", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_ctz", ftype, BUILT_IN_CTZ, "__builtin_ctz", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_parity", ftype, BUILT_IN_PARITY, "__builtin_parity", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_popcount", ftype, BUILT_IN_POPCOUNT, "__builtin_popcount", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (integer_type_node, long_unsigned_type_node, NULL_TREE); gfc_define_builtin ("__builtin_clzl", ftype, BUILT_IN_CLZL, "__builtin_clzl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_ctzl", ftype, BUILT_IN_CTZL, "__builtin_ctzl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_parityl", ftype, BUILT_IN_PARITYL, "__builtin_parityl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_popcountl", ftype, BUILT_IN_POPCOUNTL, "__builtin_popcountl", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (integer_type_node, long_long_unsigned_type_node, NULL_TREE); gfc_define_builtin ("__builtin_clzll", ftype, BUILT_IN_CLZLL, "__builtin_clzll", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_ctzll", ftype, BUILT_IN_CTZLL, "__builtin_ctzll", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_parityll", ftype, BUILT_IN_PARITYLL, "__builtin_parityll", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_popcountll", ftype, BUILT_IN_POPCOUNTLL, "__builtin_popcountll", ATTR_CONST_NOTHROW_LEAF_LIST); /* Other builtin functions we use. */ ftype = build_function_type_list (long_integer_type_node, long_integer_type_node, long_integer_type_node, NULL_TREE); gfc_define_builtin ("__builtin_expect", ftype, BUILT_IN_EXPECT, "__builtin_expect", ATTR_CONST_NOTHROW_LEAF_LIST); ftype = build_function_type_list (void_type_node, pvoid_type_node, NULL_TREE); gfc_define_builtin ("__builtin_free", ftype, BUILT_IN_FREE, "free", ATTR_NOTHROW_LEAF_LIST); ftype = build_function_type_list (pvoid_type_node, size_type_node, NULL_TREE); gfc_define_builtin ("__builtin_malloc", ftype, BUILT_IN_MALLOC, "malloc", ATTR_NOTHROW_LEAF_MALLOC_LIST); ftype = build_function_type_list (pvoid_type_node, size_type_node, size_type_node, NULL_TREE); gfc_define_builtin ("__builtin_calloc", ftype, BUILT_IN_CALLOC, "calloc", ATTR_NOTHROW_LEAF_MALLOC_LIST); DECL_IS_MALLOC (builtin_decl_explicit (BUILT_IN_CALLOC)) = 1; ftype = build_function_type_list (pvoid_type_node, size_type_node, pvoid_type_node, NULL_TREE); gfc_define_builtin ("__builtin_realloc", ftype, BUILT_IN_REALLOC, "realloc", ATTR_NOTHROW_LEAF_LIST); ftype = build_function_type_list (integer_type_node, void_type_node, NULL_TREE); gfc_define_builtin ("__builtin_isnan", ftype, BUILT_IN_ISNAN, "__builtin_isnan", ATTR_CONST_NOTHROW_LEAF_LIST); #define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \ builtin_types[(int) ENUM] = VALUE; #define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ NULL_TREE); #define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ NULL_TREE); #define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ NULL_TREE); #define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ NULL_TREE); #define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ NULL_TREE); #define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ NULL_TREE); #define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ NULL_TREE); #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ NULL_TREE); #define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) \ builtin_types[(int) ENUM] \ = build_function_type_list (builtin_types[(int) RETURN], \ builtin_types[(int) ARG1], \ builtin_types[(int) ARG2], \ builtin_types[(int) ARG3], \ builtin_types[(int) ARG4], \ builtin_types[(int) ARG5], \ builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ builtin_types[(int) ARG8], \ NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ NULL_TREE); #define DEF_POINTER_TYPE(ENUM, TYPE) \ builtin_types[(int) ENUM] \ = build_pointer_type (builtin_types[(int) TYPE]); #include "types.def" #undef DEF_PRIMITIVE_TYPE #undef DEF_FUNCTION_TYPE_0 #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_VAR_0 #undef DEF_POINTER_TYPE builtin_types[(int) BT_LAST] = NULL_TREE; /* Initialize synchronization builtins. */ #undef DEF_SYNC_BUILTIN #define DEF_SYNC_BUILTIN(code, name, type, attr) \ gfc_define_builtin (name, builtin_types[type], code, name, \ attr); #include "../sync-builtins.def" #undef DEF_SYNC_BUILTIN if (gfc_option.gfc_flag_openmp || flag_tree_parallelize_loops) { #undef DEF_GOMP_BUILTIN #define DEF_GOMP_BUILTIN(code, name, type, attr) \ gfc_define_builtin ("__builtin_" name, builtin_types[type], \ code, name, attr); #include "../omp-builtins.def" #undef DEF_GOMP_BUILTIN } gfc_define_builtin ("__builtin_trap", builtin_types[BT_FN_VOID], BUILT_IN_TRAP, NULL, ATTR_NOTHROW_LEAF_LIST); TREE_THIS_VOLATILE (builtin_decl_explicit (BUILT_IN_TRAP)) = 1; gfc_define_builtin ("__emutls_get_address", builtin_types[BT_FN_PTR_PTR], BUILT_IN_EMUTLS_GET_ADDRESS, "__emutls_get_address", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__emutls_register_common", builtin_types[BT_FN_VOID_PTR_WORD_WORD_PTR], BUILT_IN_EMUTLS_REGISTER_COMMON, "__emutls_register_common", ATTR_NOTHROW_LEAF_LIST); build_common_builtin_nodes (); targetm.init_builtins (); }
tree ubsan_instrument_shift (location_t loc, enum tree_code code, tree op0, tree op1) { tree t, tt = NULL_TREE; tree type0 = TREE_TYPE (op0); tree type1 = TREE_TYPE (op1); tree op1_utype = unsigned_type_for (type1); HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0); tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1); tree precm1 = build_int_cst (type1, op0_prec - 1); t = fold_convert_loc (loc, op1_utype, op1); t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1); /* For signed x << y, in C99/C11, the following: (unsigned) x >> (precm1 - y) if non-zero, is undefined. */ if (code == LSHIFT_EXPR && !TYPE_UNSIGNED (type0) && flag_isoc99) { tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1); tt = fold_convert_loc (loc, unsigned_type_for (type0), op0); tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x); tt = fold_build2 (NE_EXPR, boolean_type_node, tt, build_int_cst (TREE_TYPE (tt), 0)); } /* For signed x << y, in C++11/C++14, the following: x < 0 || ((unsigned) x >> (precm1 - y)) if > 1, is undefined. */ if (code == LSHIFT_EXPR && !TYPE_UNSIGNED (TREE_TYPE (op0)) && (cxx_dialect == cxx11 || cxx_dialect == cxx1y)) { tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1); tt = fold_convert_loc (loc, unsigned_type_for (type0), op0); tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x); tt = fold_build2 (GT_EXPR, boolean_type_node, tt, build_int_cst (TREE_TYPE (tt), 1)); x = fold_build2 (LT_EXPR, boolean_type_node, op0, build_int_cst (type0, 0)); tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt); } /* In case we have a SAVE_EXPR in a conditional context, we need to make sure it gets evaluated before the condition. */ t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), op0, t); tree data = ubsan_create_data ("__ubsan_shift_data", loc, ubsan_type_descriptor (type0), ubsan_type_descriptor (type1), NULL_TREE); data = build_fold_addr_expr_loc (loc, data); t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt ? tt : integer_zero_node); tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS); tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0), ubsan_encode_value (op1)); t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node); return t; }
tree build_exc_ptr (void) { return build_call_n (builtin_decl_explicit (BUILT_IN_EH_POINTER), 1, integer_zero_node); }
tree ubsan_instrument_float_cast (location_t loc, tree type, tree expr) { tree expr_type = TREE_TYPE (expr); tree t, tt, fn, min, max; enum machine_mode mode = TYPE_MODE (expr_type); int prec = TYPE_PRECISION (type); bool uns_p = TYPE_UNSIGNED (type); /* Float to integer conversion first truncates toward zero, so even signed char c = 127.875f; is not problematic. Therefore, we should complain only if EXPR is unordered or smaller or equal than TYPE_MIN_VALUE - 1.0 or greater or equal than TYPE_MAX_VALUE + 1.0. */ if (REAL_MODE_FORMAT (mode)->b == 2) { /* For maximum, TYPE_MAX_VALUE might not be representable in EXPR_TYPE, e.g. if TYPE is 64-bit long long and EXPR_TYPE is IEEE single float, but TYPE_MAX_VALUE + 1.0 is either representable or infinity. */ REAL_VALUE_TYPE maxval = dconst1; SET_REAL_EXP (&maxval, REAL_EXP (&maxval) + prec - !uns_p); real_convert (&maxval, mode, &maxval); max = build_real (expr_type, maxval); /* For unsigned, assume -1.0 is always representable. */ if (uns_p) min = build_minus_one_cst (expr_type); else { /* TYPE_MIN_VALUE is generally representable (or -inf), but TYPE_MIN_VALUE - 1.0 might not be. */ REAL_VALUE_TYPE minval = dconstm1, minval2; SET_REAL_EXP (&minval, REAL_EXP (&minval) + prec - 1); real_convert (&minval, mode, &minval); real_arithmetic (&minval2, MINUS_EXPR, &minval, &dconst1); real_convert (&minval2, mode, &minval2); if (real_compare (EQ_EXPR, &minval, &minval2) && !real_isinf (&minval)) { /* If TYPE_MIN_VALUE - 1.0 is not representable and rounds to TYPE_MIN_VALUE, we need to subtract more. As REAL_MODE_FORMAT (mode)->p is the number of base digits, we want to subtract a number that will be 1 << (REAL_MODE_FORMAT (mode)->p - 1) times smaller than minval. */ minval2 = dconst1; gcc_assert (prec > REAL_MODE_FORMAT (mode)->p); SET_REAL_EXP (&minval2, REAL_EXP (&minval2) + prec - 1 - REAL_MODE_FORMAT (mode)->p + 1); real_arithmetic (&minval2, MINUS_EXPR, &minval, &minval2); real_convert (&minval2, mode, &minval2); } min = build_real (expr_type, minval2); } } else if (REAL_MODE_FORMAT (mode)->b == 10) { /* For _Decimal128 up to 34 decimal digits, - sign, dot, e, exponent. */ char buf[64]; mpfr_t m; int p = REAL_MODE_FORMAT (mode)->p; REAL_VALUE_TYPE maxval, minval; /* Use mpfr_snprintf rounding to compute the smallest representable decimal number greater or equal than 1 << (prec - !uns_p). */ mpfr_init2 (m, prec + 2); mpfr_set_ui_2exp (m, 1, prec - !uns_p, GMP_RNDN); mpfr_snprintf (buf, sizeof buf, "%.*RUe", p - 1, m); decimal_real_from_string (&maxval, buf); max = build_real (expr_type, maxval); /* For unsigned, assume -1.0 is always representable. */ if (uns_p) min = build_minus_one_cst (expr_type); else { /* Use mpfr_snprintf rounding to compute the largest representable decimal number less or equal than (-1 << (prec - 1)) - 1. */ mpfr_set_si_2exp (m, -1, prec - 1, GMP_RNDN); mpfr_sub_ui (m, m, 1, GMP_RNDN); mpfr_snprintf (buf, sizeof buf, "%.*RDe", p - 1, m); decimal_real_from_string (&minval, buf); min = build_real (expr_type, minval); } mpfr_clear (m); } else return NULL_TREE; if (flag_sanitize_undefined_trap_on_error) fn = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); else { /* Create the __ubsan_handle_float_cast_overflow fn call. */ tree data = ubsan_create_data ("__ubsan_float_cast_overflow_data", NULL, NULL, ubsan_type_descriptor (expr_type), ubsan_type_descriptor (type), NULL_TREE); enum built_in_function bcode = flag_sanitize_recover ? BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW : BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW_ABORT; fn = builtin_decl_explicit (bcode); fn = build_call_expr_loc (loc, fn, 2, build_fold_addr_expr_loc (loc, data), ubsan_encode_value (expr, false)); } t = fold_build2 (UNLE_EXPR, boolean_type_node, expr, min); tt = fold_build2 (UNGE_EXPR, boolean_type_node, expr, max); return fold_build3 (COND_EXPR, void_type_node, fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt), fn, integer_zero_node); }