| /* Built-in and inline functions for gcj |
| Copyright (C) 2001-2013 Free Software Foundation, Inc. |
| |
| 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. |
| |
| . |
| |
| . |
| |
| Java and all Java-based marks are trademarks or registered trademarks |
| of Sun Microsystems, Inc. in the United States and other countries. |
| The Free Software Foundation is independent of Sun Microsystems, Inc. */ |
| |
| /* Written by Tom Tromey <tromey@redhat.com>. */ |
| |
| /* FIXME: Still need to include rtl.h here (see below). */ |
| #undef IN_GCC_FRONTEND |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "tree.h" |
| #include "ggc.h" |
| #include "flags.h" |
| #include "langhooks.h" |
| #include "java-tree.h" |
| |
| /* FIXME: All these headers are necessary for sync_compare_and_swap. |
| Front ends should never have to look at that. */ |
| #include "rtl.h" |
| #include "insn-codes.h" |
| #include "expr.h" |
| #include "optabs.h" |
| |
| static tree max_builtin (tree, tree); |
| static tree min_builtin (tree, tree); |
| static tree abs_builtin (tree, tree); |
| static tree convert_real (tree, tree); |
| |
| static tree java_build_function_call_expr (tree, tree); |
| |
| static tree putObject_builtin (tree, tree); |
| static tree compareAndSwapInt_builtin (tree, tree); |
| static tree compareAndSwapLong_builtin (tree, tree); |
| static tree compareAndSwapObject_builtin (tree, tree); |
| static tree putVolatile_builtin (tree, tree); |
| static tree getVolatile_builtin (tree, tree); |
| static tree VMSupportsCS8_builtin (tree, tree); |
| |
| |
| /* Functions of this type are used to inline a given call. Such a |
| function should either return an expression, if the call is to be |
| inlined, or NULL_TREE if a real call should be emitted. Arguments |
| are method return type and the original CALL_EXPR containing the |
| arguments to the call. */ |
| typedef tree builtin_creator_function (tree, tree); |
| |
| /* Hold a char*, before initialization, or a tree, after |
| initialization. */ |
| union GTY(()) string_or_tree { |
| const char * GTY ((tag ("0"))) s; |
| tree GTY ((tag ("1"))) t; |
| }; |
| |
| /* Used to hold a single builtin record. */ |
| struct GTY(()) builtin_record { |
| union string_or_tree GTY ((desc ("1"))) class_name; |
| union string_or_tree GTY ((desc ("1"))) method_name; |
| builtin_creator_function * GTY((skip)) creator; |
| enum built_in_function builtin_code; |
| }; |
| |
| static GTY(()) struct builtin_record java_builtins[] = |
| { |
| { { "java.lang.Math" }, { "min" }, min_builtin, (enum built_in_function) 0 }, |
| { { "java.lang.Math" }, { "max" }, max_builtin, (enum built_in_function) 0 }, |
| { { "java.lang.Math" }, { "abs" }, abs_builtin, (enum built_in_function) 0 }, |
| { { "java.lang.Math" }, { "acos" }, NULL, BUILT_IN_ACOS }, |
| { { "java.lang.Math" }, { "asin" }, NULL, BUILT_IN_ASIN }, |
| { { "java.lang.Math" }, { "atan" }, NULL, BUILT_IN_ATAN }, |
| { { "java.lang.Math" }, { "atan2" }, NULL, BUILT_IN_ATAN2 }, |
| { { "java.lang.Math" }, { "ceil" }, NULL, BUILT_IN_CEIL }, |
| { { "java.lang.Math" }, { "cos" }, NULL, BUILT_IN_COS }, |
| { { "java.lang.Math" }, { "exp" }, NULL, BUILT_IN_EXP }, |
| { { "java.lang.Math" }, { "floor" }, NULL, BUILT_IN_FLOOR }, |
| { { "java.lang.Math" }, { "log" }, NULL, BUILT_IN_LOG }, |
| { { "java.lang.Math" }, { "pow" }, NULL, BUILT_IN_POW }, |
| { { "java.lang.Math" }, { "sin" }, NULL, BUILT_IN_SIN }, |
| { { "java.lang.Math" }, { "sqrt" }, NULL, BUILT_IN_SQRT }, |
| { { "java.lang.Math" }, { "tan" }, NULL, BUILT_IN_TAN }, |
| { { "java.lang.Float" }, { "intBitsToFloat" }, convert_real, |
| (enum built_in_function) 0 }, |
| { { "java.lang.Double" }, { "longBitsToDouble" }, convert_real, |
| (enum built_in_function) 0 }, |
| { { "java.lang.Float" }, { "floatToRawIntBits" }, convert_real, |
| (enum built_in_function) 0 }, |
| { { "java.lang.Double" }, { "doubleToRawLongBits" }, convert_real, |
| (enum built_in_function) 0 }, |
| { { "sun.misc.Unsafe" }, { "putInt" }, putObject_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "putLong" }, putObject_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "putObject" }, putObject_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "compareAndSwapInt" }, |
| compareAndSwapInt_builtin, (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "compareAndSwapLong" }, |
| compareAndSwapLong_builtin, (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "compareAndSwapObject" }, |
| compareAndSwapObject_builtin, (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "putOrderedInt" }, putVolatile_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "putOrderedLong" }, putVolatile_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "putOrderedObject" }, putVolatile_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "putIntVolatile" }, putVolatile_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "putLongVolatile" }, putVolatile_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "putObjectVolatile" }, putVolatile_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "getObjectVolatile" }, getVolatile_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "getIntVolatile" }, getVolatile_builtin, |
| (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "getLongVolatile" }, getVolatile_builtin, (enum built_in_function) 0}, |
| { { "sun.misc.Unsafe" }, { "getLong" }, getVolatile_builtin, |
| (enum built_in_function) 0}, |
| { { "java.util.concurrent.atomic.AtomicLong" }, { "VMSupportsCS8" }, |
| VMSupportsCS8_builtin, (enum built_in_function) 0}, |
| { { NULL }, { NULL }, NULL, END_BUILTINS } |
| }; |
| |
| |
| /* Internal functions which implement various builtin conversions. */ |
| |
| static tree |
| max_builtin (tree method_return_type, tree orig_call) |
| { |
| /* MAX_EXPR does not handle -0.0 in the Java style. */ |
| if (TREE_CODE (method_return_type) == REAL_TYPE) |
| return NULL_TREE; |
| return fold_build2 (MAX_EXPR, method_return_type, |
| CALL_EXPR_ARG (orig_call, 0), |
| CALL_EXPR_ARG (orig_call, 1)); |
| } |
| |
| static tree |
| min_builtin (tree method_return_type, tree orig_call) |
| { |
| /* MIN_EXPR does not handle -0.0 in the Java style. */ |
| if (TREE_CODE (method_return_type) == REAL_TYPE) |
| return NULL_TREE; |
| return fold_build2 (MIN_EXPR, method_return_type, |
| CALL_EXPR_ARG (orig_call, 0), |
| CALL_EXPR_ARG (orig_call, 1)); |
| } |
| |
| static tree |
| abs_builtin (tree method_return_type, tree orig_call) |
| { |
| return fold_build1 (ABS_EXPR, method_return_type, |
| CALL_EXPR_ARG (orig_call, 0)); |
| } |
| |
| /* Construct a new call to FN using the arguments from ORIG_CALL. */ |
| |
| static tree |
| java_build_function_call_expr (tree fn, tree orig_call) |
| { |
| int nargs = call_expr_nargs (orig_call); |
| switch (nargs) |
| { |
| /* Although we could handle the 0-3 argument cases using the general |
| logic in the default case, splitting them out permits folding to |
| be performed without constructing a temporary CALL_EXPR. */ |
| case 0: |
| return build_call_expr (fn, 0); |
| case 1: |
| return build_call_expr (fn, 1, CALL_EXPR_ARG (orig_call, 0)); |
| case 2: |
| return build_call_expr (fn, 2, |
| CALL_EXPR_ARG (orig_call, 0), |
| CALL_EXPR_ARG (orig_call, 1)); |
| case 3: |
| return build_call_expr (fn, 3, |
| CALL_EXPR_ARG (orig_call, 0), |
| CALL_EXPR_ARG (orig_call, 1), |
| CALL_EXPR_ARG (orig_call, 2)); |
| default: |
| { |
| tree fntype = TREE_TYPE (fn); |
| fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fn); |
| return fold (build_call_array (TREE_TYPE (fntype), |
| fn, nargs, CALL_EXPR_ARGP (orig_call))); |
| } |
| } |
| } |
| |
| static tree |
| convert_real (tree method_return_type, tree orig_call) |
| { |
| return build1 (VIEW_CONVERT_EXPR, method_return_type, |
| CALL_EXPR_ARG (orig_call, 0)); |
| } |
| |
| |
| |
| /* Provide builtin support for atomic operations. These are |
| documented at length in libjava/sun/misc/Unsafe.java. */ |
| |
| /* FIXME. There are still a few things wrong with this logic. In |
| particular, atomic writes of multi-word integers are not truly |
| atomic: this requires more work. |
| |
| In general, double-word compare-and-swap cannot portably be |
| implemented, so we need some kind of fallback for 32-bit machines. |
| |
| */ |
| |
| |
| /* Macros to unmarshal arguments from a CALL_EXPR into a few |
| variables. We also convert the offset arg from a long to an |
| integer that is the same size as a pointer. */ |
| |
| #define UNMARSHAL3(METHOD_CALL) \ |
| tree this_arg, obj_arg, offset_arg; \ |
| do \ |
| { \ |
| tree orig_method_call = METHOD_CALL; \ |
| this_arg = CALL_EXPR_ARG (orig_method_call, 0); \ |
| obj_arg = CALL_EXPR_ARG (orig_method_call, 1); \ |
| offset_arg = fold_convert (java_type_for_size (POINTER_SIZE, 0), \ |
| CALL_EXPR_ARG (orig_method_call, 2)); \ |
| } \ |
| while (0) |
| |
| #define UNMARSHAL4(METHOD_CALL) \ |
| tree value_type, this_arg, obj_arg, offset_arg, value_arg; \ |
| do \ |
| { \ |
| tree orig_method_call = METHOD_CALL; \ |
| this_arg = CALL_EXPR_ARG (orig_method_call, 0); \ |
| obj_arg = CALL_EXPR_ARG (orig_method_call, 1); \ |
| offset_arg = fold_convert (java_type_for_size (POINTER_SIZE, 0), \ |
| CALL_EXPR_ARG (orig_method_call, 2)); \ |
| value_arg = CALL_EXPR_ARG (orig_method_call, 3); \ |
| value_type = TREE_TYPE (value_arg); \ |
| } \ |
| while (0) |
| |
| #define UNMARSHAL5(METHOD_CALL) \ |
| tree value_type, this_arg, obj_arg, offset_arg, expected_arg, value_arg; \ |
| do \ |
| { \ |
| tree orig_method_call = METHOD_CALL; \ |
| this_arg = CALL_EXPR_ARG (orig_method_call, 0); \ |
| obj_arg = CALL_EXPR_ARG (orig_method_call, 1); \ |
| offset_arg = fold_convert (java_type_for_size (POINTER_SIZE, 0), \ |
| CALL_EXPR_ARG (orig_method_call, 2)); \ |
| expected_arg = CALL_EXPR_ARG (orig_method_call, 3); \ |
| value_arg = CALL_EXPR_ARG (orig_method_call, 4); \ |
| value_type = TREE_TYPE (value_arg); \ |
| } \ |
| while (0) |
| |
| /* Add an address to an offset, forming a sum. */ |
| |
| static tree |
| build_addr_sum (tree type, tree addr, tree offset) |
| { |
| tree ptr_type = build_pointer_type (type); |
| return fold_build_pointer_plus (fold_convert (ptr_type, addr), offset); |
| } |
| |
| /* Make sure that this-arg is non-NULL. This is a security check. */ |
| |
| static tree |
| build_check_this (tree stmt, tree this_arg) |
| { |
| return build2 (COMPOUND_EXPR, TREE_TYPE (stmt), |
| java_check_reference (this_arg, 1), stmt); |
| } |
| |
| /* Now the builtins. These correspond to the primitive functions in |
| libjava/sun/misc/natUnsafe.cc. */ |
| |
| static tree |
| putObject_builtin (tree method_return_type ATTRIBUTE_UNUSED, |
| tree orig_call) |
| { |
| tree addr, stmt; |
| UNMARSHAL4 (orig_call); |
| |
| addr = build_addr_sum (value_type, obj_arg, offset_arg); |
| stmt = fold_build2 (MODIFY_EXPR, value_type, |
| build_java_indirect_ref (value_type, addr, |
| flag_check_references), |
| value_arg); |
| |
| return build_check_this (stmt, this_arg); |
| } |
| |
| 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; |
| } |
| |
| static tree |
| compareAndSwapLong_builtin (tree method_return_type ATTRIBUTE_UNUSED, |
| tree orig_call) |
| { |
| enum machine_mode mode = TYPE_MODE (long_type_node); |
| /* We don't trust flag_use_atomic_builtins for multi-word compareAndSwap. |
| Some machines such as ARM have atomic libfuncs but not the multi-word |
| versions. */ |
| if (can_compare_and_swap_p (mode, |
| (flag_use_atomic_builtins |
| && GET_MODE_SIZE (mode) <= UNITS_PER_WORD))) |
| { |
| tree addr, stmt; |
| enum built_in_function fncode = BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8; |
| UNMARSHAL5 (orig_call); |
| (void) value_type; /* Avoid set but not used warning. */ |
| |
| addr = build_addr_sum (long_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; |
| } |
| 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; |
| } |
| |
| 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 |
| getVolatile_builtin (tree method_return_type ATTRIBUTE_UNUSED, |
| tree orig_call) |
| { |
| tree addr, stmt, modify_stmt, tmp; |
| UNMARSHAL3 (orig_call); |
| (void) this_arg; /* Avoid set but not used warning. */ |
| |
| addr = build_addr_sum (method_return_type, obj_arg, offset_arg); |
| addr |
| = fold_convert (build_pointer_type (build_type_variant |
| (method_return_type, 0, 1)), addr); |
| |
| stmt = build_call_expr (builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE), 0); |
| tmp = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL, method_return_type); |
| DECL_IGNORED_P (tmp) = 1; |
| DECL_ARTIFICIAL (tmp) = 1; |
| pushdecl (tmp); |
| |
| modify_stmt = fold_build2 (MODIFY_EXPR, method_return_type, |
| tmp, |
| build_java_indirect_ref (method_return_type, addr, |
| flag_check_references)); |
| |
| stmt = build2 (COMPOUND_EXPR, void_type_node, modify_stmt, stmt); |
| stmt = build2 (COMPOUND_EXPR, method_return_type, stmt, tmp); |
| |
| return stmt; |
| } |
| |
| static tree |
| VMSupportsCS8_builtin (tree method_return_type, |
| tree orig_call ATTRIBUTE_UNUSED) |
| { |
| enum machine_mode mode = TYPE_MODE (long_type_node); |
| gcc_assert (method_return_type == boolean_type_node); |
| if (can_compare_and_swap_p (mode, false)) |
| return boolean_true_node; |
| else |
| return boolean_false_node; |
| } |
| |
| |
| |
| /* Define a single builtin. */ |
| static void |
| define_builtin (enum built_in_function val, |
| const char *name, |
| tree type, |
| const char *libname, |
| int flags) |
| { |
| tree decl; |
| |
| decl = build_decl (BUILTINS_LOCATION, |
| FUNCTION_DECL, get_identifier (name), type); |
| DECL_EXTERNAL (decl) = 1; |
| TREE_PUBLIC (decl) = 1; |
| SET_DECL_ASSEMBLER_NAME (decl, get_identifier (libname)); |
| pushdecl (decl); |
| DECL_BUILT_IN_CLASS (decl) = BUILT_IN_NORMAL; |
| DECL_FUNCTION_CODE (decl) = val; |
| set_call_expr_flags (decl, flags); |
| |
| set_builtin_decl (val, decl, true); |
| } |
| |
| |
| |
| /* Initialize the builtins. */ |
| void |
| initialize_builtins (void) |
| { |
| tree double_ftype_double, double_ftype_double_double; |
| tree float_ftype_float_float; |
| tree boolean_ftype_boolean_boolean; |
| int i; |
| |
| for (i = 0; java_builtins[i].builtin_code != END_BUILTINS; ++i) |
| { |
| tree klass_id = get_identifier (java_builtins[i].class_name.s); |
| tree m = get_identifier (java_builtins[i].method_name.s); |
| |
| java_builtins[i].class_name.t = klass_id; |
| java_builtins[i].method_name.t = m; |
| } |
| |
| void_list_node = end_params_node; |
| |
| float_ftype_float_float |
| = build_function_type_list (float_type_node, |
| float_type_node, float_type_node, NULL_TREE); |
| |
| double_ftype_double |
| = build_function_type_list (double_type_node, double_type_node, NULL_TREE); |
| double_ftype_double_double |
| = build_function_type_list (double_type_node, |
| double_type_node, double_type_node, NULL_TREE); |
| |
| define_builtin (BUILT_IN_FMOD, "__builtin_fmod", |
| double_ftype_double_double, "fmod", ECF_CONST); |
| define_builtin (BUILT_IN_FMODF, "__builtin_fmodf", |
| float_ftype_float_float, "fmodf", ECF_CONST); |
| |
| define_builtin (BUILT_IN_ACOS, "__builtin_acos", |
| double_ftype_double, "_ZN4java4lang4Math4acosEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_ASIN, "__builtin_asin", |
| double_ftype_double, "_ZN4java4lang4Math4asinEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_ATAN, "__builtin_atan", |
| double_ftype_double, "_ZN4java4lang4Math4atanEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_ATAN2, "__builtin_atan2", |
| double_ftype_double_double, "_ZN4java4lang4Math5atan2EJddd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_CEIL, "__builtin_ceil", |
| double_ftype_double, "_ZN4java4lang4Math4ceilEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_COS, "__builtin_cos", |
| double_ftype_double, "_ZN4java4lang4Math3cosEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_EXP, "__builtin_exp", |
| double_ftype_double, "_ZN4java4lang4Math3expEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_FLOOR, "__builtin_floor", |
| double_ftype_double, "_ZN4java4lang4Math5floorEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_LOG, "__builtin_log", |
| double_ftype_double, "_ZN4java4lang4Math3logEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_POW, "__builtin_pow", |
| double_ftype_double_double, "_ZN4java4lang4Math3powEJddd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_SIN, "__builtin_sin", |
| double_ftype_double, "_ZN4java4lang4Math3sinEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_SQRT, "__builtin_sqrt", |
| double_ftype_double, "_ZN4java4lang4Math4sqrtEJdd", |
| ECF_CONST); |
| define_builtin (BUILT_IN_TAN, "__builtin_tan", |
| double_ftype_double, "_ZN4java4lang4Math3tanEJdd", |
| ECF_CONST); |
| |
| boolean_ftype_boolean_boolean |
| = build_function_type_list (boolean_type_node, |
| boolean_type_node, boolean_type_node, |
| NULL_TREE); |
| define_builtin (BUILT_IN_EXPECT, "__builtin_expect", |
| boolean_ftype_boolean_boolean, |
| "__builtin_expect", |
| ECF_CONST | ECF_NOTHROW); |
| define_builtin (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4, |
| "__sync_bool_compare_and_swap_4", |
| build_function_type_list (boolean_type_node, |
| int_type_node, |
| build_pointer_type (int_type_node), |
| int_type_node, NULL_TREE), |
| "__sync_bool_compare_and_swap_4", ECF_NOTHROW | ECF_LEAF); |
| define_builtin (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8, |
| "__sync_bool_compare_and_swap_8", |
| build_function_type_list (boolean_type_node, |
| long_type_node, |
| build_pointer_type (long_type_node), |
| int_type_node, NULL_TREE), |
| "__sync_bool_compare_and_swap_8", ECF_NOTHROW | ECF_LEAF); |
| define_builtin (BUILT_IN_SYNC_SYNCHRONIZE, "__sync_synchronize", |
| build_function_type_list (void_type_node, NULL_TREE), |
| "__sync_synchronize", ECF_NOTHROW | ECF_LEAF); |
| |
| define_builtin (BUILT_IN_RETURN_ADDRESS, "__builtin_return_address", |
| build_function_type_list (ptr_type_node, int_type_node, NULL_TREE), |
| "__builtin_return_address", ECF_NOTHROW | ECF_LEAF); |
| |
| build_common_builtin_nodes (); |
| } |
| |
| /* 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; |
| } |
| |
| #include "gt-java-builtins.h" |