builtins.c 20.9 KB
Newer Older
1
/* Built-in and inline functions for gcj
Jakub Jelinek committed
2
   Copyright (C) 2001-2015 Free Software Foundation, Inc.
3

4
This file is part of GCC.
5

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

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

16 17 18
.

.  
19 20 21 22 23 24 25

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

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

29 30
#include "config.h"
#include "system.h"
31 32
#include "coretypes.h"
#include "tm.h"
33
#include "rtl.h"
34
#include "tree.h"
35 36 37
#include "stringpool.h"
#include "expmed.h"
#include "optabs.h"
38
#include "fold-const.h"
39
#include "stor-layout.h"
40
#include "java-tree.h"
41 42 43

/* FIXME: All these headers are necessary for sync_compare_and_swap.
   Front ends should never have to look at that.  */
44

45 46 47
static tree max_builtin (tree, tree);
static tree min_builtin (tree, tree);
static tree abs_builtin (tree, tree);
48
static tree convert_real (tree, tree);
49

50
static tree java_build_function_call_expr (tree, tree);
51

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

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

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

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

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

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

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

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

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

177 178
/* Construct a new call to FN using the arguments from ORIG_CALL.  */

179
static tree
180
java_build_function_call_expr (tree fn, tree orig_call)
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 207 208
  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)));
      }
    }
209 210
}

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

218 219


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

*/


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

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

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

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

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

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

      addr = build_addr_sum (int_type_node, obj_arg, offset_arg);
328 329
      stmt = build_call_expr (builtin_decl_explicit (fncode),
			      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
  machine_mode mode = TYPE_MODE (long_type_node);
341 342 343 344 345 346
  /* 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)))
347
    {
348
      tree addr, stmt;
349
      enum built_in_function fncode = BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8;
350
      UNMARSHAL5 (orig_call);
351
      (void) value_type; /* Avoid set but not used warning.  */
352 353

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

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

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

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

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

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

417 418
  addr = build_addr_sum (method_return_type, obj_arg, offset_arg);
  addr 
419 420 421
    = fold_convert (build_pointer_type (build_qualified_type
					(method_return_type,
					 TYPE_QUAL_VOLATILE)), addr);
422
  
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
  machine_mode mode = TYPE_MODE (long_type_node);
Andrew Haley committed
445
  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 a single builtin.  */
static void
456 457 458
define_builtin (enum built_in_function val,
		const char *name,
		tree type,
459 460
		const char *libname,
		int flags)
461 462 463
{
  tree decl;

464 465
  decl = build_decl (BUILTINS_LOCATION,
		     FUNCTION_DECL, get_identifier (name), type);
466 467
  DECL_EXTERNAL (decl) = 1;
  TREE_PUBLIC (decl) = 1;
468
  SET_DECL_ASSEMBLER_NAME (decl, get_identifier (libname));
469
  pushdecl (decl);
470
  DECL_BUILT_IN_CLASS (decl) = BUILT_IN_NORMAL;
471
  DECL_FUNCTION_CODE (decl) = val;
472
  set_call_expr_flags (decl, flags);
473

474
  set_builtin_decl (val, decl, true);
475 476 477 478 479 480
}



/* Initialize the builtins.  */
void
481
initialize_builtins (void)
482
{
483
  tree double_ftype_double, double_ftype_double_double;
484
  tree float_ftype_float_float;
485
  tree boolean_ftype_boolean_boolean;
486 487
  int i;

488
  for (i = 0; java_builtins[i].builtin_code != END_BUILTINS; ++i)
489 490 491 492 493 494 495 496 497 498
    {
      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;

499 500 501
  float_ftype_float_float
    = build_function_type_list (float_type_node,
				float_type_node, float_type_node, NULL_TREE);
502

503 504 505 506 507
  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);
508 509

  define_builtin (BUILT_IN_FMOD, "__builtin_fmod",
510
		  double_ftype_double_double, "fmod", ECF_CONST);
511
  define_builtin (BUILT_IN_FMODF, "__builtin_fmodf",
512
		  float_ftype_float_float, "fmodf", ECF_CONST);
513

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