. */
if (TREE_CODE (addr) != ADDR_EXPR
|| DECL_P (TREE_OPERAND (addr, 0)))
return fold_build2 (MEM_REF, type,
addr,
wide_int_to_tree (ptype, wi::to_wide (off)));
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (subtype)))) == INTEGER_CST
&& useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (subtype))))
{
tree type_domain;
tree min_val = size_zero_node;
tree osub = sub;
sub = gimple_fold_indirect_ref (sub);
if (! sub)
sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub);
type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
if (type_domain && TYPE_MIN_VALUE (type_domain))
min_val = TYPE_MIN_VALUE (type_domain);
if (TREE_CODE (min_val) == INTEGER_CST)
return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE);
}
return NULL_TREE;
}
/* Return true if CODE is an operation that when operating on signed
integer types involves undefined behavior on overflow and the
operation can be expressed with unsigned arithmetic. */
bool
arith_code_with_undefined_signed_overflow (tree_code code)
{
switch (code)
{
case ABS_EXPR:
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
case NEGATE_EXPR:
case POINTER_PLUS_EXPR:
return true;
default:
return false;
}
}
/* Rewrite STMT, an assignment with a signed integer or pointer arithmetic
operation that can be transformed to unsigned arithmetic by converting
its operand, carrying out the operation in the corresponding unsigned
type and converting the result back to the original type.
If IN_PLACE is true, *GSI points to STMT, adjust the stmt in place and
return NULL.
Otherwise returns a sequence of statements that replace STMT and also
contain a modified form of STMT itself. */
static gimple_seq
rewrite_to_defined_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
bool in_place)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "rewriting stmt with undefined signed "
"overflow ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
tree lhs = gimple_assign_lhs (stmt);
tree type = unsigned_type_for (TREE_TYPE (lhs));
gimple_seq stmts = NULL;
if (gimple_assign_rhs_code (stmt) == ABS_EXPR)
gimple_assign_set_rhs_code (stmt, ABSU_EXPR);
else
for (unsigned i = 1; i < gimple_num_ops (stmt); ++i)
{
tree op = gimple_op (stmt, i);
op = gimple_convert (&stmts, type, op);
gimple_set_op (stmt, i, op);
}
gimple_assign_set_lhs (stmt, make_ssa_name (type, stmt));
if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
gimple_assign_set_rhs_code (stmt, PLUS_EXPR);
gimple_set_modified (stmt, true);
if (in_place)
{
if (stmts)
gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
stmts = NULL;
}
else
gimple_seq_add_stmt (&stmts, stmt);
gimple *cvt = gimple_build_assign (lhs, NOP_EXPR, gimple_assign_lhs (stmt));
if (in_place)
{
gsi_insert_after (gsi, cvt, GSI_SAME_STMT);
update_stmt (stmt);
}
else
gimple_seq_add_stmt (&stmts, cvt);
return stmts;
}
void
rewrite_to_defined_overflow (gimple_stmt_iterator *gsi)
{
rewrite_to_defined_overflow (gsi, gsi_stmt (*gsi), true);
}
gimple_seq
rewrite_to_defined_overflow (gimple *stmt)
{
return rewrite_to_defined_overflow (nullptr, stmt, false);
}
/* The valueization hook we use for the gimple_build API simplification.
This makes us match fold_buildN behavior by only combining with
statements in the sequence(s) we are currently building. */
static tree
gimple_build_valueize (tree op)
{
if (gimple_bb (SSA_NAME_DEF_STMT (op)) == NULL)
return op;
return NULL_TREE;
}
/* Helper for gimple_build to perform the final insertion of stmts on SEQ. */
static inline void
gimple_build_insert_seq (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
gimple_seq seq)
{
if (before)
{
if (gsi->bb)
gsi_insert_seq_before (gsi, seq, update);
else
gsi_insert_seq_before_without_update (gsi, seq, update);
}
else
{
if (gsi->bb)
gsi_insert_seq_after (gsi, seq, update);
else
gsi_insert_seq_after_without_update (gsi, seq, update);
}
}
/* Build the expression CODE OP0 of type TYPE with location LOC,
simplifying it first if possible. Returns the built
expression value and inserts statements possibly defining it
before GSI if BEFORE is true or after GSI if false and advance
the iterator accordingly.
If gsi refers to a basic block simplifying is allowed to look
at all SSA defs while when it does not it is restricted to
SSA defs that are not associated with a basic block yet,
indicating they belong to the currently building sequence. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, enum tree_code code, tree type, tree op0)
{
gimple_seq seq = NULL;
tree res
= gimple_simplify (code, type, op0, &seq,
gsi->bb ? follow_all_ssa_edges : gimple_build_valueize);
if (!res)
{
res = create_tmp_reg_or_ssa_name (type);
gimple *stmt;
if (code == REALPART_EXPR
|| code == IMAGPART_EXPR
|| code == VIEW_CONVERT_EXPR)
stmt = gimple_build_assign (res, code, build1 (code, type, op0));
else
stmt = gimple_build_assign (res, code, op0);
gimple_set_location (stmt, loc);
gimple_seq_add_stmt_without_update (&seq, stmt);
}
gimple_build_insert_seq (gsi, before, update, seq);
return res;
}
/* Build the expression OP0 CODE OP1 of type TYPE with location LOC,
simplifying it first if possible. Returns the built
expression value inserting any new statements at GSI honoring BEFORE
and UPDATE. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, enum tree_code code, tree type,
tree op0, tree op1)
{
gimple_seq seq = NULL;
tree res
= gimple_simplify (code, type, op0, op1, &seq,
gsi->bb ? follow_all_ssa_edges : gimple_build_valueize);
if (!res)
{
res = create_tmp_reg_or_ssa_name (type);
gimple *stmt = gimple_build_assign (res, code, op0, op1);
gimple_set_location (stmt, loc);
gimple_seq_add_stmt_without_update (&seq, stmt);
}
gimple_build_insert_seq (gsi, before, update, seq);
return res;
}
/* Build the expression (CODE OP0 OP1 OP2) of type TYPE with location LOC,
simplifying it first if possible. Returns the built
expression value inserting any new statements at GSI honoring BEFORE
and UPDATE. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, enum tree_code code, tree type,
tree op0, tree op1, tree op2)
{
gimple_seq seq = NULL;
tree res
= gimple_simplify (code, type, op0, op1, op2, &seq,
gsi->bb ? follow_all_ssa_edges : gimple_build_valueize);
if (!res)
{
res = create_tmp_reg_or_ssa_name (type);
gimple *stmt;
if (code == BIT_FIELD_REF)
stmt = gimple_build_assign (res, code,
build3 (code, type, op0, op1, op2));
else
stmt = gimple_build_assign (res, code, op0, op1, op2);
gimple_set_location (stmt, loc);
gimple_seq_add_stmt_without_update (&seq, stmt);
}
gimple_build_insert_seq (gsi, before, update, seq);
return res;
}
/* Build the call FN () with a result of type TYPE (or no result if TYPE is
void) with a location LOC. Returns the built expression value (or NULL_TREE
if TYPE is void) inserting any new statements at GSI honoring BEFORE
and UPDATE. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, combined_fn fn, tree type)
{
tree res = NULL_TREE;
gimple_seq seq = NULL;
gcall *stmt;
if (internal_fn_p (fn))
stmt = gimple_build_call_internal (as_internal_fn (fn), 0);
else
{
tree decl = builtin_decl_implicit (as_builtin_fn (fn));
stmt = gimple_build_call (decl, 0);
}
if (!VOID_TYPE_P (type))
{
res = create_tmp_reg_or_ssa_name (type);
gimple_call_set_lhs (stmt, res);
}
gimple_set_location (stmt, loc);
gimple_seq_add_stmt_without_update (&seq, stmt);
gimple_build_insert_seq (gsi, before, update, seq);
return res;
}
/* Build the call FN (ARG0) with a result of type TYPE
(or no result if TYPE is void) with location LOC,
simplifying it first if possible. Returns the built
expression value (or NULL_TREE if TYPE is void) inserting any new
statements at GSI honoring BEFORE and UPDATE. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, combined_fn fn,
tree type, tree arg0)
{
gimple_seq seq = NULL;
tree res = gimple_simplify (fn, type, arg0, &seq, gimple_build_valueize);
if (!res)
{
gcall *stmt;
if (internal_fn_p (fn))
stmt = gimple_build_call_internal (as_internal_fn (fn), 1, arg0);
else
{
tree decl = builtin_decl_implicit (as_builtin_fn (fn));
stmt = gimple_build_call (decl, 1, arg0);
}
if (!VOID_TYPE_P (type))
{
res = create_tmp_reg_or_ssa_name (type);
gimple_call_set_lhs (stmt, res);
}
gimple_set_location (stmt, loc);
gimple_seq_add_stmt_without_update (&seq, stmt);
}
gimple_build_insert_seq (gsi, before, update, seq);
return res;
}
/* Build the call FN (ARG0, ARG1) with a result of type TYPE
(or no result if TYPE is void) with location LOC,
simplifying it first if possible. Returns the built
expression value (or NULL_TREE if TYPE is void) inserting any new
statements at GSI honoring BEFORE and UPDATE. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, combined_fn fn,
tree type, tree arg0, tree arg1)
{
gimple_seq seq = NULL;
tree res = gimple_simplify (fn, type, arg0, arg1, &seq,
gimple_build_valueize);
if (!res)
{
gcall *stmt;
if (internal_fn_p (fn))
stmt = gimple_build_call_internal (as_internal_fn (fn), 2, arg0, arg1);
else
{
tree decl = builtin_decl_implicit (as_builtin_fn (fn));
stmt = gimple_build_call (decl, 2, arg0, arg1);
}
if (!VOID_TYPE_P (type))
{
res = create_tmp_reg_or_ssa_name (type);
gimple_call_set_lhs (stmt, res);
}
gimple_set_location (stmt, loc);
gimple_seq_add_stmt_without_update (&seq, stmt);
}
gimple_build_insert_seq (gsi, before, update, seq);
return res;
}
/* Build the call FN (ARG0, ARG1, ARG2) with a result of type TYPE
(or no result if TYPE is void) with location LOC,
simplifying it first if possible. Returns the built
expression value (or NULL_TREE if TYPE is void) inserting any new
statements at GSI honoring BEFORE and UPDATE. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, combined_fn fn,
tree type, tree arg0, tree arg1, tree arg2)
{
gimple_seq seq = NULL;
tree res = gimple_simplify (fn, type, arg0, arg1, arg2,
&seq, gimple_build_valueize);
if (!res)
{
gcall *stmt;
if (internal_fn_p (fn))
stmt = gimple_build_call_internal (as_internal_fn (fn),
3, arg0, arg1, arg2);
else
{
tree decl = builtin_decl_implicit (as_builtin_fn (fn));
stmt = gimple_build_call (decl, 3, arg0, arg1, arg2);
}
if (!VOID_TYPE_P (type))
{
res = create_tmp_reg_or_ssa_name (type);
gimple_call_set_lhs (stmt, res);
}
gimple_set_location (stmt, loc);
gimple_seq_add_stmt_without_update (&seq, stmt);
}
gimple_build_insert_seq (gsi, before, update, seq);
return res;
}
/* Build CODE (OP0) with a result of type TYPE (or no result if TYPE is
void) with location LOC, simplifying it first if possible. Returns the
built expression value (or NULL_TREE if TYPE is void) inserting any new
statements at GSI honoring BEFORE and UPDATE. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, code_helper code, tree type, tree op0)
{
if (code.is_tree_code ())
return gimple_build (gsi, before, update, loc, tree_code (code), type, op0);
return gimple_build (gsi, before, update, loc, combined_fn (code), type, op0);
}
/* Build CODE (OP0, OP1) with a result of type TYPE (or no result if TYPE is
void) with location LOC, simplifying it first if possible. Returns the
built expression value (or NULL_TREE if TYPE is void) inserting any new
statements at GSI honoring BEFORE and UPDATE. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, code_helper code, tree type, tree op0, tree op1)
{
if (code.is_tree_code ())
return gimple_build (gsi, before, update,
loc, tree_code (code), type, op0, op1);
return gimple_build (gsi, before, update,
loc, combined_fn (code), type, op0, op1);
}
/* Build CODE (OP0, OP1, OP2) with a result of type TYPE (or no result if TYPE
is void) with location LOC, simplifying it first if possible. Returns the
built expression value (or NULL_TREE if TYPE is void) inserting any new
statements at GSI honoring BEFORE and UPDATE. */
tree
gimple_build (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, code_helper code,
tree type, tree op0, tree op1, tree op2)
{
if (code.is_tree_code ())
return gimple_build (gsi, before, update,
loc, tree_code (code), type, op0, op1, op2);
return gimple_build (gsi, before, update,
loc, combined_fn (code), type, op0, op1, op2);
}
/* Build the conversion (TYPE) OP with a result of type TYPE
with location LOC if such conversion is neccesary in GIMPLE,
simplifying it first.
Returns the built expression inserting any new statements
at GSI honoring BEFORE and UPDATE. */
tree
gimple_convert (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, tree type, tree op)
{
if (useless_type_conversion_p (type, TREE_TYPE (op)))
return op;
return gimple_build (gsi, before, update, loc, NOP_EXPR, type, op);
}
/* Build the conversion (ptrofftype) OP with a result of a type
compatible with ptrofftype with location LOC if such conversion
is neccesary in GIMPLE, simplifying it first.
Returns the built expression value inserting any new statements
at GSI honoring BEFORE and UPDATE. */
tree
gimple_convert_to_ptrofftype (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, tree op)
{
if (ptrofftype_p (TREE_TYPE (op)))
return op;
return gimple_convert (gsi, before, update, loc, sizetype, op);
}
/* Build a vector of type TYPE in which each element has the value OP.
Return a gimple value for the result, inserting any new statements
at GSI honoring BEFORE and UPDATE. */
tree
gimple_build_vector_from_val (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, tree type, tree op)
{
if (!TYPE_VECTOR_SUBPARTS (type).is_constant ()
&& !CONSTANT_CLASS_P (op))
return gimple_build (gsi, before, update,
loc, VEC_DUPLICATE_EXPR, type, op);
tree res, vec = build_vector_from_val (type, op);
if (is_gimple_val (vec))
return vec;
if (gimple_in_ssa_p (cfun))
res = make_ssa_name (type);
else
res = create_tmp_reg (type);
gimple_seq seq = NULL;
gimple *stmt = gimple_build_assign (res, vec);
gimple_set_location (stmt, loc);
gimple_seq_add_stmt_without_update (&seq, stmt);
gimple_build_insert_seq (gsi, before, update, seq);
return res;
}
/* Build a vector from BUILDER, handling the case in which some elements
are non-constant. Return a gimple value for the result, inserting
any new instructions to GSI honoring BEFORE and UPDATE.
BUILDER must not have a stepped encoding on entry. This is because
the function is not geared up to handle the arithmetic that would
be needed in the variable case, and any code building a vector that
is known to be constant should use BUILDER->build () directly. */
tree
gimple_build_vector (gimple_stmt_iterator *gsi,
bool before, gsi_iterator_update update,
location_t loc, tree_vector_builder *builder)
{
gcc_assert (builder->nelts_per_pattern () <= 2);
unsigned int encoded_nelts = builder->encoded_nelts ();
for (unsigned int i = 0; i < encoded_nelts; ++i)
if (!CONSTANT_CLASS_P ((*builder)[i]))
{
gimple_seq seq = NULL;
tree type = builder->type ();
unsigned int nelts = TYPE_VECTOR_SUBPARTS (type).to_constant ();
vec