===================================================================
@@ -14074,66 +14074,76 @@ fold_ternary_loc (location_t loc, enum t
unsigned HOST_WIDE_INT n = tree_low_cst (arg1, 1);
unsigned HOST_WIDE_INT idx = tree_low_cst (op2, 1);
if (n != 0
&& (idx % width) == 0
&& (n % width) == 0
&& ((idx + n) / width) <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))
{
idx = idx / width;
n = n / width;
- if (TREE_CODE (type) == VECTOR_TYPE)
+
+ if (TREE_CODE (arg0) == VECTOR_CST)
{
- 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, va_gc> *vals;
- unsigned i;
- if (CONSTRUCTOR_NELTS (arg0) == 0)
- return build_constructor (type,
- NULL);
- if (TREE_CODE (TREE_TYPE (CONSTRUCTOR_ELT (arg0,
- 0)->value))
- != VECTOR_TYPE)
- {
- vec_alloc (vals, 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);
- }
- }
+ if (n == 1)
+ return VECTOR_CST_ELT (arg0, idx);
+
+ tree *vals = XALLOCAVEC (tree, n);
+ for (unsigned i = 0; i < n; ++i)
+ vals[i] = VECTOR_CST_ELT (arg0, idx + i);
+ return build_vector (type, vals);
}
- else if (n == 1)
+
+ /* Constructor elements can be subvectors. */
+ unsigned HOST_WIDE_INT k = 1;
+ if (CONSTRUCTOR_NELTS (arg0) != 0)
{
- if (TREE_CODE (arg0) == VECTOR_CST)
- return VECTOR_CST_ELT (arg0, idx);
- else if (CONSTRUCTOR_NELTS (arg0) == 0)
- return build_zero_cst (type);
- else if (TREE_CODE (TREE_TYPE (CONSTRUCTOR_ELT (arg0,
- 0)->value))
- != VECTOR_TYPE)
+ tree cons_elem = TREE_TYPE (CONSTRUCTOR_ELT (arg0, 0)->value);
+ if (TREE_CODE (cons_elem) == VECTOR_TYPE)
+ k = TYPE_VECTOR_SUBPARTS (cons_elem);
+ }
+
+ /* We keep an exact subset of the constructor elements. */
+ if ((idx % k) == 0 && (n % k) == 0)
+ {
+ if (CONSTRUCTOR_NELTS (arg0) == 0)
+ return build_constructor (type, NULL);
+ idx /= k;
+ n /= k;
+ if (n == 1)
{
if (idx < CONSTRUCTOR_NELTS (arg0))
return CONSTRUCTOR_ELT (arg0, idx)->value;
return build_zero_cst (type);
}
+
+ vec<constructor_elt, va_gc> *vals;
+ vec_alloc (vals, n);
+ for (unsigned 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);
+ }
+ /* The bitfield references a single constructor element. */
+ else if (idx + n <= (idx / k + 1) * k)
+ {
+ if (CONSTRUCTOR_NELTS (arg0) <= idx / k)
+ return build_zero_cst (type);
+ else if (n == k)
+ return CONSTRUCTOR_ELT (arg0, idx / k)->value;
+ else
+ return fold_build3_loc (loc, code, type,
+ CONSTRUCTOR_ELT (arg0, idx / k)->value, op1,
+ build_int_cst (TREE_TYPE (op2), (idx % k) * width));
}
}
}
/* A bit-field-ref that referenced the full argument can be stripped. */
if (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
&& TYPE_PRECISION (TREE_TYPE (arg0)) == tree_low_cst (arg1, 1)
&& integer_zerop (op2))
return fold_convert_loc (loc, type, arg0);
===================================================================
@@ -604,24 +604,38 @@ valid_gimple_rhs_p (tree expr)
break;
}
return false;
}
break;
case tcc_vl_exp:
return false;
case tcc_exceptional:
+ if (code == CONSTRUCTOR)
+ {
+ unsigned i;
+ tree elt;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), i, elt)
+ if (!is_gimple_val (elt))
+ return false;
+ return true;
+ }
if (code != SSA_NAME)
return false;
break;
+ case tcc_reference:
+ if (code == BIT_FIELD_REF)
+ return is_gimple_val (TREE_OPERAND (expr, 0));
+ return false;
+
default:
return false;
}
return true;
}
/* Return true if EXPR is a CALL_EXPR suitable for representation
as a single GIMPLE_CALL statement. If the arguments require