summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/expr.c')
-rw-r--r--contrib/gcc/expr.c239
1 files changed, 169 insertions, 70 deletions
diff --git a/contrib/gcc/expr.c b/contrib/gcc/expr.c
index 812e1fb..3624f77 100644
--- a/contrib/gcc/expr.c
+++ b/contrib/gcc/expr.c
@@ -191,6 +191,7 @@ static rtx expand_builtin PROTO((tree, rtx, rtx,
static int apply_args_size PROTO((void));
static int apply_result_size PROTO((void));
static rtx result_vector PROTO((int, rtx));
+static rtx expand_builtin_setjmp PROTO((tree, rtx));
static rtx expand_builtin_apply_args PROTO((void));
static rtx expand_builtin_apply PROTO((rtx, rtx, rtx));
static void expand_builtin_return PROTO((rtx));
@@ -2679,19 +2680,79 @@ emit_move_insn_1 (x, y)
}
else
{
- /* Show the output dies here. This is necessary for pseudos;
+ rtx realpart_x, realpart_y;
+ rtx imagpart_x, imagpart_y;
+
+ /* If this is a complex value with each part being smaller than a
+ word, the usual calling sequence will likely pack the pieces into
+ a single register. Unfortunately, SUBREG of hard registers only
+ deals in terms of words, so we have a problem converting input
+ arguments to the CONCAT of two registers that is used elsewhere
+ for complex values. If this is before reload, we can copy it into
+ memory and reload. FIXME, we should see about using extract and
+ insert on integer registers, but complex short and complex char
+ variables should be rarely used. */
+ if (GET_MODE_BITSIZE (mode) < 2*BITS_PER_WORD
+ && (reload_in_progress | reload_completed) == 0)
+ {
+ int packed_dest_p = (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER);
+ int packed_src_p = (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER);
+
+ if (packed_dest_p || packed_src_p)
+ {
+ enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT)
+ ? MODE_FLOAT : MODE_INT);
+
+ enum machine_mode reg_mode =
+ mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
+
+ if (reg_mode != BLKmode)
+ {
+ rtx mem = assign_stack_temp (reg_mode,
+ GET_MODE_SIZE (mode), 0);
+
+ rtx cmem = change_address (mem, mode, NULL_RTX);
+
+ current_function_cannot_inline
+ = "function using short complex types cannot be inline";
+
+ if (packed_dest_p)
+ {
+ rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
+ emit_move_insn_1 (cmem, y);
+ return emit_move_insn_1 (sreg, mem);
+ }
+ else
+ {
+ rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
+ emit_move_insn_1 (mem, sreg);
+ return emit_move_insn_1 (x, cmem);
+ }
+ }
+ }
+ }
+
+ realpart_x = gen_realpart (submode, x);
+ realpart_y = gen_realpart (submode, y);
+ imagpart_x = gen_imagpart (submode, x);
+ imagpart_y = gen_imagpart (submode, y);
+
+ /* Show the output dies here. This is necessary for SUBREGs
+ of pseudos since we cannot track their lifetimes correctly;
hard regs shouldn't appear here except as return values.
We never want to emit such a clobber after reload. */
if (x != y
- && ! (reload_in_progress || reload_completed))
+ && ! (reload_in_progress || reload_completed)
+ && (GET_CODE (realpart_x) == SUBREG
+ || GET_CODE (imagpart_x) == SUBREG))
{
emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
}
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
- (gen_realpart (submode, x), gen_realpart (submode, y)));
+ (realpart_x, realpart_y));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
- (gen_imagpart (submode, x), gen_imagpart (submode, y)));
+ (imagpart_x, imagpart_y));
}
return get_last_insn ();
@@ -2703,6 +2764,8 @@ emit_move_insn_1 (x, y)
else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
{
rtx last_insn = 0;
+ rtx seq;
+ int need_clobber;
#ifdef PUSH_ROUNDING
@@ -2715,15 +2778,9 @@ emit_move_insn_1 (x, y)
}
#endif
- /* Show the output dies here. This is necessary for pseudos;
- hard regs shouldn't appear here except as return values.
- We never want to emit such a clobber after reload. */
- if (x != y
- && ! (reload_in_progress || reload_completed))
- {
- emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
- }
+ start_sequence ();
+ need_clobber = 0;
for (i = 0;
i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
i++)
@@ -2745,9 +2802,27 @@ emit_move_insn_1 (x, y)
if (xpart == 0 || ypart == 0)
abort ();
+ need_clobber |= (GET_CODE (xpart) == SUBREG);
+
last_insn = emit_move_insn (xpart, ypart);
}
+ seq = gen_sequence ();
+ end_sequence ();
+
+ /* Show the output dies here. This is necessary for SUBREGs
+ of pseudos since we cannot track their lifetimes correctly;
+ hard regs shouldn't appear here except as return values.
+ We never want to emit such a clobber after reload. */
+ if (x != y
+ && ! (reload_in_progress || reload_completed)
+ && need_clobber != 0)
+ {
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+ }
+
+ emit_insn (seq);
+
return last_insn;
}
else
@@ -6262,12 +6337,8 @@ expand_expr (exp, target, tmode, modifier)
}
temp = gen_rtx_MEM (mode, op0);
- /* If address was computed by addition,
- mark this as an element of an aggregate. */
- if (TREE_CODE (exp1) == PLUS_EXPR
- || (TREE_CODE (exp1) == SAVE_EXPR
- && TREE_CODE (TREE_OPERAND (exp1, 0)) == PLUS_EXPR)
- || AGGREGATE_TYPE_P (TREE_TYPE (exp))
+
+ if (AGGREGATE_TYPE_P (TREE_TYPE (exp))
|| (TREE_CODE (exp1) == ADDR_EXPR
&& (exp2 = TREE_OPERAND (exp1, 0))
&& AGGREGATE_TYPE_P (TREE_TYPE (exp2))))
@@ -8473,44 +8544,29 @@ expand_builtin_return_addr (fndecl_code, count, tem)
return tem;
}
-/* __builtin_setjmp is passed a pointer to an array of five words (not
- all will be used on all machines). It operates similarly to the C
- library function of the same name, but is more efficient. Much of
- the code below (and for longjmp) is copied from the handling of
- non-local gotos.
+/* Construct the leading half of a __builtin_setjmp call. Control will
+ return to RECEIVER_LABEL. This is used directly by sjlj exception
+ handling code. */
- NOTE: This is intended for use by GNAT and the exception handling
- scheme in the compiler and will only work in the method used by
- them. */
-
-rtx
-expand_builtin_setjmp (buf_addr, target, first_label, next_label)
+void
+expand_builtin_setjmp_setup (buf_addr, receiver_label)
rtx buf_addr;
- rtx target;
- rtx first_label, next_label;
+ rtx receiver_label;
{
- rtx lab1 = gen_label_rtx ();
enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
- enum machine_mode value_mode;
rtx stack_save;
- value_mode = TYPE_MODE (integer_type_node);
-
#ifdef POINTERS_EXTEND_UNSIGNED
buf_addr = convert_memory_address (Pmode, buf_addr);
#endif
buf_addr = force_reg (Pmode, buf_addr);
- if (target == 0 || GET_CODE (target) != REG
- || REGNO (target) < FIRST_PSEUDO_REGISTER)
- target = gen_reg_rtx (value_mode);
-
emit_queue ();
- /* We store the frame pointer and the address of lab1 in the buffer
- and use the rest of it for the stack save area, which is
- machine-dependent. */
+ /* We store the frame pointer and the address of receiver_label in
+ the buffer and use the rest of it for the stack save area, which
+ is machine-dependent. */
#ifndef BUILTIN_SETJMP_FRAME_VALUE
#define BUILTIN_SETJMP_FRAME_VALUE virtual_stack_vars_rtx
@@ -8522,7 +8578,7 @@ expand_builtin_setjmp (buf_addr, target, first_label, next_label)
(gen_rtx_MEM (Pmode,
plus_constant (buf_addr,
GET_MODE_SIZE (Pmode)))),
- force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, lab1)));
+ force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
stack_save = gen_rtx_MEM (sa_mode,
plus_constant (buf_addr,
@@ -8535,20 +8591,22 @@ expand_builtin_setjmp (buf_addr, target, first_label, next_label)
emit_insn (gen_builtin_setjmp_setup (buf_addr));
#endif
- /* Set TARGET to zero and branch to the first-time-through label. */
- emit_move_insn (target, const0_rtx);
- emit_jump_insn (gen_jump (first_label));
- emit_barrier ();
- emit_label (lab1);
-
- /* Tell flow about the strange goings on. Putting `lab1' on
- `nonlocal_goto_handler_labels' to indicates that function
- calls may traverse the arc back to this label. */
+ /* Tell optimize_save_area_alloca that extra work is going to
+ need to go on during alloca. */
+ current_function_calls_setjmp = 1;
+ /* Set this so all the registers get saved in our frame; we need to be
+ able to copy the saved values for any registers from frames we unwind. */
current_function_has_nonlocal_label = 1;
- nonlocal_goto_handler_labels =
- gen_rtx_EXPR_LIST (VOIDmode, lab1, nonlocal_goto_handler_labels);
+}
+/* Construct the trailing part of a __builtin_setjmp call.
+ This is used directly by sjlj exception handling code. */
+
+void
+expand_builtin_setjmp_receiver (receiver_label)
+ rtx receiver_label ATTRIBUTE_UNUSED;
+{
/* Clobber the FP when we get here, so we have to make sure it's
marked as used by this function. */
emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
@@ -8595,7 +8653,7 @@ expand_builtin_setjmp (buf_addr, target, first_label, next_label)
#ifdef HAVE_builtin_setjmp_receiver
if (HAVE_builtin_setjmp_receiver)
- emit_insn (gen_builtin_setjmp_receiver (lab1));
+ emit_insn (gen_builtin_setjmp_receiver (receiver_label));
else
#endif
#ifdef HAVE_nonlocal_goto_receiver
@@ -8606,12 +8664,61 @@ expand_builtin_setjmp (buf_addr, target, first_label, next_label)
{
; /* Nothing */
}
+}
- /* Set TARGET, and branch to the next-time-through label. */
- emit_move_insn (target, const1_rtx);
- emit_jump_insn (gen_jump (next_label));
+
+/* __builtin_setjmp is passed a pointer to an array of five words (not
+ all will be used on all machines). It operates similarly to the C
+ library function of the same name, but is more efficient. Much of
+ the code below (and for longjmp) is copied from the handling of
+ non-local gotos.
+
+ NOTE: This is intended for use by GNAT and the exception handling
+ scheme in the compiler and will only work in the method used by
+ them. */
+
+static rtx
+expand_builtin_setjmp (arglist, target)
+ tree arglist;
+ rtx target;
+{
+ rtx buf_addr, next_lab, cont_lab;
+
+ if (arglist == 0
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
+ return NULL_RTX;
+
+ if (target == 0 || GET_CODE (target) != REG
+ || REGNO (target) < FIRST_PSEUDO_REGISTER)
+ target = gen_reg_rtx (TYPE_MODE (integer_type_node));
+
+ buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+
+ next_lab = gen_label_rtx ();
+ cont_lab = gen_label_rtx ();
+
+ expand_builtin_setjmp_setup (buf_addr, next_lab);
+
+ /* Set TARGET to zero and branch to the continue label. */
+ emit_move_insn (target, const0_rtx);
+ emit_jump_insn (gen_jump (cont_lab));
emit_barrier ();
+ emit_label (next_lab);
+
+ expand_builtin_setjmp_receiver (next_lab);
+
+ /* Set TARGET to one. */
+ emit_move_insn (target, const1_rtx);
+ emit_label (cont_lab);
+
+ /* Tell flow about the strange goings on. Putting `next_lab' on
+ `nonlocal_goto_handler_labels' to indicates that function
+ calls may traverse the arc back to this label. */
+ current_function_has_nonlocal_label = 1;
+ nonlocal_goto_handler_labels
+ = gen_rtx_EXPR_LIST (VOIDmode, next_lab, nonlocal_goto_handler_labels);
+
return target;
}
@@ -9632,18 +9739,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
#endif
case BUILT_IN_SETJMP:
- if (arglist == 0
- || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
- break;
- else
- {
- rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
- VOIDmode, 0);
- rtx lab = gen_label_rtx ();
- rtx ret = expand_builtin_setjmp (buf_addr, target, lab, lab);
- emit_label (lab);
- return ret;
- }
+ target = expand_builtin_setjmp (arglist, target);
+ if (target)
+ return target;
+ break;
/* __builtin_longjmp is passed a pointer to an array of five words.
It's similar to the C library longjmp function but works with
OpenPOWER on IntegriCloud