+/* Helper function for tree_add_const_value_attribute. Natively encode
+ initializer INIT into an array. Return true if successful. */
+
+static bool
+native_encode_initializer (tree init, unsigned char *array, int size)
+{
+ tree type;
+
+ if (init == NULL_TREE)
+ return false;
+
+ STRIP_NOPS (init);
+ switch (TREE_CODE (init))
+ {
+ case STRING_CST:
+ type = TREE_TYPE (init);
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree enttype = TREE_TYPE (type);
+ enum machine_mode mode = TYPE_MODE (enttype);
+
+ if (GET_MODE_CLASS (mode) != MODE_INT || GET_MODE_SIZE (mode) != 1)
+ return false;
+ if (int_size_in_bytes (type) != size)
+ return false;
+ if (size > TREE_STRING_LENGTH (init))
+ {
+ memcpy (array, TREE_STRING_POINTER (init),
+ TREE_STRING_LENGTH (init));
+ memset (array + TREE_STRING_LENGTH (init),
+ '\0', size - TREE_STRING_LENGTH (init));
+ }
+ else
+ memcpy (array, TREE_STRING_POINTER (init), size);
+ return true;
+ }
+ return false;
+ case CONSTRUCTOR:
+ type = TREE_TYPE (init);
+ if (int_size_in_bytes (type) != size)
+ return false;
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ HOST_WIDE_INT min_index;
+ unsigned HOST_WIDE_INT cnt;
+ int curpos = 0, fieldsize;
+ constructor_elt *ce;
+
+ if (TYPE_DOMAIN (type) == NULL_TREE
+ || !host_integerp (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), 0))
+ return false;
+
+ fieldsize = int_size_in_bytes (TREE_TYPE (type));
+ if (fieldsize <= 0)
+ return false;
+
+ min_index = tree_low_cst (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), 0);
+ memset (array, '\0', size);
+ for (cnt = 0;
+ VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce);
+ cnt++)
+ {
+ tree val = ce->value;
+ tree index = ce->index;
+ int pos = curpos;
+ if (index && TREE_CODE (index) == RANGE_EXPR)
+ pos = (tree_low_cst (TREE_OPERAND (index, 0), 0) - min_index)
+ * fieldsize;
+ else if (index)
+ pos = (tree_low_cst (index, 0) - min_index) * fieldsize;
+
+ if (val)
+ {
+ STRIP_NOPS (val);
+ if (!native_encode_initializer (val, array + pos, fieldsize))
+ return false;
+ }
+ curpos = pos + fieldsize;
+ if (index && TREE_CODE (index) == RANGE_EXPR)
+ {
+ int count = tree_low_cst (TREE_OPERAND (index, 1), 0)
+ - tree_low_cst (TREE_OPERAND (index, 0), 0);
+ while (count > 0)
+ {
+ if (val)
+ memcpy (array + curpos, array + pos, fieldsize);
+ curpos += fieldsize;
+ }
+ }
+ gcc_assert (curpos <= size);
+ }
+ return true;
+ }
+ else if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ {
+ tree field = NULL_TREE;
+ unsigned HOST_WIDE_INT cnt;
+ constructor_elt *ce;
+
+ if (int_size_in_bytes (type) != size)
+ return false;
+
+ if (TREE_CODE (type) == RECORD_TYPE)
+ field = TYPE_FIELDS (type);
+
+ for (cnt = 0;
+ VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce);
+ cnt++, field = field ? TREE_CHAIN (field) : 0)
+ {
+ tree val = ce->value;
+ int pos, fieldsize;
+
+ if (ce->index != 0)
+ field = ce->index;
+
+ if (val)
+ STRIP_NOPS (val);
+
+ if (field == NULL_TREE || DECL_BIT_FIELD (field))
+ return false;
+
+ if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+ && TYPE_DOMAIN (TREE_TYPE (field))
+ && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
+ return false;
+ else if (DECL_SIZE_UNIT (field) == NULL_TREE
+ || !host_integerp (DECL_SIZE_UNIT (field), 0))
+ return false;
+ fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 0);
+ pos = int_byte_position (field);
+ gcc_assert (pos + fieldsize <= size);
+ if (val
+ && !native_encode_initializer (val, array + pos, fieldsize))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ case VIEW_CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ return native_encode_initializer (TREE_OPERAND (init, 0), array, size);
+ default:
+ return native_encode_expr (init, array, size) == size;
+ }
+}
+