Skip to content

Bind every scalar pointer as type(c_ptr), add its typed form as _typed - #581

Merged
amontoison merged 2 commits into
developfrom
fortran_typed_variants
Oct 7, 2026
Merged

amontoison merged 2 commits into
developfrom
fortran_typed_variants

Conversation

@amontoison

@amontoison amontoison commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Every scalar pointer argument now comes in two forms under the same generic:

  • the bind(C) specific takes it as type(c_ptr), value, the C API's own spelling;
  • a new <routine>_typed module procedure takes the Fortran variable (integer, real, complex or the enum kind) and passes its address.

Both forms resolve, so either of these calls works:

st = rocblas_daxpy(handle, n, alpha, dx, incx, dy, incy)          ! _typed
st = rocblas_daxpy(handle, n, c_loc(alpha), dx, incx, dy, incy)   ! bind(C)

This covers two kinds of scalar:

Two more forms cover the calls neither of those can spell:

  • <routine>_devptr, for the 42 rocSPARSE/hipSPARSE routines with both a pointer-mode scalar and a host output (alpha next to buffer_size). This is the device-pointer-mode call: the pointer-mode scalars as type(c_ptr), the host outputs typed.
  • <routine>_rank_N_devptr, next to the hipSOLVER array overloads. In those overloads devInfo is now an integer, like the device arrays next to it, as in 0.9.0. The _devptr twins take it as a type(c_ptr).

devInfo gets no typed form on the type(c_ptr) interface, because a host integer next to type(c_ptr) buffers would be written by the GPU.

Compatibility with 0.9.0

728 of the 807 test programs of hipfort 0.9.0 now compile against these modules, up from 585 against develop. The 79 that still fail break at compile time, for six reasons; the CHANGELOG update will list them:

  • hipSOLVER, 57 programs: an integer devInfo passed with type(c_ptr) buffers. Excluded on purpose.
  • hipSOLVER array overloads, 12 programs: tau passed as dTau(1).
  • *syevdx/*heevdx, 4 programs: nev passed as a c_ptr while lwork is typed.
  • rocsolver_{c,z}hegvdx, 4 programs: nev is now a device pointer (fb8f244).
  • hipFFTW guru, 1 program: dims passed as a scalar.
  • ROCTx, 1 program: Fortran strings (different library).

One change still compiles but behaves differently: hipsolverRfBatch* now takes its array of host pointers by value.

Contents

  • lib/hipfort, regenerated with rocm-fortran 9854af6.
  • The bind(C) symbol tests, regenerated against these bindings (on top of Regenerate the bind(C) symbol tests #580, which regenerated them for the previous ones).
  • The supported-API tables. Only the generated diff is applied: the variants column gains typed/devptr.

Validation

Against ROCm 10.1, with gfortran and amdflang:

  • Compilation: the modules compile with no macro, with USE_ASSUMED_SHAPE, with USE_ASSUMED_RANK, and with USE_ASSUMED_SHAPE + USE_CUDA_NAMES. The current tests build 1245/1245.
  • ctest with -DHIPFORT_EXTENDED_TESTS=ON: 1255/1258. The 3 failures are the known WSL ones (hip_mem_advise f2003/f2008, hip_module_kernel).
    • The shared-link tests resolve every symbol against ROCm 10.1.
    • Against CUDA 13.3 they also resolve without libcuda: the _typed forms of the 6 HIP routines mapped to the CUDA driver API exist on ROCm only.
  • On a gfx1101 GPU: every 0.9.0 test program that builds behaves the same against the 0.9.0 library and against this one.
  • Docs: Doxygen reports no new warning.

Generator fixes found along the way

  • gfortran 13 passes a garbage byte when a by-reference character(c_char) is forwarded to a bind(C) value dummy. hipsolverSgesvd_bufferSize then returned INVALID_VALUE. The wrappers now take a C char by value.
  • CUDA backend: no _typed form calls the CUDA driver API, so hipfort still needs only the CUDA runtime libraries.

The bind(C) specific of each routine now spells every scalar pointer the
way the C API does, type(c_ptr), value: alpha/beta as before, and the host
outputs (getters, buffer sizes, counts) as well, which were typed in the
specific itself. Their Fortran type moves to a <routine>_typed module
procedure of the same generic, which takes the variable and forwards
c_loc of it (c_null_ptr for an absent optional). Both forms resolve, as
they differ in the type of those arguments, so a call can pass c_loc(x),
a device address or NULL, or the variable itself:

  rocblas_dgemm(handle, ..., alpha, dA, ...)         ! _typed
  rocblas_dgemm(handle, ..., c_loc(alpha), dA, ...)  ! bind(C)

Two more forms:
- <routine>_devptr, for the 42 sparse routines with both a pointer-mode
  scalar and a host-only one: in device pointer mode alpha/beta are
  addresses while buffer_size stays a host variable.
- <routine>_rank_N_devptr beside the hipSOLVER array overloads: devInfo
  is typed in the array overloads, like the device arrays next to it (it
  was a type(c_ptr) there), and a type(c_ptr) in the _devptr twins.
devInfo gets no _typed form on the type(c_ptr) interface: a typed host
variable beside type(c_ptr) buffers is a shape the API never accepts.

Code written against hipfort 0.9.0 compiles again: 728 of its 807 test
programs, against 585 before this change. The 79 that do not are listed
in the changelog; none is silent.

Regenerated with rocm-fortran 9854af6 (lib/hipfort, the symbol tests and
the supported-API tables, the latter patched with the generated diff only).

Checked against ROCm 10.1, gfortran and amdflang:
- the modules compile with no macro, USE_ASSUMED_SHAPE, USE_ASSUMED_RANK
  and USE_ASSUMED_SHAPE + USE_CUDA_NAMES; the current tests build
  1245/1245;
- full ctest with -DHIPFORT_EXTENDED_TESTS=ON: 1255/1258, the three known
  WSL failures; the shared-link tests resolve every symbol against ROCm
  10.1 and, without libcuda, against CUDA 13.3;
- on a gfx1101 GPU, no 0.9.0 test program that builds behaves differently
  against the 0.9.0 library and this one.
@amontoison
amontoison requested a review from a team as a code owner October 6, 2026 23:36
develop regenerated the symbol tests (#580) against its own bindings. The
ones here are regenerated with the same tool against the bindings of this
branch, so they are kept as they are.
@amontoison
amontoison merged commit 1857a2d into develop Oct 7, 2026
1 of 3 checks passed
@amontoison
amontoison deleted the fortran_typed_variants branch October 7, 2026 04:16
amontoison added a commit that referenced this pull request Oct 7, 2026
#581 gives every scalar pointer argument two forms under one generic: the
bind(C) specific takes a type(c_ptr), the _typed module procedure the
Fortran variable. Nothing in the user documentation said so, and the test
suite only called the type(c_ptr) form for alpha/beta (with c_loc, since
#564), so the _typed path was not covered by CTest.

docs/how-to/fortran-interfaces.rst gains a section "Scalar arguments
passed by pointer": when to pass the variable and when its address, the
device pointer mode (including the routines that mix a pointer-mode scalar
with a host output, and the array overloads, whose alpha/beta are typed),
and hipSOLVER's device-only devInfo. Its examples compile against these
bindings with gfortran and amdflang.

Eight tests take an existing check through the _typed form, with alpha and
beta passed as named constants instead of c_loc(): rocBLAS dgemm and
caxpy, hipBLAS sgemm and zaxpy, rocSPARSE dgemvi and dcsrgemm (alpha, beta
and buffer_size all typed), hipSPARSE dgemvi and zcsrsv2. Each object file
references the _typed procedures it is meant to (checked with nm), and the
two copies whose alpha was 1 use 2 and (2,1) instead, so a lost or
misread alpha fails the check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant