Hi! When a multiply stmt has zero uses, convert_mult_to_fma immediately returns true, meaning the multiplication can be deleted. Normally it should be DCE job to remove dead stmts, not widening_mul pass IMHO, and in this case it shouldn't be removed because it can throw and wasn't DCEd because of it. For -fnon-call-exceptions if there is at least one use, we wouldn't be optimizing multiply and add/sub into FMA, because the multiplication (stmt_can_throw_p) would be in different bb from the addition/subtraction, so there is no need to purge dead eh edges etc. in the caller.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2011-12-05 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/51396 * tree-ssa-math-opts.c (convert_mult_to_fma): Don't optimize if MUL_RESULT has zero uses. * g++.dg/opt/pr51396.C: New test. --- gcc/tree-ssa-math-opts.c.jj 2011-10-18 23:52:03.000000000 +0200 +++ gcc/tree-ssa-math-opts.c 2011-12-05 19:00:42.467551532 +0100 @@ -2429,6 +2429,12 @@ convert_mult_to_fma (gimple mul_stmt, tr if (optab_handler (fma_optab, TYPE_MODE (type)) == CODE_FOR_nothing) return false; + /* If the multiplication has zero uses, it is kept around probably because + of -fnon-call-exceptions. Don't optimize it away in that case, + it is DCE job. */ + if (has_zero_uses (mul_result)) + return false; + /* Make sure that the multiplication statement becomes dead after the transformation, thus that all uses are transformed to FMAs. This means we assume that an FMA operation has the same cost --- gcc/testsuite/g++.dg/opt/pr51396.C.jj 2011-12-05 19:03:36.793523559 +0100 +++ gcc/testsuite/g++.dg/opt/pr51396.C 2011-12-05 19:03:16.000000000 +0100 @@ -0,0 +1,24 @@ +// PR tree-optimization/51396 +// { dg-do compile } +// { dg-options "-O2 -fnon-call-exceptions -mfma" } +// { dg-options "-O2 -fnon-call-exceptions -mfma" { target i?86-*-* x86_64-*-* } } + +double baz (double) throw (); + +struct C +{ + C (double d = 0.0) : c (d) {} + double c; +}; + +static inline void +foo (double x, const C &y) +{ + x ? (y.c * baz (x)) : (C (), y); +} + +void +bar (double x, C y) +{ + foo (x, y); +} Jakub