aboutsummaryrefslogtreecommitdiff
path: root/gcc/convert.c
diff options
context:
space:
mode:
authorKai Tietz <ktietz70@googlemail.com>2015-11-13 22:24:45 +0000
committerJason Merrill <jason@gcc.gnu.org>2015-11-13 17:24:45 -0500
commit269e63b735d6e4e18367e94e8417b5d5eb799960 (patch)
tree2ab66075ba691c6242d45ab66643cf2f0358a6a5 /gcc/convert.c
parent9514e74fcd529835a8963f91e12e1ee853149095 (diff)
downloadgcc-269e63b735d6e4e18367e94e8417b5d5eb799960.zip
gcc-269e63b735d6e4e18367e94e8417b5d5eb799960.tar.gz
gcc-269e63b735d6e4e18367e94e8417b5d5eb799960.tar.bz2
Add non-folding variants for convert_to_*.
2015-11-13 Kai Tietz <ktietz70@googlemail.com> Marek Polacek <polacek@redhat.com> Jason Merrill <jason@redhat.com> gcc/ * convert.c (maybe_fold_build1_loc): New. (maybe_fold_build2_loc): New. (convert_to_pointer_1): Split out from convert_to_pointer. (convert_to_pointer_nofold): New. (convert_to_real_1): Split out from convert_to_real. (convert_to_real_nofold): New. (convert_to_integer_1): Split out from convert_to_integer. (convert_to_integer_nofold): New. (convert_to_complex_1): Split out from convert_to_complex. (convert_to_complex_nofold): New. * convert.h: Declare new functions. * tree-complex.c (create_one_component_var): Break up line to avoid sequence point issues. gcc/c-family/ * c-lex.c (interpret_float): Use fold_convert. Co-Authored-By: Jason Merrill <jason@redhat.com> Co-Authored-By: Marek Polacek <polacek@redhat.com> From-SVN: r230359
Diffstat (limited to 'gcc/convert.c')
-rw-r--r--gcc/convert.c265
1 files changed, 190 insertions, 75 deletions
diff --git a/gcc/convert.c b/gcc/convert.c
index 113c11f..e27a6fe 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -34,12 +34,20 @@ along with GCC; see the file COPYING3. If not see
#include "builtins.h"
#include "ubsan.h"
+#define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \
+ ((FOLD_P) ? fold_build1_loc (LOC, CODE, TYPE, EXPR) \
+ : build1_loc (LOC, CODE, TYPE, EXPR))
+#define maybe_fold_build2_loc(FOLD_P, LOC, CODE, TYPE, EXPR1, EXPR2) \
+ ((FOLD_P) ? fold_build2_loc (LOC, CODE, TYPE, EXPR1, EXPR2) \
+ : build2_loc (LOC, CODE, TYPE, EXPR1, EXPR2))
+
/* Convert EXPR to some pointer or reference type TYPE.
EXPR must be pointer, reference, integer, enumeral, or literal zero;
- in other cases error is called. */
+ in other cases error is called. If FOLD_P is true, try to fold the
+ expression. */
-tree
-convert_to_pointer (tree type, tree expr)
+static tree
+convert_to_pointer_1 (tree type, tree expr, bool fold_p)
{
location_t loc = EXPR_LOCATION (expr);
if (TREE_TYPE (expr) == type)
@@ -56,9 +64,10 @@ convert_to_pointer (tree type, tree expr)
addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (expr)));
if (to_as == from_as)
- return fold_build1_loc (loc, NOP_EXPR, type, expr);
+ return maybe_fold_build1_loc (fold_p, loc, NOP_EXPR, type, expr);
else
- return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr);
+ return maybe_fold_build1_loc (fold_p, loc, ADDR_SPACE_CONVERT_EXPR,
+ type, expr);
}
case INTEGER_TYPE:
@@ -72,35 +81,54 @@ convert_to_pointer (tree type, tree expr)
unsigned int pprec = TYPE_PRECISION (type);
unsigned int eprec = TYPE_PRECISION (TREE_TYPE (expr));
- if (eprec != pprec)
- expr = fold_build1_loc (loc, NOP_EXPR,
- lang_hooks.types.type_for_size (pprec, 0),
- expr);
+ if (eprec != pprec)
+ expr
+ = maybe_fold_build1_loc (fold_p, loc, NOP_EXPR,
+ lang_hooks.types.type_for_size (pprec, 0),
+ expr);
}
-
- return fold_build1_loc (loc, CONVERT_EXPR, type, expr);
+ return maybe_fold_build1_loc (fold_p, loc, CONVERT_EXPR, type, expr);
default:
error ("cannot convert to a pointer type");
- return convert_to_pointer (type, integer_zero_node);
+ return convert_to_pointer_1 (type, integer_zero_node, fold_p);
}
}
+/* A wrapper around convert_to_pointer_1 that always folds the
+ expression. */
+
+tree
+convert_to_pointer (tree type, tree expr)
+{
+ return convert_to_pointer_1 (type, expr, true);
+}
+
+/* A wrapper around convert_to_pointer_1 that only folds the
+ expression if it is CONSTANT_CLASS_P. */
+
+tree
+convert_to_pointer_nofold (tree type, tree expr)
+{
+ return convert_to_pointer_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
/* Convert EXPR to some floating-point type TYPE.
EXPR must be float, fixed-point, integer, or enumeral;
- in other cases error is called. */
+ in other cases error is called. If FOLD_P is true, try to fold
+ the expression. */
-tree
-convert_to_real (tree type, tree expr)
+static tree
+convert_to_real_1 (tree type, tree expr, bool fold_p)
{
enum built_in_function fcode = builtin_mathfn_code (expr);
tree itype = TREE_TYPE (expr);
+ location_t loc = EXPR_LOCATION (expr);
if (TREE_CODE (expr) == COMPOUND_EXPR)
{
- tree t = convert_to_real (type, TREE_OPERAND (expr, 1));
+ tree t = convert_to_real_1 (type, TREE_OPERAND (expr, 1), fold_p);
if (t == TREE_OPERAND (expr, 1))
return expr;
return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR, TREE_TYPE (t),
@@ -208,14 +236,13 @@ convert_to_real (tree type, tree expr)
|| TYPE_MODE (newtype) == TYPE_MODE (float_type_node)))
{
tree fn = mathfn_built_in (newtype, fcode);
-
if (fn)
- {
- tree arg = fold (convert_to_real (newtype, arg0));
- expr = build_call_expr (fn, 1, arg);
- if (newtype == type)
- return expr;
- }
+ {
+ tree arg = convert_to_real_1 (newtype, arg0, fold_p);
+ expr = build_call_expr (fn, 1, arg);
+ if (newtype == type)
+ return expr;
+ }
}
}
default:
@@ -234,9 +261,11 @@ convert_to_real (tree type, tree expr)
if (!flag_rounding_math
&& FLOAT_TYPE_P (itype)
&& TYPE_PRECISION (type) < TYPE_PRECISION (itype))
- return build1 (TREE_CODE (expr), type,
- fold (convert_to_real (type,
- TREE_OPERAND (expr, 0))));
+ {
+ tree arg = convert_to_real_1 (type, TREE_OPERAND (expr, 0),
+ fold_p);
+ return build1 (TREE_CODE (expr), type, arg);
+ }
break;
/* Convert (outertype)((innertype0)a+(innertype1)b)
into ((newtype)a+(newtype)b) where newtype
@@ -272,8 +301,10 @@ convert_to_real (tree type, tree expr)
|| newtype == dfloat128_type_node)
{
expr = build2 (TREE_CODE (expr), newtype,
- fold (convert_to_real (newtype, arg0)),
- fold (convert_to_real (newtype, arg1)));
+ convert_to_real_1 (newtype, arg0,
+ fold_p),
+ convert_to_real_1 (newtype, arg1,
+ fold_p));
if (newtype == type)
return expr;
break;
@@ -312,8 +343,10 @@ convert_to_real (tree type, tree expr)
&& !excess_precision_type (newtype))))
{
expr = build2 (TREE_CODE (expr), newtype,
- fold (convert_to_real (newtype, arg0)),
- fold (convert_to_real (newtype, arg1)));
+ convert_to_real_1 (newtype, arg0,
+ fold_p),
+ convert_to_real_1 (newtype, arg1,
+ fold_p));
if (newtype == type)
return expr;
}
@@ -344,30 +377,51 @@ convert_to_real (tree type, tree expr)
case COMPLEX_TYPE:
return convert (type,
- fold_build1 (REALPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)), expr));
+ maybe_fold_build1_loc (fold_p, loc, REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr));
case POINTER_TYPE:
case REFERENCE_TYPE:
error ("pointer value used where a floating point value was expected");
- return convert_to_real (type, integer_zero_node);
+ return convert_to_real_1 (type, integer_zero_node, fold_p);
default:
error ("aggregate value used where a float was expected");
- return convert_to_real (type, integer_zero_node);
+ return convert_to_real_1 (type, integer_zero_node, fold_p);
}
}
+/* A wrapper around convert_to_real_1 that always folds the
+ expression. */
+
+tree
+convert_to_real (tree type, tree expr)
+{
+ return convert_to_real_1 (type, expr, true);
+}
+
+/* A wrapper around convert_to_real_1 that only folds the
+ expression if it is CONSTANT_CLASS_P. */
+
+tree
+convert_to_real_nofold (tree type, tree expr)
+{
+ return convert_to_real_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
+
/* Convert EXPR to some integer (or enum) type TYPE.
EXPR must be pointer, integer, discrete (enum, char, or bool), float,
fixed-point or vector; in other cases error is called.
+ If DOFOLD is TRUE, we try to simplify newly-created patterns by folding.
+
The result of this is always supposed to be a newly created tree node
not in use in any existing structure. */
-tree
-convert_to_integer (tree type, tree expr)
+static tree
+convert_to_integer_1 (tree type, tree expr, bool dofold)
{
enum tree_code ex_form = TREE_CODE (expr);
tree intype = TREE_TYPE (expr);
@@ -385,7 +439,7 @@ convert_to_integer (tree type, tree expr)
if (ex_form == COMPOUND_EXPR)
{
- tree t = convert_to_integer (type, TREE_OPERAND (expr, 1));
+ tree t = convert_to_integer_1 (type, TREE_OPERAND (expr, 1), dofold);
if (t == TREE_OPERAND (expr, 1))
return expr;
return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR, TREE_TYPE (t),
@@ -479,7 +533,7 @@ convert_to_integer (tree type, tree expr)
break;
CASE_FLT_FN (BUILT_IN_TRUNC):
- return convert_to_integer (type, CALL_EXPR_ARG (s_expr, 0));
+ return convert_to_integer_1 (type, CALL_EXPR_ARG (s_expr, 0), dofold);
default:
break;
@@ -488,7 +542,7 @@ convert_to_integer (tree type, tree expr)
if (fn)
{
tree newexpr = build_call_expr (fn, 1, CALL_EXPR_ARG (s_expr, 0));
- return convert_to_integer (type, newexpr);
+ return convert_to_integer_1 (type, newexpr, dofold);
}
}
@@ -519,7 +573,7 @@ convert_to_integer (tree type, tree expr)
if (fn)
{
tree newexpr = build_call_expr (fn, 1, CALL_EXPR_ARG (s_expr, 0));
- return convert_to_integer (type, newexpr);
+ return convert_to_integer_1 (type, newexpr, dofold);
}
}
@@ -534,6 +588,8 @@ convert_to_integer (tree type, tree expr)
there widen/truncate to the required type. Some targets support the
coexistence of multiple valid pointer sizes, so fetch the one we need
from the type. */
+ if (!dofold)
+ return build1 (CONVERT_EXPR, type, expr);
expr = fold_build1 (CONVERT_EXPR,
lang_hooks.types.type_for_size
(TYPE_PRECISION (intype), 0),
@@ -578,7 +634,7 @@ convert_to_integer (tree type, tree expr)
else
code = NOP_EXPR;
- return fold_build1 (code, type, expr);
+ return maybe_fold_build1_loc (dofold, loc, code, type, expr);
}
/* If TYPE is an enumeral type or a type with a precision less
@@ -784,10 +840,12 @@ convert_to_integer (tree type, tree expr)
if (TYPE_UNSIGNED (typex))
typex = signed_type_for (typex);
}
- return convert (type,
- fold_build2 (ex_form, typex,
- convert (typex, arg0),
- convert (typex, arg1)));
+ /* We should do away with all this once we have a proper
+ type promotion/demotion pass, see PR45397. */
+ expr = maybe_fold_build2_loc (dofold, loc, ex_form, typex,
+ convert (typex, arg0),
+ convert (typex, arg1));
+ return convert (type, expr);
}
}
}
@@ -798,6 +856,9 @@ convert_to_integer (tree type, tree expr)
/* This is not correct for ABS_EXPR,
since we must test the sign before truncation. */
{
+ if (!dofold)
+ break;
+
/* Do the arithmetic in type TYPEX,
then convert result to TYPE. */
tree typex = type;
@@ -833,13 +894,15 @@ convert_to_integer (tree type, tree expr)
the conditional and never loses. A COND_EXPR may have a throw
as one operand, which then has void type. Just leave void
operands as they are. */
- return fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0),
- VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1)))
- ? TREE_OPERAND (expr, 1)
- : convert (type, TREE_OPERAND (expr, 1)),
- VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2)))
- ? TREE_OPERAND (expr, 2)
- : convert (type, TREE_OPERAND (expr, 2)));
+ if (dofold)
+ return
+ fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0),
+ VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1)))
+ ? TREE_OPERAND (expr, 1)
+ : convert (type, TREE_OPERAND (expr, 1)),
+ VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2)))
+ ? TREE_OPERAND (expr, 2)
+ : convert (type, TREE_OPERAND (expr, 2)));
default:
break;
@@ -860,7 +923,8 @@ convert_to_integer (tree type, tree expr)
expr = build1 (FIX_TRUNC_EXPR, type, expr);
if (check == NULL)
return expr;
- return fold_build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr);
+ return maybe_fold_build2_loc (dofold, loc, COMPOUND_EXPR,
+ TREE_TYPE (expr), check, expr);
}
else
return build1 (FIX_TRUNC_EXPR, type, expr);
@@ -869,9 +933,9 @@ convert_to_integer (tree type, tree expr)
return build1 (FIXED_CONVERT_EXPR, type, expr);
case COMPLEX_TYPE:
- return convert (type,
- fold_build1 (REALPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)), expr));
+ expr = maybe_fold_build1_loc (dofold, loc, REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)), expr);
+ return convert (type, expr);
case VECTOR_TYPE:
if (!tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (expr))))
@@ -889,11 +953,42 @@ convert_to_integer (tree type, tree expr)
}
}
-/* Convert EXPR to the complex type TYPE in the usual ways. */
+/* Convert EXPR to some integer (or enum) type TYPE.
+
+ EXPR must be pointer, integer, discrete (enum, char, or bool), float,
+ fixed-point or vector; in other cases error is called.
+
+ The result of this is always supposed to be a newly created tree node
+ not in use in any existing structure. */
tree
-convert_to_complex (tree type, tree expr)
+convert_to_integer (tree type, tree expr)
+{
+ return convert_to_integer_1 (type, expr, true);
+}
+
+/* Convert EXPR to some integer (or enum) type TYPE.
+
+ EXPR must be pointer, integer, discrete (enum, char, or bool), float,
+ fixed-point or vector; in other cases error is called.
+
+ The result of this is always supposed to be a newly created tree node
+ not in use in any existing structure. The tree node isn't folded,
+ beside EXPR is of constant class. */
+
+tree
+convert_to_integer_nofold (tree type, tree expr)
{
+ return convert_to_integer_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
+
+/* Convert EXPR to the complex type TYPE in the usual ways. If FOLD_P is
+ true, try to fold the expression. */
+
+static tree
+convert_to_complex_1 (tree type, tree expr, bool fold_p)
+{
+ location_t loc = EXPR_LOCATION (expr);
tree subtype = TREE_TYPE (type);
switch (TREE_CODE (TREE_TYPE (expr)))
@@ -914,43 +1009,63 @@ convert_to_complex (tree type, tree expr)
return expr;
else if (TREE_CODE (expr) == COMPOUND_EXPR)
{
- tree t = convert_to_complex (type, TREE_OPERAND (expr, 1));
+ tree t = convert_to_complex_1 (type, TREE_OPERAND (expr, 1),
+ fold_p);
if (t == TREE_OPERAND (expr, 1))
return expr;
return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR,
TREE_TYPE (t), TREE_OPERAND (expr, 0), t);
- }
+ }
else if (TREE_CODE (expr) == COMPLEX_EXPR)
- return fold_build2 (COMPLEX_EXPR, type,
- convert (subtype, TREE_OPERAND (expr, 0)),
- convert (subtype, TREE_OPERAND (expr, 1)));
+ return maybe_fold_build2_loc (fold_p, loc, COMPLEX_EXPR, type,
+ convert (subtype,
+ TREE_OPERAND (expr, 0)),
+ convert (subtype,
+ TREE_OPERAND (expr, 1)));
else
{
expr = save_expr (expr);
- return
- fold_build2 (COMPLEX_EXPR, type,
- convert (subtype,
- fold_build1 (REALPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)),
- expr)),
- convert (subtype,
- fold_build1 (IMAGPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)),
- expr)));
+ tree realp = maybe_fold_build1_loc (fold_p, loc, REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr);
+ tree imagp = maybe_fold_build1_loc (fold_p, loc, IMAGPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr);
+ return maybe_fold_build2_loc (fold_p, loc, COMPLEX_EXPR, type,
+ convert (subtype, realp),
+ convert (subtype, imagp));
}
}
case POINTER_TYPE:
case REFERENCE_TYPE:
error ("pointer value used where a complex was expected");
- return convert_to_complex (type, integer_zero_node);
+ return convert_to_complex_1 (type, integer_zero_node, fold_p);
default:
error ("aggregate value used where a complex was expected");
- return convert_to_complex (type, integer_zero_node);
+ return convert_to_complex_1 (type, integer_zero_node, fold_p);
}
}
+/* A wrapper around convert_to_complex_1 that always folds the
+ expression. */
+
+tree
+convert_to_complex (tree type, tree expr)
+{
+ return convert_to_complex_1 (type, expr, true);
+}
+
+/* A wrapper around convert_to_complex_1 that only folds the
+ expression if it is CONSTANT_CLASS_P. */
+
+tree
+convert_to_complex_nofold (tree type, tree expr)
+{
+ return convert_to_complex_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
+
/* Convert EXPR to the vector type TYPE in the usual ways. */
tree