[PATCH] Fix COMPONENT_REF expansion (PR rtl-optimization/77919)

Jakub Jelinek jakub@redhat.com
Fri Oct 28 08:46:00 GMT 2016


On Fri, Oct 28, 2016 at 01:32:22AM -0600, Jeff Law wrote:
> >I think so.  I'll leave the rest to people more familiar with RTL
> >expansion -- generally I thought the callers of expand() have to deal
> >with expansions that return a different mode?
> You generally have to deal with expansions that return the object in a new
> pseudo instead of the one you asked for -- so the caller has to test for
> that and emit a copy when it happens.
> 
> I don't offhand recall cases where we have to deal with getting a result in
> a different mode than was asked.  But given the history of the expanders, I
> wouldn't be surprised if there's oddball cases where that can happen.

I've already committed the original patch based on Eric's review, but
managed to come up with another testcase that still ICEs (one with two
different complex modes).  Is the following ok for trunk if it passes
bootstrap/regtest?

2016-10-28  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/77919
	* expr.c (expand_expr_real_1) <normal_inner_ref>: Only avoid forcing
	into memory if both modes are complex and their inner modes have the
	same precision.  If the two modes are different complex modes, convert
	each part separately and generate a new CONCAT.

	* g++.dg/torture/pr77919-2.C: New test.

--- gcc/expr.c.jj	2016-10-28 10:35:14.753234774 +0200
+++ gcc/expr.c	2016-10-28 10:35:28.760057716 +0200
@@ -10422,10 +10422,35 @@ expand_expr_real_1 (tree exp, rtx target
 	  {
 	    if (bitpos == 0
 		&& bitsize == GET_MODE_BITSIZE (GET_MODE (op0))
-		&& COMPLEX_MODE_P (mode1))
+		&& COMPLEX_MODE_P (mode1)
+		&& COMPLEX_MODE_P (GET_MODE (op0))
+		&& (GET_MODE_PRECISION (GET_MODE_INNER (mode1))
+		    == GET_MODE_PRECISION (GET_MODE_INNER (GET_MODE (op0)))))
 	      {
 		if (reversep)
 		  op0 = flip_storage_order (GET_MODE (op0), op0);
+		if (mode1 != GET_MODE (op0))
+		  {
+		    rtx parts[2];
+		    for (int i = 0; i < 2; i++)
+		      {
+			rtx op = read_complex_part (op0, i != 0);
+			if (GET_CODE (op) == SUBREG)
+			  op = force_reg (GET_MODE (op), op);
+			rtx temp = gen_lowpart_common (GET_MODE_INNER (mode1),
+						       op);
+			if (temp)
+			  op = temp;
+			else
+			  {
+			    if (!REG_P (op) && !MEM_P (op))
+			      op = force_reg (GET_MODE (op), op);
+			    op = gen_lowpart (GET_MODE_INNER (mode1), op);
+			  }
+			parts[i] = op;
+		      }
+		    op0 = gen_rtx_CONCAT (mode1, parts[0], parts[1]);
+		  }
 		return op0;
 	      }
 	    if (bitpos == 0
--- gcc/testsuite/g++.dg/torture/pr77919-2.C.jj	2016-10-28 10:35:49.294798140 +0200
+++ gcc/testsuite/g++.dg/torture/pr77919-2.C	2016-10-28 10:29:38.000000000 +0200
@@ -0,0 +1,10 @@
+// PR rtl-optimization/77919
+// { dg-do compile }
+
+typedef _Complex long long B;
+struct A { A (double) {} _Complex double i; };
+typedef struct { B b; } C;
+struct D { D (const B &x) : b (x) {} B b; };
+static inline B foo (const double *x) { C *a; a = (C *) x; return a->b; }
+static inline D baz (const A &x) { return foo ((double *) &x); }
+D b = baz (0);


	Jakub



More information about the Gcc-patches mailing list