Hi, welcome to another blog of mine. I am back with GSoC, Season 2, this time with LFortran, an awesome compiler project for Fortran, an underappreciated but beautiful programming language. I am working on adding support for arrays under the mentorship of Ondřej Čertík, who is also the founder of LFortran. In this and upcoming blogs I will be discussing weekly progress of my GSoC project. Let’s get started with the first week.
During the first week, I worked on three things, first one being extending support for declaring any type of static array, the second one involves making initialiser expressions work for static arrays and the last one is about passing arrays to intrinsic functions such as
size. I have provided details on each of the three in the following subsections.
Declaring Static Arrays
In Fortran, arrays are declared by providing dimensions to the type or variable in either of the following ways,
real, dimension(2,3,4) :: h or
real :: h(2, 3, 4). This code was getting parsed for
integer and LLVM IR was successfully generated. However, for other types such as
complex and derived types, the support was only available till Abstract Semantic Representation (ASR) level. Note that LFortran has three levels of abstraction, Abstract Syntax Representation (AST) which extracts all the syntactic information directly available from the Fortran program; ASR, which makes out the meaning from ASR and checks whether the program is making sense and Backend (such as LLVM) generates target code (binary, C++, etc) depending upon the user input. Now coming back to the blog. So, in this week I extended support for generating LLVM IR for declarations of
logical and derived types.
Merge Request - !931
Initialising Static Arrays
After completing declaration, I headed towards providing support for initialzer expressions for arrays. One example is,
x = [(i+1, i*2, i = 1, 3)], where
x is the array variable. First I added
ImpliedDoLoop node at ASR level and then I introduced an ASR pass to convert the overall assignment operation with array variable on the LHS and an ArrayInitializer wrapping an ImpliedDoLoop to a DoLoop. Basically the pass performs the following task,
x = [(i*2, i = 1, 6)]
do i = 1, 6 x(i) = i*2 end do
This allows us to generate LLVM IR without even touching the backend algorithm as the resulting do loop has all the logic already implemented in the LLVM backend to generate LLVM IR. I learnt the trick of writing ASR passes from Ondřej before GSoC and that worked beautifully here.
Merge Request - !932
Passing Fortran Arrays To Intrinsic Functions
I would say this was the most challenging part of the first week. It required a hell lot of brainstorming. The main problem was to decide the interface of
size intrinsic function in LLVM IR. The LLVM IR considers static arrays of different sizes as different types altogether. Hence, we may need to define different
size functions for different sized arrays doing exactly the same thing again and again. So, in the end I finally decided to extract the dimension information (lower bound, upper bound) and pass it to the interface. Since, dimension descriptor is of a single unique type we will be needing just one definition of
size function at LLVM level. However, the game is not over yet. Ondřej highlighted some important points today. One of them is the issue of overshadowing of user defined
size function with the intrinsic function but the opposite should happen. I am working on it and will let you know in the next week’s update. Until then stay tuned…
Merge Request - !918