[RFC][flang] reasssociate within real and complex expressions by default

TL;DR I added a transformation behind a flag which reassociates some floating point expressions to a form with a shorter arithmetic tree depth: therefore allowing faster execution on cores with multiple arithmetic units. I would like to enable it by default.


In section 10.1.5.2.4 of the 2023 Fortran standard “Evaluation of numerical intrinsic operations”, the standard explicitly allows alternate mathematically equivalent lowerings. For example the source expression X + Y + Z could be evaluated (X + Y) + Z, X + (Y + Z) or even (X + Z) + Y, etc.

The open source benchmark SNBone shows significantly better results with classic flang because classic flang emits real arithmetic expressions in a different order. In the case of this benchmark it reduces dependency depth for instructions issued to the vector unit, allowing for more of the arithmetic to be parallelised over multiple vector execution units.

The lowering added by this transformation tries to mimic the way classic flang orders instructions for these expressions. There is still a notable difference in that classic flang uses FMA intrinsics whereas LLVM Flang relies on the rest of the pipeline to introduce FMA when it is safe to do so.

This is a much less aggressive optimisation than simply enabling reassoc in the fast-math flags because it does not allow reassociation between Fortran language statements (which I do not think would be allowable under the Fortran language standard). Therefore this is distinct from fast-math.

I would like to enable this transformation by default in flang, rather than continuing with our current left to right expression evaluation. I think that doing this is standards compliant, but it could change floating point rounding under some circumstances. I see a few tests in the Fujistu compiler test suite regress with this change due to these rounding changes.

I have tried SPEC2026, SPEC2017, the llvm test suite, the Fujitsu test suite, and a suite of proprietary and open source HPC applications and have not observed any regressions due to these changes, other than the handful of Fujitsu test suite programs noted above which assert exact floating point results.

Does anyone object to this change from always lowering real expressions left-to-right to instead allowing re-association within the expression for optimal code generation?

2 Likes

Does this mean the current left-to-right evaluation will be removed? Since some users may prefer to keep the current behavior, I believe it would be beneficial to provide an option to do so.

I see a few tests in the Fujistu compiler test suite regress with this change due to these rounding changes.

We will address the failures by force-disabling this feature or setting a tolerance for the affected tests. (I personally prefer the former.)

Thanks for taking a look at the RFC.

Agreed. My intention is to leave the current flags present, just switch the default value. Somebody who wanted left-to-right evaluation could supply the negative flag to disable this.

1 Like

I think this is a good idea. We should be taking advantage of what the standard allows us to do.

1 Like

I would like to enable this transformation by default in flang, rather than continuing with our current left to right expression evaluation.

This sounds reasonable to me. Would you set the default based on optimization level, so that it remains disabled at -O0?

This sounds reasonable to me. Would you set the default based on optimization level, so that it remains disabled at -O0?

Sure. O1 and above sound good to me.

Draft PR [flang] Enable FP sum reassociation by default at O1 and above by tblah · Pull Request #218746 · llvm/llvm-project · GitHub

1 Like

I would favor being consistent between O0 and O… so that people using -g to debug a program previously compiled with -O1 or -O2 get a program behavior as close as possible from it.

+1 for having/exposing a switch to control it however.

Having thought about it, I agree with Jean and will take this approach. I sufficiently badly written program could have control flow differences due to the small numerical differences and that would be very frustrating to debug if the problem goes away at -O0 -g. I will enable by default at all optimisation levels.

I have taken the PR out of draft.