diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0385d8fd002a89c98130dfb5601fede4e14b5560..95c9bad85ca9fdd4ea15d0ce74878bed04cf9a55 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2006-05-30 Roger Sayle <roger@eyesopen.com> + + 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. + 2006-05-30 Kazu Hirata <kazu@codesourcery.com> * c-common.h: Remove the prototype for yyparse. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7ef0fa11839af029be5a95c4a7f0d40313ff5f5c..19058b2f1431b302d707d52a283f9066e752cf30 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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1cc2f13451bd6c7101c9f9f8143b53c7b9a29cef..3738afa6fa78deca327b32d79336c22f5d33908f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-05-30 Roger Sayle <roger@eyesopen.com> + + PR tree-optimization/23452 + * gcc.dg/fold-mulconj-1.c: New test case. + 2006-05-30 Mark Mitchell <mark@codesourcery.com> PR c++/27803 diff --git a/gcc/testsuite/gcc.dg/fold-mulconj-1.c b/gcc/testsuite/gcc.dg/fold-mulconj-1.c new file mode 100644 index 0000000000000000000000000000000000000000..0e04653e393f66e88a866d45747a554979ecaea6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-mulconj-1.c @@ -0,0 +1,16 @@ +/* PR tree-optimization/23452 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -ffast-math -fdump-tree-gimple" } */ + +_Complex double foo(_Complex double z) +{ + return z * ~z; +} + +_Complex int bar(_Complex int z) +{ + return z * ~z; +} + +/* { dg-final { scan-tree-dump-times "CONJ_EXPR" 0 "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */