+/* Construct a MEM_REF that would reference a part of aggregate BASE of type
+ EXP_TYPE at the given OFFSET. If BASE is something for which
+ get_addr_base_and_unit_offset returns NULL, gsi must be non-NULL and is used
+ to insert new statements either before or below the current one as specified
+ by INSERT_AFTER. This function is not capable of handling bitfields. */
+
+tree
+build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
+ tree exp_type, gimple_stmt_iterator *gsi,
+ bool insert_after)
+{
+ tree prev_base = base;
+ tree off;
+ HOST_WIDE_INT base_offset;
+
+ gcc_checking_assert (offset % BITS_PER_UNIT == 0);
+
+ base = get_addr_base_and_unit_offset (base, &base_offset);
+
+ /* get_addr_base_and_unit_offset returns NULL for references with a variable
+ offset such as array[var_index]. */
+ if (!base)
+ {
+ gimple stmt;
+ tree tmp, addr;
+
+ gcc_checking_assert (gsi);
+ tmp = create_tmp_reg (build_pointer_type (TREE_TYPE (prev_base)), NULL);
+ add_referenced_var (tmp);
+ tmp = make_ssa_name (tmp, NULL);
+ addr = build_fold_addr_expr (unshare_expr (prev_base));
+ stmt = gimple_build_assign (tmp, addr);
+ gimple_set_location (stmt, loc);
+ SSA_NAME_DEF_STMT (tmp) = stmt;
+ if (insert_after)
+ gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
+ else
+ gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+ update_stmt (stmt);
+
+ off = build_int_cst (reference_alias_ptr_type (prev_base),
+ offset / BITS_PER_UNIT);
+ base = tmp;
+ }
+ else if (TREE_CODE (base) == MEM_REF)
+ {
+ off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)),
+ base_offset + offset / BITS_PER_UNIT);
+ off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off, 0);
+ base = unshare_expr (TREE_OPERAND (base, 0));
+ }
+ else
+ {
+ off = build_int_cst (reference_alias_ptr_type (base),
+ base_offset + offset / BITS_PER_UNIT);
+ base = build_fold_addr_expr (unshare_expr (base));
+ }
+
+ return fold_build2_loc (loc, MEM_REF, exp_type, base, off);
+}
+
+/* Construct a memory reference to a part of an aggregate BASE at the given
+ OFFSET and of the same type as MODEL. In case this is a reference to a
+ component, the function will replicate the last COMPONENT_REF of model's
+ expr to access it. GSI and INSERT_AFTER have the same meaning as in
+ build_ref_for_offset. */
+
+static tree
+build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
+ struct access *model, gimple_stmt_iterator *gsi,
+ bool insert_after)
+{
+ if (TREE_CODE (model->expr) == COMPONENT_REF)
+ {
+ tree t, exp_type;
+ offset -= int_bit_position (TREE_OPERAND (model->expr, 1));
+ exp_type = TREE_TYPE (TREE_OPERAND (model->expr, 0));
+ t = build_ref_for_offset (loc, base, offset, exp_type, gsi, insert_after);
+ return fold_build3_loc (loc, COMPONENT_REF, model->type, t,
+ TREE_OPERAND (model->expr, 1), NULL_TREE);
+ }
+ else
+ return build_ref_for_offset (loc, base, offset, model->type,
+ gsi, insert_after);
+}
+
+/* Construct a memory reference consisting of component_refs and array_refs to
+ a part of an aggregate *RES (which is of type TYPE). The requested part
+ should have type EXP_TYPE at be the given OFFSET. This function might not
+ succeed, it returns true when it does and only then *RES points to something
+ meaningful. This function should be used only to build expressions that we
+ might need to present to user (e.g. in warnings). In all other situations,
+ build_ref_for_model or build_ref_for_offset should be used instead. */