State of Fortran on iOS

State of Fortran on iOS

If you have any ideas, questions or want to help, message me.

Why care about Fortran on iOS? Because Numpy depends on Lapack and BLAS, both of which need Fortran. Scipy needs Fortran directly and indirectly through Numpy. OpenCV needs Numpy but it’s still not clear to me wether it indirectly needs LAPACK and BLAS or if it can work with pure Numpy.

What needs to be done to port a Fortran compiler to iOS?

  • The runtime may need changes. Those are things like basic mathematical functions e.g. cos, sin, array multiply, etc.

  • Support for the Apple ABI needs to be added.

The Apple ARM ABI differs a bit from the standard ARM ABI. Specifically the call convention for variadic functions is different. On ARM the arguments for variadic functions are put on registers, until they are full, then anything else is put on the stack. On Apple all variadic arguments are put on the stack. The rationale for this actually makes sense but unfortunately also means Fortran compilers won’t work out of the box.

We have a few options at different levels of not working:

Flang clasic: I tried to port flang classic to Apple Silicon. Given it’s based on LLVM, which already targets iOS, I naively assumed the runtime would be the hardest part, and thus that’s where I started (I prefer to hit an wall as soon as possible and move to something else). There were some things to be done on the runtime, such as polyfills for the GNU libc extensions to set FPU modes. But unfortunately I was not able to implement the call convention.

Flang doesn’t use only the LLVM IR, it also has its own intermediate representation called ILI. The great people at flang suggested I do the ABI port by modifying how the IL_VA_ARG opcode is lowered.

There is an ILI opcode, IL_VA_ARG, which is lowered by gen_va_arg in cgmain.cpp, which is heavily customized for PowerPC. There is no ILI opcode for va_start or va_end, even though cgmain.cpp defines gen_va_start and gen_va_end, which generate IR that calls the llvm.va_start and llvm.va_end intrinsics. These two functions are also never called by flang2.

Fortran code doesn’t consume the va_list data structure so that probably explains why we don’t need gen_va_start and gen_va_end.

Bryan Chan

If you have any ideas on how to do the IL_VA_ARG lowering, or just wants to know more about it, please contact me. Simply explaining a problem to someone else can be enlightening.

GCC: There is an ongoing effort to port GCC to Apple Silicon gcc-darwin-arm64. It seems to be making progress. Someone was able to build an iOS cross-compiler. Proper support for iOS would still require the addition of the iOS triplet arm64-apple-ios.

Apple’s Accelerate framework: Apple has its own LAPACK/BLAS implementation shipped with every macOS and iOS device. This would be enough to get Numpy working, while Scipy would still need a Fortran compiler. Unfortunately Accelerate has bugs and implements LAPACK 3.2.1, a version from 2009. Neither Numpy nor Scipy support it.

The Pyodide approach: It seems the Pyodide project was able to compile scipy to wasm. Initially they used CLAPACK and f2c (a Fortran to C transpiler). CLAPACK is also stuck on 3.2.1, just like Accelerate, a very interesting coincidence. Now they seem to be using LFortran.

LFortran: Doesn’t seem to support Apple Silicon as of June 2022, I still have to investigate how easy a port would be. This time I will start with the ABI. (Someone was able to get it running on Apple Silicon, it worked for basic arithmetic but in all likelihood will run into the same ABI problem as Flang. The ABI support doesn’t come out of the box with LLVM).