builtins.c 20.9 KB
Newer Older
1
/* Built-in and inline functions for gcj
2
   Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2009, 2010
3 4
   Free Software Foundation, Inc.

5
This file is part of GCC.
6

7
GCC is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 3, or (at your option)
10 11
any later version.

12
GCC is distributed in the hope that it will be useful,
13 14 15 16
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.

17 18 19
.

.  
20 21 22 23 24 25 26

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>.  */

27 28 29
/* FIXME: Still need to include rtl.h here (see below).  */
#undef IN_GCC_FRONTEND

30 31
#include "config.h"
#include "system.h"
32 33
#include "coretypes.h"
#include "tm.h"
34 35 36
#include "tree.h"
#include "ggc.h"
#include "flags.h"
37
#include "langhooks.h"
38
#include "java-tree.h"
39 40 41

/* FIXME: All these headers are necessary for sync_compare_and_swap.
   Front ends should never have to look at that.  */
42 43 44 45
#include "rtl.h"
#include "insn-codes.h"
#include "expr.h"
#include "optabs.h"
46

47 48 49
static tree max_builtin (tree, tree);
static tree min_builtin (tree, tree);
static tree abs_builtin (tree, tree);
50
static tree convert_real (tree, tree);
51

52
static tree java_build_function_call_expr (tree, tree);
53

54 55 56 57 58 59
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);
Andrew Haley committed
60
static tree VMSupportsCS8_builtin (tree, tree);
61 62 63 64 65


/* 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
66 67
   are method return type and the original CALL_EXPR containing the
   arguments to the call.  */
68
typedef tree builtin_creator_function (tree, tree);
69 70 71

/* Hold a char*, before initialization, or a tree, after
   initialization.  */
72
union GTY(()) string_or_tree {
73 74
  const char * GTY ((tag ("0"))) s;
  tree GTY ((tag ("1"))) t;
75 76 77
};

/* Used to hold a single builtin record.  */
78
struct GTY(()) builtin_record {
79 80
  union string_or_tree GTY ((desc ("1"))) class_name;
  union string_or_tree GTY ((desc ("1"))) method_name;
81
  builtin_creator_function * GTY((skip)) creator;
82
  enum built_in_function builtin_code;
83 84
};

85
static GTY(()) struct builtin_record java_builtins[] =
86
{
87 88 89
  { { "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 },
90 91
  { { "java.lang.Math" }, { "acos" }, NULL, BUILT_IN_ACOS },
  { { "java.lang.Math" }, { "asin" }, NULL, BUILT_IN_ASIN },
92 93
  { { "java.lang.Math" }, { "atan" }, NULL, BUILT_IN_ATAN },
  { { "java.lang.Math" }, { "atan2" }, NULL, BUILT_IN_ATAN2 },
94
  { { "java.lang.Math" }, { "ceil" }, NULL, BUILT_IN_CEIL },
95 96
  { { "java.lang.Math" }, { "cos" }, NULL, BUILT_IN_COS },
  { { "java.lang.Math" }, { "exp" }, NULL, BUILT_IN_EXP },
97
  { { "java.lang.Math" }, { "floor" }, NULL, BUILT_IN_FLOOR },
98 99 100 101 102
  { { "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 },
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  { { "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},
144
  { { NULL }, { NULL }, NULL, END_BUILTINS }
145 146 147 148 149 150
};


/* Internal functions which implement various builtin conversions.  */

static tree
151
max_builtin (tree method_return_type, tree orig_call)
152
{
153 154 155
  /* MAX_EXPR does not handle -0.0 in the Java style.  */
  if (TREE_CODE (method_return_type) == REAL_TYPE)
    return NULL_TREE;
156
  return fold_build2 (MAX_EXPR, method_return_type,
157 158
		      CALL_EXPR_ARG (orig_call, 0),
		      CALL_EXPR_ARG (orig_call, 1));
159 160 161
}

static tree
162
min_builtin (tree method_return_type, tree orig_call)
163
{
164 165 166
  /* MIN_EXPR does not handle -0.0 in the Java style.  */
  if (TREE_CODE (method_return_type) == REAL_TYPE)
    return NULL_TREE;
167
  return fold_build2 (MIN_EXPR, method_return_type,
168 169
		      CALL_EXPR_ARG (orig_call, 0),
		      CALL_EXPR_ARG (orig_call, 1));
170 171 172
}

static tree
173
abs_builtin (tree method_return_type, tree orig_call)
174
{
175
  return fold_build1 (ABS_EXPR, method_return_type,
176
		      CALL_EXPR_ARG (orig_call, 0));
177 178
}

179 180
/* Construct a new call to FN using the arguments from ORIG_CALL.  */

181
static tree
182
java_build_function_call_expr (tree fn, tree orig_call)
183
{
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
  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)));
      }
    }
211 212
}

213
static tree
214
convert_real (tree method_return_type, tree orig_call)
215 216
{
  return build1 (VIEW_CONVERT_EXPR, method_return_type,
217
		 CALL_EXPR_ARG (orig_call, 0));
218 219
}

220 221


222 223 224 225 226 227 228 229 230 231 232 233 234
/* 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.

*/


235
/* Macros to unmarshal arguments from a CALL_EXPR into a few
236 237 238
   variables.  We also convert the offset arg from a long to an
   integer that is the same size as a pointer.  */

239
#define UNMARSHAL3(METHOD_CALL)					\
240 241 242
tree this_arg, obj_arg, offset_arg;					\
do									\
{									\
243 244 245
  tree orig_method_call = METHOD_CALL;					\
  this_arg = CALL_EXPR_ARG (orig_method_call, 0);			\
  obj_arg = CALL_EXPR_ARG (orig_method_call, 1);			\
246
  offset_arg = fold_convert (java_type_for_size (POINTER_SIZE, 0),	\
247
			     CALL_EXPR_ARG (orig_method_call, 2));	\
248 249 250
}									\
while (0)

251
#define UNMARSHAL4(METHOD_CALL)					\
252 253 254
tree value_type, this_arg, obj_arg, offset_arg, value_arg;		\
do									\
{									\
255 256 257
  tree orig_method_call = METHOD_CALL;					\
  this_arg = CALL_EXPR_ARG (orig_method_call, 0);			\
  obj_arg = CALL_EXPR_ARG (orig_method_call, 1);			\
258
  offset_arg = fold_convert (java_type_for_size (POINTER_SIZE, 0),	\
259 260
			     CALL_EXPR_ARG (orig_method_call, 2));	\
  value_arg = CALL_EXPR_ARG (orig_method_call, 3);			\
261 262 263 264
  value_type = TREE_TYPE (value_arg);					\
}									\
while (0)

265
#define UNMARSHAL5(METHOD_CALL)					\
266 267 268
tree value_type, this_arg, obj_arg, offset_arg, expected_arg, value_arg; \
do									\
{									\
269 270 271
  tree orig_method_call = METHOD_CALL;					\
  this_arg = CALL_EXPR_ARG (orig_method_call, 0);			\
  obj_arg = CALL_EXPR_ARG (orig_method_call, 1);			\
272
  offset_arg = fold_convert (java_type_for_size (POINTER_SIZE, 0),	\
273 274 275
			     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);			\
276 277 278 279 280 281 282 283 284 285
  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);
286
  return fold_build_pointer_plus (fold_convert (ptr_type, addr), offset);
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
}

/* 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, 
303
		   tree orig_call)
304 305
{
  tree addr, stmt;
306
  UNMARSHAL4 (orig_call);
307 308 309 310 311 312 313 314 315 316 317 318

  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,
319
			   tree orig_call)
320 321
{
  enum machine_mode mode = TYPE_MODE (int_type_node);
322
  if (can_compare_and_swap_p (mode, flag_use_atomic_builtins))
323
    {
324
      tree addr, stmt;
325
      enum built_in_function fncode = BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4;
326
      UNMARSHAL5 (orig_call);
327
      (void) value_type; /* Avoid set but not used warning.  */
328 329

      addr = build_addr_sum (int_type_node, obj_arg, offset_arg);
330 331
      stmt = build_call_expr (builtin_decl_explicit (fncode),
			      3, addr, expected_arg, value_arg);
332 333 334 335 336 337 338 339

      return build_check_this (stmt, this_arg);
    }
  return NULL_TREE;
}

static tree
compareAndSwapLong_builtin (tree method_return_type ATTRIBUTE_UNUSED,
340
			    tree orig_call)
341 342
{
  enum machine_mode mode = TYPE_MODE (long_type_node);
343 344 345 346 347 348
  /* 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)))
349
    {
350
      tree addr, stmt;
351
      enum built_in_function fncode = BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8;
352
      UNMARSHAL5 (orig_call);
353
      (void) value_type; /* Avoid set but not used warning.  */
354 355

      addr = build_addr_sum (long_type_node, obj_arg, offset_arg);
356 357
      stmt = build_call_expr (builtin_decl_explicit (fncode),
			      3, addr, expected_arg, value_arg);
358 359 360 361 362 363 364

      return build_check_this (stmt, this_arg);
    }
  return NULL_TREE;
}
static tree
compareAndSwapObject_builtin (tree method_return_type ATTRIBUTE_UNUSED, 
365
			      tree orig_call)
366 367
{
  enum machine_mode mode = TYPE_MODE (ptr_type_node);
368
  if (can_compare_and_swap_p (mode, flag_use_atomic_builtins))
369
  {
370
    tree addr, stmt;
371
    enum built_in_function builtin;
372

373
    UNMARSHAL5 (orig_call);
374
    builtin = (POINTER_SIZE == 32 
375 376
	       ? BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4 
	       : BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8);
377 378

    addr = build_addr_sum (value_type, obj_arg, offset_arg);
379
    stmt = build_call_expr (builtin_decl_explicit (builtin),
380
			    3, addr, expected_arg, value_arg);
381 382 383 384 385 386 387 388

    return build_check_this (stmt, this_arg);
  }
  return NULL_TREE;
}

static tree
putVolatile_builtin (tree method_return_type ATTRIBUTE_UNUSED, 
389
		     tree orig_call)
390
{
391 392
  tree addr, stmt, modify_stmt;
  UNMARSHAL4 (orig_call);
393 394 395 396 397 398
  
  addr = build_addr_sum (value_type, obj_arg, offset_arg);
  addr 
    = fold_convert (build_pointer_type (build_type_variant (value_type, 0, 1)),
		    addr);
  
399
  stmt = build_call_expr (builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE), 0);
400 401 402 403 404 405 406 407 408 409 410 411
  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, 
412
		     tree orig_call)
413
{
414 415
  tree addr, stmt, modify_stmt, tmp;
  UNMARSHAL3 (orig_call);
416 417
  (void) this_arg; /* Avoid set but not used warning.  */

418 419 420 421 422
  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);
  
423
  stmt = build_call_expr (builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE), 0);
424
  tmp = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL, method_return_type);
425 426 427 428 429 430 431 432 433 434 435 436 437 438
  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;
}
Andrew Haley committed
439 440 441

static tree
VMSupportsCS8_builtin (tree method_return_type, 
442
		       tree orig_call ATTRIBUTE_UNUSED)
Andrew Haley committed
443 444 445
{
  enum machine_mode mode = TYPE_MODE (long_type_node);
  gcc_assert (method_return_type == boolean_type_node);
446
  if (can_compare_and_swap_p (mode, false))
Andrew Haley committed
447 448 449 450 451
    return boolean_true_node;
  else
    return boolean_false_node;
}  

452 453


454 455
#define BUILTIN_NOTHROW 1
#define BUILTIN_CONST 2
456 457
/* Define a single builtin.  */
static void
458 459 460
define_builtin (enum built_in_function val,
		const char *name,
		tree type,
461 462
		const char *libname,
		int flags)
463 464 465
{
  tree decl;

466 467
  decl = build_decl (BUILTINS_LOCATION,
		     FUNCTION_DECL, get_identifier (name), type);
468 469
  DECL_EXTERNAL (decl) = 1;
  TREE_PUBLIC (decl) = 1;
470
  SET_DECL_ASSEMBLER_NAME (decl, get_identifier (libname));
471
  pushdecl (decl);
472
  DECL_BUILT_IN_CLASS (decl) = BUILT_IN_NORMAL;
473
  DECL_FUNCTION_CODE (decl) = val;
474 475 476 477
  if (flags & BUILTIN_NOTHROW)
    TREE_NOTHROW (decl) = 1;
  if (flags & BUILTIN_CONST)
    TREE_READONLY (decl) = 1;
478

479
  set_builtin_decl (val, decl, true);
480 481 482 483 484 485
}



/* Initialize the builtins.  */
void
486
initialize_builtins (void)
487
{
488
  tree double_ftype_double, double_ftype_double_double;
489
  tree float_ftype_float_float;
490
  tree boolean_ftype_boolean_boolean;
491 492
  int i;

493
  for (i = 0; java_builtins[i].builtin_code != END_BUILTINS; ++i)
494 495 496 497 498 499 500 501 502 503
    {
      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;

504 505 506
  float_ftype_float_float
    = build_function_type_list (float_type_node,
				float_type_node, float_type_node, NULL_TREE);
507

508 509 510 511 512
  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);
513 514

  define_builtin (BUILT_IN_FMOD, "__builtin_fmod",
515
		  double_ftype_double_double, "fmod", BUILTIN_CONST);
516
  define_builtin (BUILT_IN_FMODF, "__builtin_fmodf",
517
		  float_ftype_float_float, "fmodf", BUILTIN_CONST);
518

519
  define_builtin (BUILT_IN_ACOS, "__builtin_acos",
Terry Laurenzo committed
520
		  double_ftype_double, "_ZN4java4lang4Math4acosEJdd",
521
		  BUILTIN_CONST);
522
  define_builtin (BUILT_IN_ASIN, "__builtin_asin",
Terry Laurenzo committed
523
		  double_ftype_double, "_ZN4java4lang4Math4asinEJdd",
524
		  BUILTIN_CONST);
525
  define_builtin (BUILT_IN_ATAN, "__builtin_atan",
Terry Laurenzo committed
526
		  double_ftype_double, "_ZN4java4lang4Math4atanEJdd",
527
		  BUILTIN_CONST);
528
  define_builtin (BUILT_IN_ATAN2, "__builtin_atan2",
Terry Laurenzo committed
529
		  double_ftype_double_double, "_ZN4java4lang4Math5atan2EJddd",
530
		  BUILTIN_CONST);
531
  define_builtin (BUILT_IN_CEIL, "__builtin_ceil",
Terry Laurenzo committed
532
		  double_ftype_double, "_ZN4java4lang4Math4ceilEJdd",
533
		  BUILTIN_CONST);
534
  define_builtin (BUILT_IN_COS, "__builtin_cos",
Terry Laurenzo committed
535
		  double_ftype_double, "_ZN4java4lang4Math3cosEJdd",
536
		  BUILTIN_CONST);
537
  define_builtin (BUILT_IN_EXP, "__builtin_exp",
Terry Laurenzo committed
538
		  double_ftype_double, "_ZN4java4lang4Math3expEJdd",
539
		  BUILTIN_CONST);
540
  define_builtin (BUILT_IN_FLOOR, "__builtin_floor",
Terry Laurenzo committed
541
		  double_ftype_double, "_ZN4java4lang4Math5floorEJdd",
542
		  BUILTIN_CONST);
543
  define_builtin (BUILT_IN_LOG, "__builtin_log",
Terry Laurenzo committed
544
		  double_ftype_double, "_ZN4java4lang4Math3logEJdd",
545
		  BUILTIN_CONST);
546
  define_builtin (BUILT_IN_POW, "__builtin_pow",
Terry Laurenzo committed
547
		  double_ftype_double_double, "_ZN4java4lang4Math3powEJddd",
548
		  BUILTIN_CONST);
549
  define_builtin (BUILT_IN_SIN, "__builtin_sin",
Terry Laurenzo committed
550
		  double_ftype_double, "_ZN4java4lang4Math3sinEJdd",
551
		  BUILTIN_CONST);
552
  define_builtin (BUILT_IN_SQRT, "__builtin_sqrt",
Terry Laurenzo committed
553
		  double_ftype_double, "_ZN4java4lang4Math4sqrtEJdd",
554
		  BUILTIN_CONST);
555
  define_builtin (BUILT_IN_TAN, "__builtin_tan",
Terry Laurenzo committed
556
		  double_ftype_double, "_ZN4java4lang4Math3tanEJdd",
557
		  BUILTIN_CONST);
558
  
559 560 561 562
  boolean_ftype_boolean_boolean
    = build_function_type_list (boolean_type_node,
				boolean_type_node, boolean_type_node,
				NULL_TREE);
563 564
  define_builtin (BUILT_IN_EXPECT, "__builtin_expect", 
		  boolean_ftype_boolean_boolean,
565 566
		  "__builtin_expect",
		  BUILTIN_CONST | BUILTIN_NOTHROW);
567
  define_builtin (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4, 
568 569 570 571 572 573
		  "__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", 0);
574
  define_builtin (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8, 
575 576 577 578 579 580
		  "__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", 0);
581
  define_builtin (BUILT_IN_SYNC_SYNCHRONIZE, "__sync_synchronize",
582
		  build_function_type_list (void_type_node, NULL_TREE),
583
		  "__sync_synchronize", BUILTIN_NOTHROW);
584 585 586 587
  
  define_builtin (BUILT_IN_RETURN_ADDRESS, "__builtin_return_address",
		  build_function_type_list (ptr_type_node, int_type_node, NULL_TREE),
		  "__builtin_return_address", BUILTIN_NOTHROW);
588

589
  build_common_builtin_nodes ();
590 591
}

592
/* If the call matches a builtin, return the
593 594
   appropriate builtin expression instead.  */
tree
595
check_for_builtin (tree method, tree call)
596
{
597
  if (optimize && TREE_CODE (call) == CALL_EXPR)
598 599
    {
      int i;
600 601 602
      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));
603

604
      for (i = 0; java_builtins[i].builtin_code != END_BUILTINS; ++i)
605 606 607 608
	{
	  if (method_class == java_builtins[i].class_name.t
	      && method_name == java_builtins[i].method_name.t)
	    {
609 610 611
	      tree fn;

	      if (java_builtins[i].creator != NULL)
612 613
		{
		  tree result
614
		    = (*java_builtins[i].creator) (method_return_type, call);
615 616
		  return result == NULL_TREE ? call : result;
		}
617 618 619 620 621

	      /* Builtin functions emit a direct call which is incompatible
	         with the BC-ABI.  */
	      if (flag_indirect_dispatch)
	        return call;
622
	      fn = builtin_decl_explicit (java_builtins[i].builtin_code);
623
	      if (fn == NULL_TREE)
624
		return call;
625
	      return java_build_function_call_expr (fn, call);
626 627 628 629 630
	    }
	}
    }
  return call;
}
631 632

#include "gt-java-builtins.h"