Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@
/projects/hipfft/**/.readthedocs.yaml @ROCm/fft-reviewers @ROCm/fft-docs-reviewers
/projects/hipfft/docs/ @ROCm/fft-reviewers @ROCm/fft-docs-reviewers
/projects/hipfft/library/include/ @ROCm/fft-reviewers @ROCm/fft-docs-reviewers
/bindings/fortran/hipfft/ @ROCm/rocm-fortran-maintainers @ROCm/fft-reviewers

/projects/hiprand/**/*.md @ROCm/prims-rands-reviewers @ROCm/rands-docs-reviewers
/projects/hiprand/**/*.rst @ROCm/prims-rands-reviewers @ROCm/rands-docs-reviewers
Expand Down
9 changes: 9 additions & 0 deletions .github/repos-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,15 @@
"auto_subtree_pull": false,
"auto_subtree_push": false,
"monorepo_source_of_truth": true
},
{
"name": "hipfft",
"url": "ROCm/rocm-libraries",
"branch": "develop",
"category": "bindings/fortran",
"auto_subtree_pull": false,
"auto_subtree_push": false,
"monorepo_source_of_truth": true
}
]
}
4 changes: 4 additions & 0 deletions bindings/fortran/hipfft/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Generated by the rocm-fortran generator
/hipfft.F90 linguist-generated=true
/hipfftxt.F90 linguist-generated=true
/hipfftw.F90 linguist-generated=true
18 changes: 18 additions & 0 deletions bindings/fortran/hipfft/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Changelog for the hipFFT Fortran binding

## Unreleased

### Added

* Generated Fortran bindings, split as CUDA Fortran's `cufft` and `cufftXt`: `use hipfft`, or
`use hipfftxt` (every `hipfftXt*` and `hipfftMp*` function; it uses and re-exports `hipfft`, so
it alone gives the whole API), and link `hip::hipfft_fortran`; or `use hipfftw`
(`hipfftw.h`) and link `hip::hipfftw_fortran` for the FFTW compatibility API. Fortran is
case-insensitive, so `use hipfftXt` works too.
Controlled by `BUILD_FORTRAN_BINDINGS` (on by default on Linux, off on Windows),
`BUILD_FORTRAN_CLIENTS` and `FORTRAN_ARRAY_INTERFACES` (`assumed-shape` by default; `none` or
`assumed-rank`). Found with `find_package(hipfft-fortran)` and
`find_package(hipfftw-fortran)`; the archives and the `.mod` files install per compiler,
under `<libdir>/fortran/<compiler>` and `<includedir>/fortran/<compiler>`.
The archive has one section per procedure: link with `-Wl,--gc-sections` to keep only the wrappers
you call.
294 changes: 294 additions & 0 deletions bindings/fortran/hipfft/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
# #############################################################################
# Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ############################################################################

# Fortran bindings for hipFFT and hipFFTW. hipfft.F90, hipfftxt.F90 and
# hipfftw.F90 are GENERATED by the rocm-fortran generator: regenerate them, do
# not edit them. As CUDA Fortran's cufft and cufftXt: hipfft, and hipfftxt
# (every hipfftXt* and hipfftMp* function; it uses and re-exports hipfft). hipfftw
# (hipfftw.h) is independent of the other two.

cmake_minimum_required(VERSION 3.19)

project(hipfft-fortran LANGUAGES NONE)

# Not ON: ROCm ships no Fortran compiler on Windows.
option(BUILD_FORTRAN_BINDINGS "Build the hipFFT and hipFFTW Fortran bindings" "${UNIX}")
option(BUILD_FORTRAN_CLIENTS "Build the hipFFT and hipFFTW Fortran binding tests" ON)

set(FORTRAN_ARRAY_INTERFACES "assumed-shape" CACHE STRING
"Array-argument overloads to expose: none, assumed-shape, or assumed-rank")
set_property(CACHE FORTRAN_ARRAY_INTERFACES PROPERTY STRINGS
none assumed-shape assumed-rank)

if(NOT BUILD_FORTRAN_BINDINGS)
return()
endif()

include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/ROCmFortranCompiler.cmake")
if(NOT CMAKE_Fortran_COMPILER)
message(STATUS "hipFFT: no Fortran compiler found, skipping the Fortran bindings")
return()
endif()

enable_language(Fortran)

include(GNUInstallDirs)

if(NOT FORTRAN_ARRAY_INTERFACES MATCHES "^(none|assumed-shape|assumed-rank)$")
message(FATAL_ERROR
"FORTRAN_ARRAY_INTERFACES must be none, assumed-shape or assumed-rank, "
"not '${FORTRAN_ARRAY_INTERFACES}'.")
endif()

# A .mod is compiler-specific, so artifacts install per compiler. This mapping
# MUST match the one in both config templates.
if(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
set(_fc_name "gfortran")
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Flang") # Flang, LLVMFlang
set(_fc_name "amdflang")
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray")
set(_fc_name "ftn")
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
set(_fc_name "ifx")
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
set(_fc_name "ifort")
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC")
set(_fc_name "nvfortran")
else()
get_filename_component(_fc_name "${CMAKE_Fortran_COMPILER}" NAME_WE)
string(TOLOWER "${_fc_name}" _fc_name)
endif()

set(HIPFFT_FORTRAN_COMPILER_DIR "${_fc_name}" CACHE STRING
"Per-compiler subdirectory the .mod files and archives install under")

# One layout for both bindings; the mirror only feeds hipfftw's config template.
set(HIPFFTW_FORTRAN_COMPILER_DIR "${HIPFFT_FORTRAN_COMPILER_DIR}")

set(_moddir "${CMAKE_CURRENT_BINARY_DIR}/include")

# Link interface only; one lookup defines hip::hipfft and hip::hipfftw. C is
# enabled because hip-config-amd.cmake reaches FindThreads.
enable_language(C)
find_package(hipfft QUIET)

if(NOT TARGET hip::hipfft AND NOT TARGET hip::hipfftw)
message(STATUS
"hipFFT: neither hip::hipfft nor hip::hipfftw was found, so the Fortran "
"bindings carry no link interface; a consumer will have to link the C "
"library (-lhipfft / -lhipfftw) itself. Point CMAKE_PREFIX_PATH at an "
"installed ROCm to have it recorded.")
endif()

add_library(hipfft_fortran STATIC hipfft.F90 hipfftxt.F90)
add_library(hip::hipfft_fortran ALIAS hipfft_fortran)

# Each module compiles to one object, and a linker extracts whole objects from
# an archive, so a program that calls one wrapper links all of them. One section
# per procedure lets a program linked with -Wl,--gc-sections keep only the
# wrappers it calls, and still link when another wrapper names a C function the
# installed library does not export. Only these compilers split the sections
# (the Intel ones accept the flags but do not).
target_compile_options(hipfft_fortran PRIVATE
"$<$<COMPILE_LANG_AND_ID:Fortran,GNU,LLVMFlang,Flang,NVHPC>:-ffunction-sections;-fdata-sections>")

set_target_properties(hipfft_fortran PROPERTIES
Fortran_MODULE_DIRECTORY "${_moddir}"
Fortran_PREPROCESS ON
Fortran_FORMAT FREE
POSITION_INDEPENDENT_CODE ON)

if(FORTRAN_ARRAY_INTERFACES STREQUAL "assumed-shape")
target_compile_definitions(hipfft_fortran PRIVATE USE_ASSUMED_SHAPE=1)
elseif(FORTRAN_ARRAY_INTERFACES STREQUAL "assumed-rank")
target_compile_definitions(hipfft_fortran PRIVATE USE_ASSUMED_RANK=1)
endif()

target_include_directories(hipfft_fortran PUBLIC
"$<BUILD_INTERFACE:${_moddir}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/fortran/${HIPFFT_FORTRAN_COMPILER_DIR}>")

# Always TRUE or FALSE: the config template substitutes it into an if().
if(TARGET hip::hipfft)
target_link_libraries(hipfft_fortran INTERFACE hip::hipfft)
set(HIPFFT_FORTRAN_NEEDS_HIPFFT_PACKAGE TRUE)
else()
set(HIPFFT_FORTRAN_NEEDS_HIPFFT_PACKAGE FALSE)
endif()

add_library(hipfftw_fortran STATIC hipfftw.F90)
add_library(hip::hipfftw_fortran ALIAS hipfftw_fortran)

# One section per procedure, as for hipfft_fortran.
target_compile_options(hipfftw_fortran PRIVATE
"$<$<COMPILE_LANG_AND_ID:Fortran,GNU,LLVMFlang,Flang,NVHPC>:-ffunction-sections;-fdata-sections>")

# hipfftw.F90 has no guards today; kept so a regenerated one needs no change.
set_target_properties(hipfftw_fortran PROPERTIES
Fortran_MODULE_DIRECTORY "${_moddir}"
Fortran_PREPROCESS ON
Fortran_FORMAT FREE
POSITION_INDEPENDENT_CODE ON)

if(FORTRAN_ARRAY_INTERFACES STREQUAL "assumed-shape")
target_compile_definitions(hipfftw_fortran PRIVATE USE_ASSUMED_SHAPE=1)
elseif(FORTRAN_ARRAY_INTERFACES STREQUAL "assumed-rank")
target_compile_definitions(hipfftw_fortran PRIVATE USE_ASSUMED_RANK=1)
endif()

target_include_directories(hipfftw_fortran PUBLIC
"$<BUILD_INTERFACE:${_moddir}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/fortran/${HIPFFTW_FORTRAN_COMPILER_DIR}>")

if(TARGET hip::hipfftw)
target_link_libraries(hipfftw_fortran INTERFACE hip::hipfftw)
set(HIPFFTW_FORTRAN_NEEDS_HIPFFT_PACKAGE TRUE)
else()
set(HIPFFTW_FORTRAN_NEEDS_HIPFFT_PACKAGE FALSE)
endif()

# The uninstrumented Fortran executables cannot link an ASan libhipfft.
if(BUILD_FORTRAN_CLIENTS AND BUILD_ADDRESS_SANITIZER)
message(STATUS
"hipFFT: address sanitizer is enabled, skipping the Fortran binding tests.")
set(BUILD_FORTRAN_CLIENTS OFF)
endif()

if(BUILD_FORTRAN_CLIENTS)
enable_testing()
add_subdirectory(test)
endif()

include(CMakePackageConfigHelpers)

# Read from this tree, not hipfft_VERSION, which is the INSTALLED hipFFT's. One
# version for both packages.
set(_fortran_version "")
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../../projects/hipfft/CMakeLists.txt")
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/../../../projects/hipfft/CMakeLists.txt" _hipfft_root)
set(_v_parts "")
foreach(_v_comp MAJOR MINOR PATCH)
# Judged on the whole match: a failed match leaves CMAKE_MATCH_1 stale.
string(REGEX MATCH "set[ \t]*\\([ \t]*HIPFFT_VERSION_${_v_comp}[ \t]+\"([0-9]+)\""
_v_whole "${_hipfft_root}")
if(_v_whole)
list(APPEND _v_parts "${CMAKE_MATCH_1}")
endif()
endforeach()
list(LENGTH _v_parts _v_n)
if(_v_n EQUAL 3)
list(JOIN _v_parts "." _fortran_version)
endif()
unset(_hipfft_root)
endif()

if(NOT _fortran_version)
message(STATUS
"hipFFT: could not determine the version for the Fortran packages, so no "
"hipfft-fortran-config-version.cmake or hipfftw-fortran-config-version.cmake "
"is installed; find_package(hipfft-fortran <version>) and "
"find_package(hipfftw-fortran <version>) will not match.")
endif()

install(DIRECTORY "${_moddir}/"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/fortran/${HIPFFT_FORTRAN_COMPILER_DIR}"
COMPONENT devel
FILES_MATCHING PATTERN "*.mod")

set(HIPFFT_FORTRAN_LIBDIR "${CMAKE_INSTALL_LIBDIR}/fortran")
set(HIPFFT_FORTRAN_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/fortran")
set(HIPFFTW_FORTRAN_LIBDIR "${HIPFFT_FORTRAN_LIBDIR}")
set(HIPFFTW_FORTRAN_INCLUDEDIR "${HIPFFT_FORTRAN_INCLUDEDIR}")

# Two independent packages, each in its own lib/cmake/<package> directory.
set(_hipfft_pkgdir "${CMAKE_INSTALL_LIBDIR}/cmake/hipfft-fortran")
set(_hipfftw_pkgdir "${CMAKE_INSTALL_LIBDIR}/cmake/hipfftw-fortran")

install(TARGETS hipfft_fortran
EXPORT hipfft-fortran-targets
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/fortran/${HIPFFT_FORTRAN_COMPILER_DIR}"
COMPONENT devel)
install(EXPORT hipfft-fortran-targets
FILE hipfft-fortran-targets.cmake
NAMESPACE hip::
DESTINATION "${_hipfft_pkgdir}"
COMPONENT devel)

# Under share/: the config reads every entry of include/fortran/ as a compiler.
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/hipfft.F90"
"${CMAKE_CURRENT_SOURCE_DIR}/hipfftxt.F90"
DESTINATION "${CMAKE_INSTALL_DATADIR}/hipfft/fortran"
COMPONENT devel)

configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/hipfft-fortran-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/hipfft-fortran-config.cmake"
INSTALL_DESTINATION "${_hipfft_pkgdir}"
PATH_VARS HIPFFT_FORTRAN_LIBDIR HIPFFT_FORTRAN_INCLUDEDIR)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/hipfft-fortran-config.cmake"
DESTINATION "${_hipfft_pkgdir}"
COMPONENT devel)

if(_fortran_version)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/hipfft-fortran-config-version.cmake"
VERSION "${_fortran_version}"
COMPATIBILITY SameMajorVersion)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/hipfft-fortran-config-version.cmake"
DESTINATION "${_hipfft_pkgdir}"
COMPONENT devel)
endif()

install(TARGETS hipfftw_fortran
EXPORT hipfftw-fortran-targets
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/fortran/${HIPFFTW_FORTRAN_COMPILER_DIR}"
COMPONENT devel)
install(EXPORT hipfftw-fortran-targets
FILE hipfftw-fortran-targets.cmake
NAMESPACE hip::
DESTINATION "${_hipfftw_pkgdir}"
COMPONENT devel)

install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/hipfftw.F90"
DESTINATION "${CMAKE_INSTALL_DATADIR}/hipfft/fortran"
COMPONENT devel)

configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/hipfftw-fortran-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/hipfftw-fortran-config.cmake"
INSTALL_DESTINATION "${_hipfftw_pkgdir}"
PATH_VARS HIPFFTW_FORTRAN_LIBDIR HIPFFTW_FORTRAN_INCLUDEDIR)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/hipfftw-fortran-config.cmake"
DESTINATION "${_hipfftw_pkgdir}"
COMPONENT devel)

if(_fortran_version)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/hipfftw-fortran-config-version.cmake"
VERSION "${_fortran_version}"
COMPATIBILITY SameMajorVersion)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/hipfftw-fortran-config-version.cmake"
DESTINATION "${_hipfftw_pkgdir}"
COMPONENT devel)
endif()
Loading
Loading