From 8052bde17c187fdf1aa59e79f449ebb55e3c840a Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 7 May 2026 13:03:31 +0100 Subject: [PATCH 01/31] Add enzyme_mod containing activity descriptor bindings --- enzyme/Fortran/enzyme_mod.f90 | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 enzyme/Fortran/enzyme_mod.f90 diff --git a/enzyme/Fortran/enzyme_mod.f90 b/enzyme/Fortran/enzyme_mod.f90 new file mode 100644 index 00000000000..a28de48bb36 --- /dev/null +++ b/enzyme/Fortran/enzyme_mod.f90 @@ -0,0 +1,36 @@ +! ===- enzyme_mod.f90 - Fortran bindings for Enzyme -----------------------=== ! +! +! 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. +! +! ===----------------------------------------------------------------------=== ! +module enzyme_mod + use iso_c_binding, only: c_int + implicit none + private + + ! Bindings for activity descriptors + integer(c_int), public, bind(C, name="enzyme_const") :: enzyme_const + integer(c_int), public, bind(C, name="enzyme_dup") :: enzyme_dup + integer(c_int), public, bind(C, name="enzyme_dupnoneed") :: enzyme_dupnoneed + integer(c_int), public, bind(C, name="enzyme_out") :: enzyme_out + 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 +end module enzyme_mod From 47c59bd689eff51c08be939a613e0507f2953203 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 7 May 2026 13:46:07 +0100 Subject: [PATCH 02/31] Hook Fortran bindings up in build system --- enzyme/CMakeLists.txt | 3 ++- enzyme/Fortran/CMakeLists.txt | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 enzyme/Fortran/CMakeLists.txt diff --git a/enzyme/CMakeLists.txt b/enzyme/CMakeLists.txt index 25a6a78940d..b489f43195d 100644 --- a/enzyme/CMakeLists.txt +++ b/enzyme/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.13) -project(Enzyme) +project(Enzyme LANGUAGES C CXX Fortran) include(CMakePackageConfigHelpers) include(CheckIncludeFile) @@ -299,6 +299,7 @@ endif() if (ENZYME_ENABLE_PLUGINS) add_subdirectory(test) endif() +add_subdirectory(Fortran) # The benchmarks data are not in git-exported source archives to minimize size. # Only add the benchmarks if the directory exists. diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt new file mode 100644 index 00000000000..cd98bc6f162 --- /dev/null +++ b/enzyme/Fortran/CMakeLists.txt @@ -0,0 +1,25 @@ +include(FortranCInterface) +FortranCInterface_VERIFY(QUIET) + +add_library(EnzymeFortran enzyme_mod.f90) + +# Install library, create target file +install( + TARGETS EnzymeFortran + EXPORT EnzymeFortranTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/EnzymeFortran) + +# Install Fortran module file +if(NOT DEFINED CMAKE_INSTALL_MODULEDIR) + set( + CMAKE_INSTALL_MODULEDIR + "${CMAKE_INSTALL_INCLUDEDIR}/EnzymeFortran" + CACHE STRING "Directory in prefix to install generated module files" + ) +endif() +install(FILES "${CMAKE_Fortran_MODULE_DIRECTORY}/enzyme_mod.mod" + DESTINATION "${CMAKE_INSTALL_MODULEDIR}") From 27b7edc9658da36fcfc8881a97b73aa68d4b986a Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 7 May 2026 15:21:33 +0100 Subject: [PATCH 03/31] Rename enzyme_mod->enzyme --- enzyme/Fortran/CMakeLists.txt | 4 ++-- enzyme/Fortran/{enzyme_mod.f90 => enzyme.f90} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename enzyme/Fortran/{enzyme_mod.f90 => enzyme.f90} (93%) diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt index cd98bc6f162..fb6b62454f0 100644 --- a/enzyme/Fortran/CMakeLists.txt +++ b/enzyme/Fortran/CMakeLists.txt @@ -1,7 +1,7 @@ include(FortranCInterface) FortranCInterface_VERIFY(QUIET) -add_library(EnzymeFortran enzyme_mod.f90) +add_library(EnzymeFortran enzyme.f90) # Install library, create target file install( @@ -21,5 +21,5 @@ if(NOT DEFINED CMAKE_INSTALL_MODULEDIR) CACHE STRING "Directory in prefix to install generated module files" ) endif() -install(FILES "${CMAKE_Fortran_MODULE_DIRECTORY}/enzyme_mod.mod" +install(FILES "${CMAKE_Fortran_MODULE_DIRECTORY}/enzyme.mod" DESTINATION "${CMAKE_INSTALL_MODULEDIR}") diff --git a/enzyme/Fortran/enzyme_mod.f90 b/enzyme/Fortran/enzyme.f90 similarity index 93% rename from enzyme/Fortran/enzyme_mod.f90 rename to enzyme/Fortran/enzyme.f90 index a28de48bb36..1e999ff1004 100644 --- a/enzyme/Fortran/enzyme_mod.f90 +++ b/enzyme/Fortran/enzyme.f90 @@ -1,4 +1,4 @@ -! ===- enzyme_mod.f90 - Fortran bindings for Enzyme -----------------------=== ! +! ===- enzyme.f90 - Fortran bindings for Enzyme ---------------------------=== ! ! ! Enzyme Project ! @@ -20,7 +20,7 @@ ! This file provides Fortran bindings for Enzyme. ! ! ===----------------------------------------------------------------------=== ! -module enzyme_mod +module enzyme use iso_c_binding, only: c_int implicit none private @@ -33,4 +33,4 @@ module enzyme_mod 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 -end module enzyme_mod +end module enzyme From eec11393abf20a4d980023fd14b5ca6d536efbf9 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 7 May 2026 15:00:58 +0100 Subject: [PATCH 04/31] Use implicit interface in square example --- enzyme/test/Fortran/ReverseMode/square.f90 | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index 1baf9b6d477..da45fa6ba32 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -4,18 +4,6 @@ ! 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 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 @@ -26,13 +14,14 @@ end module math program app use math implicit none + external :: __enzyme_autodiff 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 From b34ce8654342ea761106eaef5e169cdd1d03cd07 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 7 May 2026 15:34:30 +0100 Subject: [PATCH 05/31] Add bindings for __enzyme_autodiff and __enzyme_fwddiff to the Fortran module --- enzyme/Fortran/enzyme.f90 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/enzyme/Fortran/enzyme.f90 b/enzyme/Fortran/enzyme.f90 index 1e999ff1004..eed5b0b705e 100644 --- a/enzyme/Fortran/enzyme.f90 +++ b/enzyme/Fortran/enzyme.f90 @@ -33,4 +33,10 @@ 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 + external :: __enzyme_autodiff + external :: __enzyme_fwddiff end module enzyme From 3c114978dd666522b876e050b67b9b1bb2adee9f Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 7 May 2026 15:36:03 +0100 Subject: [PATCH 06/31] Use __enzyme_autodiff binding in square example --- enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 | 2 +- enzyme/test/Fortran/ReverseMode/square.f90 | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 b/enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 index 66a51fe5467..f2ad32dccfb 100644 --- a/enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 +++ b/enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 @@ -58,4 +58,4 @@ program app ! CHECK-NEXT: 1 ! CHECK-NEXT: 0 ! CHECK-NEXT: 0 -! CHECK-NEXT: 1 \ No newline at end of file +! CHECK-NEXT: 1 diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index da45fa6ba32..a26789587bf 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -12,7 +12,8 @@ real function square( x ) end module math program app - use math + use enzyme, only: __enzyme_autodiff + use math, only: square implicit none external :: __enzyme_autodiff real :: x, dx @@ -27,4 +28,4 @@ program app end program app ! CHECK: 9 -! CHECK-NEXT: 6 \ No newline at end of file +! CHECK-NEXT: 6 From 237ebc64e90883b675e91be5885376cb0e323d23 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 11 May 2026 17:05:36 +0100 Subject: [PATCH 07/31] Prepend function hooks with f --- enzyme/Fortran/enzyme.f90 | 10 ++++++---- enzyme/test/Fortran/ReverseMode/square.f90 | 5 ++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/enzyme/Fortran/enzyme.f90 b/enzyme/Fortran/enzyme.f90 index eed5b0b705e..21f0b8de9a7 100644 --- a/enzyme/Fortran/enzyme.f90 +++ b/enzyme/Fortran/enzyme.f90 @@ -35,8 +35,10 @@ module enzyme integer(c_int), public, bind(C, name="enzyme_vector") :: enzyme_vector ! Bindings for function hooks - public :: __enzyme_autodiff - public :: __enzyme_fwddiff - external :: __enzyme_autodiff - external :: __enzyme_fwddiff + ! 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 diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index a26789587bf..3ddab902781 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -12,17 +12,16 @@ real function square( x ) end module math program app - use enzyme, only: __enzyme_autodiff + use enzyme, only: f__enzyme_autodiff use math, only: square implicit none - external :: __enzyme_autodiff real :: x, dx x = 3 print *, square(x) dx = 0 - call __enzyme_autodiff(square, x, dx); + call f__enzyme_autodiff(square, x, dx); print *, dx end program app From 2338caf09adef509b1693c2c77d2fc66f8a25e92 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 11 May 2026 17:19:38 +0100 Subject: [PATCH 08/31] Trigger Fortran CI on changes to enzyme/Fortran --- .github/workflows/fortran.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/fortran.yml b/.github/workflows/fortran.yml index 04ac75fc41f..b6c03385438 100644 --- a/.github/workflows/fortran.yml +++ b/.github/workflows/fortran.yml @@ -7,6 +7,7 @@ on: paths: - '.github/workflows/fortran.yml' - 'enzyme/Enzyme/**' + - 'enzyme/Fortran/**' - 'enzyme/includes/**' - 'enzyme/test/**' - 'enzyme/tools/**' @@ -20,6 +21,7 @@ on: paths: - '.github/workflows/fortran.yml' - 'enzyme/Enzyme/**' + - 'enzyme/Fortran/**' - 'enzyme/includes/**' - 'enzyme/test/**' - 'enzyme/tools/**' From 16090da616508b2693ca76a3ce8202129f24cc64 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 10:01:32 +0100 Subject: [PATCH 09/31] Reorder to compile Fortran module before tests --- enzyme/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/enzyme/CMakeLists.txt b/enzyme/CMakeLists.txt index c123e52ddc3..3a17fe54c41 100644 --- a/enzyme/CMakeLists.txt +++ b/enzyme/CMakeLists.txt @@ -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. From b7685e02f9f875e4cbbccab4c1593f9fea8ce743 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 10:44:52 +0100 Subject: [PATCH 10/31] Drop duplicate option --- enzyme/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/enzyme/CMakeLists.txt b/enzyme/CMakeLists.txt index 3a17fe54c41..c3ec3ec84d7 100644 --- a/enzyme/CMakeLists.txt +++ b/enzyme/CMakeLists.txt @@ -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" From 96ddb906dbbd932d26e7b0e9a866acd7ef894380 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 10:45:07 +0100 Subject: [PATCH 11/31] Build with ENZYME_FORTRAN=ON in CI --- .github/workflows/fortran.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fortran.yml b/.github/workflows/fortran.yml index b6c03385438..2a031f41119 100644 --- a/.github/workflows/fortran.yml +++ b/.github/workflows/fortran.yml @@ -72,7 +72,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 -DENZYME_IFX=ON - name: build enzyme working-directory: 'build' run: ninja LLVMEnzyme-${{ matrix.llvm }} From 7a842585e0a0df1c2fd1185250ecf59ff37d2cbc Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 10:45:51 +0100 Subject: [PATCH 12/31] Only build Fortran tests if ENZYME_FORTRAN --- enzyme/test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enzyme/test/CMakeLists.txt b/enzyme/test/CMakeLists.txt index 8f781a0f04c..6d39180d94c 100644 --- a/enzyme/test/CMakeLists.txt +++ b/enzyme/test/CMakeLists.txt @@ -20,7 +20,7 @@ add_custom_target(test-cmake COMMAND rm -rf ${CMAKE_CURRENT_BINARY_DIR}/test_cma endif() endif() endif() -if (ENZYME_IFX) +if (ENZYME_FORTRAN AND ENZYME_IFX) add_subdirectory(Fortran) endif() if (ENZYME_BC_LOADER) From 89abe9f250971d944229decf61718668e45e0ecd Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 11:06:26 +0100 Subject: [PATCH 13/31] Remove CMake commands not needed --- enzyme/Fortran/CMakeLists.txt | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt index d3e6fdaa139..fd6a340951e 100644 --- a/enzyme/Fortran/CMakeLists.txt +++ b/enzyme/Fortran/CMakeLists.txt @@ -3,24 +3,3 @@ include(FortranCInterface) FortranCInterface_VERIFY(QUIET) add_library(EnzymeFortran enzyme.f90) - -# Install library, create target file -install( - TARGETS EnzymeFortran - EXPORT EnzymeFortranTargets - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - INCLUDES - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/EnzymeFortran) - -# Install Fortran module file -if(NOT DEFINED CMAKE_INSTALL_MODULEDIR) - set( - CMAKE_INSTALL_MODULEDIR - "${CMAKE_INSTALL_INCLUDEDIR}/EnzymeFortran" - CACHE STRING "Directory in prefix to install generated module files" - ) -endif() -install(FILES "${CMAKE_Fortran_MODULE_DIRECTORY}/enzyme.mod" - DESTINATION "${CMAKE_INSTALL_MODULEDIR}") From 981e5c06cd3006394bcfc4b9802b57fef29383d6 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 11:49:03 +0100 Subject: [PATCH 14/31] Use enzyme.mod in Fortran square test --- enzyme/test/Fortran/ReverseMode/square.f90 | 8 ++++---- enzyme/test/lit.site.cfg.py.in | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index 3ddab902781..f7dbafd85c5 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -1,7 +1,7 @@ -! 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 +! RUN: if [ %llvmver -ge 13 ]; then ifx -flto -O0 -c %loadFortran %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 %loadFortran %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 %loadFortran %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 %loadFortran %s -o /dev/stdout | %opt %loadEnzyme -enzyme -o %t && ifx -flto -O3 %t -o %t1 && %t1 | FileCheck %s; fi module math contains diff --git a/enzyme/test/lit.site.cfg.py.in b/enzyme/test/lit.site.cfg.py.in index 0cc5e6f28f3..792fe38b7f2 100644 --- a/enzyme/test/lit.site.cfg.py.in +++ b/enzyme/test/lit.site.cfg.py.in @@ -97,6 +97,7 @@ 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(('%loadFortran', '-I@ENZYME_BINARY_DIR@/Fortran')) config.substitutions.append(('%loadBC', '' + ' @ENZYME_BINARY_DIR@/BCLoad/BCPass-' + config.llvm_ver + config.llvm_shlib_ext From 9822b1c49ac2b8fb0d9df00dbe9ed8173883bb95 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 12:05:41 +0100 Subject: [PATCH 15/31] Add back in CMake from Fortran subdir --- enzyme/Fortran/CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt index fd6a340951e..c3b9f1c1f85 100644 --- a/enzyme/Fortran/CMakeLists.txt +++ b/enzyme/Fortran/CMakeLists.txt @@ -3,3 +3,13 @@ include(FortranCInterface) FortranCInterface_VERIFY(QUIET) add_library(EnzymeFortran enzyme.f90) + +# Install library, create target file +install( + TARGETS EnzymeFortran + EXPORT EnzymeFortranTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/EnzymeFortran) From 48db7db71e187e7fc73fa1c81ab3abf7cc5df4ad Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 12:09:39 +0100 Subject: [PATCH 16/31] Drop unrelated editor changes --- enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 | 2 +- enzyme/test/Fortran/ReverseMode/square.f90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 b/enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 index f2ad32dccfb..66a51fe5467 100644 --- a/enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 +++ b/enzyme/test/Fortran/ForwardMode/allocatableArraySimple.f90 @@ -58,4 +58,4 @@ program app ! CHECK-NEXT: 1 ! CHECK-NEXT: 0 ! CHECK-NEXT: 0 -! CHECK-NEXT: 1 +! CHECK-NEXT: 1 \ No newline at end of file diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index f7dbafd85c5..1fbf1826328 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -27,4 +27,4 @@ program app end program app ! CHECK: 9 -! CHECK-NEXT: 6 +! CHECK-NEXT: 6 \ No newline at end of file From 9f65061d24e577392c234b8ecd40686b25bd5b47 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 12:11:10 +0100 Subject: [PATCH 17/31] Fixes for root CMakeLists --- enzyme/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enzyme/CMakeLists.txt b/enzyme/CMakeLists.txt index c3ec3ec84d7..add53afda31 100644 --- a/enzyme/CMakeLists.txt +++ b/enzyme/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.13) -project(Enzyme LANGUAGES C CXX Fortran) +project(Enzyme) include(CMakePackageConfigHelpers) include(CheckIncludeFile) From ebcfca1bc82ee56a16cdef6bb8bb299295995002 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 13:13:46 +0100 Subject: [PATCH 18/31] Add messages for building Fortran bindings and tests --- enzyme/CMakeLists.txt | 1 + enzyme/test/Fortran/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/enzyme/CMakeLists.txt b/enzyme/CMakeLists.txt index add53afda31..5a2305b02ea 100644 --- a/enzyme/CMakeLists.txt +++ b/enzyme/CMakeLists.txt @@ -298,6 +298,7 @@ if (ENZYME_BC_LOADER) add_subdirectory(BCLoad) endif() if (ENZYME_FORTRAN) + message("Building Fortran bindings") add_subdirectory(Fortran) endif() if (ENZYME_ENABLE_PLUGINS) diff --git a/enzyme/test/Fortran/CMakeLists.txt b/enzyme/test/Fortran/CMakeLists.txt index 9487564e769..975cca7940b 100644 --- a/enzyme/test/Fortran/CMakeLists.txt +++ b/enzyme/test/Fortran/CMakeLists.txt @@ -1,3 +1,5 @@ +message("Building Fortran tests") + add_subdirectory(ForwardMode) add_subdirectory(ReverseMode) From db7cbffa066d9052a4ecefc752eb7244b9352e06 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 13:31:15 +0100 Subject: [PATCH 19/31] Move message into Fortran subdir --- enzyme/CMakeLists.txt | 1 - enzyme/Fortran/CMakeLists.txt | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/enzyme/CMakeLists.txt b/enzyme/CMakeLists.txt index 5a2305b02ea..add53afda31 100644 --- a/enzyme/CMakeLists.txt +++ b/enzyme/CMakeLists.txt @@ -298,7 +298,6 @@ if (ENZYME_BC_LOADER) add_subdirectory(BCLoad) endif() if (ENZYME_FORTRAN) - message("Building Fortran bindings") add_subdirectory(Fortran) endif() if (ENZYME_ENABLE_PLUGINS) diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt index c3b9f1c1f85..a9c5fe2ef44 100644 --- a/enzyme/Fortran/CMakeLists.txt +++ b/enzyme/Fortran/CMakeLists.txt @@ -1,3 +1,5 @@ +message("Building Fortran bindings") + enable_language(Fortran) include(FortranCInterface) FortranCInterface_VERIFY(QUIET) From be84f81288f81dd8c0bd6365660b716d8135d412 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 13:53:57 +0100 Subject: [PATCH 20/31] Make EnzymeFortran a shared object --- enzyme/Fortran/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt index a9c5fe2ef44..abddd686a32 100644 --- a/enzyme/Fortran/CMakeLists.txt +++ b/enzyme/Fortran/CMakeLists.txt @@ -4,7 +4,7 @@ enable_language(Fortran) include(FortranCInterface) FortranCInterface_VERIFY(QUIET) -add_library(EnzymeFortran enzyme.f90) +add_library(EnzymeFortran SHARED enzyme.f90) # Install library, create target file install( From e6e07ca85c050bc10e31e9f5e9d92a2709f884d4 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 17:16:47 +0100 Subject: [PATCH 21/31] Try putting module in modules dir --- enzyme/Fortran/CMakeLists.txt | 16 ++++++++++++++++ enzyme/test/lit.site.cfg.py.in | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt index abddd686a32..f498093260c 100644 --- a/enzyme/Fortran/CMakeLists.txt +++ b/enzyme/Fortran/CMakeLists.txt @@ -4,6 +4,11 @@ enable_language(Fortran) include(FortranCInterface) FortranCInterface_VERIFY(QUIET) +# 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) # Install library, create target file @@ -15,3 +20,14 @@ install( PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/EnzymeFortran) + +# Install Fortran module file +if(NOT DEFINED CMAKE_INSTALL_MODULEDIR) + set( + CMAKE_INSTALL_MODULEDIR + "${CMAKE_INSTALL_INCLUDEDIR}/EnzymeFortran" + CACHE STRING "Directory in prefix to install generated module files" + ) +endif() +install(FILES "${CMAKE_Fortran_MODULE_DIRECTORY}/enzyme.mod" + DESTINATION "${CMAKE_INSTALL_MODULEDIR}") diff --git a/enzyme/test/lit.site.cfg.py.in b/enzyme/test/lit.site.cfg.py.in index 792fe38b7f2..617adb87612 100644 --- a/enzyme/test/lit.site.cfg.py.in +++ b/enzyme/test/lit.site.cfg.py.in @@ -97,7 +97,7 @@ 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(('%loadFortran', '-I@ENZYME_BINARY_DIR@/Fortran')) +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 From 2be33a7d5cfb19a53534597560f2978b69cf706b Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Mon, 18 May 2026 17:31:17 +0100 Subject: [PATCH 22/31] Introduce another module for function hooks to facilitate aliasing --- enzyme/Fortran/CMakeLists.txt | 2 +- enzyme/Fortran/enzyme.f90 | 10 +++--- enzyme/Fortran/enzyme_function_hooks.f90 | 39 ++++++++++++++++++++++ enzyme/test/Fortran/ReverseMode/square.f90 | 4 +-- 4 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 enzyme/Fortran/enzyme_function_hooks.f90 diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt index f498093260c..aac46086e9d 100644 --- a/enzyme/Fortran/CMakeLists.txt +++ b/enzyme/Fortran/CMakeLists.txt @@ -9,7 +9,7 @@ if(NOT DEFINED CMAKE_Fortran_MODULE_DIRECTORY) set(CMAKE_Fortran_MODULE_DIRECTORY "${CMAKE_BINARY_DIR}/modules") endif() -add_library(EnzymeFortran SHARED enzyme.f90) +add_library(EnzymeFortran SHARED enzyme.f90 enzyme_function_hooks.f90) # Install library, create target file install( diff --git a/enzyme/Fortran/enzyme.f90 b/enzyme/Fortran/enzyme.f90 index 21f0b8de9a7..a5bd9bad0de 100644 --- a/enzyme/Fortran/enzyme.f90 +++ b/enzyme/Fortran/enzyme.f90 @@ -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 @@ -35,10 +37,6 @@ module enzyme integer(c_int), public, bind(C, name="enzyme_vector") :: enzyme_vector ! 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 + public :: enzyme_autodiff + public :: enzyme_fwddiff end module enzyme diff --git a/enzyme/Fortran/enzyme_function_hooks.f90 b/enzyme/Fortran/enzyme_function_hooks.f90 new file mode 100644 index 00000000000..714fd415dbd --- /dev/null +++ b/enzyme/Fortran/enzyme_function_hooks.f90 @@ -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 diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index 1fbf1826328..108345df764 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -12,7 +12,7 @@ real function square( x ) end module math program app - use enzyme, only: f__enzyme_autodiff + use enzyme, only: enzyme_autodiff use math, only: square implicit none real :: x, dx @@ -21,7 +21,7 @@ program app print *, square(x) dx = 0 - call f__enzyme_autodiff(square, x, dx); + call enzyme_autodiff(square, x, dx); print *, dx end program app From 6847dd6027d7cb38be828802956ffca5947081c7 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Tue, 19 May 2026 09:30:09 +0100 Subject: [PATCH 23/31] Add EnzymeFortran to test dependencies --- enzyme/test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/enzyme/test/CMakeLists.txt b/enzyme/test/CMakeLists.txt index 6d39180d94c..447edb5b1c8 100644 --- a/enzyme/test/CMakeLists.txt +++ b/enzyme/test/CMakeLists.txt @@ -21,6 +21,7 @@ endif() endif() endif() if (ENZYME_FORTRAN AND ENZYME_IFX) + list(APPEND ENZYME_TEST_DEPS EnzymeFortran) add_subdirectory(Fortran) endif() if (ENZYME_BC_LOADER) From 090547bfad4415dda95598a2bc9ca2878978e166 Mon Sep 17 00:00:00 2001 From: Joe Wallwork <22053413+joewallwork@users.noreply.github.com> Date: Tue, 19 May 2026 15:55:27 +0100 Subject: [PATCH 24/31] Apply suggestions from code review Co-authored-by: Valentin Churavy --- .github/workflows/fortran.yml | 2 +- enzyme/test/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/fortran.yml b/.github/workflows/fortran.yml index 2a031f41119..f9a99622ed9 100644 --- a/.github/workflows/fortran.yml +++ b/.github/workflows/fortran.yml @@ -72,7 +72,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_FORTRAN=ON -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 - name: build enzyme working-directory: 'build' run: ninja LLVMEnzyme-${{ matrix.llvm }} diff --git a/enzyme/test/CMakeLists.txt b/enzyme/test/CMakeLists.txt index 447edb5b1c8..dcfc38492b5 100644 --- a/enzyme/test/CMakeLists.txt +++ b/enzyme/test/CMakeLists.txt @@ -20,7 +20,7 @@ add_custom_target(test-cmake COMMAND rm -rf ${CMAKE_CURRENT_BINARY_DIR}/test_cma endif() endif() endif() -if (ENZYME_FORTRAN AND ENZYME_IFX) +if (ENZYME_FORTRAN) list(APPEND ENZYME_TEST_DEPS EnzymeFortran) add_subdirectory(Fortran) endif() From b50179cc14516f275f771774e4b1c4ad97fb07a8 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Tue, 19 May 2026 16:01:49 +0100 Subject: [PATCH 25/31] Set CMake Fortran compiler in test suite --- .github/workflows/fortran.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fortran.yml b/.github/workflows/fortran.yml index f9a99622ed9..97d985a941c 100644 --- a/.github/workflows/fortran.yml +++ b/.github/workflows/fortran.yml @@ -72,7 +72,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_FORTRAN=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 }} From fa15388283a2b42112c3a65004ffaa46569b6b9f Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Tue, 19 May 2026 16:20:41 +0100 Subject: [PATCH 26/31] Hook Fortran compiler up in test suite --- enzyme/CMakeLists.txt | 1 + enzyme/test/BUILD | 1 + enzyme/test/Fortran/ReverseMode/square.f90 | 8 ++++---- enzyme/test/lit.site.cfg.py.in | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/enzyme/CMakeLists.txt b/enzyme/CMakeLists.txt index add53afda31..da113754287 100644 --- a/enzyme/CMakeLists.txt +++ b/enzyme/CMakeLists.txt @@ -48,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}") diff --git a/enzyme/test/BUILD b/enzyme/test/BUILD index 9ec7dda4641..0b480eb41e0 100644 --- a/enzyme/test/BUILD +++ b/enzyme/test/BUILD @@ -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__"], diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index 108345df764..c0ddecd902c 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -1,7 +1,7 @@ -! RUN: if [ %llvmver -ge 13 ]; then ifx -flto -O0 -c %loadFortran %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 %loadFortran %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 %loadFortran %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 %loadFortran %s -o /dev/stdout | %opt %loadEnzyme -enzyme -o %t && ifx -flto -O3 %t -o %t1 && %t1 | FileCheck %s; fi +! RUN: 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 contains diff --git a/enzyme/test/lit.site.cfg.py.in b/enzyme/test/lit.site.cfg.py.in index 617adb87612..dafafca769a 100644 --- a/enzyme/test/lit.site.cfg.py.in +++ b/enzyme/test/lit.site.cfg.py.in @@ -97,6 +97,7 @@ 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', '' From 57855fae9cb71c56bcf18383c6b92e009f2b522c Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 11 Jun 2026 10:20:13 +0100 Subject: [PATCH 27/31] Revert to f__enzyme_autodiff --- enzyme/Fortran/CMakeLists.txt | 2 +- enzyme/Fortran/enzyme.f90 | 10 +++--- enzyme/Fortran/enzyme_function_hooks.f90 | 39 ---------------------- enzyme/test/Fortran/ReverseMode/square.f90 | 6 ++-- 4 files changed, 10 insertions(+), 47 deletions(-) delete mode 100644 enzyme/Fortran/enzyme_function_hooks.f90 diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt index aac46086e9d..f498093260c 100644 --- a/enzyme/Fortran/CMakeLists.txt +++ b/enzyme/Fortran/CMakeLists.txt @@ -9,7 +9,7 @@ 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) +add_library(EnzymeFortran SHARED enzyme.f90) # Install library, create target file install( diff --git a/enzyme/Fortran/enzyme.f90 b/enzyme/Fortran/enzyme.f90 index a5bd9bad0de..21f0b8de9a7 100644 --- a/enzyme/Fortran/enzyme.f90 +++ b/enzyme/Fortran/enzyme.f90 @@ -22,8 +22,6 @@ ! ===----------------------------------------------------------------------=== ! 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 @@ -37,6 +35,10 @@ module enzyme integer(c_int), public, bind(C, name="enzyme_vector") :: enzyme_vector ! Bindings for function hooks - public :: enzyme_autodiff - public :: enzyme_fwddiff + ! 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 diff --git a/enzyme/Fortran/enzyme_function_hooks.f90 b/enzyme/Fortran/enzyme_function_hooks.f90 deleted file mode 100644 index 714fd415dbd..00000000000 --- a/enzyme/Fortran/enzyme_function_hooks.f90 +++ /dev/null @@ -1,39 +0,0 @@ -! ===- 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 diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index c0ddecd902c..775ee73a819 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -12,7 +12,7 @@ real function square( x ) end module math program app - use enzyme, only: enzyme_autodiff + use enzyme, only: f__enzyme_autodiff use math, only: square implicit none real :: x, dx @@ -21,10 +21,10 @@ program app print *, square(x) dx = 0 - call enzyme_autodiff(square, x, dx); + call f__enzyme_autodiff(square, x, dx); print *, dx end program app ! CHECK: 9 -! CHECK-NEXT: 6 \ No newline at end of file +! CHECK-NEXT: 6 From 53ea72dad187749e24a14e794ef3897820774eb4 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 11 Jun 2026 13:48:18 +0100 Subject: [PATCH 28/31] Revert 57855fae9cb71c56bcf18383c6b92e009f2b522c --- enzyme/Fortran/CMakeLists.txt | 2 +- enzyme/Fortran/enzyme.f90 | 10 +++--- enzyme/Fortran/enzyme_function_hooks.f90 | 39 ++++++++++++++++++++++ enzyme/test/Fortran/ReverseMode/square.f90 | 6 ++-- 4 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 enzyme/Fortran/enzyme_function_hooks.f90 diff --git a/enzyme/Fortran/CMakeLists.txt b/enzyme/Fortran/CMakeLists.txt index f498093260c..aac46086e9d 100644 --- a/enzyme/Fortran/CMakeLists.txt +++ b/enzyme/Fortran/CMakeLists.txt @@ -9,7 +9,7 @@ if(NOT DEFINED CMAKE_Fortran_MODULE_DIRECTORY) set(CMAKE_Fortran_MODULE_DIRECTORY "${CMAKE_BINARY_DIR}/modules") endif() -add_library(EnzymeFortran SHARED enzyme.f90) +add_library(EnzymeFortran SHARED enzyme.f90 enzyme_function_hooks.f90) # Install library, create target file install( diff --git a/enzyme/Fortran/enzyme.f90 b/enzyme/Fortran/enzyme.f90 index 21f0b8de9a7..a5bd9bad0de 100644 --- a/enzyme/Fortran/enzyme.f90 +++ b/enzyme/Fortran/enzyme.f90 @@ -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 @@ -35,10 +37,6 @@ module enzyme integer(c_int), public, bind(C, name="enzyme_vector") :: enzyme_vector ! 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 + public :: enzyme_autodiff + public :: enzyme_fwddiff end module enzyme diff --git a/enzyme/Fortran/enzyme_function_hooks.f90 b/enzyme/Fortran/enzyme_function_hooks.f90 new file mode 100644 index 00000000000..714fd415dbd --- /dev/null +++ b/enzyme/Fortran/enzyme_function_hooks.f90 @@ -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 diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index f74d58cb494..b38da80929c 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -12,7 +12,7 @@ real function square( x ) end module math program app - use enzyme, only: f__enzyme_autodiff + use enzyme, only: enzyme_autodiff use math, only: square implicit none real :: x, dx @@ -21,10 +21,10 @@ program app print *, square(x) dx = 0 - call f__enzyme_autodiff(square, x, dx); + call enzyme_autodiff(square, x, dx); print *, dx end program app ! CHECK: 9 -! CHECK-NEXT: 6 +! CHECK-NEXT: 6 \ No newline at end of file From c76b261f9d867b48ff7cdf6f2eabb40a77d4fb68 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 11 Jun 2026 13:53:07 +0100 Subject: [PATCH 29/31] Disable -O0 test for now --- enzyme/test/Fortran/ReverseMode/square.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index b38da80929c..be5a1b78565 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -1,4 +1,4 @@ -! RUN: 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 +! 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 @@ -27,4 +27,4 @@ program app end program app ! CHECK: 9 -! CHECK-NEXT: 6 \ No newline at end of file +! CHECK-NEXT: 6 From 42d8f08d847cc3a5a6daaf0b9ee8b8cdff32706b Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 11 Jun 2026 14:44:11 +0100 Subject: [PATCH 30/31] Drop unnecessary semicolon --- enzyme/test/Fortran/ReverseMode/square.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enzyme/test/Fortran/ReverseMode/square.f90 b/enzyme/test/Fortran/ReverseMode/square.f90 index be5a1b78565..6875df196a5 100644 --- a/enzyme/test/Fortran/ReverseMode/square.f90 +++ b/enzyme/test/Fortran/ReverseMode/square.f90 @@ -21,7 +21,7 @@ program app print *, square(x) dx = 0 - call enzyme_autodiff(square, x, dx); + call enzyme_autodiff(square, x, dx) print *, dx end program app From 70a98be289f366dd4c8aa548f26922fb1fbd27b3 Mon Sep 17 00:00:00 2001 From: Joe Wallwork Date: Thu, 11 Jun 2026 14:46:46 +0100 Subject: [PATCH 31/31] Add README for Fortran bindings --- enzyme/Fortran/README.md | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 enzyme/Fortran/README.md diff --git a/enzyme/Fortran/README.md b/enzyme/Fortran/README.md new file mode 100644 index 00000000000..05f6f4fcbc4 --- /dev/null +++ b/enzyme/Fortran/README.md @@ -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 +```