diff options
author | Roger Sayle <roger@eyesopen.com> | 2006-05-30 21:34:04 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2006-05-30 21:34:04 +0000 |
commit | 99b25753bb82141b1f9b9a8eb62e14d6237c7a23 (patch) | |
tree | e8c7d9474db25736fdee60d42de43372bd6ae36e /gcc/fold-const.c | |
parent | 606791f69894426ecd59d7baf18664fb77138324 (diff) | |
download | gcc-99b25753bb82141b1f9b9a8eb62e14d6237c7a23.zip gcc-99b25753bb82141b1f9b9a8eb62e14d6237c7a23.tar.gz gcc-99b25753bb82141b1f9b9a8eb62e14d6237c7a23.tar.bz2 |
re PR tree-optimization/23452 (Optimizing CONJG_EXPR (a) * a)
PR tree-optimization/23452
* fold-const.c (fold_mult_zconjz): New subroutine of fold_binary,
to optimize z * conj(z) as realpart(z)^2 + imagpart(z)^2.
(fold_binary) <MULT_EXPR>: Call fold_mult_zconjz for integral
complex values and with -ffast-math for FP complex values.
* gcc.dg/fold-mulconj-1.c: New test case.
From-SVN: r114246
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7ef0fa1..19058b2 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -8105,6 +8105,44 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) return NULL_TREE; } + +/* Subroutine of fold_binary. Optimize complex multiplications of the + form z * conj(z), as pow(realpart(z),2) + pow(imagpart(z),2). The + argument EXPR represents the expression "z" of type TYPE. */ + +static tree +fold_mult_zconjz (tree type, tree expr) +{ + tree itype = TREE_TYPE (type); + tree rpart, ipart, tem; + + if (TREE_CODE (expr) == COMPLEX_EXPR) + { + rpart = TREE_OPERAND (expr, 0); + ipart = TREE_OPERAND (expr, 1); + } + else if (TREE_CODE (expr) == COMPLEX_CST) + { + rpart = TREE_REALPART (expr); + ipart = TREE_IMAGPART (expr); + } + else + { + expr = save_expr (expr); + rpart = fold_build1 (REALPART_EXPR, itype, expr); + ipart = fold_build1 (IMAGPART_EXPR, itype, expr); + } + + rpart = save_expr (rpart); + ipart = save_expr (ipart); + tem = fold_build2 (PLUS_EXPR, itype, + fold_build2 (MULT_EXPR, itype, rpart, rpart), + fold_build2 (MULT_EXPR, itype, ipart, ipart)); + return fold_build2 (COMPLEX_EXPR, type, tem, + fold_convert (itype, integer_zero_node)); +} + + /* Fold a binary expression of code CODE and type TYPE with operands OP0 and OP1. Return the folded expression if folding is successful. Otherwise, return NULL_TREE. */ @@ -8768,6 +8806,13 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) code, NULL_TREE))) return fold_convert (type, tem); + /* Optimize z * conj(z) for integer complex numbers. */ + if (TREE_CODE (arg0) == CONJ_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return fold_mult_zconjz (type, arg1); + if (TREE_CODE (arg1) == CONJ_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return fold_mult_zconjz (type, arg0); } else { @@ -8813,6 +8858,18 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) } } + /* Optimize z * conj(z) for floating point complex numbers. + Guarded by flag_unsafe_math_optimizations as non-finite + imaginary components don't produce scalar results. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg0) == CONJ_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return fold_mult_zconjz (type, arg1); + if (flag_unsafe_math_optimizations + && TREE_CODE (arg1) == CONJ_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return fold_mult_zconjz (type, arg0); + if (flag_unsafe_math_optimizations) { enum built_in_function fcode0 = builtin_mathfn_code (arg0); |