+/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE->field_of_orig_type
+ or BASE[index] or by combination of those.
+
+ Before attempting the conversion strip off existing ADDR_EXPRs and
+ handled component refs. */
+
+tree
+maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
+{
+ tree ret;
+ tree type;
+ bool base_is_ptr = true;
+
+ STRIP_NOPS (base);
+ if (TREE_CODE (base) == ADDR_EXPR)
+ {
+ base_is_ptr = false;
+
+ base = TREE_OPERAND (base, 0);
+
+ /* Handle case where existing COMPONENT_REF pick e.g. wrong field of union,
+ so it needs to be removed and new COMPONENT_REF constructed.
+ The wrong COMPONENT_REF are often constructed by folding the
+ (type *)&object within the expression (type *)&object+offset */
+ if (handled_component_p (base) && 0)
+ {
+ HOST_WIDE_INT sub_offset, size, maxsize;
+ tree newbase;
+ newbase = get_ref_base_and_extent (base, &sub_offset,
+ &size, &maxsize);
+ gcc_assert (newbase);
+ gcc_assert (!(sub_offset & (BITS_PER_UNIT - 1)));
+ if (size == maxsize)
+ {
+ base = newbase;
+ if (sub_offset)
+ offset = int_const_binop (PLUS_EXPR, offset,
+ build_int_cst (TREE_TYPE (offset),
+ sub_offset / BITS_PER_UNIT), 1);
+ }
+ }
+ if (useless_type_conversion_p (orig_type, TREE_TYPE (base))
+ && integer_zerop (offset))
+ return base;
+ type = TREE_TYPE (base);
+ }
+ else
+ {
+ base_is_ptr = true;
+ if (!POINTER_TYPE_P (TREE_TYPE (base)))
+ return NULL_TREE;
+ type = TREE_TYPE (TREE_TYPE (base));
+ }
+ ret = maybe_fold_offset_to_component_ref (type, base, offset,
+ orig_type, base_is_ptr);
+ if (!ret)
+ {
+ if (base_is_ptr)
+ base = build1 (INDIRECT_REF, type, base);
+ ret = maybe_fold_offset_to_array_ref (base, offset, orig_type);
+ }
+ return ret;
+}