builtins.c 20.7 KB
Newer Older
1
/* Built-in and inline functions for gcj
2
   Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2009
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 27 28

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

#include "config.h"
#include "system.h"
29 30
#include "coretypes.h"
#include "tm.h"
31 32 33
#include "tree.h"
#include "ggc.h"
#include "flags.h"
34
#include "langhooks.h"
35
#include "java-tree.h"
36 37 38 39 40 41
#include <stdarg.h>
#include "convert.h"
#include "rtl.h"
#include "insn-codes.h"
#include "expr.h"
#include "optabs.h"
42

43 44 45
static tree max_builtin (tree, tree);
static tree min_builtin (tree, tree);
static tree abs_builtin (tree, tree);
46
static tree convert_real (tree, tree);
47

48
static tree java_build_function_call_expr (tree, tree);
49

50 51 52 53 54 55
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
56
static tree VMSupportsCS8_builtin (tree, tree);
57 58 59 60 61


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

/* Hold a char*, before initialization, or a tree, after
   initialization.  */
68
union GTY(()) string_or_tree {
69 70
  const char * GTY ((tag ("0"))) s;
  tree GTY ((tag ("1"))) t;
71 72 73
};

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

81
static GTY(()) struct builtin_record java_builtins[] =
82
{
83 84 85
  { { "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 },
86 87
  { { "java.lang.Math" }, { "acos" }, NULL, BUILT_IN_ACOS },
  { { "java.lang.Math" }, { "asin" }, NULL, BUILT_IN_ASIN },
88 89
  { { "java.lang.Math" }, { "atan" }, NULL, BUILT_IN_ATAN },
  { { "java.lang.Math" }, { "atan2" }, NULL, BUILT_IN_ATAN2 },
90
  { { "java.lang.Math" }, { "ceil" }, NULL, BUILT_IN_CEIL },
91 92
  { { "java.lang.Math" }, { "cos" }, NULL, BUILT_IN_COS },
  { { "java.lang.Math" }, { "exp" }, NULL, BUILT_IN_EXP },
93
  { { "java.lang.Math" }, { "floor" }, NULL, BUILT_IN_FLOOR },
94 95 96 97 98
  { { "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 },
99 100 101 102 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
  { { "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},
140
  { { NULL }, { NULL }, NULL, END_BUILTINS }
141 142 143 144 145 146
};

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

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

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

static tree
169
abs_builtin (tree method_return_type, tree orig_call)
170
{
171
  return fold_build1 (ABS_EXPR, method_return_type,
172
		      CALL_EXPR_ARG (orig_call, 0));
173 174
}

175 176
/* Construct a new call to FN using the arguments from ORIG_CALL.  */

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

209
static tree
210
convert_real (tree method_return_type, tree orig_call)
211 212
{
  return build1 (VIEW_CONVERT_EXPR, method_return_type,
213
		 CALL_EXPR_ARG (orig_call, 0));
214 215
}

216 217


218 219 220 221 222 223 224 225 226 227 228 229 230
/* 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.

*/


231
/* Macros to unmarshal arguments from a CALL_EXPR into a few
232 233 234
   variables.  We also convert the offset arg from a long to an
   integer that is the same size as a pointer.  */

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

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

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

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

  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,
318
			   tree orig_call)
319 320
{
  enum machine_mode mode = TYPE_MODE (int_type_node);
321 322
  if (sync_compare_and_swap[mode] != CODE_FOR_nothing
      || flag_use_atomic_builtins)
323
    {
324 325
      tree addr, stmt;
      UNMARSHAL5 (orig_call);
326 327

      addr = build_addr_sum (int_type_node, obj_arg, offset_arg);
328 329
      stmt = build_call_expr (built_in_decls[BUILT_IN_BOOL_COMPARE_AND_SWAP_4],
			      3, addr, expected_arg, value_arg);
330 331 332 333 334 335 336 337

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

static tree
compareAndSwapLong_builtin (tree method_return_type ATTRIBUTE_UNUSED,
338
			    tree orig_call)
339 340
{
  enum machine_mode mode = TYPE_MODE (long_type_node);
341 342 343 344 345 346
  if (sync_compare_and_swap[mode] != CODE_FOR_nothing
      || (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (word_mode)
	  && flag_use_atomic_builtins))
    /* 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.  */
347
    {
348 349
      tree addr, stmt;
      UNMARSHAL5 (orig_call);
350 351

      addr = build_addr_sum (long_type_node, obj_arg, offset_arg);
352 353
      stmt = build_call_expr (built_in_decls[BUILT_IN_BOOL_COMPARE_AND_SWAP_8],
			      3, addr, expected_arg, value_arg);
354 355 356 357 358 359 360

      return build_check_this (stmt, this_arg);
    }
  return NULL_TREE;
}
static tree
compareAndSwapObject_builtin (tree method_return_type ATTRIBUTE_UNUSED, 
361
			      tree orig_call)
362 363
{
  enum machine_mode mode = TYPE_MODE (ptr_type_node);
364 365
  if (sync_compare_and_swap[mode] != CODE_FOR_nothing
      || flag_use_atomic_builtins)
366
  {
367
    tree addr, stmt;
368 369
    int builtin;

370
    UNMARSHAL5 (orig_call);
371 372 373 374 375
    builtin = (POINTER_SIZE == 32 
	       ? BUILT_IN_BOOL_COMPARE_AND_SWAP_4 
	       : BUILT_IN_BOOL_COMPARE_AND_SWAP_8);

    addr = build_addr_sum (value_type, obj_arg, offset_arg);
376 377
    stmt = build_call_expr (built_in_decls[builtin],
			    3, addr, expected_arg, value_arg);
378 379 380 381 382 383 384 385

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

static tree
putVolatile_builtin (tree method_return_type ATTRIBUTE_UNUSED, 
386
		     tree orig_call)
387
{
388 389
  tree addr, stmt, modify_stmt;
  UNMARSHAL4 (orig_call);
390 391 392 393 394 395
  
  addr = build_addr_sum (value_type, obj_arg, offset_arg);
  addr 
    = fold_convert (build_pointer_type (build_type_variant (value_type, 0, 1)),
		    addr);
  
396
  stmt = build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0);
397 398 399 400 401 402 403 404 405 406 407 408
  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, 
409
		     tree orig_call)
410
{
411 412
  tree addr, stmt, modify_stmt, tmp;
  UNMARSHAL3 (orig_call);
413 414 415 416 417 418
  
  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);
  
419
  stmt = build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0);
420
  
421
  tmp = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL, method_return_type);
422 423 424 425 426 427 428 429 430 431 432 433 434 435
  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
436 437 438

static tree
VMSupportsCS8_builtin (tree method_return_type, 
439
		       tree orig_call ATTRIBUTE_UNUSED)
Andrew Haley committed
440 441 442
{
  enum machine_mode mode = TYPE_MODE (long_type_node);
  gcc_assert (method_return_type == boolean_type_node);
Paolo Bonzini committed
443
  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
Andrew Haley committed
444 445 446 447 448
    return boolean_true_node;
  else
    return boolean_false_node;
}  

449 450


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

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

476 477
  implicit_built_in_decls[val] = decl;
  built_in_decls[val] = decl;
478 479 480 481 482 483
}



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

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

503 504 505 506 507 508 509 510 511 512
  t = tree_cons (NULL_TREE, float_type_node, end_params_node);
  t = tree_cons (NULL_TREE, float_type_node, t);
  float_ftype_float_float = build_function_type (float_type_node, t);

  t = tree_cons (NULL_TREE, double_type_node, end_params_node);
  double_ftype_double = build_function_type (double_type_node, t);
  t = tree_cons (NULL_TREE, double_type_node, t);
  double_ftype_double_double = build_function_type (double_type_node, t);

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

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

586
  build_common_builtin_nodes ();
587 588
}

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

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

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

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

#include "gt-java-builtins.h"