diff options
author | Jakub Jelinek <jakub@redhat.com> | 2013-01-18 18:15:07 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2013-01-18 18:15:07 +0100 |
commit | 3f0fee7b4d54d49364a47021c7d2dd9bd4c84c73 (patch) | |
tree | c961c9a38a96cfcad2a5854770ba3b274de81430 /gcc/expr.c | |
parent | b69a7864fbaf0a80b6e39b9680b821fba6eb8d0c (diff) | |
download | gcc-3f0fee7b4d54d49364a47021c7d2dd9bd4c84c73.zip gcc-3f0fee7b4d54d49364a47021c7d2dd9bd4c84c73.tar.gz gcc-3f0fee7b4d54d49364a47021c7d2dd9bd4c84c73.tar.bz2 |
re PR middle-end/56015 (expand expands p[9] = COMPLEX_EXPR <-IMAGPART_EXPR <p[9]>, REALPART_EXPR <p[9]>>; incorrectly.)
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.
From-SVN: r195301
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 48 |
1 files changed, 48 insertions, 0 deletions
@@ -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); |