. */
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.
Returns a sequence of statements that replace STMT and also contain
a modified form of STMT itself. */
gimple_seq
rewrite_to_defined_overflow (gimple *stmt)
{
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);
gimple_seq_add_stmt (&stmts, stmt);
gimple *cvt = gimple_build_assign (lhs, NOP_EXPR, gimple_assign_lhs (stmt));
gimple_seq_add_stmt (&stmts, cvt);
return stmts;
}
/* 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;
}
/* Build the expression CODE OP0 of type TYPE with location LOC,
simplifying it first if possible. Returns the built
expression value and appends statements possibly defining it
to SEQ. */
tree
gimple_build (gimple_seq *seq, location_t loc,
enum tree_code code, tree type, tree op0)
{
tree res = gimple_simplify (code, type, op0, seq, 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);
}
return res;
}
/* Build the expression OP0 CODE OP1 of type TYPE with location LOC,
simplifying it first if possible. Returns the built
expression value and appends statements possibly defining it
to SEQ. */
tree
gimple_build (gimple_seq *seq, location_t loc,
enum tree_code code, tree type, tree op0, tree op1)
{
tree res = gimple_simplify (code, type, op0, op1, seq, 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);
}
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 and appends statements possibly defining it
to SEQ. */
tree
gimple_build (gimple_seq *seq, location_t loc,
enum tree_code code, tree type, tree op0, tree op1, tree op2)
{
tree res = gimple_simplify (code, type, op0, op1, op2,
seq, 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);
}
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) and appends
statements possibly defining it to SEQ. */
tree
gimple_build (gimple_seq *seq, location_t loc, combined_fn fn,
tree type, tree arg0)
{
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);
}
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) and appends
statements possibly defining it to SEQ. */
tree
gimple_build (gimple_seq *seq, location_t loc, combined_fn fn,
tree type, tree arg0, tree arg1)
{
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);
}
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) and appends
statements possibly defining it to SEQ. */
tree
gimple_build (gimple_seq *seq, location_t loc, combined_fn fn,
tree type, tree arg0, tree arg1, tree arg2)
{
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);
}
return res;
}
/* 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 value and appends
statements possibly defining it to SEQ. */
tree
gimple_convert (gimple_seq *seq, location_t loc, tree type, tree op)
{
if (useless_type_conversion_p (type, TREE_TYPE (op)))
return op;
return gimple_build (seq, 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 and appends
statements possibly defining it to SEQ. */
tree
gimple_convert_to_ptrofftype (gimple_seq *seq, location_t loc, tree op)
{
if (ptrofftype_p (TREE_TYPE (op)))
return op;
return gimple_convert (seq, loc, sizetype, op);
}
/* Build a vector of type TYPE in which each element has the value OP.
Return a gimple value for the result, appending any new statements
to SEQ. */
tree
gimple_build_vector_from_val (gimple_seq *seq, location_t loc, tree type,
tree op)
{
if (!TYPE_VECTOR_SUBPARTS (type).is_constant ()
&& !CONSTANT_CLASS_P (op))
return gimple_build (seq, 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 *stmt = gimple_build_assign (res, vec);
gimple_set_location (stmt, loc);
gimple_seq_add_stmt_without_update (seq, stmt);
return res;
}
/* Build a vector from BUILDER, handling the case in which some elements
are non-constant. Return a gimple value for the result, appending any
new instructions to SEQ.
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_seq *seq, 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 (!TREE_CONSTANT ((*builder)[i]))
{
tree type = builder->type ();
unsigned int nelts = TYPE_VECTOR_SUBPARTS (type).to_constant ();
vec