From 189b339816238133988b6e976a05256f9d2d3426 Mon Sep 17 00:00:00 2001 From: rth Date: Thu, 24 Feb 2005 20:00:09 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@95511 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 11 ++ gcc/builtins.c | 48 +++++++- gcc/fold-const.c | 181 +++++++++++++++++++++++++++--- gcc/testsuite/gcc.dg/tree-ssa/complex-1.c | 12 ++ gcc/testsuite/gcc.dg/tree-ssa/complex-2.c | 12 ++ gcc/tree.h | 3 + 6 files changed, 248 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/complex-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/complex-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7677cf84bc8..3e2bcb49474 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2005-02-24 Richard Henderson + + 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 * tree-ssa-ccp.c (visit_assignment): Verify that result of diff --git a/gcc/builtins.c b/gcc/builtins.c index f0dd878d36b..078edc39b51 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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; } diff --git a/gcc/fold-const.c b/gcc/fold-const.c index a75ccdc92be..5c3139ccb50 100644 --- a/gcc/fold-const.c +++ b/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: diff --git a/gcc/testsuite/gcc.dg/tree-ssa/complex-1.c b/gcc/testsuite/gcc.dg/tree-ssa/complex-1.c new file mode 100644 index 00000000000..7dff01ce425 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/complex-1.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/complex-2.c b/gcc/testsuite/gcc.dg/tree-ssa/complex-2.c new file mode 100644 index 00000000000..ce72eb2172f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/complex-2.c @@ -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" } } */ diff --git a/gcc/tree.h b/gcc/tree.h index 62e9bb332bb..81992f904bd 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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); -- 2.11.0