Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8052bde
Add enzyme_mod containing activity descriptor bindings
joewallwork May 7, 2026
47c59bd
Hook Fortran bindings up in build system
joewallwork May 7, 2026
27b7edc
Rename enzyme_mod->enzyme
joewallwork May 7, 2026
eec1139
Use implicit interface in square example
joewallwork May 7, 2026
b34ce86
Add bindings for __enzyme_autodiff and __enzyme_fwddiff to the Fortra…
joewallwork May 7, 2026
3c11497
Use __enzyme_autodiff binding in square example
joewallwork May 7, 2026
237ebc6
Prepend function hooks with f
joewallwork May 11, 2026
2338caf
Trigger Fortran CI on changes to enzyme/Fortran
joewallwork May 11, 2026
3219957
Merge branch 'main' into 2808_fortran-implicit-interfaces
joewallwork May 18, 2026
16090da
Reorder to compile Fortran module before tests
joewallwork May 18, 2026
b7685e0
Drop duplicate option
joewallwork May 18, 2026
96ddb90
Build with ENZYME_FORTRAN=ON in CI
joewallwork May 18, 2026
7a84258
Only build Fortran tests if ENZYME_FORTRAN
joewallwork May 18, 2026
89abe9f
Remove CMake commands not needed
joewallwork May 18, 2026
981e5c0
Use enzyme.mod in Fortran square test
joewallwork May 18, 2026
9822b1c
Add back in CMake from Fortran subdir
joewallwork May 18, 2026
48db7db
Drop unrelated editor changes
joewallwork May 18, 2026
9f65061
Fixes for root CMakeLists
joewallwork May 18, 2026
ebcfca1
Add messages for building Fortran bindings and tests
joewallwork May 18, 2026
db7cbff
Move message into Fortran subdir
joewallwork May 18, 2026
be84f81
Make EnzymeFortran a shared object
joewallwork May 18, 2026
e6e07ca
Try putting module in modules dir
joewallwork May 18, 2026
2be33a7
Introduce another module for function hooks to facilitate aliasing
joewallwork May 18, 2026
6847dd6
Add EnzymeFortran to test dependencies
joewallwork May 19, 2026
090547b
Apply suggestions from code review
joewallwork May 19, 2026
b50179c
Set CMake Fortran compiler in test suite
joewallwork May 19, 2026
fa15388
Hook Fortran compiler up in test suite
joewallwork May 19, 2026
57855fa
Revert to f__enzyme_autodiff
joewallwork Jun 11, 2026
9c5e14a
Merge branch 'main' into 2808_fortran-implicit-interfaces
joewallwork Jun 11, 2026
53ea72d
Revert 57855fae9cb71c56bcf18383c6b92e009f2b522c
joewallwork Jun 11, 2026
c76b261
Disable -O0 test for now
joewallwork Jun 11, 2026
42d8f08
Drop unnecessary semicolon
joewallwork Jun 11, 2026
70a98be
Add README for Fortran bindings
joewallwork Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/fortran.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
paths:
- '.github/workflows/fortran.yml'
- 'enzyme/Enzyme/**'
- 'enzyme/Fortran/**'
- 'enzyme/includes/**'
- 'enzyme/test/**'
- 'enzyme/tools/**'
Expand All @@ -20,6 +21,7 @@ on:
paths:
- '.github/workflows/fortran.yml'
- 'enzyme/Enzyme/**'
- 'enzyme/Fortran/**'
- 'enzyme/includes/**'
- 'enzyme/test/**'
- 'enzyme/tools/**'
Expand Down Expand Up @@ -73,7 +75,7 @@ jobs:
- name: generate build system
run: |
rm -rf build && mkdir build && cd build
cmake ../enzyme -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build }} -DLLVM_DIR=/usr/lib/llvm-${{ matrix.llvm }}/lib/cmake/llvm -DLLVM_EXTERNAL_LIT=`which lit` -DENZYME_IFX=ON
cmake ../enzyme -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build }} -DLLVM_DIR=/usr/lib/llvm-${{ matrix.llvm }}/lib/cmake/llvm -DLLVM_EXTERNAL_LIT=`which lit` -DENZYME_FORTRAN=ON -DCMAKE_Fortran_COMPILER=ifx
- name: build enzyme
working-directory: 'build'
run: ninja LLVMEnzyme-${{ matrix.llvm }}
Expand Down
8 changes: 4 additions & 4 deletions enzyme/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ option(ENZYME_CLANG "Build enzyme clang plugin" ON)
option(ENZYME_FLANG "Build enzyme flang symlink" OFF)
option(ENZYME_MLIR "Build enzyme mlir plugin" OFF)
option(ENZYME_IFX "Enable enzyme support for the Intel Fortran compiler IFX" OFF)
option(ENZYME_IFX "Enable enzyme support for the Intel Fortran compiler IFX" OFF)
option(ENZYME_EXTERNAL_SHARED_LIB "Build external shared library" OFF)
option(ENZYME_APPLE_DYNAMIC_LOOKUP
"On Apple, link Enzyme shared library with -flat_namespace/-undefined,dynamic_lookup instead of linking LLVM"
Expand All @@ -49,6 +48,7 @@ option(ENZYME_WARN_COMPILER "Warn if enzyme detects potentially incompatible com
option(ENZYME_ENABLE_REACTANT "Build support library for Reactant C++ frontend" OFF)
set(ENZYME_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(ENZYME_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(Fortran_COMPILER ${CMAKE_Fortran_COMPILER})
list(APPEND CMAKE_MODULE_PATH "${ENZYME_SOURCE_DIR}/cmake/modules")

set(LLVM_SHLIBEXT "${CMAKE_SHARED_MODULE_SUFFIX}")
Expand Down Expand Up @@ -298,12 +298,12 @@ add_subdirectory(Enzyme)
if (ENZYME_BC_LOADER)
add_subdirectory(BCLoad)
endif()
if (ENZYME_ENABLE_PLUGINS)
add_subdirectory(test)
endif()
if (ENZYME_FORTRAN)
add_subdirectory(Fortran)
endif()
if (ENZYME_ENABLE_PLUGINS)
add_subdirectory(test)
endif()

# The benchmarks data are not in git-exported source archives to minimize size.
# Only add the benchmarks if the directory exists.
Expand Down
9 changes: 8 additions & 1 deletion enzyme/Fortran/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
message("Building Fortran bindings")

enable_language(Fortran)
include(FortranCInterface)
FortranCInterface_VERIFY(QUIET)

add_library(EnzymeFortran enzyme.f90)
# Initialize Fortran module build output directory for all subsequent targets
if(NOT DEFINED CMAKE_Fortran_MODULE_DIRECTORY)
set(CMAKE_Fortran_MODULE_DIRECTORY "${CMAKE_BINARY_DIR}/modules")
endif()

add_library(EnzymeFortran SHARED enzyme.f90 enzyme_function_hooks.f90)

# Install library, create target file
install(
Expand Down
74 changes: 74 additions & 0 deletions enzyme/Fortran/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Fortran bindings for Enzyme

Source files in this subdirectory provides Fortran bindings for Enzyme, as
detailed in the following.

## Function hooks

We provide bindings for the `__enzyme_fwddiff` and `__enzyme_autodiff` function
hooks using implicit interfaces. Some Fortran compilers disallow procedure names
starting with an underscore so we rename the function hooks to remove the
leading double underscore.

To make use of the `enzyme_autodiff` function hook in your code, import via
```fortran
use enzyme, only: enzyme_autodiff
```
and call it as a subroutine or function as appropriate. For example, if you have
a function
```fortran
real function square(x)
real, intent(in) :: x
square = x**2
end function
```
then you can compute its derivative with reverse mode with the call
```fortran
call enzyme_autodiff(square, x, dx)
```

Similarly for
`enzyme_fwddiff`. Thanks to the implicit interface, arbitrary signatures are
supported, with the following caveats.

> [!NOTE]
> A limitation of the implicit interfacing is that it only works for arguments
> that are passed by reference - the default in Fortran. If you want to pass any
> arguments by value using the `value` attribute then you will need to write an
> explicit interface block to the function hook yourself.

> [!WARNING]
> The implicit interfacing approach is not supported by the Intel Fortran
> compiler ifx when running without optimizations, i.e., running with `-O0`. If
> you want to use ifx with `-O0` then you will need to write an explicit
> interface block, even if you are only passing arguments by reference.

> [!WARNING]
> Differentiation with respect to procedures with assumed shape arrays is not
> currently supported when compiling with Flang. It should work with ifx,
> however.

## Activity descriptors

We provide bindings for the activity descriptors `enzyme_const`, `enzyme_dup`,
`enzyme_dupnoneed`, and `enzyme_out`, as well as the descriptors
`enzyme_scalar`, `enzyme_width`, and `enzyme_vector`. To make use of these in
your code, import via
```fortran
use enzyme, only: enzyme_const, enzyme_dup
```
and then include them in calls to function hooks as you would in C or C++. For
example, if you have a subroutine
```fortran
subroutine my_subroutine(n, x, y)
integer, intent(in) :: n
real, dimension(n), intent(in) :: x
real, dimension(n), intent(out) :: y
! ...
end subroutine my_subroutine
```
then you can make use of activity descriptors like so:
```fortran
call enzyme_autodiff(my_subroutine, enzyme_const, n, &
enzyme_dup, x, dx, enzyme_dup, y, dy
```
6 changes: 6 additions & 0 deletions enzyme/Fortran/enzyme.f90
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
! ===----------------------------------------------------------------------=== !
module enzyme
use iso_c_binding, only: c_int
use enzyme_function_hooks, only: enzyme_autodiff => f__enzyme_autodiff, &
enzyme_fwddiff => f__enzyme_fwddiff
implicit none
private

Expand All @@ -33,4 +35,8 @@ module enzyme
integer(c_int), public, bind(C, name="enzyme_scalar") :: enzyme_scalar
integer(c_int), public, bind(C, name="enzyme_width") :: enzyme_width
integer(c_int), public, bind(C, name="enzyme_vector") :: enzyme_vector

! Bindings for function hooks
public :: enzyme_autodiff
public :: enzyme_fwddiff
end module enzyme
39 changes: 39 additions & 0 deletions enzyme/Fortran/enzyme_function_hooks.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
! ===- enzyme_function_hooks.f90 - Fortran bindings function hooks --------=== !
!
! Enzyme Project
!
! Part of the Enzyme Project, under the Apache License v2.0 with LLVM
! Exceptions. See https://llvm.org/LICENSE.txt for license information.
! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
!
! If using this code in an academic setting, please cite the following:
! @misc{enzymeGithub,
! author = {William S. Moses and Valentin Churavy},
! title = {Enzyme: High Performance Automatic Differentiation of LLVM},
! year = {2020},
! howpublished = {\url{https://github.com/wsmoses/Enzyme}},
! note = {commit xxxxxxx}
! }
!
! ===----------------------------------------------------------------------=== !
!
! This file provides Fortran bindings for Enzyme's function hooks.
!
! The fact that the double-underscore function hook names appears in the
! implicit interfaces defined in this module is sufficient to get Enzyme to be
! applied in the appropriate way. We provide cleaner bindings without
! double-underscores in the main Fortran Enzyme module in enzyme.f90.
!
! ===----------------------------------------------------------------------=== !
module enzyme_function_hooks
implicit none
private

! Bindings for function hooks
! NOTE: Leading underscores are not permitted by some Fortran compilers so we
! prepend with 'f' in the Fortran versions of the function hooks.
public :: f__enzyme_autodiff
public :: f__enzyme_fwddiff
external :: f__enzyme_autodiff
external :: f__enzyme_fwddiff
end module enzyme_function_hooks
1 change: 1 addition & 0 deletions enzyme/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ expand_template(
"@TARGET_TRIPLE@": "",
"@TARGETS_TO_BUILD@": "ALL",
"@LLVM_SHLIBEXT@": ".so",
"@Fortran_COMPILER@": "",
},
template = "lit.site.cfg.py.in",
visibility = [":__subpackages__"],
Expand Down
3 changes: 2 additions & 1 deletion enzyme/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ add_custom_target(test-cmake COMMAND rm -rf ${CMAKE_CURRENT_BINARY_DIR}/test_cma
endif()
endif()
endif()
if (ENZYME_IFX)
if (ENZYME_FORTRAN)
list(APPEND ENZYME_TEST_DEPS EnzymeFortran)
add_subdirectory(Fortran)
endif()
if (ENZYME_BC_LOADER)
Expand Down
2 changes: 2 additions & 0 deletions enzyme/test/Fortran/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
message("Building Fortran tests")

add_subdirectory(ForwardMode)
add_subdirectory(ReverseMode)

Expand Down
25 changes: 7 additions & 18 deletions enzyme/test/Fortran/ReverseMode/square.f90
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
! RUN: if [ %llvmver -ge 13 ]; then ifx -flto -O0 -c %s -o /dev/stdout | %opt %loadEnzyme %enzyme -o %t && ifx -flto -O0 %t -o %t1 && %t1 | FileCheck %s; fi
! RUN: if [ %llvmver -ge 13 ]; then ifx -flto -O1 -c %s -o /dev/stdout | %opt %loadEnzyme %enzyme -o %t && ifx -flto -O1 %t -o %t1 && %t1 | FileCheck %s; fi
! RUN: if [ %llvmver -ge 13 ]; then ifx -flto -O2 -c %s -o /dev/stdout | %opt %loadEnzyme %enzyme -o %t && ifx -flto -O2 %t -o %t1 && %t1 | FileCheck %s; fi
! RUN: if [ %llvmver -ge 13 ]; then ifx -flto -O3 -c %s -o /dev/stdout | %opt %loadEnzyme %enzyme -o %t && ifx -flto -O3 %t -o %t1 && %t1 | FileCheck %s; fi
! TODO: if [ %llvmver -ge 13 ]; then %fc -flto -O0 -c %loadFortran %s -o /dev/stdout | %opt %loadEnzyme %enzyme -o %t && %fc -flto -O0 %t -o %t1 && %t1 | FileCheck %s; fi
! RUN: if [ %llvmver -ge 13 ]; then %fc -flto -O1 -c %loadFortran %s -o /dev/stdout | %opt %loadEnzyme %enzyme -o %t && %fc -flto -O1 %t -o %t1 && %t1 | FileCheck %s; fi
! RUN: if [ %llvmver -ge 13 ]; then %fc -flto -O2 -c %loadFortran %s -o /dev/stdout | %opt %loadEnzyme %enzyme -o %t && %fc -flto -O2 %t -o %t1 && %t1 | FileCheck %s; fi
! RUN: if [ %llvmver -ge 13 ]; then %fc -flto -O3 -c %loadFortran %s -o /dev/stdout | %opt %loadEnzyme %enzyme -o %t && %fc -flto -O3 %t -o %t1 && %t1 | FileCheck %s; fi

module math
interface
subroutine square__enzyme_autodiff(fn, x, dx)
interface
real function fn_decal(a)
real, intent(in) :: a
end function
end interface
procedure(fn_decal) :: fn
real, intent(in) :: x
real, intent(inout) :: dx
end subroutine
end interface
contains
real function square( x )
real, intent(in) :: x
Expand All @@ -24,15 +12,16 @@ real function square( x )
end module math

program app
use math
use enzyme, only: enzyme_autodiff
use math, only: square
implicit none
real :: x, dx

x = 3
print *, square(x)

dx = 0
call square__enzyme_autodiff(square, x, dx);
call enzyme_autodiff(square, x, dx)

print *, dx
end program app
Expand Down
2 changes: 2 additions & 0 deletions enzyme/test/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ config.substitutions.append(('%OPnewLoadEnzyme', newPMOP))
config.substitutions.append(('%enzyme', ('-enzyme' if int(config.llvm_ver) < 16 else '-passes="enzyme"')))
config.substitutions.append(('%simplifycfg', ("simplify-cfg" if int(config.llvm_ver) < 11 else "simplifycfg")))
config.substitutions.append(('%loopmssa', ("loop" if int(config.llvm_ver) < 11 else "loop-mssa")))
config.substitutions.append(('%fc', '@Fortran_COMPILER@'))
config.substitutions.append(('%loadFortran', '-I@ENZYME_BINARY_DIR@/modules'))

config.substitutions.append(('%loadBC', ''
+ ' @ENZYME_BINARY_DIR@/BCLoad/BCPass-' + config.llvm_ver + config.llvm_shlib_ext
Expand Down
Loading