]>
Commit | Line | Data |
---|---|---|
fcffb974 | 1 | /* Built-in and inline functions for gcj |
f1717362 | 2 | Copyright (C) 2001-2016 Free Software Foundation, Inc. |
fcffb974 | 3 | |
7d82ed5e | 4 | This file is part of GCC. |
fcffb974 | 5 | |
7d82ed5e | 6 | GCC is free software; you can redistribute it and/or modify |
fcffb974 | 7 | it under the terms of the GNU General Public License as published by |
e4b52719 | 8 | the Free Software Foundation; either version 3, or (at your option) |
fcffb974 | 9 | any later version. |
10 | ||
7d82ed5e | 11 | GCC is distributed in the hope that it will be useful, |
fcffb974 | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
e4b52719 | 16 | . |
17 | ||
18 | . | |
fcffb974 | 19 | |
20 | Java and all Java-based marks are trademarks or registered trademarks | |
21 | of Sun Microsystems, Inc. in the United States and other countries. | |
22 | The Free Software Foundation is independent of Sun Microsystems, Inc. */ | |
23 | ||
24 | /* Written by Tom Tromey <tromey@redhat.com>. */ | |
25 | ||
141acd01 | 26 | /* FIXME: Still need to include rtl.h here (see below). */ |
27 | #undef IN_GCC_FRONTEND | |
28 | ||
fcffb974 | 29 | #include "config.h" |
30 | #include "system.h" | |
805e22b2 | 31 | #include "coretypes.h" |
32 | #include "tm.h" | |
4cba6f60 | 33 | #include "rtl.h" |
fcffb974 | 34 | #include "tree.h" |
4cba6f60 | 35 | #include "stringpool.h" |
36 | #include "expmed.h" | |
37 | #include "optabs.h" | |
b20a8bb4 | 38 | #include "fold-const.h" |
9ed99284 | 39 | #include "stor-layout.h" |
fcffb974 | 40 | #include "java-tree.h" |
3484143b | 41 | |
42 | /* FIXME: All these headers are necessary for sync_compare_and_swap. | |
43 | Front ends should never have to look at that. */ | |
fcffb974 | 44 | |
6852521a | 45 | static tree max_builtin (tree, tree); |
46 | static tree min_builtin (tree, tree); | |
47 | static tree abs_builtin (tree, tree); | |
1ec490b9 | 48 | static tree convert_real (tree, tree); |
fcffb974 | 49 | |
a0d2d33f | 50 | static tree java_build_function_call_expr (tree, tree); |
fcffb974 | 51 | |
65bf3316 | 52 | static tree putObject_builtin (tree, tree); |
53 | static tree compareAndSwapInt_builtin (tree, tree); | |
54 | static tree compareAndSwapLong_builtin (tree, tree); | |
55 | static tree compareAndSwapObject_builtin (tree, tree); | |
56 | static tree putVolatile_builtin (tree, tree); | |
57 | static tree getVolatile_builtin (tree, tree); | |
751d3443 | 58 | static tree VMSupportsCS8_builtin (tree, tree); |
fcffb974 | 59 | \f |
60 | ||
61 | /* Functions of this type are used to inline a given call. Such a | |
62 | function should either return an expression, if the call is to be | |
63 | inlined, or NULL_TREE if a real call should be emitted. Arguments | |
c2f47e15 | 64 | are method return type and the original CALL_EXPR containing the |
65 | arguments to the call. */ | |
228ea8f0 | 66 | typedef tree builtin_creator_function (tree, tree); |
fcffb974 | 67 | |
68 | /* Hold a char*, before initialization, or a tree, after | |
69 | initialization. */ | |
fb1e4f4a | 70 | union GTY(()) string_or_tree { |
1f3233d1 | 71 | const char * GTY ((tag ("0"))) s; |
72 | tree GTY ((tag ("1"))) t; | |
fcffb974 | 73 | }; |
74 | ||
75 | /* Used to hold a single builtin record. */ | |
fb1e4f4a | 76 | struct GTY(()) builtin_record { |
1f3233d1 | 77 | union string_or_tree GTY ((desc ("1"))) class_name; |
78 | union string_or_tree GTY ((desc ("1"))) method_name; | |
7035b2ab | 79 | builtin_creator_function * GTY((skip)) creator; |
1799e0bd | 80 | enum built_in_function builtin_code; |
fcffb974 | 81 | }; |
82 | ||
1f3233d1 | 83 | static GTY(()) struct builtin_record java_builtins[] = |
fcffb974 | 84 | { |
bc620c5c | 85 | { { "java.lang.Math" }, { "min" }, min_builtin, (enum built_in_function) 0 }, |
86 | { { "java.lang.Math" }, { "max" }, max_builtin, (enum built_in_function) 0 }, | |
87 | { { "java.lang.Math" }, { "abs" }, abs_builtin, (enum built_in_function) 0 }, | |
91da6229 | 88 | { { "java.lang.Math" }, { "acos" }, NULL, BUILT_IN_ACOS }, |
89 | { { "java.lang.Math" }, { "asin" }, NULL, BUILT_IN_ASIN }, | |
1799e0bd | 90 | { { "java.lang.Math" }, { "atan" }, NULL, BUILT_IN_ATAN }, |
91 | { { "java.lang.Math" }, { "atan2" }, NULL, BUILT_IN_ATAN2 }, | |
91da6229 | 92 | { { "java.lang.Math" }, { "ceil" }, NULL, BUILT_IN_CEIL }, |
1799e0bd | 93 | { { "java.lang.Math" }, { "cos" }, NULL, BUILT_IN_COS }, |
94 | { { "java.lang.Math" }, { "exp" }, NULL, BUILT_IN_EXP }, | |
91da6229 | 95 | { { "java.lang.Math" }, { "floor" }, NULL, BUILT_IN_FLOOR }, |
1799e0bd | 96 | { { "java.lang.Math" }, { "log" }, NULL, BUILT_IN_LOG }, |
97 | { { "java.lang.Math" }, { "pow" }, NULL, BUILT_IN_POW }, | |
98 | { { "java.lang.Math" }, { "sin" }, NULL, BUILT_IN_SIN }, | |
99 | { { "java.lang.Math" }, { "sqrt" }, NULL, BUILT_IN_SQRT }, | |
100 | { { "java.lang.Math" }, { "tan" }, NULL, BUILT_IN_TAN }, | |
bc620c5c | 101 | { { "java.lang.Float" }, { "intBitsToFloat" }, convert_real, |
102 | (enum built_in_function) 0 }, | |
103 | { { "java.lang.Double" }, { "longBitsToDouble" }, convert_real, | |
104 | (enum built_in_function) 0 }, | |
105 | { { "java.lang.Float" }, { "floatToRawIntBits" }, convert_real, | |
106 | (enum built_in_function) 0 }, | |
107 | { { "java.lang.Double" }, { "doubleToRawLongBits" }, convert_real, | |
108 | (enum built_in_function) 0 }, | |
109 | { { "sun.misc.Unsafe" }, { "putInt" }, putObject_builtin, | |
110 | (enum built_in_function) 0}, | |
111 | { { "sun.misc.Unsafe" }, { "putLong" }, putObject_builtin, | |
112 | (enum built_in_function) 0}, | |
113 | { { "sun.misc.Unsafe" }, { "putObject" }, putObject_builtin, | |
114 | (enum built_in_function) 0}, | |
115 | { { "sun.misc.Unsafe" }, { "compareAndSwapInt" }, | |
116 | compareAndSwapInt_builtin, (enum built_in_function) 0}, | |
117 | { { "sun.misc.Unsafe" }, { "compareAndSwapLong" }, | |
118 | compareAndSwapLong_builtin, (enum built_in_function) 0}, | |
119 | { { "sun.misc.Unsafe" }, { "compareAndSwapObject" }, | |
120 | compareAndSwapObject_builtin, (enum built_in_function) 0}, | |
121 | { { "sun.misc.Unsafe" }, { "putOrderedInt" }, putVolatile_builtin, | |
122 | (enum built_in_function) 0}, | |
123 | { { "sun.misc.Unsafe" }, { "putOrderedLong" }, putVolatile_builtin, | |
124 | (enum built_in_function) 0}, | |
125 | { { "sun.misc.Unsafe" }, { "putOrderedObject" }, putVolatile_builtin, | |
126 | (enum built_in_function) 0}, | |
127 | { { "sun.misc.Unsafe" }, { "putIntVolatile" }, putVolatile_builtin, | |
128 | (enum built_in_function) 0}, | |
129 | { { "sun.misc.Unsafe" }, { "putLongVolatile" }, putVolatile_builtin, | |
130 | (enum built_in_function) 0}, | |
131 | { { "sun.misc.Unsafe" }, { "putObjectVolatile" }, putVolatile_builtin, | |
132 | (enum built_in_function) 0}, | |
133 | { { "sun.misc.Unsafe" }, { "getObjectVolatile" }, getVolatile_builtin, | |
134 | (enum built_in_function) 0}, | |
135 | { { "sun.misc.Unsafe" }, { "getIntVolatile" }, getVolatile_builtin, | |
136 | (enum built_in_function) 0}, | |
137 | { { "sun.misc.Unsafe" }, { "getLongVolatile" }, getVolatile_builtin, (enum built_in_function) 0}, | |
138 | { { "sun.misc.Unsafe" }, { "getLong" }, getVolatile_builtin, | |
139 | (enum built_in_function) 0}, | |
140 | { { "java.util.concurrent.atomic.AtomicLong" }, { "VMSupportsCS8" }, | |
141 | VMSupportsCS8_builtin, (enum built_in_function) 0}, | |
1799e0bd | 142 | { { NULL }, { NULL }, NULL, END_BUILTINS } |
fcffb974 | 143 | }; |
144 | ||
fcffb974 | 145 | \f |
146 | /* Internal functions which implement various builtin conversions. */ | |
147 | ||
148 | static tree | |
c2f47e15 | 149 | max_builtin (tree method_return_type, tree orig_call) |
fcffb974 | 150 | { |
e60fa8e9 | 151 | /* MAX_EXPR does not handle -0.0 in the Java style. */ |
152 | if (TREE_CODE (method_return_type) == REAL_TYPE) | |
153 | return NULL_TREE; | |
7662002a | 154 | return fold_build2 (MAX_EXPR, method_return_type, |
c2f47e15 | 155 | CALL_EXPR_ARG (orig_call, 0), |
156 | CALL_EXPR_ARG (orig_call, 1)); | |
fcffb974 | 157 | } |
158 | ||
159 | static tree | |
c2f47e15 | 160 | min_builtin (tree method_return_type, tree orig_call) |
fcffb974 | 161 | { |
e60fa8e9 | 162 | /* MIN_EXPR does not handle -0.0 in the Java style. */ |
163 | if (TREE_CODE (method_return_type) == REAL_TYPE) | |
164 | return NULL_TREE; | |
7662002a | 165 | return fold_build2 (MIN_EXPR, method_return_type, |
c2f47e15 | 166 | CALL_EXPR_ARG (orig_call, 0), |
167 | CALL_EXPR_ARG (orig_call, 1)); | |
fcffb974 | 168 | } |
169 | ||
170 | static tree | |
c2f47e15 | 171 | abs_builtin (tree method_return_type, tree orig_call) |
fcffb974 | 172 | { |
7662002a | 173 | return fold_build1 (ABS_EXPR, method_return_type, |
c2f47e15 | 174 | CALL_EXPR_ARG (orig_call, 0)); |
fcffb974 | 175 | } |
176 | ||
c2f47e15 | 177 | /* Construct a new call to FN using the arguments from ORIG_CALL. */ |
178 | ||
fcffb974 | 179 | static tree |
c2f47e15 | 180 | java_build_function_call_expr (tree fn, tree orig_call) |
fcffb974 | 181 | { |
c2f47e15 | 182 | int nargs = call_expr_nargs (orig_call); |
183 | switch (nargs) | |
184 | { | |
185 | /* Although we could handle the 0-3 argument cases using the general | |
186 | logic in the default case, splitting them out permits folding to | |
187 | be performed without constructing a temporary CALL_EXPR. */ | |
188 | case 0: | |
189 | return build_call_expr (fn, 0); | |
190 | case 1: | |
191 | return build_call_expr (fn, 1, CALL_EXPR_ARG (orig_call, 0)); | |
192 | case 2: | |
193 | return build_call_expr (fn, 2, | |
194 | CALL_EXPR_ARG (orig_call, 0), | |
195 | CALL_EXPR_ARG (orig_call, 1)); | |
196 | case 3: | |
197 | return build_call_expr (fn, 3, | |
198 | CALL_EXPR_ARG (orig_call, 0), | |
199 | CALL_EXPR_ARG (orig_call, 1), | |
200 | CALL_EXPR_ARG (orig_call, 2)); | |
201 | default: | |
202 | { | |
203 | tree fntype = TREE_TYPE (fn); | |
204 | fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fn); | |
205 | return fold (build_call_array (TREE_TYPE (fntype), | |
206 | fn, nargs, CALL_EXPR_ARGP (orig_call))); | |
207 | } | |
208 | } | |
fcffb974 | 209 | } |
210 | ||
1ec490b9 | 211 | static tree |
c2f47e15 | 212 | convert_real (tree method_return_type, tree orig_call) |
1ec490b9 | 213 | { |
214 | return build1 (VIEW_CONVERT_EXPR, method_return_type, | |
c2f47e15 | 215 | CALL_EXPR_ARG (orig_call, 0)); |
1ec490b9 | 216 | } |
217 | ||
fcffb974 | 218 | \f |
219 | ||
65bf3316 | 220 | /* Provide builtin support for atomic operations. These are |
221 | documented at length in libjava/sun/misc/Unsafe.java. */ | |
222 | ||
223 | /* FIXME. There are still a few things wrong with this logic. In | |
224 | particular, atomic writes of multi-word integers are not truly | |
225 | atomic: this requires more work. | |
226 | ||
227 | In general, double-word compare-and-swap cannot portably be | |
228 | implemented, so we need some kind of fallback for 32-bit machines. | |
229 | ||
230 | */ | |
231 | ||
232 | ||
c2f47e15 | 233 | /* Macros to unmarshal arguments from a CALL_EXPR into a few |
65bf3316 | 234 | variables. We also convert the offset arg from a long to an |
235 | integer that is the same size as a pointer. */ | |
236 | ||
c2f47e15 | 237 | #define UNMARSHAL3(METHOD_CALL) \ |
65bf3316 | 238 | tree this_arg, obj_arg, offset_arg; \ |
239 | do \ | |
240 | { \ | |
c2f47e15 | 241 | tree orig_method_call = METHOD_CALL; \ |
242 | this_arg = CALL_EXPR_ARG (orig_method_call, 0); \ | |
243 | obj_arg = CALL_EXPR_ARG (orig_method_call, 1); \ | |
65bf3316 | 244 | offset_arg = fold_convert (java_type_for_size (POINTER_SIZE, 0), \ |
c2f47e15 | 245 | CALL_EXPR_ARG (orig_method_call, 2)); \ |
65bf3316 | 246 | } \ |
247 | while (0) | |
248 | ||
c2f47e15 | 249 | #define UNMARSHAL4(METHOD_CALL) \ |
65bf3316 | 250 | tree value_type, this_arg, obj_arg, offset_arg, value_arg; \ |
251 | do \ | |
252 | { \ | |
c2f47e15 | 253 | tree orig_method_call = METHOD_CALL; \ |
254 | this_arg = CALL_EXPR_ARG (orig_method_call, 0); \ | |
255 | obj_arg = CALL_EXPR_ARG (orig_method_call, 1); \ | |
65bf3316 | 256 | offset_arg = fold_convert (java_type_for_size (POINTER_SIZE, 0), \ |
c2f47e15 | 257 | CALL_EXPR_ARG (orig_method_call, 2)); \ |
258 | value_arg = CALL_EXPR_ARG (orig_method_call, 3); \ | |
65bf3316 | 259 | value_type = TREE_TYPE (value_arg); \ |
260 | } \ | |
261 | while (0) | |
262 | ||
c2f47e15 | 263 | #define UNMARSHAL5(METHOD_CALL) \ |
65bf3316 | 264 | tree value_type, this_arg, obj_arg, offset_arg, expected_arg, value_arg; \ |
265 | do \ | |
266 | { \ | |
c2f47e15 | 267 | tree orig_method_call = METHOD_CALL; \ |
268 | this_arg = CALL_EXPR_ARG (orig_method_call, 0); \ | |
269 | obj_arg = CALL_EXPR_ARG (orig_method_call, 1); \ | |
65bf3316 | 270 | offset_arg = fold_convert (java_type_for_size (POINTER_SIZE, 0), \ |
c2f47e15 | 271 | CALL_EXPR_ARG (orig_method_call, 2)); \ |
272 | expected_arg = CALL_EXPR_ARG (orig_method_call, 3); \ | |
273 | value_arg = CALL_EXPR_ARG (orig_method_call, 4); \ | |
65bf3316 | 274 | value_type = TREE_TYPE (value_arg); \ |
275 | } \ | |
276 | while (0) | |
277 | ||
65bf3316 | 278 | /* Add an address to an offset, forming a sum. */ |
279 | ||
280 | static tree | |
281 | build_addr_sum (tree type, tree addr, tree offset) | |
282 | { | |
283 | tree ptr_type = build_pointer_type (type); | |
2cc66f2a | 284 | return fold_build_pointer_plus (fold_convert (ptr_type, addr), offset); |
65bf3316 | 285 | } |
286 | ||
287 | /* Make sure that this-arg is non-NULL. This is a security check. */ | |
288 | ||
289 | static tree | |
290 | build_check_this (tree stmt, tree this_arg) | |
291 | { | |
292 | return build2 (COMPOUND_EXPR, TREE_TYPE (stmt), | |
293 | java_check_reference (this_arg, 1), stmt); | |
294 | } | |
295 | ||
296 | /* Now the builtins. These correspond to the primitive functions in | |
297 | libjava/sun/misc/natUnsafe.cc. */ | |
298 | ||
299 | static tree | |
300 | putObject_builtin (tree method_return_type ATTRIBUTE_UNUSED, | |
c2f47e15 | 301 | tree orig_call) |
65bf3316 | 302 | { |
303 | tree addr, stmt; | |
c2f47e15 | 304 | UNMARSHAL4 (orig_call); |
65bf3316 | 305 | |
306 | addr = build_addr_sum (value_type, obj_arg, offset_arg); | |
307 | stmt = fold_build2 (MODIFY_EXPR, value_type, | |
308 | build_java_indirect_ref (value_type, addr, | |
309 | flag_check_references), | |
310 | value_arg); | |
311 | ||
312 | return build_check_this (stmt, this_arg); | |
313 | } | |
314 | ||
315 | static tree | |
316 | compareAndSwapInt_builtin (tree method_return_type ATTRIBUTE_UNUSED, | |
c2f47e15 | 317 | tree orig_call) |
65bf3316 | 318 | { |
3754d046 | 319 | machine_mode mode = TYPE_MODE (int_type_node); |
29139cdc | 320 | if (can_compare_and_swap_p (mode, flag_use_atomic_builtins)) |
65bf3316 | 321 | { |
c2f47e15 | 322 | tree addr, stmt; |
b9a16870 | 323 | enum built_in_function fncode = BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4; |
c2f47e15 | 324 | UNMARSHAL5 (orig_call); |
4081d362 | 325 | (void) value_type; /* Avoid set but not used warning. */ |
65bf3316 | 326 | |
327 | addr = build_addr_sum (int_type_node, obj_arg, offset_arg); | |
b9a16870 | 328 | stmt = build_call_expr (builtin_decl_explicit (fncode), |
329 | 3, addr, expected_arg, value_arg); | |
65bf3316 | 330 | |
331 | return build_check_this (stmt, this_arg); | |
332 | } | |
333 | return NULL_TREE; | |
334 | } | |
335 | ||
336 | static tree | |
337 | compareAndSwapLong_builtin (tree method_return_type ATTRIBUTE_UNUSED, | |
c2f47e15 | 338 | tree orig_call) |
65bf3316 | 339 | { |
3754d046 | 340 | machine_mode mode = TYPE_MODE (long_type_node); |
29139cdc | 341 | /* We don't trust flag_use_atomic_builtins for multi-word compareAndSwap. |
342 | Some machines such as ARM have atomic libfuncs but not the multi-word | |
343 | versions. */ | |
344 | if (can_compare_and_swap_p (mode, | |
345 | (flag_use_atomic_builtins | |
346 | && GET_MODE_SIZE (mode) <= UNITS_PER_WORD))) | |
65bf3316 | 347 | { |
c2f47e15 | 348 | tree addr, stmt; |
b9a16870 | 349 | enum built_in_function fncode = BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8; |
c2f47e15 | 350 | UNMARSHAL5 (orig_call); |
4081d362 | 351 | (void) value_type; /* Avoid set but not used warning. */ |
65bf3316 | 352 | |
353 | addr = build_addr_sum (long_type_node, obj_arg, offset_arg); | |
b9a16870 | 354 | stmt = build_call_expr (builtin_decl_explicit (fncode), |
355 | 3, addr, expected_arg, value_arg); | |
65bf3316 | 356 | |
357 | return build_check_this (stmt, this_arg); | |
358 | } | |
359 | return NULL_TREE; | |
360 | } | |
361 | static tree | |
362 | compareAndSwapObject_builtin (tree method_return_type ATTRIBUTE_UNUSED, | |
c2f47e15 | 363 | tree orig_call) |
65bf3316 | 364 | { |
3754d046 | 365 | machine_mode mode = TYPE_MODE (ptr_type_node); |
29139cdc | 366 | if (can_compare_and_swap_p (mode, flag_use_atomic_builtins)) |
65bf3316 | 367 | { |
c2f47e15 | 368 | tree addr, stmt; |
b9a16870 | 369 | enum built_in_function builtin; |
65bf3316 | 370 | |
c2f47e15 | 371 | UNMARSHAL5 (orig_call); |
65bf3316 | 372 | builtin = (POINTER_SIZE == 32 |
2797f13a | 373 | ? BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4 |
374 | : BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8); | |
65bf3316 | 375 | |
376 | addr = build_addr_sum (value_type, obj_arg, offset_arg); | |
b9a16870 | 377 | stmt = build_call_expr (builtin_decl_explicit (builtin), |
c2f47e15 | 378 | 3, addr, expected_arg, value_arg); |
65bf3316 | 379 | |
380 | return build_check_this (stmt, this_arg); | |
381 | } | |
382 | return NULL_TREE; | |
383 | } | |
384 | ||
385 | static tree | |
386 | putVolatile_builtin (tree method_return_type ATTRIBUTE_UNUSED, | |
c2f47e15 | 387 | tree orig_call) |
65bf3316 | 388 | { |
c2f47e15 | 389 | tree addr, stmt, modify_stmt; |
390 | UNMARSHAL4 (orig_call); | |
65bf3316 | 391 | |
392 | addr = build_addr_sum (value_type, obj_arg, offset_arg); | |
393 | addr | |
661a9b00 | 394 | = fold_convert (build_pointer_type (build_qualified_type |
395 | (value_type, TYPE_QUAL_VOLATILE)), | |
65bf3316 | 396 | addr); |
397 | ||
b9a16870 | 398 | stmt = build_call_expr (builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE), 0); |
65bf3316 | 399 | modify_stmt = fold_build2 (MODIFY_EXPR, value_type, |
400 | build_java_indirect_ref (value_type, addr, | |
401 | flag_check_references), | |
402 | value_arg); | |
403 | stmt = build2 (COMPOUND_EXPR, TREE_TYPE (modify_stmt), | |
404 | stmt, modify_stmt); | |
405 | ||
406 | return build_check_this (stmt, this_arg); | |
407 | } | |
408 | ||
409 | static tree | |
410 | getVolatile_builtin (tree method_return_type ATTRIBUTE_UNUSED, | |
c2f47e15 | 411 | tree orig_call) |
65bf3316 | 412 | { |
c2f47e15 | 413 | tree addr, stmt, modify_stmt, tmp; |
414 | UNMARSHAL3 (orig_call); | |
4081d362 | 415 | (void) this_arg; /* Avoid set but not used warning. */ |
416 | ||
65bf3316 | 417 | addr = build_addr_sum (method_return_type, obj_arg, offset_arg); |
418 | addr | |
661a9b00 | 419 | = fold_convert (build_pointer_type (build_qualified_type |
420 | (method_return_type, | |
421 | TYPE_QUAL_VOLATILE)), addr); | |
65bf3316 | 422 | |
b9a16870 | 423 | stmt = build_call_expr (builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE), 0); |
e60a6f7b | 424 | tmp = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL, method_return_type); |
65bf3316 | 425 | DECL_IGNORED_P (tmp) = 1; |
426 | DECL_ARTIFICIAL (tmp) = 1; | |
427 | pushdecl (tmp); | |
428 | ||
429 | modify_stmt = fold_build2 (MODIFY_EXPR, method_return_type, | |
430 | tmp, | |
431 | build_java_indirect_ref (method_return_type, addr, | |
432 | flag_check_references)); | |
433 | ||
434 | stmt = build2 (COMPOUND_EXPR, void_type_node, modify_stmt, stmt); | |
435 | stmt = build2 (COMPOUND_EXPR, method_return_type, stmt, tmp); | |
436 | ||
437 | return stmt; | |
438 | } | |
751d3443 | 439 | |
440 | static tree | |
441 | VMSupportsCS8_builtin (tree method_return_type, | |
c2f47e15 | 442 | tree orig_call ATTRIBUTE_UNUSED) |
751d3443 | 443 | { |
3754d046 | 444 | machine_mode mode = TYPE_MODE (long_type_node); |
751d3443 | 445 | gcc_assert (method_return_type == boolean_type_node); |
29139cdc | 446 | if (can_compare_and_swap_p (mode, false)) |
751d3443 | 447 | return boolean_true_node; |
448 | else | |
449 | return boolean_false_node; | |
450 | } | |
451 | ||
65bf3316 | 452 | \f |
453 | ||
fcffb974 | 454 | /* Define a single builtin. */ |
455 | static void | |
2883a3ed | 456 | define_builtin (enum built_in_function val, |
457 | const char *name, | |
2883a3ed | 458 | tree type, |
a89ea5ec | 459 | const char *libname, |
460 | int flags) | |
fcffb974 | 461 | { |
462 | tree decl; | |
463 | ||
e60a6f7b | 464 | decl = build_decl (BUILTINS_LOCATION, |
465 | FUNCTION_DECL, get_identifier (name), type); | |
fcffb974 | 466 | DECL_EXTERNAL (decl) = 1; |
467 | TREE_PUBLIC (decl) = 1; | |
f1e69817 | 468 | SET_DECL_ASSEMBLER_NAME (decl, get_identifier (libname)); |
fcffb974 | 469 | pushdecl (decl); |
f1e69817 | 470 | DECL_BUILT_IN_CLASS (decl) = BUILT_IN_NORMAL; |
fcffb974 | 471 | DECL_FUNCTION_CODE (decl) = val; |
2d68d2ef | 472 | set_call_expr_flags (decl, flags); |
fcffb974 | 473 | |
b9a16870 | 474 | set_builtin_decl (val, decl, true); |
fcffb974 | 475 | } |
476 | ||
477 | \f | |
478 | ||
479 | /* Initialize the builtins. */ | |
480 | void | |
2883a3ed | 481 | initialize_builtins (void) |
fcffb974 | 482 | { |
f1e69817 | 483 | tree double_ftype_double, double_ftype_double_double; |
ff9ddbc5 | 484 | tree float_ftype_float_float; |
f53ce661 | 485 | tree boolean_ftype_boolean_boolean; |
fcffb974 | 486 | int i; |
487 | ||
1799e0bd | 488 | for (i = 0; java_builtins[i].builtin_code != END_BUILTINS; ++i) |
fcffb974 | 489 | { |
490 | tree klass_id = get_identifier (java_builtins[i].class_name.s); | |
491 | tree m = get_identifier (java_builtins[i].method_name.s); | |
492 | ||
493 | java_builtins[i].class_name.t = klass_id; | |
494 | java_builtins[i].method_name.t = m; | |
fcffb974 | 495 | } |
496 | ||
497 | void_list_node = end_params_node; | |
498 | ||
bfa624b3 | 499 | float_ftype_float_float |
500 | = build_function_type_list (float_type_node, | |
501 | float_type_node, float_type_node, NULL_TREE); | |
f1e69817 | 502 | |
bfa624b3 | 503 | double_ftype_double |
504 | = build_function_type_list (double_type_node, double_type_node, NULL_TREE); | |
505 | double_ftype_double_double | |
506 | = build_function_type_list (double_type_node, | |
507 | double_type_node, double_type_node, NULL_TREE); | |
f1e69817 | 508 | |
509 | define_builtin (BUILT_IN_FMOD, "__builtin_fmod", | |
2d68d2ef | 510 | double_ftype_double_double, "fmod", ECF_CONST); |
f1e69817 | 511 | define_builtin (BUILT_IN_FMODF, "__builtin_fmodf", |
2d68d2ef | 512 | float_ftype_float_float, "fmodf", ECF_CONST); |
f1e69817 | 513 | |
91da6229 | 514 | define_builtin (BUILT_IN_ACOS, "__builtin_acos", |
4c8420c9 | 515 | double_ftype_double, "_ZN4java4lang4Math4acosEJdd", |
2d68d2ef | 516 | ECF_CONST); |
91da6229 | 517 | define_builtin (BUILT_IN_ASIN, "__builtin_asin", |
4c8420c9 | 518 | double_ftype_double, "_ZN4java4lang4Math4asinEJdd", |
2d68d2ef | 519 | ECF_CONST); |
f1e69817 | 520 | define_builtin (BUILT_IN_ATAN, "__builtin_atan", |
4c8420c9 | 521 | double_ftype_double, "_ZN4java4lang4Math4atanEJdd", |
2d68d2ef | 522 | ECF_CONST); |
f1e69817 | 523 | define_builtin (BUILT_IN_ATAN2, "__builtin_atan2", |
4c8420c9 | 524 | double_ftype_double_double, "_ZN4java4lang4Math5atan2EJddd", |
2d68d2ef | 525 | ECF_CONST); |
91da6229 | 526 | define_builtin (BUILT_IN_CEIL, "__builtin_ceil", |
4c8420c9 | 527 | double_ftype_double, "_ZN4java4lang4Math4ceilEJdd", |
2d68d2ef | 528 | ECF_CONST); |
f1e69817 | 529 | define_builtin (BUILT_IN_COS, "__builtin_cos", |
4c8420c9 | 530 | double_ftype_double, "_ZN4java4lang4Math3cosEJdd", |
2d68d2ef | 531 | ECF_CONST); |
f1e69817 | 532 | define_builtin (BUILT_IN_EXP, "__builtin_exp", |
4c8420c9 | 533 | double_ftype_double, "_ZN4java4lang4Math3expEJdd", |
2d68d2ef | 534 | ECF_CONST); |
91da6229 | 535 | define_builtin (BUILT_IN_FLOOR, "__builtin_floor", |
4c8420c9 | 536 | double_ftype_double, "_ZN4java4lang4Math5floorEJdd", |
2d68d2ef | 537 | ECF_CONST); |
f1e69817 | 538 | define_builtin (BUILT_IN_LOG, "__builtin_log", |
4c8420c9 | 539 | double_ftype_double, "_ZN4java4lang4Math3logEJdd", |
2d68d2ef | 540 | ECF_CONST); |
f1e69817 | 541 | define_builtin (BUILT_IN_POW, "__builtin_pow", |
4c8420c9 | 542 | double_ftype_double_double, "_ZN4java4lang4Math3powEJddd", |
2d68d2ef | 543 | ECF_CONST); |
f1e69817 | 544 | define_builtin (BUILT_IN_SIN, "__builtin_sin", |
4c8420c9 | 545 | double_ftype_double, "_ZN4java4lang4Math3sinEJdd", |
2d68d2ef | 546 | ECF_CONST); |
f1e69817 | 547 | define_builtin (BUILT_IN_SQRT, "__builtin_sqrt", |
4c8420c9 | 548 | double_ftype_double, "_ZN4java4lang4Math4sqrtEJdd", |
2d68d2ef | 549 | ECF_CONST); |
f1e69817 | 550 | define_builtin (BUILT_IN_TAN, "__builtin_tan", |
4c8420c9 | 551 | double_ftype_double, "_ZN4java4lang4Math3tanEJdd", |
2d68d2ef | 552 | ECF_CONST); |
f53ce661 | 553 | |
bfa624b3 | 554 | boolean_ftype_boolean_boolean |
555 | = build_function_type_list (boolean_type_node, | |
556 | boolean_type_node, boolean_type_node, | |
557 | NULL_TREE); | |
f53ce661 | 558 | define_builtin (BUILT_IN_EXPECT, "__builtin_expect", |
559 | boolean_ftype_boolean_boolean, | |
a89ea5ec | 560 | "__builtin_expect", |
2d68d2ef | 561 | ECF_CONST | ECF_NOTHROW); |
2797f13a | 562 | define_builtin (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4, |
65bf3316 | 563 | "__sync_bool_compare_and_swap_4", |
564 | build_function_type_list (boolean_type_node, | |
565 | int_type_node, | |
566 | build_pointer_type (int_type_node), | |
567 | int_type_node, NULL_TREE), | |
2d68d2ef | 568 | "__sync_bool_compare_and_swap_4", ECF_NOTHROW | ECF_LEAF); |
2797f13a | 569 | define_builtin (BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8, |
65bf3316 | 570 | "__sync_bool_compare_and_swap_8", |
571 | build_function_type_list (boolean_type_node, | |
572 | long_type_node, | |
573 | build_pointer_type (long_type_node), | |
574 | int_type_node, NULL_TREE), | |
2d68d2ef | 575 | "__sync_bool_compare_and_swap_8", ECF_NOTHROW | ECF_LEAF); |
2797f13a | 576 | define_builtin (BUILT_IN_SYNC_SYNCHRONIZE, "__sync_synchronize", |
bfa624b3 | 577 | build_function_type_list (void_type_node, NULL_TREE), |
2d68d2ef | 578 | "__sync_synchronize", ECF_NOTHROW | ECF_LEAF); |
65bf3316 | 579 | |
580 | define_builtin (BUILT_IN_RETURN_ADDRESS, "__builtin_return_address", | |
581 | build_function_type_list (ptr_type_node, int_type_node, NULL_TREE), | |
2d68d2ef | 582 | "__builtin_return_address", ECF_NOTHROW | ECF_LEAF); |
a3eb5a98 | 583 | define_builtin (BUILT_IN_TRAP, "__builtin_trap", |
584 | build_function_type_list (void_type_node, NULL_TREE), | |
585 | "__builtin_trap", ECF_NOTHROW | ECF_LEAF | ECF_NORETURN); | |
471eff36 | 586 | build_common_builtin_nodes (); |
fcffb974 | 587 | } |
588 | ||
85dce5fa | 589 | /* If the call matches a builtin, return the |
fcffb974 | 590 | appropriate builtin expression instead. */ |
591 | tree | |
2883a3ed | 592 | check_for_builtin (tree method, tree call) |
fcffb974 | 593 | { |
6548e808 | 594 | if (optimize && TREE_CODE (call) == CALL_EXPR) |
fcffb974 | 595 | { |
596 | int i; | |
85dce5fa | 597 | tree method_class = DECL_NAME (TYPE_NAME (DECL_CONTEXT (method))); |
598 | tree method_name = DECL_NAME (method); | |
599 | tree method_return_type = TREE_TYPE (TREE_TYPE (method)); | |
fcffb974 | 600 | |
1799e0bd | 601 | for (i = 0; java_builtins[i].builtin_code != END_BUILTINS; ++i) |
fcffb974 | 602 | { |
603 | if (method_class == java_builtins[i].class_name.t | |
604 | && method_name == java_builtins[i].method_name.t) | |
605 | { | |
1799e0bd | 606 | tree fn; |
607 | ||
608 | if (java_builtins[i].creator != NULL) | |
e60fa8e9 | 609 | { |
610 | tree result | |
c2f47e15 | 611 | = (*java_builtins[i].creator) (method_return_type, call); |
e60fa8e9 | 612 | return result == NULL_TREE ? call : result; |
613 | } | |
096fda97 | 614 | |
615 | /* Builtin functions emit a direct call which is incompatible | |
616 | with the BC-ABI. */ | |
617 | if (flag_indirect_dispatch) | |
618 | return call; | |
b9a16870 | 619 | fn = builtin_decl_explicit (java_builtins[i].builtin_code); |
1799e0bd | 620 | if (fn == NULL_TREE) |
e60fa8e9 | 621 | return call; |
c2f47e15 | 622 | return java_build_function_call_expr (fn, call); |
fcffb974 | 623 | } |
624 | } | |
625 | } | |
fcffb974 | 626 | return call; |
627 | } | |
1f3233d1 | 628 | |
629 | #include "gt-java-builtins.h" |