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