This is an archive of the discontinued LLVM Phabricator instance.

[Flang] Change complex divide lowering
ClosedPublic

Authored by kiranchandramohan on Apr 30 2023, 5:56 AM.

Details

Summary

Currently complex division is lowered to a fir.divc operation and the
fir.divc is later converted to a sequence of llvm operations to perform
complex division, however this causes issues for extreme values when
the calculations overflow.

This patch changes the lowering of complex division to use the Intrinsic
Call functionality to lower into library calls (for single, double,
extended and quad precisions) or an MLIR complex dialect division operation
(for half and bfloat precisions).

A new wrapper function genLibSplitComplexArgsCall is written to handle
the case of the arguments of the Complex Library calls being split to
its real and imaginary real components.

Note 1: If the Complex To Standard conversion of division operation
matures then we can use it for all precisions. Currently it has the
same issues as the conversion of fir.divc.
Note 2: A previous patch (D145808) did the same but during conversion of
the fir.divc operation. But using function calls at that stage leads to
ABI issues since the conversion to LLVM is not aware of the complex target
rewrite.
Note 3: If the patch is accepted, fir.divc can be removed from FIR. We
can use the complex.div operation where any transformation is required.

Diff Detail

Event Timeline

Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptApr 30 2023, 5:56 AM
kiranchandramohan requested review of this revision.Apr 30 2023, 5:56 AM
PeteSteinfeld accepted this revision.May 3 2023, 10:03 AM

Thanks for fixing this up, Kiran.

All builds, tests, and looks good. All tests that failed with the previous effort now pass.

This revision is now accepted and ready to land.May 3 2023, 10:03 AM

Would it be possible to continue to use MLIR ComplexToStandard when building with fast math? When I did some tests before, using ComplexToStandard is significantly faster than doing the library calls.

Would it be possible to continue to use MLIR ComplexToStandard when building with fast math? When I did some tests before, using ComplexToStandard is significantly faster than doing the library calls.

With the present settings, the MLIR operations are used by default and would cause correctness issues for Complex Divide when not using fast math. If we can change the setting to only use MLIR Operations with fast-math or approx-func then we can switch to MLIR Complex operations for divide at all precisions and take advantage of ComplexToStandard.

Sorry not sure I understand; from what I can see this patch changes it to always use a function call rather than any MLIR operation. I was wondering if we can keep the MLIR operation when fastmath is turned on

kiranchandramohan added a comment.EditedMay 4 2023, 1:55 PM

Sorry not sure I understand; from what I can see this patch changes it to always use a function call rather than any MLIR operation. I was wondering if we can keep the MLIR operation when fastmath is turned on

Currently, the default setting of mathRuntimeVersion is fastVersion. So if I add MLIR complex.div generation then it will always be generated and that will cause precision issues.

I think we should explore setting the mathRuntimeVersion to preciseVersion or fastVersion based on user flags in a separate patch. Once that is done, we can enable MLIR complex.div generation with fast-math or approx-func or something similar.

vzakhari accepted this revision.May 4 2023, 6:42 PM

Thank you for fixing this, Kiran!

DavidTruby accepted this revision.May 5 2023, 5:47 AM

Ok I understand, this patch looks good to fix the issue in the mean time, thanks!

This revision was automatically updated to reflect the committed changes.
Renaud-K reopened this revision.May 5 2023, 10:35 AM
Renaud-K added a subscriber: Renaud-K.

Hello,

The signature for __divsc3 is

complex float __divsc3 (float a, float b, float c, float d)

not

complex float __divsc3 (complex float a, complex float b)

Can you please fix it?

This revision is now accepted and ready to land.May 5 2023, 10:35 AM

Hello,

The signature for __divsc3 is

complex float __divsc3 (float a, float b, float c, float d)

not

complex float __divsc3 (complex float a, complex float b)

Can you please fix it?

Thanks @Renaud-K. Will revert for now.

Note 3: If the patch is accepted, fir.divc can be removed from FIR.

Are you sure you want to get rid of exposing the operation to the compiler's optimizer? There may be special-case transformations such a cplx1 * cplx2 / cplx2 -> cplx1 (see Fortran rules about arithmetic simplification), {0,0} / cplx -> {0,0}, or even floating point projection {re1, 0} / {re2, 0} -> re1 / re2 that could be performed for better performance.

Note 3: If the patch is accepted, fir.divc can be removed from FIR.

Are you sure you want to get rid of exposing the operation to the compiler's optimizer? There may be special-case transformations such a cplx1 * cplx2 / cplx2 -> cplx1 (see Fortran rules about arithmetic simplification), {0,0} / cplx -> {0,0}, or even floating point projection {re1, 0} / {re2, 0} -> re1 / re2 that could be performed for better performance.

Hi Eric,
I was hoping can use the MLIR complex dialect complex.div for these transformations just like we use the math dialect operations.

Update to fix issue pointed by @Renaud-K. This is accomplished by
a wrapper function that correctly calls the library functions with
the complex arguments split into the real and imaginary parts, the
result value is still a complex value.

Also updated HLFIR to use the new lowering.

kiranchandramohan edited the summary of this revision. (Show Details)May 9 2023, 7:21 AM
kiranchandramohan added a reviewer: jeanPerier.
jeanPerier accepted this revision.May 11 2023, 12:29 AM

Thanks for updating the HLFIR path too!

This revision was automatically updated to reflect the committed changes.