diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-01-18 17:15:07 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-01-18 17:15:07 +0000 |
commit | 83014b2054e99af8f6be8f077de17bc31f2d6c51 (patch) | |
tree | c961c9a38a96cfcad2a5854770ba3b274de81430 /gcc/expr.c | |
parent | 516ad6808051a6977c1fe1fe52c4cf70977736c0 (diff) | |
download | gcc-83014b2054e99af8f6be8f077de17bc31f2d6c51.tar.gz |
PR middle-end/56015
* expr.c (expand_expr_real_2) <case COMPLEX_EXPR>: Handle
the case where writing real complex part of target modifies
op1.
* gfortran.dg/pr56015.f90: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@195301 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/gcc/expr.c b/gcc/expr.c index 12029d6915a..08c5c9d0c58 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8860,6 +8860,54 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, if (!target) target = gen_reg_rtx (TYPE_MODE (type)); + else + /* If target overlaps with op1, then either we need to force + op1 into a pseudo (if target also overlaps with op0), + or write the complex parts in reverse order. */ + switch (GET_CODE (target)) + { + case CONCAT: + if (reg_overlap_mentioned_p (XEXP (target, 0), op1)) + { + if (reg_overlap_mentioned_p (XEXP (target, 1), op0)) + { + complex_expr_force_op1: + temp = gen_reg_rtx (GET_MODE_INNER (GET_MODE (target))); + emit_move_insn (temp, op1); + op1 = temp; + break; + } + complex_expr_swap_order: + /* Move the imaginary (op1) and real (op0) parts to their + location. */ + write_complex_part (target, op1, true); + write_complex_part (target, op0, false); + + return target; + } + break; + case MEM: + temp = adjust_address_nv (target, + GET_MODE_INNER (GET_MODE (target)), 0); + if (reg_overlap_mentioned_p (temp, op1)) + { + enum machine_mode imode = GET_MODE_INNER (GET_MODE (target)); + temp = adjust_address_nv (target, imode, + GET_MODE_SIZE (imode)); + if (reg_overlap_mentioned_p (temp, op0)) + goto complex_expr_force_op1; + goto complex_expr_swap_order; + } + break; + default: + if (reg_overlap_mentioned_p (target, op1)) + { + if (reg_overlap_mentioned_p (target, op0)) + goto complex_expr_force_op1; + goto complex_expr_swap_order; + } + break; + } /* Move the real (op0) and imaginary (op1) parts to their location. */ write_complex_part (target, op0, false); |