diff options
author | Jim Wilson <wilson@gcc.gnu.org> | 1996-06-06 16:04:56 -0700 |
---|---|---|
committer | Jim Wilson <wilson@gcc.gnu.org> | 1996-06-06 16:04:56 -0700 |
commit | fffa9c1d2e774bb163859c10b9b491ed918bca99 (patch) | |
tree | 5ccc1ccdc8ba86018c12062cf036bb0417e495ed | |
parent | cacbd53270c2cd3f67d1e3c72ad0f7b5bf5ba124 (diff) | |
download | gcc-fffa9c1d2e774bb163859c10b9b491ed918bca99.zip gcc-fffa9c1d2e774bb163859c10b9b491ed918bca99.tar.gz gcc-fffa9c1d2e774bb163859c10b9b491ed918bca99.tar.bz2 |
(emit_group_load, emit_group_store): New functions.
(use_group_regs): New function.
(emit_push_insn): Handle PARALLEL parameter in REG.
(expand_assignment): Handle PARALLEL to_rtx.
(store_expr): Handle PARALLEL target.
From-SVN: r12189
-rw-r--r-- | gcc/expr.c | 127 |
1 files changed, 125 insertions, 2 deletions
@@ -1817,6 +1817,92 @@ move_block_from_reg (regno, x, nregs, size) } } +/* Emit code to move a block Y to a block X, where X is non-consecutive + registers represented by a PARALLEL. */ + +void +emit_group_load (x, y) + rtx x, y; +{ + rtx target_reg, source; + int i; + + if (GET_CODE (x) != PARALLEL) + abort (); + + /* Check for a NULL entry, used to indicate that the parameter goes + both on the stack and in registers. */ + if (XEXP (XVECEXP (x, 0, 0), 0)) + i = 0; + else + i = 1; + + for (; i < XVECLEN (x, 0); i++) + { + rtx element = XVECEXP (x, 0, i); + + target_reg = XEXP (element, 0); + + if (GET_CODE (y) == MEM) + source = change_address (y, GET_MODE (target_reg), + plus_constant (XEXP (y, 0), + INTVAL (XEXP (element, 1)))); + else if (XEXP (element, 1) == const0_rtx) + { + if (GET_MODE (target_reg) == GET_MODE (y)) + source = y; + else if (GET_MODE_SIZE (GET_MODE (target_reg)) + == GET_MODE_SIZE (GET_MODE (y))) + source = gen_rtx (SUBREG, GET_MODE (target_reg), y, 0); + else + abort (); + } + else + abort (); + + emit_move_insn (target_reg, source); + } +} + +/* Emit code to move a block Y to a block X, where Y is non-consecutive + registers represented by a PARALLEL. */ + +void +emit_group_store (x, y) + rtx x, y; +{ + rtx source_reg, target; + int i; + + if (GET_CODE (y) != PARALLEL) + abort (); + + /* Check for a NULL entry, used to indicate that the parameter goes + both on the stack and in registers. */ + if (XEXP (XVECEXP (y, 0, 0), 0)) + i = 0; + else + i = 1; + + for (; i < XVECLEN (y, 0); i++) + { + rtx element = XVECEXP (y, 0, i); + + source_reg = XEXP (element, 0); + + if (GET_CODE (x) == MEM) + target = change_address (x, GET_MODE (source_reg), + plus_constant (XEXP (x, 0), + INTVAL (XEXP (element, 1)))); + else if (XEXP (element, 1) == const0_rtx) + target = x; + else + abort (); + + emit_move_insn (target, source_reg); + } +} + /* Add a USE expression for REG to the (possibly empty) list pointed to by CALL_FUSAGE. REG must denote a hard register. */ @@ -1850,6 +1936,28 @@ use_regs (call_fusage, regno, nregs) for (i = 0; i < nregs; i++) use_reg (call_fusage, gen_rtx (REG, reg_raw_mode[regno + i], regno + i)); } + +/* Add USE expressions to *CALL_FUSAGE for each REG contained in the + PARALLEL REGS. This is for calls that pass values in multiple + non-contiguous locations. The Irix 6 ABI has examples of this. */ + +void +use_group_regs (call_fusage, regs) + rtx *call_fusage; + rtx regs; +{ + int i; + + /* Check for a NULL entry, used to indicate that the parameter goes + both on the stack and in registers. */ + if (XEXP (XVECEXP (regs, 0, 0), 0)) + i = 0; + else + i = 1; + + for (; i < XVECLEN (regs, 0); i++) + use_reg (call_fusage, XEXP (XVECEXP (regs, 0, i), 0)); +} /* Generate several move instructions to clear LEN bytes of block TO. (A MEM rtx with BLKmode). The caller must pass TO through @@ -2648,7 +2756,14 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra, into the appropriate registers. Do this now, at the end, since mem-to-mem copies above may do function calls. */ if (partial > 0 && reg != 0) - move_block_to_reg (REGNO (reg), x, partial, mode); + { + /* Handle calls that pass values in multiple non-contiguous locations. + The Irix 6 ABI has examples of this. */ + if (GET_CODE (reg) == PARALLEL) + emit_group_load (reg, x); + else + move_block_to_reg (REGNO (reg), x, partial, mode); + } if (extra && args_addr == 0 && where_pad == stack_direction) anti_adjust_stack (GEN_INT (extra)); @@ -2812,7 +2927,11 @@ expand_assignment (to, from, want_value, suggest_reg) if (to_rtx == 0) to_rtx = expand_expr (to, NULL_RTX, VOIDmode, 0); - if (GET_MODE (to_rtx) == BLKmode) + /* Handle calls that return values in multiple non-contiguous locations. + The Irix 6 ABI has examples of this. */ + if (GET_CODE (to_rtx) == PARALLEL) + emit_group_load (to_rtx, value); + else if (GET_MODE (to_rtx) == BLKmode) emit_block_move (to_rtx, value, expr_size (from), TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT); else @@ -3167,6 +3286,10 @@ store_expr (exp, target, want_value) emit_label (label); } } + /* Handle calls that return values in multiple non-contiguous locations. + The Irix 6 ABI has examples of this. */ + else if (GET_CODE (target) == PARALLEL) + emit_group_load (target, temp); else if (GET_MODE (temp) == BLKmode) emit_block_move (target, temp, expr_size (exp), TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); |