[flang][RFC] Proposal for complex number lowering through MLIR
[platform/upstream/llvm.git] / flang / docs / ComplexOperations.md
1 # Complex Operations
2
3 ```eval_rst
4 .. contents::
5    :local:
6 ```
7
8 Fortran includes support for complex number types and a set of operators and
9 intrinsics that work on these types. Some of those operations are complicated
10 and require runtime function calls to implement.
11
12 This document outlines a design for generating these operations using the MLIR
13 complex dialect while avoiding cross-platform ABI issues.
14
15 ## FIR Representation
16
17 MLIR contains a complex dialect, similar to the Math dialect also used for
18 lowering some integer and floating point operations in Flang. Conversion between
19 fir.complex types and MLIR complex types is supported.
20
21 As a result at the FIR level, complex operations can be represented as
22 conversions from the fir.complex type to the equivalent MLIR complex type, use
23 of the MLIR operation and a conversion back.
24
25 This is similar to the way the math intrinsics are lowered, as proposed [here][1]
26
27 **Fortran**
28 ```fortran
29 function pow_self(c)
30   complex, intent(in) :: c
31   complex :: pow_self
32   pow_self = c ** c
33 end function pow_self
34 ```
35
36 **FIR**
37 ```c
38 func.func @_QPpow_self(%arg0: !fir.ref<!fir.complex<4>>) -> !fir.complex<4> {
39     %0 = fir.alloca !fir.complex<4>
40     %1 = fir.load %arg0 : !fir.ref<!fir.complex<4>>
41     %2 = fir.load %arg0 : !fir.ref<!fir.complex<4>>
42     %3 = fir.convert %1 : (!fir.complex<4>) -> complex<f32>
43     %4 = fir.convert %2 : (!fir.complex<4>) -> complex<f32>
44     %5 = complex.pow %3, %4 : complex<f32>
45     %6 = fir.convert %5 : (complex<f32>) -> !fir.complex<4>
46     fir.store %6 to %0 : !fir.ref<!fir.complex<4>>
47     %7 = fir.load %0 : !fir.ref<!fir.complex<4>>
48     return %7 : !fir.complex<4>
49   }
50 ```
51
52 Some operations are currently missing in the MLIR complex dialect that we would
53 want to use here, such as powi and the hyperbolic trigonometry functions.
54 For the missing operations we call directly to libm where possible, for powi
55 we provide an implementation in the flang runtime.
56
57 ## Lowering
58
59 The MLIR complex dialect supports lowering either by emitting calls to the
60 complex functions in libm (ComplexToLibm), or through lowering to the standard
61 dialect (ComplexToStandard). However, as MLIR has no target awareness, the
62 lowering to libm functions suffers from ABI incompatibilities on some platforms.
63 As such the custom lowering to the standard dialect is used. This may be
64 something to revisit in future if performance could be improved by using the
65 libm functions.
66
67 Similarly to the numerical lowering through the math dialect, certain MLIR
68 optimisations could violate the precise floating point model, so when that is
69 requested lowering manually emits calls to libm, rather than going through the 
70 MLIR complex dialect.
71
72 The ComplexToStandard dialect does still call into libm for some floating
73 point math operations, however these don't have the same ABI issues as the
74 complex libm functions.
75
76 [1]: https://discourse.llvm.org/t/rfc-change-lowering-of-fortran-math-intrinsics/63971