diff mbox

Fix PR52584, fold sub-vector selects with BIT_FIELD_REF

Message ID alpine.LNX.2.00.1203161342520.27160@zhemvz.fhfr.qr
State New
Headers show

Commit Message

Richard Biener March 16, 2012, 12:44 p.m. UTC
At least generic vector lowering can end up using BIT_FIELD_REF
to generate sub-vector selects such as low/high part of vector
constants/constructors.  We do not fold these currently, leading
to quite absymal code.  Thus the following patch which teaches
fold to do this.

Bootstrap and regtest pending on x86_64-unknown-linux-gnu.

Richard.

2012-03-16  Richard Guenther  <rguenther@suse.de>

	PR middle-end/52584
	* fold-const.c (fold_ternary_loc): Fold vector typed BIT_FIELD_REFs
	of vector constants and constructors.
diff mbox

Patch

Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 185465)
+++ gcc/fold-const.c	(working copy)
@@ -13920,22 +13946,55 @@  fold_ternary_loc (location_t loc, enum t
     case BIT_FIELD_REF:
       if ((TREE_CODE (arg0) == VECTOR_CST
 	   || TREE_CODE (arg0) == CONSTRUCTOR)
-	  && type == TREE_TYPE (TREE_TYPE (arg0)))
-	{
-	  unsigned HOST_WIDE_INT width = tree_low_cst (arg1, 1);
+	  && (type == TREE_TYPE (TREE_TYPE (arg0))))
+	      || (TREE_CODE (type) == VECTOR_TYPE
+		  && TREE_TYPE (type) == TREE_TYPE (TREE_TYPE (arg0)))))
+	{
+	  tree eltype = TREE_TYPE (TREE_TYPE (arg0));
+	  unsigned HOST_WIDE_INT width = tree_low_cst (TYPE_SIZE (eltype), 1);
+	  unsigned HOST_WIDE_INT n = tree_low_cst (arg1, 1);
 	  unsigned HOST_WIDE_INT idx = tree_low_cst (op2, 1);
 
-	  if (width != 0
-	      && simple_cst_equal (arg1, TYPE_SIZE (type)) == 1
+	  if (n != 0
 	      && (idx % width) == 0
-	      && (idx = idx / width)
-		 < TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))
+	      && (n % width) == 0
+	      && ((idx + n) / width) <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))
 	    {
-	      if (TREE_CODE (arg0) == VECTOR_CST)
-		return VECTOR_CST_ELT (arg0, idx);
-	      else if (idx < CONSTRUCTOR_NELTS (arg0))
-		return CONSTRUCTOR_ELT (arg0, idx)->value;
-	      return build_zero_cst (type);
+	      idx = idx / width;
+	      n = n / width;
+	      if (TREE_CODE (type) == VECTOR_TYPE)
+		{
+		  if (TREE_CODE (arg0) == VECTOR_CST)
+		    {
+		      tree *vals = XALLOCAVEC (tree, n);
+		      unsigned i;
+		      for (i = 0; i < n; ++i)
+			vals[i] = VECTOR_CST_ELT (arg0, idx + i);
+		      return build_vector (type, vals);
+		    }
+		  else
+		    {
+		      VEC(constructor_elt, gc) *vals;
+		      unsigned i;
+		      if (CONSTRUCTOR_NELTS (arg0) == 0)
+			return build_constructor (type, NULL);
+		      vals = VEC_alloc (constructor_elt, gc, n);
+		      for (i = 0; i < n && idx + i < CONSTRUCTOR_NELTS (arg0);
+			   ++i)
+			CONSTRUCTOR_APPEND_ELT (vals, NULL_TREE,
+						CONSTRUCTOR_ELT
+						  (arg0, idx + i)->value);
+		      return build_constructor (type, vals);
+		    }
+		}
+	      else if (n == 1)
+		{
+		  if (TREE_CODE (arg0) == VECTOR_CST)
+		    return VECTOR_CST_ELT (arg0, idx);
+		  else if (idx < CONSTRUCTOR_NELTS (arg0))
+		    return CONSTRUCTOR_ELT (arg0, idx)->value;
+		  return build_zero_cst (type);
+		}
 	    }
 	}