/* Fold a constant sub-tree into a single node for C-compiler
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
static tree const_binop (enum tree_code, tree, tree, int);
static enum comparison_code comparison_to_compcode (enum tree_code);
static enum tree_code compcode_to_comparison (enum comparison_code);
-static tree combine_comparisons (enum tree_code, enum tree_code,
- enum tree_code, tree, tree, tree);
static int operand_equal_for_comparison_p (tree, tree, tree);
static int twoval_comparison_p (tree, tree *, tree *, int *);
static tree eval_subst (tree, tree, tree, tree, tree);
}
/* Build an expression for the address of T. Folds away INDIRECT_REF
- to avoid confusing the gimplify process. When IN_FOLD is true
- avoid modifications of T. */
+ to avoid confusing the gimplify process. */
-static tree
-build_fold_addr_expr_with_type_1 (tree t, tree ptrtype, bool in_fold)
+tree
+build_fold_addr_expr_with_type (tree t, tree ptrtype)
{
/* The size of the object is not relevant when talking about its address. */
if (TREE_CODE (t) == WITH_SIZE_EXPR)
if (TREE_TYPE (t) != ptrtype)
t = build1 (NOP_EXPR, ptrtype, t);
}
- else if (!in_fold)
- {
- tree base = t;
-
- while (handled_component_p (base))
- base = TREE_OPERAND (base, 0);
-
- if (DECL_P (base))
- TREE_ADDRESSABLE (base) = 1;
-
- t = build1 (ADDR_EXPR, ptrtype, t);
- }
else
t = build1 (ADDR_EXPR, ptrtype, t);
return t;
}
-/* Build an expression for the address of T with type PTRTYPE. This
- function modifies the input parameter 'T' by sometimes setting the
- TREE_ADDRESSABLE flag. */
-
-tree
-build_fold_addr_expr_with_type (tree t, tree ptrtype)
-{
- return build_fold_addr_expr_with_type_1 (t, ptrtype, false);
-}
-
-/* Build an expression for the address of T. This function modifies
- the input parameter 'T' by sometimes setting the TREE_ADDRESSABLE
- flag. When called from fold functions, use fold_addr_expr instead. */
+/* Build an expression for the address of T. */
tree
build_fold_addr_expr (tree t)
{
- return build_fold_addr_expr_with_type_1 (t,
- build_pointer_type (TREE_TYPE (t)),
- false);
-}
-
-/* Same as build_fold_addr_expr, builds an expression for the address
- of T, but avoids touching the input node 't'. Fold functions
- should use this version. */
-
-static tree
-fold_addr_expr (tree t)
-{
tree ptrtype = build_pointer_type (TREE_TYPE (t));
- return build_fold_addr_expr_with_type_1 (t, ptrtype, true);
+ return build_fold_addr_expr_with_type (t, ptrtype);
}
/* Fold a unary expression of code CODE and type TYPE with operand
&& inter_prec >= final_prec)
return fold_build1 (code, type, TREE_OPERAND (op0, 0));
- /* Likewise, if the intermediate and final types are either both
- float or both integer, we don't need the middle conversion if
- it is wider than the final type and doesn't change the signedness
- (for integers). Avoid this if the final type is a pointer
- since then we sometimes need the inner conversion. Likewise if
- the outer has a precision not equal to the size of its mode. */
+ /* Likewise, if the intermediate and initial types are either both
+ float or both integer, we don't need the middle conversion if the
+ former is wider than the latter and doesn't change the signedness
+ (for integers). Avoid this if the final type is a pointer since
+ then we sometimes need the middle conversion. Likewise if the
+ final type has a precision not equal to the size of its mode. */
if (((inter_int && inside_int)
|| (inter_float && inside_float)
|| (inter_vec && inside_vec))
if (! offset && bitpos == 0
&& TYPE_MAIN_VARIANT (TREE_TYPE (type))
== TYPE_MAIN_VARIANT (TREE_TYPE (base)))
- return fold_convert (type, fold_addr_expr (base));
+ return fold_convert (type, build_fold_addr_expr (base));
}
if (TREE_CODE (op0) == MODIFY_EXPR
} /* switch (code) */
}
+
+/* If the operation was a conversion do _not_ mark a resulting constant
+ with TREE_OVERFLOW if the original constant was not. These conversions
+ have implementation defined behavior and retaining the TREE_OVERFLOW
+ flag here would confuse later passes such as VRP. */
+tree
+fold_unary_ignore_overflow (enum tree_code code, tree type, tree op0)
+{
+ tree res = fold_unary (code, type, op0);
+ if (res
+ && TREE_CODE (res) == INTEGER_CST
+ && TREE_CODE (op0) == INTEGER_CST
+ && CONVERT_EXPR_CODE_P (code))
+ TREE_OVERFLOW (res) = TREE_OVERFLOW (op0);
+
+ return res;
+}
+
/* Fold a binary expression of code CODE and type TYPE with operands
OP0 and OP1, containing either a MIN-MAX or a MAX-MIN combination.
Return the folded expression if folding is successful. Otherwise,
&& operand_equal_p (offset0, offset1, 0))))
{
if (indirect_base0)
- base0 = fold_addr_expr (base0);
+ base0 = build_fold_addr_expr (base0);
if (indirect_base1)
- base1 = fold_addr_expr (base1);
+ base1 = build_fold_addr_expr (base1);
return fold_build2 (code, type, base0, base1);
}
}
}
/* Fold comparisons against infinity. */
- if (REAL_VALUE_ISINF (cst))
+ if (REAL_VALUE_ISINF (cst)
+ && MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1))))
{
tem = fold_inf_compare (code, type, arg0, arg1);
if (tem != NULL_TREE)
0 <= N < M as is common. In general, the precise value of P is unknown.
M is chosen as large as possible such that constant N can be determined.
- Returns M and sets *RESIDUE to N. */
+ Returns M and sets *RESIDUE to N.
+
+ If ALLOW_FUNC_ALIGN is true, do take functions' DECL_ALIGN_UNIT into
+ account. This is not always possible due to PR 35705.
+ */
static unsigned HOST_WIDE_INT
-get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue)
+get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue,
+ bool allow_func_align)
{
enum tree_code code;
}
}
- if (DECL_P (expr) && TREE_CODE (expr) != FUNCTION_DECL)
+ if (DECL_P (expr)
+ && (allow_func_align || TREE_CODE (expr) != FUNCTION_DECL))
return DECL_ALIGN_UNIT (expr);
}
else if (code == POINTER_PLUS_EXPR)
op0 = TREE_OPERAND (expr, 0);
STRIP_NOPS (op0);
- modulus = get_pointer_modulus_and_residue (op0, residue);
+ modulus = get_pointer_modulus_and_residue (op0, residue,
+ allow_func_align);
op1 = TREE_OPERAND (expr, 1);
STRIP_NOPS (op1);
return NULL_TREE;
case PLUS_EXPR:
- /* PTR + INT -> (INT)(PTR p+ INT) */
- if (POINTER_TYPE_P (TREE_TYPE (arg0))
- && INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
- return fold_convert (type, fold_build2 (POINTER_PLUS_EXPR,
- TREE_TYPE (arg0),
- arg0,
- fold_convert (sizetype, arg1)));
- /* INT + PTR -> (INT)(PTR p+ INT) */
- if (POINTER_TYPE_P (TREE_TYPE (arg1))
- && INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
- return fold_convert (type, fold_build2 (POINTER_PLUS_EXPR,
- TREE_TYPE (arg1),
- arg1,
- fold_convert (sizetype, arg0)));
/* A + (-B) -> A - B */
if (TREE_CODE (arg1) == NEGATE_EXPR)
return fold_build2 (MINUS_EXPR, type,
unsigned HOST_WIDE_INT modulus, residue;
unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg1);
- modulus = get_pointer_modulus_and_residue (arg0, &residue);
+ modulus = get_pointer_modulus_and_residue (arg0, &residue,
+ integer_onep (arg1));
/* This works because modulus is a power of 2. If this weren't the
case, we'd have to replace it by its greatest power-of-2
core = get_inner_reference (TREE_OPERAND (exp, 0), &bitsize, pbitpos,
poffset, &mode, &unsignedp, &volatilep,
false);
- core = fold_addr_expr (core);
+ core = build_fold_addr_expr (core);
}
else
{