Skip to content

[Flang][AArch64][VecLib] Add libmvec support for Flang/AArch64 #146453

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

kawashima-fj
Copy link
Member

-fveclib=libmvec for AArch64 (NEON and SVE) in Clang was supported by #143696. This patch does the same for Flang.

Vector functions defined in libmvec are used for the following Fortran operator and functions currently.

  • Power operator (**)
  • Fortran intrinsic functions listed below for real(kind=4) and real(kind=8) (including their coresponding specific intrinsic functions)
  • Fortran intrinsic functions which are expanded using functions listed below (for example, sin for complex(kind=8))
sin
tan
cos
asin
acos
atan (both atan(x) and atan(y, x))
atan2
cosh
tanh
asinh
acosh
atanh
erf
erfc
exp
log
log10

As with Clang/AArch64, glibc 2.40 or higher is required to use all these functions.

`-fveclib=libmvec` for AArch64 (NEON and SVE) in Clang was supported
by llvm#143696. This patch does the same for Flang.

Vector functions defined in `libmvec` are used for the following
Fortran operator and functions currently.

- Power operator (`**`)
- Fortran intrinsic functions listed below for `real(kind=4)` and
  `real(kind=8)`
  (including their coresponding specific intrinsic functions)
- Fortran intrinsic functions which are expanded using functions
  listed below
  (for example, `sin` for `complex(kind=8)`)

```
sin
tan
cos
asin
acos
atan (both atan(x) and atan(y, x))
atan2
cosh
tanh
asinh
acosh
atanh
erf
erfc
exp
log
log10
```

As with Clang/AArch64, glibc 2.40 or higher is required to use all
these functions.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' flang Flang issues not falling into any other category labels Jul 1, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 1, 2025

@llvm/pr-subscribers-clang-driver
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-backend-aarch64

Author: KAWASHIMA Takahiro (kawashima-fj)

Changes

-fveclib=libmvec for AArch64 (NEON and SVE) in Clang was supported by #143696. This patch does the same for Flang.

Vector functions defined in libmvec are used for the following Fortran operator and functions currently.

  • Power operator (**)
  • Fortran intrinsic functions listed below for real(kind=4) and real(kind=8) (including their coresponding specific intrinsic functions)
  • Fortran intrinsic functions which are expanded using functions listed below (for example, sin for complex(kind=8))
sin
tan
cos
asin
acos
atan (both atan(x) and atan(y, x))
atan2
cosh
tanh
asinh
acosh
atanh
erf
erfc
exp
log
log10

As with Clang/AArch64, glibc 2.40 or higher is required to use all these functions.


Full diff: https://github.com/llvm/llvm-project/pull/146453.diff

4 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/Flang.cpp (+8-1)
  • (modified) flang/docs/ReleaseNotes.md (+1)
  • (modified) flang/test/Driver/fveclib-codegen.f90 (+4)
  • (modified) flang/test/Driver/fveclib.f90 (+2-1)
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index e4e321ba1e195..75ba2af543c7a 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -484,11 +484,18 @@ void Flang::addTargetOptions(const ArgList &Args,
           Triple.getArch() != llvm::Triple::x86_64)
         D.Diag(diag::err_drv_unsupported_opt_for_target)
             << Name << Triple.getArchName();
-    } else if (Name == "libmvec" || Name == "AMDLIBM") {
+    } else if (Name == "AMDLIBM") {
       if (Triple.getArch() != llvm::Triple::x86 &&
           Triple.getArch() != llvm::Triple::x86_64)
         D.Diag(diag::err_drv_unsupported_opt_for_target)
             << Name << Triple.getArchName();
+    } else if (Name == "libmvec") {
+      if (Triple.getArch() != llvm::Triple::x86 &&
+          Triple.getArch() != llvm::Triple::x86_64 &&
+          Triple.getArch() != llvm::Triple::aarch64 &&
+          Triple.getArch() != llvm::Triple::aarch64_be)
+        D.Diag(diag::err_drv_unsupported_opt_for_target)
+            << Name << Triple.getArchName();
     } else if (Name == "SLEEF" || Name == "ArmPL") {
       if (Triple.getArch() != llvm::Triple::aarch64 &&
           Triple.getArch() != llvm::Triple::aarch64_be)
diff --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md
index 35da8323e0a10..bd3a215323de2 100644
--- a/flang/docs/ReleaseNotes.md
+++ b/flang/docs/ReleaseNotes.md
@@ -34,6 +34,7 @@ page](https://llvm.org/releases/).
 
 * -floop-interchange is now recognized by flang.
 * -floop-interchange is enabled by default at -O2 and above.
+* -fveclib=libmvec is supported for AArch64 (same as Flang/x86 and Clang/AArch64)
 
 ## Windows Support
 
diff --git a/flang/test/Driver/fveclib-codegen.f90 b/flang/test/Driver/fveclib-codegen.f90
index 4cbb1e284f18e..88b31da40167e 100644
--- a/flang/test/Driver/fveclib-codegen.f90
+++ b/flang/test/Driver/fveclib-codegen.f90
@@ -1,6 +1,8 @@
 ! test that -fveclib= is passed to the backend
 ! RUN: %if aarch64-registered-target %{ %flang -S -Ofast -target aarch64-unknown-linux-gnu -fveclib=SLEEF -o - %s | FileCheck %s --check-prefix=SLEEF %}
 ! RUN: %if x86-registered-target %{ %flang -S -Ofast -target x86_64-unknown-linux-gnu -fveclib=libmvec -o - %s | FileCheck %s %}
+! RUN: %if aarch64-registered-target %{ %flang -S -Ofast -target aarch64-unknown-linux-gnu -fveclib=libmvec -march=armv8.2-a+nosve -o - %s | FileCheck %s --check-prefix=LIBMVEC-AARCH64-NEON %}
+! RUN: %if aarch64-registered-target %{ %flang -S -Ofast -target aarch64-unknown-linux-gnu -fveclib=libmvec -march=armv8.2-a+sve -o - %s | FileCheck %s --check-prefix=LIBMVEC-AARCH64-SVE %}
 ! RUN: %if x86-registered-target %{ %flang -S -O3 -ffast-math -target x86_64-unknown-linux-gnu -fveclib=AMDLIBM -o - %s | FileCheck %s --check-prefix=AMDLIBM %}
 ! RUN: %flang -S -Ofast -fveclib=NoLibrary -o - %s | FileCheck %s --check-prefix=NOLIB
 
@@ -11,6 +13,8 @@ subroutine sb(a, b)
 ! check that we used a vectorized call to powf()
 ! CHECK: _ZGVbN4vv_powf
 ! SLEEF: _ZGVnN4vv_powf
+! LIBMVEC-AARCH64-NEON: _ZGVnN4vv_powf
+! LIBMVEC-AARCH64-SVE: _ZGVsMxvv_powf
 ! AMDLIBM: amd_vrs4_powf
 ! NOLIB: powf
     a(i) = a(i) ** b(i)
diff --git a/flang/test/Driver/fveclib.f90 b/flang/test/Driver/fveclib.f90
index 431a4bfc02522..d21e85e486f8d 100644
--- a/flang/test/Driver/fveclib.f90
+++ b/flang/test/Driver/fveclib.f90
@@ -1,6 +1,7 @@
 ! RUN: %flang -### -c -fveclib=none %s 2>&1 | FileCheck -check-prefix CHECK-NOLIB %s
 ! RUN: %flang -### -c -fveclib=Accelerate %s 2>&1 | FileCheck -check-prefix CHECK-ACCELERATE %s
 ! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu -fveclib=libmvec %s 2>&1 | FileCheck -check-prefix CHECK-libmvec %s
+! RUN: %flang -### -c --target=aarch64-unknown-linux-gnu -fveclib=libmvec %s 2>&1 | FileCheck -check-prefix CHECK-libmvec %s
 ! RUN: %flang -### -c -fveclib=MASSV %s 2>&1 | FileCheck -check-prefix CHECK-MASSV %s
 ! RUN: %flang -### -c -fveclib=Darwin_libsystem_m %s 2>&1 | FileCheck -check-prefix CHECK-DARWIN_LIBSYSTEM_M %s
 ! RUN: %flang -### -c --target=aarch64-none-none -fveclib=SLEEF %s 2>&1 | FileCheck -check-prefix CHECK-SLEEF %s
@@ -23,7 +24,7 @@
 
 ! RUN: not %flang --target=x86-none-none -c -fveclib=SLEEF %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
 ! RUN: not %flang --target=x86-none-none -c -fveclib=ArmPL %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
-! RUN: not %flang --target=aarch64-none-none -c -fveclib=libmvec %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
+! RUN: not %flang --target=riscv64-none-none -c -fveclib=libmvec %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
 ! RUN: not %flang --target=aarch64-none-none -c -fveclib=SVML %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
 ! RUN: not %flang --target=aarch64-none-none -c -fveclib=AMDLIBM %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
 ! CHECK-ERROR: unsupported option {{.*}} for target

@llvmbot
Copy link
Member

llvmbot commented Jul 1, 2025

@llvm/pr-subscribers-flang-driver

Author: KAWASHIMA Takahiro (kawashima-fj)

Changes

-fveclib=libmvec for AArch64 (NEON and SVE) in Clang was supported by #143696. This patch does the same for Flang.

Vector functions defined in libmvec are used for the following Fortran operator and functions currently.

  • Power operator (**)
  • Fortran intrinsic functions listed below for real(kind=4) and real(kind=8) (including their coresponding specific intrinsic functions)
  • Fortran intrinsic functions which are expanded using functions listed below (for example, sin for complex(kind=8))
sin
tan
cos
asin
acos
atan (both atan(x) and atan(y, x))
atan2
cosh
tanh
asinh
acosh
atanh
erf
erfc
exp
log
log10

As with Clang/AArch64, glibc 2.40 or higher is required to use all these functions.


Full diff: https://github.com/llvm/llvm-project/pull/146453.diff

4 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/Flang.cpp (+8-1)
  • (modified) flang/docs/ReleaseNotes.md (+1)
  • (modified) flang/test/Driver/fveclib-codegen.f90 (+4)
  • (modified) flang/test/Driver/fveclib.f90 (+2-1)
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index e4e321ba1e195..75ba2af543c7a 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -484,11 +484,18 @@ void Flang::addTargetOptions(const ArgList &Args,
           Triple.getArch() != llvm::Triple::x86_64)
         D.Diag(diag::err_drv_unsupported_opt_for_target)
             << Name << Triple.getArchName();
-    } else if (Name == "libmvec" || Name == "AMDLIBM") {
+    } else if (Name == "AMDLIBM") {
       if (Triple.getArch() != llvm::Triple::x86 &&
           Triple.getArch() != llvm::Triple::x86_64)
         D.Diag(diag::err_drv_unsupported_opt_for_target)
             << Name << Triple.getArchName();
+    } else if (Name == "libmvec") {
+      if (Triple.getArch() != llvm::Triple::x86 &&
+          Triple.getArch() != llvm::Triple::x86_64 &&
+          Triple.getArch() != llvm::Triple::aarch64 &&
+          Triple.getArch() != llvm::Triple::aarch64_be)
+        D.Diag(diag::err_drv_unsupported_opt_for_target)
+            << Name << Triple.getArchName();
     } else if (Name == "SLEEF" || Name == "ArmPL") {
       if (Triple.getArch() != llvm::Triple::aarch64 &&
           Triple.getArch() != llvm::Triple::aarch64_be)
diff --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md
index 35da8323e0a10..bd3a215323de2 100644
--- a/flang/docs/ReleaseNotes.md
+++ b/flang/docs/ReleaseNotes.md
@@ -34,6 +34,7 @@ page](https://llvm.org/releases/).
 
 * -floop-interchange is now recognized by flang.
 * -floop-interchange is enabled by default at -O2 and above.
+* -fveclib=libmvec is supported for AArch64 (same as Flang/x86 and Clang/AArch64)
 
 ## Windows Support
 
diff --git a/flang/test/Driver/fveclib-codegen.f90 b/flang/test/Driver/fveclib-codegen.f90
index 4cbb1e284f18e..88b31da40167e 100644
--- a/flang/test/Driver/fveclib-codegen.f90
+++ b/flang/test/Driver/fveclib-codegen.f90
@@ -1,6 +1,8 @@
 ! test that -fveclib= is passed to the backend
 ! RUN: %if aarch64-registered-target %{ %flang -S -Ofast -target aarch64-unknown-linux-gnu -fveclib=SLEEF -o - %s | FileCheck %s --check-prefix=SLEEF %}
 ! RUN: %if x86-registered-target %{ %flang -S -Ofast -target x86_64-unknown-linux-gnu -fveclib=libmvec -o - %s | FileCheck %s %}
+! RUN: %if aarch64-registered-target %{ %flang -S -Ofast -target aarch64-unknown-linux-gnu -fveclib=libmvec -march=armv8.2-a+nosve -o - %s | FileCheck %s --check-prefix=LIBMVEC-AARCH64-NEON %}
+! RUN: %if aarch64-registered-target %{ %flang -S -Ofast -target aarch64-unknown-linux-gnu -fveclib=libmvec -march=armv8.2-a+sve -o - %s | FileCheck %s --check-prefix=LIBMVEC-AARCH64-SVE %}
 ! RUN: %if x86-registered-target %{ %flang -S -O3 -ffast-math -target x86_64-unknown-linux-gnu -fveclib=AMDLIBM -o - %s | FileCheck %s --check-prefix=AMDLIBM %}
 ! RUN: %flang -S -Ofast -fveclib=NoLibrary -o - %s | FileCheck %s --check-prefix=NOLIB
 
@@ -11,6 +13,8 @@ subroutine sb(a, b)
 ! check that we used a vectorized call to powf()
 ! CHECK: _ZGVbN4vv_powf
 ! SLEEF: _ZGVnN4vv_powf
+! LIBMVEC-AARCH64-NEON: _ZGVnN4vv_powf
+! LIBMVEC-AARCH64-SVE: _ZGVsMxvv_powf
 ! AMDLIBM: amd_vrs4_powf
 ! NOLIB: powf
     a(i) = a(i) ** b(i)
diff --git a/flang/test/Driver/fveclib.f90 b/flang/test/Driver/fveclib.f90
index 431a4bfc02522..d21e85e486f8d 100644
--- a/flang/test/Driver/fveclib.f90
+++ b/flang/test/Driver/fveclib.f90
@@ -1,6 +1,7 @@
 ! RUN: %flang -### -c -fveclib=none %s 2>&1 | FileCheck -check-prefix CHECK-NOLIB %s
 ! RUN: %flang -### -c -fveclib=Accelerate %s 2>&1 | FileCheck -check-prefix CHECK-ACCELERATE %s
 ! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu -fveclib=libmvec %s 2>&1 | FileCheck -check-prefix CHECK-libmvec %s
+! RUN: %flang -### -c --target=aarch64-unknown-linux-gnu -fveclib=libmvec %s 2>&1 | FileCheck -check-prefix CHECK-libmvec %s
 ! RUN: %flang -### -c -fveclib=MASSV %s 2>&1 | FileCheck -check-prefix CHECK-MASSV %s
 ! RUN: %flang -### -c -fveclib=Darwin_libsystem_m %s 2>&1 | FileCheck -check-prefix CHECK-DARWIN_LIBSYSTEM_M %s
 ! RUN: %flang -### -c --target=aarch64-none-none -fveclib=SLEEF %s 2>&1 | FileCheck -check-prefix CHECK-SLEEF %s
@@ -23,7 +24,7 @@
 
 ! RUN: not %flang --target=x86-none-none -c -fveclib=SLEEF %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
 ! RUN: not %flang --target=x86-none-none -c -fveclib=ArmPL %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
-! RUN: not %flang --target=aarch64-none-none -c -fveclib=libmvec %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
+! RUN: not %flang --target=riscv64-none-none -c -fveclib=libmvec %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
 ! RUN: not %flang --target=aarch64-none-none -c -fveclib=SVML %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
 ! RUN: not %flang --target=aarch64-none-none -c -fveclib=AMDLIBM %s 2>&1 | FileCheck -check-prefix CHECK-ERROR %s
 ! CHECK-ERROR: unsupported option {{.*}} for target

@kawashima-fj
Copy link
Member Author

sinh is not converted to the libmvec function currently. I did not investigate the reason yet. In FIR, most math functions are converted to math dialect (%23 = math.cosh %22 fastmath<fast> : f64) but sinh is not converted to math dialect (%23 = fir.call @sinh(%22) fastmath<fast> : (f64) -> f64). It's the difference I found. Is it an expected difference?

Copy link
Member

@MacDue MacDue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may also want to change Options.td. Currently, the note about needing GLIBC 2.40 is only displayed for Clang as it's under HelpTextForVariants<[ClangOption, CC1Option]:

HelpTextForVariants<[ClangOption, CC1Option],
"Use the given vector functions library.\n"
" Note: -fveclib={ArmPL,SLEEF,libmvec} implies -fno-math-errno.\n"
" Note: -fveclib=libmvec on AArch64 requires GLIBC 2.40 or newer.">,

Copy link
Contributor

@tblah tblah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with MacDue's comments. Thank you for contributing this!

Copy link
Member

@MacDue MacDue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM!

@@ -3487,7 +3487,8 @@ def fno_experimental_isel : Flag<["-"], "fno-experimental-isel">, Group<f_clang_
Alias<fno_global_isel>;
def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Use the given vector functions library">,
HelpText<"Use the given vector functions library.\n"
" Note: -fveclib=libmvec on AArch64 requires GLIBC 2.40 or newer.">,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the constraint on glibc >=2.40 true for clang as well? What happens if the user attempts to build with an older glibc? Will they see a configure-time error or will the build fail?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ach. Please ignore the question about the constraint on glibc. The second question about failure modes with older glibc still holds though.

Copy link
Collaborator

@paulwalker-arm paulwalker-arm Jul 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The toolchain user will see a link time failure when trying to resolve a call to a vector math routine. Note: the exact requirement depends on the function in question, but version 2.40 is what was used when deciding which math functions to add mappings for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category flang:driver flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants