From: Richard Sandiford Date: Fri, 6 Jan 2012 14:59:47 +0000 (+0000) Subject: re PR middle-end/48660 (ARM ICE in expand_expr_real_1) X-Git-Tag: releases/gcc-4.5.4~285 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=afaba6a09234eb2f84509be535d634c17ac7e7c8;p=thirdparty%2Fgcc.git re PR middle-end/48660 (ARM ICE in expand_expr_real_1) gcc/ PR middle-end/48660 * expr.h (copy_blkmode_to_reg): Declare. * expr.c (copy_blkmode_to_reg): New function. (expand_assignment): Don't expand register RESULT_DECLs before the lhs. Use copy_blkmode_to_reg to copy BLKmode values into a RESULT_DECL register. (expand_expr_real_1): Handle BLKmode decls when looking for promotion. gcc/testsuite/ PR middle-end/48660 * g++.dg/pr48660.C: New test. From-SVN: r182956 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4a1a3e04f2f6..6a8595c1d5f2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2012-01-06 Richard Sandiford + + PR middle-end/48660 + * expr.h (copy_blkmode_to_reg): Declare. + * expr.c (copy_blkmode_to_reg): New function. + (expand_assignment): Don't expand register RESULT_DECLs before + the lhs. Use copy_blkmode_to_reg to copy BLKmode values into a + RESULT_DECL register. + (expand_expr_real_1): Handle BLKmode decls when looking for promotion. + 2012-01-04 Richard Guenther Backport from mainline diff --git a/gcc/expr.c b/gcc/expr.c index 4d05c6171162..65a1c6066a8f 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -2220,6 +2220,111 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type) return tgtblk; } +/* Copy BLKmode value SRC into a register of mode MODE. Return the + register if it contains any data, otherwise return null. + + This is used on targets that return BLKmode values in registers. */ + +rtx +copy_blkmode_to_reg (enum machine_mode mode, tree src) +{ + int i, n_regs; + unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0, bytes; + unsigned int bitsize; + rtx *dst_words, dst, x, src_word = NULL_RTX, dst_word = NULL_RTX; + enum machine_mode dst_mode; + + gcc_assert (TYPE_MODE (TREE_TYPE (src)) == BLKmode); + + x = expand_normal (src); + + bytes = int_size_in_bytes (TREE_TYPE (src)); + if (bytes == 0) + return NULL_RTX; + + /* If the structure doesn't take up a whole number of words, see + whether the register value should be padded on the left or on + the right. Set PADDING_CORRECTION to the number of padding + bits needed on the left side. + + In most ABIs, the structure will be returned at the least end of + the register, which translates to right padding on little-endian + targets and left padding on big-endian targets. The opposite + holds if the structure is returned at the most significant + end of the register. */ + if (bytes % UNITS_PER_WORD != 0 + && (targetm.calls.return_in_msb (TREE_TYPE (src)) + ? !BYTES_BIG_ENDIAN + : BYTES_BIG_ENDIAN)) + padding_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) + * BITS_PER_UNIT)); + + n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + dst_words = XALLOCAVEC (rtx, n_regs); + bitsize = MIN (TYPE_ALIGN (TREE_TYPE (src)), BITS_PER_WORD); + + /* Copy the structure BITSIZE bits at a time. */ + for (bitpos = 0, xbitpos = padding_correction; + bitpos < bytes * BITS_PER_UNIT; + bitpos += bitsize, xbitpos += bitsize) + { + /* We need a new destination pseudo each time xbitpos is + on a word boundary and when xbitpos == padding_correction + (the first time through). */ + if (xbitpos % BITS_PER_WORD == 0 + || xbitpos == padding_correction) + { + /* Generate an appropriate register. */ + dst_word = gen_reg_rtx (word_mode); + dst_words[xbitpos / BITS_PER_WORD] = dst_word; + + /* Clear the destination before we move anything into it. */ + emit_move_insn (dst_word, CONST0_RTX (word_mode)); + } + + /* We need a new source operand each time bitpos is on a word + boundary. */ + if (bitpos % BITS_PER_WORD == 0) + src_word = operand_subword_force (x, bitpos / BITS_PER_WORD, BLKmode); + + /* Use bitpos for the source extraction (left justified) and + xbitpos for the destination store (right justified). */ + store_bit_field (dst_word, bitsize, xbitpos % BITS_PER_WORD, word_mode, + extract_bit_field (src_word, bitsize, + bitpos % BITS_PER_WORD, 1, + NULL_RTX, word_mode, word_mode)); + } + + if (mode == BLKmode) + { + /* Find the smallest integer mode large enough to hold the + entire structure. */ + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + /* Have we found a large enough mode? */ + if (GET_MODE_SIZE (mode) >= bytes) + break; + + /* A suitable mode should have been found. */ + gcc_assert (mode != VOIDmode); + } + + if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode)) + dst_mode = word_mode; + else + dst_mode = mode; + dst = gen_reg_rtx (dst_mode); + + for (i = 0; i < n_regs; i++) + emit_move_insn (operand_subword (dst, i, 0, dst_mode), dst_words[i]); + + if (mode != dst_mode) + dst = gen_lowpart (mode, dst); + + return dst; +} + /* Add a USE expression for REG to the (possibly empty) list pointed to by CALL_FUSAGE. REG must denote a hard register. */ @@ -4380,7 +4485,9 @@ expand_assignment (tree to, tree from, bool nontemporal) if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from) && COMPLETE_TYPE_P (TREE_TYPE (from)) && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST - && ! (((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL) + && ! (((TREE_CODE (to) == VAR_DECL + || TREE_CODE (to) == PARM_DECL + || TREE_CODE (to) == RESULT_DECL) && REG_P (DECL_RTL (to))) || TREE_CODE (to) == SSA_NAME)) { @@ -4426,12 +4533,15 @@ expand_assignment (tree to, tree from, bool nontemporal) rtx temp; push_temp_slots (); - temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL); + if (REG_P (to_rtx) && TYPE_MODE (TREE_TYPE (from)) == BLKmode) + temp = copy_blkmode_to_reg (GET_MODE (to_rtx), from); + else + temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL); if (GET_CODE (to_rtx) == PARALLEL) emit_group_load (to_rtx, temp, TREE_TYPE (from), int_size_in_bytes (TREE_TYPE (from))); - else + else if (temp) emit_move_insn (to_rtx, temp); preserve_temp_slots (to_rtx); @@ -8528,11 +8638,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return temp; } - /* If the mode of DECL_RTL does not match that of the decl, it - must be a promoted value. We return a SUBREG of the wanted mode, - but mark it so that we know that it was already extended. */ + /* If the mode of DECL_RTL does not match that of the decl, + there are two cases: we are dealing with a BLKmode value + that is returned in a register, or we are dealing with + a promoted value. In the latter case, return a SUBREG + of the wanted mode, but mark it so that we know that it + was already extended. */ if (REG_P (decl_rtl) + && DECL_MODE (exp) != BLKmode && GET_MODE (decl_rtl) != DECL_MODE (exp)) { enum machine_mode pmode; diff --git a/gcc/expr.h b/gcc/expr.h index 4fddde6006ef..c1f2396745ca 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -460,6 +460,8 @@ extern void emit_group_store (rtx, rtx, tree, int); /* Copy BLKmode object from a set of registers. */ extern rtx copy_blkmode_from_reg (rtx, rtx, tree); +extern rtx copy_blkmode_to_reg (enum machine_mode, tree); + /* Mark REG as holding a parameter for the next CALL_INSN. */ extern void use_reg (rtx *, rtx); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d5a0134200e0..4b780419d553 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-01-06 Richard Sandiford + + PR middle-end/48660 + * g++.dg/pr48660.C: New test. + 2012-01-06 Eric Botcazou * ada/acats/overflow.lst: Add cb20004. diff --git a/gcc/testsuite/g++.dg/pr48660.C b/gcc/testsuite/g++.dg/pr48660.C new file mode 100644 index 000000000000..37b61741ada9 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr48660.C @@ -0,0 +1,22 @@ +template struct val { char a[N]; }; + +class Base +{ +public: + virtual val<1> get1() const = 0; + virtual val<2> get2() const = 0; + virtual val<3> get3() const = 0; + virtual val<4> get4() const = 0; +}; + +class Derived : public virtual Base +{ +public: + virtual val<1> get1() const { return foo->get1(); } + virtual val<2> get2() const { return foo->get2(); } + virtual val<3> get3() const { return foo->get3(); } + virtual val<4> get4() const { return foo->get4(); } + Base *foo; +}; + +Base* make() { return new Derived; }