static rtx expand_builtin_mathfn (tree, rtx, rtx);
static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
+static rtx expand_builtin_sincos (tree);
static rtx expand_builtin_int_roundingfn (tree, rtx, rtx);
static rtx expand_builtin_args_info (tree);
static rtx expand_builtin_next_arg (void);
tree fndecl = get_callee_fndecl (exp);
tree arglist = TREE_OPERAND (exp, 1);
enum machine_mode mode;
- bool errno_set = false;
tree arg, narg;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
/* Make a suitable register to place result in. */
mode = TYPE_MODE (TREE_TYPE (exp));
- if (! flag_errno_math || ! HONOR_NANS (mode))
- errno_set = false;
-
/* Check if sincos insn is available, otherwise fallback
to sin or cos insn. */
if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) {
if (target != 0)
{
- if (errno_set)
- expand_errno_check (exp, target);
-
/* Output the entire sequence. */
insns = get_insns ();
end_sequence ();
return target;
}
+/* Expand a call to the builtin sincos math function.
+ Return 0 if a normal call should be emitted rather than expanding the
+ function in-line. EXP is the expression that is a call to the builtin
+ function. */
+
+static rtx
+expand_builtin_sincos (tree exp)
+{
+ rtx op0, op1, op2, target1, target2;
+ tree arglist = TREE_OPERAND (exp, 1);
+ enum machine_mode mode;
+ tree arg, sinp, cosp;
+ int result;
+
+ if (!validate_arglist (arglist, REAL_TYPE,
+ POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+ return 0;
+
+ arg = TREE_VALUE (arglist);
+ sinp = TREE_VALUE (TREE_CHAIN (arglist));
+ cosp = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+ /* Make a suitable register to place result in. */
+ mode = TYPE_MODE (TREE_TYPE (arg));
+
+ /* Check if sincos insn is available, otherwise emit the call. */
+ if (sincos_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+ return NULL_RTX;
+
+ target1 = gen_reg_rtx (mode);
+ target2 = gen_reg_rtx (mode);
+
+ op0 = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+ op1 = expand_expr (build_fold_indirect_ref (sinp), NULL_RTX, VOIDmode, 0);
+ op2 = expand_expr (build_fold_indirect_ref (cosp), NULL_RTX, VOIDmode, 0);
+
+ /* Compute into target1 and target2.
+ Set TARGET to wherever the result comes back. */
+ result = expand_twoval_unop (sincos_optab, op0, target2, target1, 0);
+ gcc_assert (result);
+
+ /* Move target1 and target2 to the memory locations indicated
+ by op1 and op2. */
+ emit_move_insn (op1, target1);
+ emit_move_insn (op2, target2);
+
+ return const0_rtx;
+}
+
/* Expand a call to one of the builtin rounding functions (lfloor).
If expanding via optab fails, lower expression to (int)(floor(x)).
EXP is the expression that is a call to the builtin function;
/* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
requires greater alignment, we must perform dynamic alignment. */
- if (boundary > align)
+ if (boundary > align
+ && !integer_zerop (TYPE_SIZE (type)))
{
t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
return mode_for_size (BITS_PER_UNIT << fcode_diff, MODE_INT, 0);
}
+/* Expand the memory expression LOC and return the appropriate memory operand
+ for the builtin_sync operations. */
+
+static rtx
+get_builtin_sync_mem (tree loc, enum machine_mode mode)
+{
+ rtx addr, mem;
+
+ addr = expand_expr (loc, NULL, Pmode, EXPAND_SUM);
+
+ /* Note that we explicitly do not want any alias information for this
+ memory, so that we kill all other live memories. Otherwise we don't
+ satisfy the full barrier semantics of the intrinsic. */
+ mem = validize_mem (gen_rtx_MEM (mode, addr));
+
+ set_mem_align (mem, get_pointer_alignment (loc, BIGGEST_ALIGNMENT));
+ MEM_VOLATILE_P (mem) = 1;
+
+ return mem;
+}
+
/* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics.
ARGLIST is the operands list to the function. CODE is the rtx code
that corresponds to the arithmetic or logical operation from the name;
enum rtx_code code, bool after,
rtx target, bool ignore)
{
- rtx addr, val, mem;
+ rtx val, mem;
/* Expand the operands. */
- addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_SUM);
+ mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
arglist = TREE_CHAIN (arglist);
val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
- /* Note that we explicitly do not want any alias information for this
- memory, so that we kill all other live memories. Otherwise we don't
- satisfy the full barrier semantics of the intrinsic. */
- mem = validize_mem (gen_rtx_MEM (mode, addr));
- MEM_VOLATILE_P (mem) = 1;
-
if (ignore)
return expand_sync_operation (mem, val, code);
else
expand_builtin_compare_and_swap (enum machine_mode mode, tree arglist,
bool is_bool, rtx target)
{
- rtx addr, old_val, new_val, mem;
+ rtx old_val, new_val, mem;
/* Expand the operands. */
- addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_SUM);
+ mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
arglist = TREE_CHAIN (arglist);
old_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
arglist = TREE_CHAIN (arglist);
new_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
- /* Note that we explicitly do not want any alias information for this
- memory, so that we kill all other live memories. Otherwise we don't
- satisfy the full barrier semantics of the intrinsic. */
- mem = validize_mem (gen_rtx_MEM (mode, addr));
- MEM_VOLATILE_P (mem) = 1;
-
if (is_bool)
return expand_bool_compare_and_swap (mem, old_val, new_val, target);
else
expand_builtin_lock_test_and_set (enum machine_mode mode, tree arglist,
rtx target)
{
- rtx addr, val, mem;
+ rtx val, mem;
/* Expand the operands. */
- addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_NORMAL);
+ mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
arglist = TREE_CHAIN (arglist);
val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
- /* Note that we explicitly do not want any alias information for this
- memory, so that we kill all other live memories. Otherwise we don't
- satisfy the barrier semantics of the intrinsic. */
- mem = validize_mem (gen_rtx_MEM (mode, addr));
- MEM_VOLATILE_P (mem) = 1;
-
return expand_sync_lock_test_and_set (mem, val, target);
}
expand_builtin_lock_release (enum machine_mode mode, tree arglist)
{
enum insn_code icode;
- rtx addr, mem, insn;
+ rtx mem, insn;
rtx val = const0_rtx;
/* Expand the operands. */
- addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_NORMAL);
-
- /* Note that we explicitly do not want any alias information for this
- memory, so that we kill all other live memories. Otherwise we don't
- satisfy the barrier semantics of the intrinsic. */
- mem = validize_mem (gen_rtx_MEM (mode, addr));
- MEM_VOLATILE_P (mem) = 1;
+ mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
/* If there is an explicit operation in the md file, use it. */
icode = sync_lock_release[mode];
return target;
break;
+ CASE_FLT_FN (BUILT_IN_SINCOS):
+ if (! flag_unsafe_math_optimizations)
+ break;
+ target = expand_builtin_sincos (exp);
+ if (target)
+ return target;
+ break;
+
case BUILT_IN_APPLY_ARGS:
return expand_builtin_apply_args ();
case BUILT_IN_FETCH_AND_ADD_2:
case BUILT_IN_FETCH_AND_ADD_4:
case BUILT_IN_FETCH_AND_ADD_8:
+ case BUILT_IN_FETCH_AND_ADD_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_ADD_1);
target = expand_builtin_sync_operation (mode, arglist, PLUS,
false, target, ignore);
case BUILT_IN_FETCH_AND_SUB_2:
case BUILT_IN_FETCH_AND_SUB_4:
case BUILT_IN_FETCH_AND_SUB_8:
+ case BUILT_IN_FETCH_AND_SUB_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_SUB_1);
target = expand_builtin_sync_operation (mode, arglist, MINUS,
false, target, ignore);
case BUILT_IN_FETCH_AND_OR_2:
case BUILT_IN_FETCH_AND_OR_4:
case BUILT_IN_FETCH_AND_OR_8:
+ case BUILT_IN_FETCH_AND_OR_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_OR_1);
target = expand_builtin_sync_operation (mode, arglist, IOR,
false, target, ignore);
case BUILT_IN_FETCH_AND_AND_2:
case BUILT_IN_FETCH_AND_AND_4:
case BUILT_IN_FETCH_AND_AND_8:
+ case BUILT_IN_FETCH_AND_AND_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_AND_1);
target = expand_builtin_sync_operation (mode, arglist, AND,
false, target, ignore);
case BUILT_IN_FETCH_AND_XOR_2:
case BUILT_IN_FETCH_AND_XOR_4:
case BUILT_IN_FETCH_AND_XOR_8:
+ case BUILT_IN_FETCH_AND_XOR_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_XOR_1);
target = expand_builtin_sync_operation (mode, arglist, XOR,
false, target, ignore);
case BUILT_IN_FETCH_AND_NAND_2:
case BUILT_IN_FETCH_AND_NAND_4:
case BUILT_IN_FETCH_AND_NAND_8:
+ case BUILT_IN_FETCH_AND_NAND_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_NAND_1);
target = expand_builtin_sync_operation (mode, arglist, NOT,
false, target, ignore);
case BUILT_IN_ADD_AND_FETCH_2:
case BUILT_IN_ADD_AND_FETCH_4:
case BUILT_IN_ADD_AND_FETCH_8:
+ case BUILT_IN_ADD_AND_FETCH_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_ADD_AND_FETCH_1);
target = expand_builtin_sync_operation (mode, arglist, PLUS,
true, target, ignore);
case BUILT_IN_SUB_AND_FETCH_2:
case BUILT_IN_SUB_AND_FETCH_4:
case BUILT_IN_SUB_AND_FETCH_8:
+ case BUILT_IN_SUB_AND_FETCH_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_SUB_AND_FETCH_1);
target = expand_builtin_sync_operation (mode, arglist, MINUS,
true, target, ignore);
case BUILT_IN_OR_AND_FETCH_2:
case BUILT_IN_OR_AND_FETCH_4:
case BUILT_IN_OR_AND_FETCH_8:
+ case BUILT_IN_OR_AND_FETCH_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_OR_AND_FETCH_1);
target = expand_builtin_sync_operation (mode, arglist, IOR,
true, target, ignore);
case BUILT_IN_AND_AND_FETCH_2:
case BUILT_IN_AND_AND_FETCH_4:
case BUILT_IN_AND_AND_FETCH_8:
+ case BUILT_IN_AND_AND_FETCH_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_AND_AND_FETCH_1);
target = expand_builtin_sync_operation (mode, arglist, AND,
true, target, ignore);
case BUILT_IN_XOR_AND_FETCH_2:
case BUILT_IN_XOR_AND_FETCH_4:
case BUILT_IN_XOR_AND_FETCH_8:
+ case BUILT_IN_XOR_AND_FETCH_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_XOR_AND_FETCH_1);
target = expand_builtin_sync_operation (mode, arglist, XOR,
true, target, ignore);
case BUILT_IN_NAND_AND_FETCH_2:
case BUILT_IN_NAND_AND_FETCH_4:
case BUILT_IN_NAND_AND_FETCH_8:
+ case BUILT_IN_NAND_AND_FETCH_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_NAND_AND_FETCH_1);
target = expand_builtin_sync_operation (mode, arglist, NOT,
true, target, ignore);
case BUILT_IN_BOOL_COMPARE_AND_SWAP_2:
case BUILT_IN_BOOL_COMPARE_AND_SWAP_4:
case BUILT_IN_BOOL_COMPARE_AND_SWAP_8:
+ case BUILT_IN_BOOL_COMPARE_AND_SWAP_16:
if (mode == VOIDmode)
mode = TYPE_MODE (boolean_type_node);
if (!target || !register_operand (target, mode))
case BUILT_IN_VAL_COMPARE_AND_SWAP_2:
case BUILT_IN_VAL_COMPARE_AND_SWAP_4:
case BUILT_IN_VAL_COMPARE_AND_SWAP_8:
+ case BUILT_IN_VAL_COMPARE_AND_SWAP_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_VAL_COMPARE_AND_SWAP_1);
target = expand_builtin_compare_and_swap (mode, arglist, false, target);
if (target)
case BUILT_IN_LOCK_TEST_AND_SET_2:
case BUILT_IN_LOCK_TEST_AND_SET_4:
case BUILT_IN_LOCK_TEST_AND_SET_8:
+ case BUILT_IN_LOCK_TEST_AND_SET_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_TEST_AND_SET_1);
target = expand_builtin_lock_test_and_set (mode, arglist, target);
if (target)
case BUILT_IN_LOCK_RELEASE_2:
case BUILT_IN_LOCK_RELEASE_4:
case BUILT_IN_LOCK_RELEASE_8:
+ case BUILT_IN_LOCK_RELEASE_16:
mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_RELEASE_1);
expand_builtin_lock_release (mode, arglist);
return const0_rtx;