hash_table<pad_type_hasher> *pad_type_hash_table;
static tree merge_sizes (tree, tree, tree, bool, bool);
+static tree fold_bit_position (const_tree);
static tree compute_related_constant (tree, tree);
static tree split_plus (tree, tree *);
static tree float_type_for_precision (int, machine_mode);
{
tree field_type = TREE_TYPE (old_field);
tree field_name = DECL_NAME (old_field);
- tree curpos = bit_position (old_field);
+ tree curpos = fold_bit_position (old_field);
tree pos, new_field;
bool var = false;
unsigned int align = 0;
- /* We're going to do some pattern matching below so remove as many
- conversions as possible. */
- curpos = remove_conversions (curpos, true);
-
/* See how the position was modified from the last position.
There are two basic cases we support: a value was added
is when there are other components at fixed positions after
it (meaning there was a rep clause for every field) and we
want to be able to encode them. */
- last_pos = size_binop (PLUS_EXPR, bit_position (old_field),
+ last_pos = size_binop (PLUS_EXPR, curpos,
(TREE_CODE (TREE_TYPE (old_field))
== QUAL_UNION_TYPE)
? bitsize_zero_node
return new_size;
}
+/* Return the bit position of FIELD, in bits from the start of the record,
+ and fold it as much as possible. This is a tree of type bitsizetype. */
+
+static tree
+fold_bit_position (const_tree field)
+{
+ tree offset = DECL_FIELD_OFFSET (field);
+ if (TREE_CODE (offset) == MULT_EXPR || TREE_CODE (offset) == PLUS_EXPR)
+ offset = size_binop (TREE_CODE (offset),
+ fold_convert (bitsizetype, TREE_OPERAND (offset, 0)),
+ fold_convert (bitsizetype, TREE_OPERAND (offset, 1)));
+ else
+ offset = fold_convert (bitsizetype, offset);
+ return size_binop (PLUS_EXPR, DECL_FIELD_BIT_OFFSET (field),
+ size_binop (MULT_EXPR, offset, bitsize_unit_node));
+}
+
/* Utility function of above to see if OP0 and OP1, both of SIZETYPE, are
related by the addition of a constant. Return that constant if so. */
static tree
compute_related_constant (tree op0, tree op1)
{
- tree op0_var, op1_var;
- tree op0_con = split_plus (op0, &op0_var);
- tree op1_con = split_plus (op1, &op1_var);
- tree result = size_binop (MINUS_EXPR, op0_con, op1_con);
+ tree factor, op0_var, op1_var, op0_cst, op1_cst, result;
- if (operand_equal_p (op0_var, op1_var, 0))
- return result;
- else if (operand_equal_p (op0, size_binop (PLUS_EXPR, op1_var, result), 0))
- return result;
+ if (TREE_CODE (op0) == MULT_EXPR
+ && TREE_CODE (op1) == MULT_EXPR
+ && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST
+ && TREE_OPERAND (op1, 1) == TREE_OPERAND (op0, 1))
+ {
+ factor = TREE_OPERAND (op0, 1);
+ op0 = TREE_OPERAND (op0, 0);
+ op1 = TREE_OPERAND (op1, 0);
+ }
else
- return 0;
+ factor = NULL_TREE;
+
+ op0_cst = split_plus (op0, &op0_var);
+ op1_cst = split_plus (op1, &op1_var);
+ result = size_binop (MINUS_EXPR, op0_cst, op1_cst);
+
+ if (operand_equal_p (op0_var, op1_var, 0))
+ return factor ? size_binop (MULT_EXPR, factor, result) : result;
+
+ return NULL_TREE;
}
/* Utility function of above to split a tree OP which may be a sum, into a