re PR middle-end/19953 (Special-case real + complex arithmetic operation (-ffast-math))
PR middle-end/19953 * builtins.c (fold_builtin_complex_mul, fold_builtin_complex_div): New. (fold_builtin_1): Call them. * fold-const.c (fold_complex_mult_parts): Split out from ... (fold_complex_mult): ... here. Fix typo in both imaginary case. (fold_complex_div_parts, fold_complex_div): New. (fold): Use them. * tree.h (fold_complex_mult_parts, fold_complex_div_parts): Declare. From-SVN: r95511
This commit is contained in:
parent
ae95537a89
commit
a0d2281e2d
|
@ -1,3 +1,14 @@
|
|||
2005-02-24 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR middle-end/19953
|
||||
* builtins.c (fold_builtin_complex_mul, fold_builtin_complex_div): New.
|
||||
(fold_builtin_1): Call them.
|
||||
* fold-const.c (fold_complex_mult_parts): Split out from ...
|
||||
(fold_complex_mult): ... here. Fix typo in both imaginary case.
|
||||
(fold_complex_div_parts, fold_complex_div): New.
|
||||
(fold): Use them.
|
||||
* tree.h (fold_complex_mult_parts, fold_complex_div_parts): Declare.
|
||||
|
||||
2005-02-24 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
|
||||
|
||||
* tree-ssa-ccp.c (visit_assignment): Verify that result of
|
||||
|
|
|
@ -7843,6 +7843,44 @@ fold_builtin_unordered_cmp (tree exp,
|
|||
fold (build2 (code, type, arg0, arg1))));
|
||||
}
|
||||
|
||||
/* Fold a call to one of the external complex multiply libcalls. */
|
||||
|
||||
static tree
|
||||
fold_builtin_complex_mul (tree type, tree arglist)
|
||||
{
|
||||
tree ar, ai, br, bi;
|
||||
|
||||
if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, REAL_TYPE,
|
||||
REAL_TYPE, VOID_TYPE))
|
||||
return NULL;
|
||||
|
||||
ar = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
|
||||
ai = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
|
||||
br = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
|
||||
bi = TREE_VALUE (arglist);
|
||||
|
||||
return fold_complex_mult_parts (type, ar, ai, br, bi);
|
||||
}
|
||||
|
||||
/* Fold a call to one of the external complex division libcalls. */
|
||||
|
||||
static tree
|
||||
fold_builtin_complex_div (tree type, tree arglist)
|
||||
{
|
||||
tree ar, ai, br, bi;
|
||||
|
||||
if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, REAL_TYPE,
|
||||
REAL_TYPE, VOID_TYPE))
|
||||
return NULL;
|
||||
|
||||
ar = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
|
||||
ai = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
|
||||
br = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
|
||||
bi = TREE_VALUE (arglist);
|
||||
|
||||
return fold_complex_div_parts (type, ar, ai, br, bi, RDIV_EXPR);
|
||||
}
|
||||
|
||||
/* Used by constant folding to simplify calls to builtin functions. EXP is
|
||||
the CALL_EXPR of a call to a builtin function. IGNORE is true if the
|
||||
result of the function call is ignored. This function returns NULL_TREE
|
||||
|
@ -7854,11 +7892,13 @@ fold_builtin_1 (tree exp, bool ignore)
|
|||
tree fndecl = get_callee_fndecl (exp);
|
||||
tree arglist = TREE_OPERAND (exp, 1);
|
||||
tree type = TREE_TYPE (TREE_TYPE (fndecl));
|
||||
enum built_in_function fcode;
|
||||
|
||||
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
|
||||
return targetm.fold_builtin (exp, ignore);
|
||||
|
||||
switch (DECL_FUNCTION_CODE (fndecl))
|
||||
fcode = DECL_FUNCTION_CODE (fndecl);
|
||||
switch (fcode)
|
||||
{
|
||||
case BUILT_IN_FPUTS:
|
||||
return fold_builtin_fputs (arglist, ignore, false, NULL_TREE);
|
||||
|
@ -8188,6 +8228,12 @@ fold_builtin_1 (tree exp, bool ignore)
|
|||
break;
|
||||
|
||||
default:
|
||||
if (fcode >= BUILT_IN_COMPLEX_MUL_MIN
|
||||
&& fcode <= BUILT_IN_COMPLEX_MUL_MAX)
|
||||
return fold_builtin_complex_mul (type, arglist);
|
||||
if (fcode >= BUILT_IN_COMPLEX_DIV_MIN
|
||||
&& fcode <= BUILT_IN_COMPLEX_DIV_MAX)
|
||||
return fold_builtin_complex_div (type, arglist);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
181
gcc/fold-const.c
181
gcc/fold-const.c
|
@ -6336,26 +6336,12 @@ fold_complex_add (tree type, tree ac, tree bc, enum tree_code code)
|
|||
/* Perform some simplifications of complex multiplication when one or more
|
||||
of the components are constants or zeros. Return non-null if successful. */
|
||||
|
||||
static tree
|
||||
fold_complex_mult (tree type, tree ac, tree bc)
|
||||
tree
|
||||
fold_complex_mult_parts (tree type, tree ar, tree ai, tree br, tree bi)
|
||||
{
|
||||
tree ar, ai, br, bi, rr, ri, inner_type, zero;
|
||||
tree rr, ri, inner_type, zero;
|
||||
bool ar0, ai0, br0, bi0, bi1;
|
||||
|
||||
if (TREE_CODE (ac) == COMPLEX_EXPR)
|
||||
ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
|
||||
else if (TREE_CODE (ac) == COMPLEX_CST)
|
||||
ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (TREE_CODE (bc) == COMPLEX_EXPR)
|
||||
br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
|
||||
else if (TREE_CODE (bc) == COMPLEX_CST)
|
||||
br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
inner_type = TREE_TYPE (type);
|
||||
zero = NULL;
|
||||
|
||||
|
@ -6432,7 +6418,7 @@ fold_complex_mult (tree type, tree ac, tree bc)
|
|||
}
|
||||
else if (ar0 && br0)
|
||||
{
|
||||
rr = fold (build2 (MULT_EXPR, inner_type, ai, br));
|
||||
rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
|
||||
rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
|
||||
ri = zero;
|
||||
}
|
||||
|
@ -6464,6 +6450,152 @@ fold_complex_mult (tree type, tree ac, tree bc)
|
|||
return fold (build2 (COMPLEX_EXPR, type, rr, ri));
|
||||
}
|
||||
|
||||
static tree
|
||||
fold_complex_mult (tree type, tree ac, tree bc)
|
||||
{
|
||||
tree ar, ai, br, bi;
|
||||
|
||||
if (TREE_CODE (ac) == COMPLEX_EXPR)
|
||||
ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
|
||||
else if (TREE_CODE (ac) == COMPLEX_CST)
|
||||
ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (TREE_CODE (bc) == COMPLEX_EXPR)
|
||||
br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
|
||||
else if (TREE_CODE (bc) == COMPLEX_CST)
|
||||
br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
return fold_complex_mult_parts (type, ar, ai, br, bi);
|
||||
}
|
||||
|
||||
/* Perform some simplifications of complex division when one or more of
|
||||
the components are constants or zeros. Return non-null if successful. */
|
||||
|
||||
tree
|
||||
fold_complex_div_parts (tree type, tree ar, tree ai, tree br, tree bi,
|
||||
enum tree_code code)
|
||||
{
|
||||
tree rr, ri, inner_type, zero;
|
||||
bool ar0, ai0, br0, bi0, bi1;
|
||||
|
||||
inner_type = TREE_TYPE (type);
|
||||
zero = NULL;
|
||||
|
||||
if (SCALAR_FLOAT_TYPE_P (inner_type))
|
||||
{
|
||||
ar0 = ai0 = br0 = bi0 = bi1 = false;
|
||||
|
||||
/* We're only interested in +0.0 here, thus we don't use real_zerop. */
|
||||
|
||||
if (TREE_CODE (ar) == REAL_CST
|
||||
&& REAL_VALUES_IDENTICAL (TREE_REAL_CST (ar), dconst0))
|
||||
ar0 = true, zero = ar;
|
||||
|
||||
if (TREE_CODE (ai) == REAL_CST
|
||||
&& REAL_VALUES_IDENTICAL (TREE_REAL_CST (ai), dconst0))
|
||||
ai0 = true, zero = ai;
|
||||
|
||||
if (TREE_CODE (br) == REAL_CST
|
||||
&& REAL_VALUES_IDENTICAL (TREE_REAL_CST (br), dconst0))
|
||||
br0 = true, zero = br;
|
||||
|
||||
if (TREE_CODE (bi) == REAL_CST)
|
||||
{
|
||||
if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst0))
|
||||
bi0 = true, zero = bi;
|
||||
else if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst1))
|
||||
bi1 = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ar0 = integer_zerop (ar);
|
||||
if (ar0)
|
||||
zero = ar;
|
||||
ai0 = integer_zerop (ai);
|
||||
if (ai0)
|
||||
zero = ai;
|
||||
br0 = integer_zerop (br);
|
||||
if (br0)
|
||||
zero = br;
|
||||
bi0 = integer_zerop (bi);
|
||||
if (bi0)
|
||||
{
|
||||
zero = bi;
|
||||
bi1 = false;
|
||||
}
|
||||
else
|
||||
bi1 = integer_onep (bi);
|
||||
}
|
||||
|
||||
/* We won't optimize anything below unless something is zero. */
|
||||
if (zero == NULL)
|
||||
return NULL;
|
||||
|
||||
if (ai0 && bi0)
|
||||
{
|
||||
rr = fold (build2 (code, inner_type, ar, br));
|
||||
ri = zero;
|
||||
}
|
||||
else if (ai0 && br0)
|
||||
{
|
||||
rr = zero;
|
||||
ri = fold (build2 (code, inner_type, ar, bi));
|
||||
ri = fold (build1 (NEGATE_EXPR, inner_type, ri));
|
||||
}
|
||||
else if (ar0 && bi0)
|
||||
{
|
||||
rr = zero;
|
||||
ri = fold (build2 (code, inner_type, ai, br));
|
||||
}
|
||||
else if (ar0 && br0)
|
||||
{
|
||||
rr = fold (build2 (code, inner_type, ai, bi));
|
||||
ri = zero;
|
||||
}
|
||||
else if (bi0)
|
||||
{
|
||||
rr = fold (build2 (code, inner_type, ar, br));
|
||||
ri = fold (build2 (code, inner_type, ai, br));
|
||||
}
|
||||
else if (br0)
|
||||
{
|
||||
rr = fold (build2 (code, inner_type, ai, bi));
|
||||
ri = fold (build2 (code, inner_type, ar, bi));
|
||||
ri = fold (build1 (NEGATE_EXPR, inner_type, ri));
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
return fold (build2 (COMPLEX_EXPR, type, rr, ri));
|
||||
}
|
||||
|
||||
static tree
|
||||
fold_complex_div (tree type, tree ac, tree bc, enum tree_code code)
|
||||
{
|
||||
tree ar, ai, br, bi;
|
||||
|
||||
if (TREE_CODE (ac) == COMPLEX_EXPR)
|
||||
ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
|
||||
else if (TREE_CODE (ac) == COMPLEX_CST)
|
||||
ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (TREE_CODE (bc) == COMPLEX_EXPR)
|
||||
br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
|
||||
else if (TREE_CODE (bc) == COMPLEX_CST)
|
||||
br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
return fold_complex_div_parts (type, ar, ai, br, bi, code);
|
||||
}
|
||||
|
||||
/* Perform constant folding and related simplification of EXPR.
|
||||
The related simplifications include x*1 => x, x*0 => 0, etc.,
|
||||
and application of the associative law.
|
||||
|
@ -8042,6 +8174,13 @@ fold (tree expr)
|
|||
TREE_OPERAND (arg1, 0)));
|
||||
}
|
||||
|
||||
if (TREE_CODE (type) == COMPLEX_TYPE)
|
||||
{
|
||||
tem = fold_complex_div (type, arg0, arg1, code);
|
||||
if (tem)
|
||||
return tem;
|
||||
}
|
||||
|
||||
if (flag_unsafe_math_optimizations)
|
||||
{
|
||||
enum built_in_function fcode = builtin_mathfn_code (arg1);
|
||||
|
@ -8166,6 +8305,12 @@ fold (tree expr)
|
|||
code, NULL_TREE)))
|
||||
return fold_convert (type, tem);
|
||||
|
||||
if (TREE_CODE (type) == COMPLEX_TYPE)
|
||||
{
|
||||
tem = fold_complex_div (type, arg0, arg1, code);
|
||||
if (tem)
|
||||
return tem;
|
||||
}
|
||||
goto binary;
|
||||
|
||||
case CEIL_MOD_EXPR:
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/* Verify that we don't libcall for complex * real. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c99 -O -fdump-tree-optimized" } */
|
||||
|
||||
typedef _Complex float C;
|
||||
|
||||
C foo(C x, float y)
|
||||
{
|
||||
return x * y;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "__mul" 0 "optimized" } } */
|
|
@ -0,0 +1,12 @@
|
|||
/* Verify that we don't libcall for complex / real. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c99 -O -fdump-tree-optimized" } */
|
||||
|
||||
typedef _Complex float C;
|
||||
|
||||
C foo(C x, float y)
|
||||
{
|
||||
return x / y;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "__div" 0 "optimized" } } */
|
|
@ -3549,6 +3549,9 @@ extern tree build_fold_indirect_ref (tree);
|
|||
extern tree fold_indirect_ref (tree);
|
||||
extern tree constant_boolean_node (int, tree);
|
||||
extern tree build_low_bits_mask (tree, unsigned);
|
||||
extern tree fold_complex_mult_parts (tree, tree, tree, tree, tree);
|
||||
extern tree fold_complex_div_parts (tree, tree, tree, tree, tree,
|
||||
enum tree_code);
|
||||
|
||||
extern bool tree_swap_operands_p (tree, tree, bool);
|
||||
extern enum tree_code swap_tree_comparison (enum tree_code);
|
||||
|
|
Loading…
Reference in New Issue