summaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2013-01-18 17:15:07 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2013-01-18 17:15:07 +0000
commit83014b2054e99af8f6be8f077de17bc31f2d6c51 (patch)
treec961c9a38a96cfcad2a5854770ba3b274de81430 /gcc/expr.c
parent516ad6808051a6977c1fe1fe52c4cf70977736c0 (diff)
downloadgcc-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.c48
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);