# \[RFC\] Proposing an Interactive Fortran Workflow with Flang using Jupyter Notebooks

**URL:** <https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116>\
**Category:** Flang\
**Created:** [December 12, 2025, 3:39pm UTC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116 "2025-12-12T15:39:07Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![anutosh491](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/anutosh491/32/26151_2.png) [@anutosh491](https://discourse.llvm.org/u/anutosh491)\
**Post date:** [December 12, 2025, 3:39pm UTC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116/1 "2025-12-12T15:39:07Z")

</div>

_Hi All,_

_I’m Anutosh, a core developer on **clang/clang-repl** , part of **Project Jupyter** and currently working at **QuantStack**. Previously I was a member at another LLVM-based Fortran compiler, [LFortran](https://github.com/lfortran/lfortran). I had presented the above idea in the previous flang biweekly meeting and was advised to frame a RFC for the same._

_TLDR_

- We believe there is a clear and technically viable path to implementing a flang Interpreter that could be the basis of a Jupyter Fortran Kernel — following a similar approach we used for the C++ Interpreter & Kernel. This should even run completely in your browser through WASM.
- We are seeking feedback from the Flang community on the feasibility and suitability of the approach described below. Community insight will be invaluable in validating assumptions, identifying challenges, and shaping the direction of a prototype.
- We would also like to understand whether the community sees value in such an interactive workflow. Our intuition is that this could meaningfully support education and teaching, exploratory numerical computing, and certain HPC workflows (such as interactive CUDA & OpenMP workflows), among other use cases.
- Finally, we would love to collaborate with potential partners (especially Flang maintainers) and explore funding opportunities to help realise this project.

* * *

## **Problem Statement**

1. The Fortran ecosystem still lacks a modern, interactive workflow—something equivalent to a REPL or an Interpreter that many other LLVM-based languages now support. This limits rapid prototyping, teaching, exploratory numerical work, and smooth integration with tools like Jupyter.

2. What was achievable through **LFortran** : During my time working on LFortran , we could leverage the Interpreter it provided to come up with a Jupyter Kernel which demonstrated an incremental, REPL-style Fortran workflow. Here’s a [demo](https://github.com/lfortran/lfortran/blob/main/share/lfortran/nb/Demo1.ipynb) notebook that we can run through LFortran.

3. Why Flang ? Since Flang is the long-term Fortran frontend for LLVM—with FIR, MLIR, and tight integration across the toolchain—it feels like the natural place to bring interactive Fortran into the mainstream.

## **Motivation**

The motivation for this work comes from the systems we, The Project Jupyter & Clang-repl Community have been working on since the past 1.5-2 years.

Even before we get started, I would like everyone to try out our [JupyterLite C++ Kernel](https://compiler-research.org/xeus-cpp-wasm/lab/index.html)

- [Jupyterlite](https://github.com/jupyterlite/jupyterlite) is a Jupyterlab distribution that runs entirely in the browser and is powered by WebAssembly.
- Open up a C++/C kernel or one of the demo notebooks provided on the left. You should be able to **“Interpret” C++ completely in the browser, no local setup whatsoever in a REPL format**.
- Feel free to explore anything from BLAS & LAPACK routines through Openblas & Xtensor, to interactive Jupyter widgets to Graphics using SDL.

Now that you might have experienced using the Kernel, let me highlight the work done for supporting the kernel.

1. [Clang-Repl](https://clang.llvm.org/docs/ClangRepl.html) is an interactive C++ interpreter that allows for incremental compilation. Please go through the link attached for the design and workflow.

The design is tightly coupled with the Clang compiler itself: clang-repl reuses Clang’s parsing, semantic analysis, and code-generation pipeline, and builds an incremental execution layer on top of LLVM’s JIT infrastructure (ORC). So clang-repl is provided both as a standalone [tool](https://github.com/llvm/llvm-project/blob/main/clang/tools/clang-repl/ClangRepl.cpp) and as a library ([libclangInterpreter](https://github.com/llvm/llvm-project/tree/main/clang/lib/Interpreter)) so its incremental facilities can be embedded directly into other applications.

1. [Xeus-Cpp](https://github.com/compiler-research/xeus-cpp) which is the native Jupyter C/C++ Kernel working on linux, macOS and windows platforms built on top of clang-repl.This enables several capabilities that go beyond what the standalone clang-repl tool provides:

- **General C++ workflows** : Here’s a [demo notebook](https://github.com/compiler-research/xeus-cpp/blob/main/notebooks/xeus-cpp.ipynb) showcasing basic C++ and Jupyter’s rich rendering capabilities (images/widgets etc)
- **CUDA support:** We recently [fixed](https://github.com/llvm/llvm-project/pull/137458#issuecomment-3223276446) running cuda through clang-repl. Here are some demo notebooks ([notebook1](https://github.com/compiler-research/xeus-clang-repl/blob/main/notebooks/kalman_CUDA_demo/run_kf.ipynb) [notebook2](https://github.com/compiler-research/xeus-cpp/blob/7059770d81716c9a6f62a5f75606640ce6a480b7/notebooks/vectorAddCuda.ipynb))
- **OpenMP support** : We also added OpenMP support to clang-repl, which may be particularly relevant for Flang given the amount of OpenMP work happening in the Fortran ecosystem. Here’s a [demo notebook](https://github.com/compiler-research/xeus-cpp/blob/da0cc730b175c2dd880d16845187e68917afc9f5/notebooks/openmp-notebooks/openmp-demo.ipynb)

1. **Xeus-Cpp-Lite** which is a JupyterLite kernel shown above using Xeus-cpp & JupyterLite.

As clang-repl uses the ORC JIT for native platforms but JIT doesn’t work with WASM, we framed a separate WASM backend for clang-repl. This involved compiling llvm, clang and the kernel, Xeus-Cpp itself to WASM. Here’s my [blogpost](https://medium.com/jupyter-blog/c-in-jupyter-interpreting-c-in-the-web-c9d93542f20b) on Project Jupyter’s medium from a technical standpoint explaining all the effort behind this.

1. **Debugger Support in Xeus-Cpp** : We have been participating in Google Summer of Code for the past few years, and this year we introduced **Debugger Support** for xeus-cpp.

This required running clang-repl out-of-process, integrating with **LLDB** and **lldb-dap** , and building on top of Jupyter’s Debug Adapter Protocol implementation. The result is the ability to set breakpoints, step through code, inspect variables, and debug JIT-generated code entirely from a Jupyter notebook.  
Here’s a [demo](https://drive.google.com/file/d/1KxMpHz7njRTb2d1FSTPumZXfgoNRHhbM/view) for the same and the [final gsoc report](https://compiler-research.org/blogs/gsoc25_abhinav_kumar_introduction_blog/).

I recently also gave a talk about the whole ecosystem revolving around interactive C++ through Jupyter at PyData Paris 2025. Here are the [slides](https://anutosh491.github.io/pydata2025/#/) for the same. The video for the talk would be available soon.

# **Proposal**

Given this background, I began exploring whether something similar could be possible for Flang.

1. Going through Andrzej Warzynski’s [talk](https://www.youtube.com/watch?v=OvTiKWfhaho&t=68s) _“How to write a new compiler driver? The LLVM Flang perspective”_ from EuroLLVM 2022 I realize that Flang’s frontend and driver architecture take intentional inspiration from Clang. This makes me think that the incremental model we use in clang-repl could also be adapted for Fortran.

2. I see an [Execution Engine](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/ExecutionEngine/ExecutionEngine.h) based on MLIR exists. Just as clang-repl lowers interactive input to LLVM IR and executes it through ORC, Flang lowers to **FIR/MLIR** , and the presence of **MLJIT** suggests a path toward an incremental, REPL-style execution model based on MLIR rather than LLVM IR.

3. **This could form the foundation for a “flang-repl,” with the possibility of extending it into a full interactive environment similar to xeus-cpp.** In particular, if an incremental pipeline for Flang were possible, we could imagine:

- A **flang-repl tool** , analogous to clang-repl. I think we can come up with a flang interpreter tightly coupled with the compiler.
- A **xeus-fortran kernel** for interactive Fortran in Jupyter, with the ability to load and use existing Fortran libraries from ecosystems such as **fpm** , **conda-forge** , or system installations.
- A **xeus-fortran-lite variant** , running Fortran entirely in the browser through WebAssembly.
- **Interactive CUDA/OpenMP workflows** , similar to what we support today in xeus-cpp.
- **Debugger integration** , using the same Jupyter DAP stack we built for C++.

# **Expected Concerns and Preliminary Responses**

These are questions that naturally arise when evaluating this proposal. I’ve attempted to provide preliminary answers, and community insight would be valuable in validating or extending them.

**Q1)**  **Flang was built with the idea of being an ahead of time compiler. Out of the box it will not be able to parse incomplete source code as that will result in semantic errors. How do incremental workflows fit here ? Will this require deep changes to parsing and semantics?**

You are absolutely right that Flang is currently an ahead-of-time compiler with a different frontend than Clang.

What I wanted to highlight is that Clang itself started in the same “pure AOT” world (technically it implements the c++ standard where neither compilation nor interpretation is mentioned so in theory should support both equally well but most of the use cases are AOT). Out of the box it assumed a complete translation unit, performed all semantic checks at end-of-TU, and then tore down state.

To get clang-repl working, we had to introduce an explicit _incremental_ mode on top of that design: a new [TU\_Incremental](https://github.com/llvm/llvm-project/blob/f1ddb2f4120645b56802859e26e2006e6db72597/clang/include/clang/Basic/LangOptions.h#L1125-L1127) kind, an [IncrementalAction](https://github.com/llvm/llvm-project/blob/f1ddb2f4120645b56802859e26e2006e6db72597/clang/lib/Interpreter/IncrementalAction.h#L24-L33) that avoids the usual end-of-TU cleanup, and an [IncrementalParser](https://github.com/llvm/llvm-project/blob/f1ddb2f4120645b56802859e26e2006e6db72597/clang/lib/Interpreter/IncrementalParser.h#L35-L38) /[IncrementalExecutor](https://github.com/llvm/llvm-project/blob/f1ddb2f4120645b56802859e26e2006e6db72597/clang/lib/Interpreter/IncrementalExecutor.h#L45) layer that keeps the AST, Sema state and generated IR alive across many snippets instead of discarding them after one compile. In other words, we didn’t change Clang’s core semantics, but we wrapped them in a growing “ever-extending” translation unit and routed each snippet through the existing frontend, then into the JIT. All of this is encapsulated within an [Interpreter](https://github.com/llvm/llvm-project/blob/f1ddb2f4120645b56802859e26e2006e6db72597/clang/include/clang/Interpreter/Interpreter.h#L90-L91).

This “ever-growing” AST can be seen through an AST dump

```auto
$ ./clang-repl --Xcc=-Xclang --Xcc=-ast-dump "int x = 10;"
TranslationUnitDecl 0x555561012608 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x5555610132c8 <<invalid sloc>> <invalid sloc> implicit __int128_t '__ int128'
| `-BuiltinType 0x555561012bd0 '__int128'
.......
.......
TranslationUnitDecl 0x555561060e08 prev 0x555561012608 <<invalid sloc>> <invalid sloc>
|-CXXRecordDecl 0x555561060e70 <input_line_0:5:5, col:39> col:12 referenced struct __clang_Interpreter_NewTag definition
| |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
.......
.......
TranslationUnitDecl 0x55556108aeb0 prev 0x555561060e08 <<invalid sloc>> <invalid sloc>
`-VarDecl 0x55556108af30 <input_line_1:1:1, col:9> col:5 x 'int' cinit
  `-IntegerLiteral 0x55556108af98 <col:9> 'int' 10

```

What can be seen here ?

- 3 TUDECL nodes - 1 for Builtin, 1 for Runtimes, 1 for Input1. Each input would have 1.
- Each TUDECL node has links with the previous node. So every node is tracked.

For Flang, I’m imagining something analogous in spirit : keeping the existing parser & semantics as-is, but adding a minimal “incremental mode” where the frontend state is preserved between snippets, and where some of the end-of-compilation checks are relaxed so that later inputs can extend earlier ones.

So there are really two orthogonal pieces:

1. making the frontend capable of being driven incrementally, and
2. feeding the resulting MLIR into MLIR JIT.

Some References

1. Here’s the [RFC](https://lists.llvm.org/pipermail/llvm-dev/2020-July/143257.html#:~:text=include%20small%20adjustments%20in%20the,9) for clang-repl. It also mentions that Clang’s existing infrastructure happened to align really well with incremental use cases.
2. Clang-repl’s [1st commit](https://github.com/llvm/llvm-project/commit/44a4000181e1a25027e87f2ae4e71cb876a7a275#diff-8f4bd8d4e1db005f0d7e05f992107d44a45589b1eb6bec4ce3fa0f557045bdcc) & [2nd commit](https://github.com/llvm/llvm-project/commit/11b47c103a36371576711cae1f7527c26f78efb5#diff-24cfc914fa9db29941f90304065878323d2710ea1c877159aed591f6474c4cdb)that have almost all of the design changes needed to support incremental mode.

**Q2)**  **Flang is technically not a cross compiler. How will the wasm use case work ? Even if we have flang-repl, would we be able to achieve flang-repl completely in the browser ?**

Absolutely true, Flang cannot generate WebAssembly output out of the box. Despite this, we’ll soon see that with LLVM’s modular design it’s possible to use the Flang frontend with LLVM’s WebAssembly backend. I would like to highlight work done by few people in this regard

1. **George Stagg** was able to hack around flang and compile BLAS & LAPACK to WASM. He describes his work & patches through a very well framed blog post [here](https://gws.phd/posts/fortran_wasm/)
2. **Serge Guelton** , a LLVM core dev was able to build on top of this and introduced some of patches in a more generic way upstream to flang. I would encourage all to go through his 5 minute long FOSDEM 2025 talk with the topic [Flang + WASM](https://archive.fosdem.org/2025/schedule/event/fosdem-2025-5202-oo-flang-wasm-oo/). He speaks on how people want to run Scipy in the browser through Jupyter for education and as Scipy depends on LAPACK, we would need to compile it to WASM.
3. Though some patches were merged some remained open. But **Axel Obermeier,** another LLVM and conda-forge core dev hosted this patched version of flang on [conda-forge](https://github.com/conda-forge/flang-feedstock/pull/69)
4. Since R relies on BLAS and LAPACK and many essential R packages wrap native libraries that use Fortran, **Isabel Parades** was able to use the above build to compile the whole R stack for WASM and get a working [Jupyterlite R kernel](https://jupyter-xeus.github.io/xeus-r/lab/index.html) working entirely in the browser.
5. **Thorsten Beier** , **Isabel Parades** and **Ian Thomas** also used this build to compile scipy for wasm. Try it out [here](https://ianthomas23.github.io/scipy-4x-deploy/lab/index.html)

Building on top of this work & the design used for clang-repl would be the way to proceed here.  
How clang-repl’s [wasm](https://github.com/llvm/llvm-project/blob/main/clang/lib/Interpreter/Wasm.h) backend works is very well explained on slides [9/10/11](https://anutosh491.github.io/pydata2025/#/8/0/6) from my PyData Paris talk, but giving an overview :

i) Every input cell is compiled into a wasm object file, which is fed to wasm-ld to generate a standalone side module.

ii) This is loaded on top of a main module at runtime using emscripten’s dlopen mechanism. These modules share the same memory as the main module and there’s symbol resolution going on at load time to access definitions from previous cells.

As an experiment we could try to replicate flang-repl in the browser through Jupyter using the C++ Kernel, Xeus-Cpp-Lite. This works because we expect the same design to work in theory.

**Cell 1** : Has a global definition for a variable  
**Cell 2** : Has an incomplete module that depends on the definiton above  
**Cell 3** : Call for module defined in cell 2

```auto
// Cell 2

MODULE mymod
  IMPLICIT NONE
  INTEGER :: a ! global symbol, not defined here

CONTAINS

  SUBROUTINE foo(y, z)
    IMPLICIT NONE
    INTEGER, INTENT(IN) :: y
    INTEGER, INTENT(OUT) :: z
    z = a + y
  END SUBROUTINE foo

END MODULE mymod

```

Now how would cell 2 execute at runtime in the browser

```auto
# Using the patched flang as discussed
# Can be installed using 
micromamba install conda-forge/label/emscripten::flang libllvm19 --no-channel-priority

# Step 1: Compile Fortran code to relocatable object file
flang --target=wasm32-unknown-emscripten -fPIC -c cell2.f08 -o cell2.o

llvm-nm cell2.o
00000000 D _QMmymodEa
00000001 T _QMmymodPfoo

# Step 2: Link to a shared WebAssembly module with undefined symbol allowed
# Because load time is responsible for symbol resolution
wasm-ld -shared \
  --experimental-pic \
  --import-memory \
  --stack-first \
  --allow-undefined \
  cell2.o -o cell2.wasm

#Step 3: Loaded using emscripten's dlopen in the backend

```

 ![image](https://us1.discourse-cdn.com/flex021/uploads/llvm/original/3X/4/4/44b8da45eff37695feed9cdab7d1a98d1de85310.png)  
The above hardcoded dlopen in the frontend would be done in the backend at runtime when we execute cell 2 as fortran code through Jupyterlite.

# **Related Work**

1. **MLIR + WASM work in the** [llvm/eudsl](https://github.com/llvm/eudsl) **incubation project** : As a final confidence boost that the above approach is feasible, I came across some independent work on the EUDSL project.  
The EUDSL project exposes MLIR through Python bindings and allows running it Jupyter/JupyterLite.

Recently, they even added a **WebAssembly MLIR execution engine** ([PR](https://github.com/llvm/eudsl/pull/248)) whose implementation is simply using clang-repl’s design. I would have introduced something similar for the “flang-repl in the browser” concept and now we also have something to take inspiration from.

Checkout the [Jupyterlite notebook](https://llvm.github.io/eudsl/jupyter/lab/index.html) they provide. In practice, this means they can parse and construct MLIR from Python, execute it via the MLIR ExecutionEngine, and do all of this inside a JupyterLite instance running entirely in the browser.

In other words: we would already know how to

- lower incremental Fortran input to FIR/MLIR via a flang-repl frontend, and
- execute MLIR both natively (with the upstream MLIR JIT) and in the browser (using the MLIR execution engine from EUDSL’s JupyterLite playground).

Taken together with the flang→WASM proof-of-concept above, this is effectively the “cherry on top”.

1. **Wasm Dialect in MLIR by the WAMI Project (Carnegie Mellon/ Yale University)** : This is something I still need to explore and haven’t had a chance to dive deeper but looks useful.

The WAMI project demonstrates a complete MLIR-based pipeline for compiling to WebAssembly. It introduces an SSA-based `SsaWasm` dialect that enables high-level MLIR dialects like `func`, `scf`, and `arith` to be directly lowered to structured WebAssembly, preserving abstractions without relying on LLVM IR. The pipeline produces valid `.wasm` binaries and supports modern WebAssembly features, offering a modular path for languages targeting the Web

Here’s the [paper](https://www.arxiv.org/abs/2506.16048) and their [talk](https://www.youtube.com/watch?v=z2xmzf8f5Ac&t=794s) on youtube for the same.

* * *

_Any comments and thoughts are welcome !_

---

<div class="post-metadata">

**Author:** ![klausler](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/klausler/32/17758_2.png) [@klausler](https://discourse.llvm.org/u/klausler)\
**Post date:** [December 12, 2025, 11:38pm UTC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116/2 "2025-12-12T23:38:09Z")

</div>

(I had questions, but they were answered by a re-reading of the TLDR above.)

---

<div class="post-metadata">

**Author:** ![anutosh491](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/anutosh491/32/26151_2.png) [@anutosh491](https://discourse.llvm.org/u/anutosh491)\
**Post date:** [December 13, 2025, 12:23pm UTC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116/3 "2025-12-13T12:23:01Z")

</div>

Thanks for your question. I realize it made more sense being a bit more explicit with our request. I have made sure to address the same through an update in the TLDR section !

---

<div class="post-metadata">

**Author:** ![banach-space](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/banach-space/32/209_2.png) [@banach-space](https://discourse.llvm.org/u/banach-space)\
**Post date:** [December 14, 2025, 2:44pm UTC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116/4 "2025-12-14T14:44:32Z")

</div>

Hi @anutosh491, thank you for this very comprehensive and detailed RFC!

I haven’t worked on Flang for a while now, but the overall idea comes across as sound. While I’m not entirely sure how widely Jupyter Notebooks are used in practice, leveraging LLVM Flang to make teaching Fortran easier certainly feels like a worthwhile endeavour.

> [@anutosh491](#):
>
> The Fortran ecosystem still lacks a modern, interactive workflow—something equivalent to a REPL or an Interpreter that many other LLVM-based languages now support.

Out of curiosity, what are the other languages here? Specifically, are there any non-Clang examples?

> [@anutosh491](#):
>
> Going through Andrzej Warzynski’s [talk](https://www.youtube.com/watch?v=OvTiKWfhaho&t=68s) _“How to write a new compiler driver? The LLVM Flang perspective”_ from EuroLLVM 2022 I realize that Flang’s frontend and driver architecture take intentional inspiration from Clang.

Great to see that the presentation was helpful! Just to clarify, and to avoid any confusion:

1. Flang’s **compiler driver** is built on top of Clang’s `clangDriver` library.
  - You should be able to re-use a fair amount from `clang-repl` here.

2. Flang’s **frontend driver** , while inspired by Clang’s, was written from scratch and is independent of Clang.
  - This part is different, meaning no direct re-use of `clang-repl` logic.

It’s worth keeping the second point in mind when drawing conclusions based on your `clang-repl` work - just to avoid surprises later. 🙂

For reference, the split into compiler and frontend drivers is documented here: [Flang drivers — The Flang Compiler](https://flang.llvm.org/docs/FlangDriver.html).

> [@anutosh491](#):
>
> Flang is technically not a cross compiler. How will the wasm use case work ?

This is another area that might require deeper investigation.

The links you provided show that cross-compiling to WASM is possible, but they appear to be downstream PoCs. Since Flang lowers through LLVM IR, we already know that - _in principle_ - any backend supported by LLVM can be supported by Flang. The challenge is in the details:

- “productising” proper cross-compilation support in Flang and removing any hidden assumptions like “target triple == host triple.”

Since I haven’t been active in Flang recently, I’m not fully up to date on the current state here. It’s possible that some of these issues are already well understood or even solved.

> [@anutosh491](#):
>
> I see an [Execution Engine](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/ExecutionEngine/ExecutionEngine.h) based on MLIR exists. Just as clang-repl lowers interactive input to LLVM IR and executes it through ORC, Flang lowers to **FIR/MLIR** , and the presence of **MLJIT** suggests a path toward an incremental, REPL-style execution model based on MLIR rather than LLVM IR.

One clarification: there is no **MLJIT**. 🙂  
MLIR, like `clang-repl`, relies on LLVM’s ORC JIT ([ORC Design and Implementation — LLVM 22.0.0git documentation](https://llvm.org/docs/ORCv2.html)) for execution. This is used extensively in MLIR’s end-to-end testing, so I would consider the JIT side of things a “solved problem.”

* * *

In summary, I see two main challenges:

- **Cross-compilation** (including WASM).
- **Incremental compilation** (including parsing + sema).

Both seem solvable, though each will require careful design.

Hopefully this helps!

Best regards,  
-Andrzej

---

<div class="post-metadata">

**Author:** ![anutosh491](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/anutosh491/32/26151_2.png) [@anutosh491](https://discourse.llvm.org/u/anutosh491)\
**Post date:** [December 15, 2025, 8:31am UTC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116/5 "2025-12-15T08:31:50Z")

</div>

> [@banach-space](#):
>
> While I’m not entirely sure how widely Jupyter Notebooks are used in practice, leveraging LLVM Flang to make teaching Fortran easier certainly feels like a worthwhile endeavour.

- I would encourage the audience here to check out the [NumPy.org](http://NumPy.org) website (and the code console provided there). The JupyterLite based code console provides a computational environment to thousands of monthly visitors without incurring any cloud costs.
- Similarly, the Capytale deployment of Jupyter, used in French high schools for education, operates on the same model. It accounts for over half a million registered users and hosts more than 200,000 user sessions weekly.
- Please checkout the [Project Jupyter | Try Jupyter](https://jupyter.org/try) website mentioning all the kernels that are being supported. We cover a broad domain from **GNU Octave** to **Ruby**. The latest additions were **Haskell** Kernel and **Ocaml** Kernels. Please check out the demos here [[Haskell](https://jupyter-xeus.github.io/xeus-haskell/lab/index.html?path=introduction_to_haskell.ipynb), [OCaml](https://davy39.github.io/xeus-ocaml/?path=demo.ipynb)]

What’s missing is fortran and hence the RFC 😉

> Out of curiosity, what are the other languages here? Specifically, are there any non-Clang examples?

From the top of my head I think the [Julia-repl](https://docs.julialang.org/en/v1/devdocs/jit/), [Jank-repl](https://jank-lang.org/) and if I remember correctly even the [rust excvr repl](https://github.com/evcxr/evcxr/tree/main/evcxr_repl) make use of LLVM’s JIT infrastructure.

> just to avoid surprises later

Yes, absolutely fair. Although I’ve tried to generate decent “proof of concept” and tried to reason that the changes for flang-repl with respect to parsing and sema would be minimalistic (just like clang-repl), we know that we would surely have to tackle some differences here and there !

**This is also where collaborating/working closely with a flang maintainer would be helpful for us.**

> - “productising” proper cross-compilation support in Flang and removing any hidden assumptions like “target triple == host triple.”

I would like to invite @serge-sans-paille, a core llvm dev, here. He worked on this thing closely while enabling wasm cross compilation through flang. He, also mentions the same in his FOSDEM 2025 talk that I linked above. He should possibly be the best person I know who can educate us with how challenging it might be to get past this. Quite some of his work on this was merged upstream too. Serge could also let us know what remains, if any !

> One clarification: there is no **MLJIT**. 🙂  
> MLIR, like `clang-repl` , relies on LLVM’s ORC JIT ([ORC Design and Implementation — LLVM 22.0.0git documentation](https://llvm.org/docs/ORCv2.html)) for execution. This is used extensively in MLIR’s end-to-end testing, so I would consider the JIT side of things a “solved problem.”

Okay wow that’s perfect. I might have made an assumption (as I came across an ExecutionEngine.h file in MLIR’s source) that there exists an “MLJIT” based on top of the “ORC JIT”. But if we would end up using the ORC JIT directly, well and good !

> Both seem solvable, though each will require careful design.

Absolutely agreed.

Thanks a lot for your comments Andrzej.

Best Regards,  
Anutosh Bhat.

---

<div class="post-metadata">

**Author:** ![tarunprabhu](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/tarunprabhu/32/14862_2.png) [@tarunprabhu](https://discourse.llvm.org/u/tarunprabhu)\
**Post date:** [December 15, 2025, 5:00pm UTC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116/6 "2025-12-15T17:00:01Z")

</div>

> [@anutosh491](#):
>
> This is also where collaborating/working closely with a flang maintainer would be helpful for us.

Could you provide more details on what such a collaboration might entail?

> [@anutosh491](#):
>
> We are seeking feedback from the Flang community on the feasibility and suitability of the approach described below.

A REPL for Fortran is an interesting idea, and I can see it being useful for teaching. What is not clear to me is how this tool affects flang directly.

1. Do you anticipate non-trivial changes being required in `flang` to support a REPL? If so, do you expect flang developers to make these changes?

2. If you do anticipate non-trivial changes, are you asking if we would be willing to accept these non-trivial code contributions from your team?

3. Do you anticipate contributing a separate, standalone `flang-repl` tool to be included in the flang code base? This would be similar to tools such as `clang-format` in `clang` that are closely tied to clang (sort of - the analogy is imperfect). If so, are you asking if we are open to maintaining such a tool?

If you are already aware of changes that might be needed in Flang to support this, it’s probably best to raise these sooner rather than later with specifics.

---

<div class="post-metadata">

**Author:** ![klausler](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/klausler/32/17758_2.png) [@klausler](https://discourse.llvm.org/u/klausler)\
**Post date:** [December 15, 2025, 6:06pm UTC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116/7 "2025-12-15T18:06:11Z")

</div>

I understood that LFortran has at least one significant extension to Fortran to support incremental compilation, namely the ability to intersperse declarations with executable statements. Is this still true? If so, that’s likely to be a deal-breaker.

---

<div class="post-metadata">

**Author:** ![anutosh491](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/anutosh491/32/26151_2.png) [@anutosh491](https://discourse.llvm.org/u/anutosh491)\
**Post date:** [September 28, 2026, 10:58am UTC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116/8 "2026-09-28T10:58:14Z")

</div>

Hi @tarunprabhu , @klausler

Sorry for the delayed response. I lost momentum on this RFC and wasn’t sure if the flang community was in support of it. But rather than replying with only a design sketch, I wanted to return with something concrete.

I revisited this over the past weekend and now have a working native prototype, including a `flangInterpreter` library, a `flang-repl` tool, and a Jupyter kernel.

Let me first answer Tarun’s questions directly.

#### 1. Do I anticipate non-trivial changes to Flang?

There is some non-trivial new code, but the changes to Flang’s existing compilation path appear to be bounded and explicitly opt-in.

The prototype needs:

- support for compiling in-memory inputs;
- an interpreter-only `InteractiveCell` parsing entry point;
- a small frontend reset boundary so one configured `CompilerInstance` can process multiple cells;
- an embeddable `flangInterpreter` library; and
- a thin `flang-repl` command-line tool.

The last 3 points overlap directly with `clangInterpreter`/`clang-repl`.

Most of the implementation lives in the new interpreter library and tool. Ordinary batch-mode Flang parsing, semantic analysis and lowering remain unchanged.

I am not asking Flang developers to implement these changes. I am happy to drive the implementation, testing, upstream patch separation and ongoing maintenance. What I need from Flang developers is feedback on whether the proposed frontend boundaries are acceptable.

#### 2. Am I asking whether Flang would accept these contributions?

Yes, subject to the normal LLVM review process. I would split it into small, independently reviewable changes, starting with generally useful embedding/frontend APIs before proposing the interpreter library and tool.

#### 3. Am I proposing an in-tree `flang-repl` tool?

The intended design is:

- an embeddable `flangInterpreter` library in the Flang tree;
- a thin in-tree `flang-repl` client of that library; and
- the xeus/Jupyter kernel maintained separately.

This is closer to `clangInterpreter` and `clang-repl` than to `clang-format`.

If the community would prefer to begin with only the reusable frontend APIs while the interpreter matures out-of-tree, that is also a reasonable path. I would appreciate guidance on which ownership boundary the Flang community would prefer.

#### Regarding the Fortran language-extension concern

Notebook users can enter declarations and executable statements in successive cells, but the prototype does not make ordinary Flang accept a Fortran program with declarations interspersed between executable statements.

The current flow is:

```plaintext
notebook cell
  → opt-in InteractiveCell parser
  → normalize into ordinary Fortran program units
  → existing Flang semantic analysis
  → existing HLFIR/FIR/OpenMP lowering
  → one MLIR module
  → persistent JIT

```

Persistent declarations are placed in versioned generated modules. Executable statements are placed in a uniquely named generated `BIND(C)` cell procedure. Later cells use ordinary Fortran module interfaces to access earlier state.

Therefore, once normalization is complete, the semantic analyser sees standard Fortran constructs. We do not relax normal Fortran semantic rules, and:

```console
flang file.f90

```

continues to reject the same non-standard source as before.

This is an explicitly opt-in input protocol for the interpreter tool, not a language extension enabled in normal Flang compilation.

Complete modules, subroutines, functions and programs can also be supplied as cells and use the ordinary Flang path directly.

For example, a notebook cell such as:

```fortran
integer :: k
k = 5
print *, k

```

is parsed as one `InteractiveCell`, with a specification part and an execution part. Before normal semantic analysis, the builder constructs the parse-tree equivalent of:

```fortran
module flang_repl_state_1
  integer :: k
contains
  subroutine flang_repl_cell_1() bind(c, name="flang_repl_cell_1")
    k = 5
    print *, k
  end subroutine
end module

```

This transformation is structural—the implementation builds ordinary Flang parse-tree constructs rather than passing non-standard loose statements into semantic analysis. A declaration entered in a later notebook cell becomes part of a new versioned state module; it is not inserted after executable statements in an existing Fortran program unit.

#### Current prototype

The prototype currently uses:

```plaintext
one Interpreter
├── one fixed CompilerInvocation
├── one reusable CompilerInstance
├── one session module directory
├── one persistent MLIR/ORC executor
└── many cells
    ├── one InteractiveCell parse result
    ├── one standard normalized parser::Program
    ├── zero or more versioned .mod interfaces
    └── one independently loadable MLIR module

```

The `.mod` files carry compile-time semantic interfaces between cells, while the corresponding MLIR/JIT modules retain the actual code and storage.

The important design contract is that `flangInterpreter` handles cell normalization, cross-cell state and transactions; it does not reimplement ordinary Fortran features. Once a cell reaches normal Flang semantic analysis, OpenMP, interoperability, arrays, derived types, I/O and lowering continue through the existing Flang pipeline.

#### Demo

**Demo video:** [https://youtu.be/08PCgVMyTX8](https://youtu.be/08PCgVMyTX8) (had to upload on youtube, discourse doesn’t allow sharing videos)

Here are some screenshots anyways

 ![image](https://us1.discourse-cdn.com/flex021/uploads/llvm/original/3X/9/6/965ea0bc70dd54c9b30dc7a478b0f561dc19eee7.png)

 ![image](https://us1.discourse-cdn.com/flex021/uploads/llvm/original/3X/b/6/b615c0e55d78d7ecc32f232596b14902fac5c12f.jpeg)

 ![image](https://us1.discourse-cdn.com/flex021/uploads/llvm/original/3X/f/6/f6968fbcf777b7c6da5085efbde92d25b3dcb740.jpeg)

 ![image](https://us1.discourse-cdn.com/flex021/uploads/llvm/original/3X/1/a/1ab77dc75b175e7e37cb8b19ed90fb55cbc54e6b.jpeg)

 ![image](https://us1.discourse-cdn.com/flex021/uploads/llvm/original/3X/4/4/448a12739c14beb3da438a886ff6b721c4dc9cb9.png)

The demo covers:

1. loose declarations and statements, persistent state and variable redefinition;
2. recovery after a failed cell without corrupting the session;
3. OpenMP reductions, sections and tasks with the thread count selected at runtime;
4. an OpenMP Mandelbrot example;
5. inspection of the HLFIR/FIR and lowered MLIR generated for a cell;
6. complete modules, procedures and recursion;
7. `ISO_C_BINDING` and cross-cell C interoperability;
8. dynamically loading OpenBLAS and calling BLAS/LAPACK routines from separate cells; and
9. OpenACC source lowering to the MLIR `acc` dialect.

For clarity, the OpenACC notebook currently demonstrates parsing and HLFIR/MLIR generation only. Executable OpenACC lowering remains limited by the current upstream Flang/OpenACC pipeline, so I do not want to claim runnable OpenACC yet.

#### WebAssembly follow-up

I am treating WebAssembly as a related but separate workstream.

I opened a [Flang/WebAssembly tracking issue](https://github.com/llvm/llvm-project/issues/226471) and started splitting the target-awareness work into small patches. The initial goal is:

```console
flang --target=wasm32-unknown-emscripten -c test.f90 -o test.o
emcc test.o <wasm libflang-rt> -o test.js

```

Separately, the accepted [MLIR/WebAssembly execution RFC](https://discourse.llvm.org/t/rfc-bringing-interactive-mlir-compilation-and-execution-to-webassembly/91566) demonstrates the execution route needed after a cell has become a lowered MLIR module:

```plaintext
MLIR module
  → LLVM IR
  → WebAssembly object
  → in-process LLD
  → shared WebAssembly side module
  → dlopen/dlsym

```

That work has received positive feedback and an offer to review the upstream patches. It removes much of the uncertainty around the browser execution backend, but it does not make the complete Flang browser port automatic: the Flang frontend, `flang-rt`, target-aware lowering and packaging still require work.

The useful design property is that every successful cell already produces one independent MLIR module. The native interpreter uses ORC, while a future browser build can use the WebAssembly side-module executor without changing the frontend cell model.

#### Next steps & collaboration

I would be happy to share the experimental kernel with anyone interested in trying it, and I can also present the implementation at a Flang biweekly call. Please go through the prototype and the approach above, and let me know if there are any technical concerns or questions.

As mentioned in the original RFC, I am also interested in finding collaborators and funding for taking this beyond the current prototype. Turning it into an upstream-quality interpreter, maintaining the Jupyter kernel, extending the OpenMP and library workflows, and completing the WebAssembly runtime and browser integration will require sustained engineering effort.

If any organisations working on Flang, HPC, OpenMP/OpenACC, scientific computing, compiler education or browser-based tooling see value in this direction, I would be very interested in discussing a funded collaboration or sponsorship.

Thanks,  
Anutosh
