[flang-commits] [flang] [llvm] [flang] Use backend fp128 support to determine REAL(16) availability (PR #221907)

Shunsuke Watanabe via flang-commits flang-commits at lists.llvm.org
Tue Sep 8 02:21:31 PDT 2026


https://github.com/s-watanabe314 updated https://github.com/llvm/llvm-project/pull/221907

>From c0eeeefdf08ac1b625c081b6fd37d19847d3252c Mon Sep 17 00:00:00 2001
From: s-watanabe314 <watanabe.shu-06 at fujitsu.com>
Date: Mon, 31 Aug 2026 11:53:36 +0900
Subject: [PATCH 1/2] [flang] Use backend fp128 support to determine REAL(16)
 availability

The existing REAL(16) availability checks depend on build-time math
library or long double support. This does not fully represent the
capabilities of a compilation target, particularly when
cross-compiling.

In addition to the existing checks, query the target's TargetLowering
information and enable REAL(16) when fp128 is a legal backend value
type. This enables the frontend to compile REAL(16) for targets such
as x86_64 and AArch64 independently of REAL(16) math intrinsic library
support.

The runtimes build cannot directly reuse the frontend's TargetLowering
query during CMake configuration. Enable the REAL(16) intrinsic modules
for x86_64 and AArch64 runtime targets, while preserving the existing
checks for an external F128 math library and LDBL_MANT_DIG == 113.
Pass the resulting setting separately to each runtime sub-build.

Update the affected tests to detect REAL(16) frontend support by
invoking the Flang driver for the configured target. Also document
that backend fp128 type support and REAL(16) math intrinsic library
support are independent.

Discussion:
https://discourse.llvm.org/t/cross-compilation-of-real-kind-16/89161
https://github.com/llvm/llvm-project/pull/182230
---
 flang/docs/Real16MathSupport.md             | 39 +++++++++++++++++++++
 flang/include/flang/Tools/TargetSetup.h     | 29 ++++++++++++++-
 flang/test/Lower/HLFIR/convert-variable.f90 |  2 +-
 flang/test/Lower/Intrinsics/abs.f90         |  2 +-
 flang/test/Lower/Intrinsics/modulo.f90      |  2 +-
 flang/test/Lower/Intrinsics/sign.f90        |  2 +-
 flang/test/Lower/assignment.f90             |  2 +-
 flang/test/Lower/math-lowering/abs.f90      | 12 +++----
 flang/test/lit.cfg.py                       | 22 ++++++++++++
 flang/test/lit.site.cfg.py.in               |  1 +
 llvm/runtimes/CMakeLists.txt                | 36 +++++++++++++++----
 11 files changed, 130 insertions(+), 19 deletions(-)

diff --git a/flang/docs/Real16MathSupport.md b/flang/docs/Real16MathSupport.md
index 93492c8b767c3..42695d0248adc 100644
--- a/flang/docs/Real16MathSupport.md
+++ b/flang/docs/Real16MathSupport.md
@@ -36,3 +36,42 @@ may provide `REAL(16)` math support without a `libquadmath`
 dependency, using standard `libc` APIs for the `long double`
 data type. It is not recommended to use the above CMake option
 for building Flang compilers for such targets.
+
+In addition to the runtime library support described above, Flang may
+also consider `REAL(16)` available when the LLVM backend supports the
+target's 128-bit floating-point type. This check is independent of the
+availability of libraries implementing `REAL(16)` math intrinsics.
+
+As a result, `REAL(16)` variables and arithmetic operations may be accepted
+even when no library support for `REAL(16)` math intrinsics is available.
+In such cases, references to math intrinsic functions can result in linker
+errors rather than frontend diagnostics. For example:
+
+```
+FIRModule:(.text+0x97): undefined reference to `_FortranASinF128'
+```
+
+In such configurations, basic arithmetic operations such as addition,
+subtraction, multiplication, and division may still work if they are
+supported by the LLVM backend, while math intrinsics such as SIN, COS, EXP,
+and LOG require additional runtime library support.
+
+This distinction can affect programs that use `SELECTED_REAL_KIND` to
+determine whether `REAL(16)` is available. For example:
+
+```Fortran
+function test(x)
+  integer, parameter :: k = merge(16, 4, selected_real_kind(p=33) .eq. 16)
+  real(kind=k) :: x
+  test = sin(x)
+end function
+```
+
+When `SELECTED_REAL_KIND(p=33)` is evaluated during constant folding, it may
+produce `16` if `REAL(16)` type support is available, even when the
+corresponding math intrinsic library support is unavailable. In such cases
+the program may compile successfully but fail to link because the required
+`REAL(16)` math intrinsic implementations cannot be found.
+
+Users who want to prevent any use of `REAL(16)` regardless of backend
+support can use the `-fdisable-real-16` option.
diff --git a/flang/include/flang/Tools/TargetSetup.h b/flang/include/flang/Tools/TargetSetup.h
index 47f886141b002..03a0acda3fb51 100644
--- a/flang/include/flang/Tools/TargetSetup.h
+++ b/flang/include/flang/Tools/TargetSetup.h
@@ -12,6 +12,10 @@
 #include "flang/Common/float128.h"
 #include "flang/Evaluate/target.h"
 #include "flang/Frontend/TargetOptions.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
 #include "llvm/Target/TargetMachine.h"
 
 namespace Fortran::tools {
@@ -67,7 +71,30 @@ namespace Fortran::tools {
   constexpr bool f128Support = false;
 #endif
 
-  if constexpr (!f128Support) {
+  bool f128BESupport = false;
+  llvm::LLVMContext ctx;
+  std::unique_ptr<llvm::Module> dummyModule =
+      std::make_unique<llvm::Module>("quad-test", ctx);
+  dummyModule->setTargetTriple(targetMachine.getTargetTriple());
+  dummyModule->setDataLayout(targetMachine.createDataLayout());
+
+  llvm::FunctionType *dummyFTy =
+      llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), false);
+  llvm::Function *dummyF = llvm::Function::Create(dummyFTy,
+      llvm::GlobalValue::ExternalLinkage, "quad-test", dummyModule.get());
+
+  const llvm::TargetLowering *dummyTLI =
+      targetMachine.getSubtargetImpl(*dummyF)->getTargetLowering();
+
+  if (dummyTLI) {
+    llvm::EVT fp128EVT = llvm::EVT::getEVT(llvm::Type::getFP128Ty(ctx));
+
+    // Query for fp128 backend support. Based on this, determine whether
+    // compilation is possible on the frontend.
+    f128BESupport = dummyTLI->isTypeLegal(fp128EVT);
+  }
+
+  if (!f128Support && !f128BESupport) {
     targetCharacteristics.DisableType(Fortran::common::TypeCategory::Real, 16);
     targetCharacteristics.DisableType(
         Fortran::common::TypeCategory::Complex, 16);
diff --git a/flang/test/Lower/HLFIR/convert-variable.f90 b/flang/test/Lower/HLFIR/convert-variable.f90
index b9fda640182d4..eb5d307676afc 100644
--- a/flang/test/Lower/HLFIR/convert-variable.f90
+++ b/flang/test/Lower/HLFIR/convert-variable.f90
@@ -1,5 +1,5 @@
 ! Test lowering of variables to fir.declare
-! RUN: bbc -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,%if flang-supports-f128-math %{F128%} %else %{F64%}
+! RUN: bbc -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,%if flang-frontend-supports-f128 %{F128%} %else %{F64%}
 
 subroutine scalar_numeric(x)
   integer :: x
diff --git a/flang/test/Lower/Intrinsics/abs.f90 b/flang/test/Lower/Intrinsics/abs.f90
index 97c58631a1329..44046fa05f001 100644
--- a/flang/test/Lower/Intrinsics/abs.f90
+++ b/flang/test/Lower/Intrinsics/abs.f90
@@ -1,4 +1,4 @@
-! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,CMPLX,CMPLX-PRECISE,%if flang-supports-f128-math %{F128%} %else %{F64%}
+! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,CMPLX,CMPLX-PRECISE,%if flang-frontend-supports-f128 %{F128%} %else %{F64%}
 ! RUN: %flang_fc1 -emit-hlfir -mllvm --math-runtime=precise %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE"
 ! RUN: %flang_fc1 -emit-hlfir -mllvm --force-mlir-complex %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-FAST"
 ! RUN: %flang_fc1 -fapprox-func -emit-hlfir %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-APPROX"
diff --git a/flang/test/Lower/Intrinsics/modulo.f90 b/flang/test/Lower/Intrinsics/modulo.f90
index 0cb91f3862f20..4512bc3c75640 100644
--- a/flang/test/Lower/Intrinsics/modulo.f90
+++ b/flang/test/Lower/Intrinsics/modulo.f90
@@ -1,5 +1,5 @@
 ! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s -check-prefixes=HONORINF,ALL
-! RUN: %flang_fc1 -menable-no-infs -emit-hlfir %s -o - | FileCheck %s -check-prefixes=CHECK,ALL,%if flang-supports-f128-math %{F128%} %else %{F64%}
+! RUN: %flang_fc1 -menable-no-infs -emit-hlfir %s -o - | FileCheck %s -check-prefixes=CHECK,ALL,%if flang-frontend-supports-f128 %{F128%} %else %{F64%}
 
 ! ALL-LABEL: func @_QPmodulo_testr(
 ! ALL-SAME: %[[arg0:.*]]: !fir.ref<f64>{{.*}}, %[[arg1:.*]]: !fir.ref<f64>{{.*}}, %[[arg2:.*]]: !fir.ref<f64>{{.*}}) {
diff --git a/flang/test/Lower/Intrinsics/sign.f90 b/flang/test/Lower/Intrinsics/sign.f90
index 965bda3d5b834..19d5d67fd3232 100644
--- a/flang/test/Lower/Intrinsics/sign.f90
+++ b/flang/test/Lower/Intrinsics/sign.f90
@@ -1,4 +1,4 @@
-! RUN: bbc %s -o - | FileCheck %s --check-prefixes=CHECK,%if flang-supports-f128-math %{F128%} %else %{F64%}
+! RUN: bbc %s -o - | FileCheck %s --check-prefixes=CHECK,%if flang-frontend-supports-f128 %{F128%} %else %{F64%}
 
 ! CHECK-LABEL: sign_testi
 subroutine sign_testi(a, b, c)
diff --git a/flang/test/Lower/assignment.f90 b/flang/test/Lower/assignment.f90
index f8bef3e99c595..91c11aa345ed0 100644
--- a/flang/test/Lower/assignment.f90
+++ b/flang/test/Lower/assignment.f90
@@ -1,4 +1,4 @@
-! RUN: %flang_fc1 %s -o "-" -emit-hlfir -cpp | FileCheck %s --check-prefixes=CHECK,%if flang-supports-f128-math %{F128%} %else %{F64%}%if target=x86_64-unknown-linux{{.*}} %{,CHECK-X86-64%}
+! RUN: %flang_fc1 %s -o "-" -emit-hlfir -cpp | FileCheck %s --check-prefixes=CHECK,%if flang-frontend-supports-f128 %{F128%} %else %{F64%}%if target=x86_64-unknown-linux{{.*}} %{,CHECK-X86-64%}
 
 subroutine sub1(a)
   integer :: a
diff --git a/flang/test/Lower/math-lowering/abs.f90 b/flang/test/Lower/math-lowering/abs.f90
index 9d3b8b92cfdd6..a7e00715a9e75 100644
--- a/flang/test/Lower/math-lowering/abs.f90
+++ b/flang/test/Lower/math-lowering/abs.f90
@@ -1,9 +1,9 @@
-! RUN: bbc -emit-fir %s -o - --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST-%if flang-supports-f128-math %{F128%} %else %{F64%} %s
-! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=fast %s -o - | FileCheck --check-prefixes=ALL,FAST,FAST-%if flang-supports-f128-math %{F128%} %else %{F64%} %s
-! RUN: bbc -emit-fir %s -o - --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED,RELAXED-%if flang-supports-f128-math %{F128%} %else %{F64%} %s
-! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=relaxed %s -o - | FileCheck --check-prefixes=ALL,RELAXED,RELAXED-%if flang-supports-f128-math %{F128%} %else %{F64%} %s
-! RUN: bbc -emit-fir %s -o - --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE,PRECISE-%if flang-supports-f128-math %{F128%} %else %{F64%} %s
-! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=precise %s -o - | FileCheck --check-prefixes=ALL,PRECISE,PRECISE-%if flang-supports-f128-math %{F128%} %else %{F64%} %s
+! RUN: bbc -emit-fir %s -o - --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST-%if flang-frontend-supports-f128 %{F128%} %else %{F64%} %s
+! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=fast %s -o - | FileCheck --check-prefixes=ALL,FAST,FAST-%if flang-frontend-supports-f128 %{F128%} %else %{F64%} %s
+! RUN: bbc -emit-fir %s -o - --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED,RELAXED-%if flang-frontend-supports-f128 %{F128%} %else %{F64%} %s
+! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=relaxed %s -o - | FileCheck --check-prefixes=ALL,RELAXED,RELAXED-%if flang-frontend-supports-f128 %{F128%} %else %{F64%} %s
+! RUN: bbc -emit-fir %s -o - --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE,PRECISE-%if flang-frontend-supports-f128 %{F128%} %else %{F64%} %s
+! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=precise %s -o - | FileCheck --check-prefixes=ALL,PRECISE,PRECISE-%if flang-frontend-supports-f128 %{F128%} %else %{F64%} %s
 
 function test_real4(x)
   real :: x, test_real4
diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py
index e7aa50e001b92..d3fabb57ae77c 100644
--- a/flang/test/lit.cfg.py
+++ b/flang/test/lit.cfg.py
@@ -265,11 +265,33 @@ def get_resource_module_intrinsic_dir(modfile):
 
 config.substitutions.append(("%openmp_flags", "-fopenmp"))
 
+def flang_supports_f128():
+    flang_exe = lit.util.which("flang", config.clang_tools_dir)
+
+    if not flang_exe:
+        return False
+
+    try:
+        testcode = b"real(16) :: x\nend"
+        flang_cmd = subprocess.run(
+            [flang_exe, "--target=" + config.target_triple, "-fsyntax-only", "-"],
+            input=testcode,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+        )
+    except OSError:
+        return False
+
+    if flang_cmd.returncode == 0:
+        return True
+
 # Add features and substitutions to test F128 math support.
 # %f128-lib substitution may be used to generate check prefixes
 # for LIT tests checking for F128 library support.
 if config.flang_runtime_f128_math_lib or config.have_ldbl_mant_dig_113:
     config.available_features.add("flang-supports-f128-math")
+if flang_supports_f128():
+    config.available_features.add("flang-frontend-supports-f128")
 if config.flang_runtime_f128_math_lib:
     config.available_features.add(
         "flang-f128-math-lib-" + config.flang_runtime_f128_math_lib
diff --git a/flang/test/lit.site.cfg.py.in b/flang/test/lit.site.cfg.py.in
index ca94ef4153390..2a9c6735e9f19 100644
--- a/flang/test/lit.site.cfg.py.in
+++ b/flang/test/lit.site.cfg.py.in
@@ -12,6 +12,7 @@ config.llvm_target_triple_env = "@LLVM_TARGET_TRIPLE_ENV@"
 config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
 config.errc_messages = "@LLVM_LIT_ERRC_MESSAGES@"
 config.flang_obj_root = path(r"@FLANG_BINARY_DIR@")
+config.clang_tools_dir = lit_config.substitute(path(r"@CURRENT_TOOLS_DIR@"))
 config.flang_tools_dir = lit_config.substitute("@FLANG_TOOLS_DIR@")
 config.flang_headers_dir = "@HEADER_BINARY_DIR@"
 config.flang_llvm_tools_dir = "@CMAKE_BINARY_DIR@/bin"
diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt
index 9bc0196b4262c..3f19fd31f1a65 100644
--- a/llvm/runtimes/CMakeLists.txt
+++ b/llvm/runtimes/CMakeLists.txt
@@ -525,6 +525,17 @@ function(runtime_register_target name)
   add_flang_mod_deps(runtimes-${name}-build ${${name}_extra_targets})
 endfunction()
 
+# Determine whether REAL(16) intrinsic modules should be built for the target.
+function(check_real16_support target result)
+  if(FLANG_RUNTIME_F128_MATH_LIB
+      OR HAVE_LDBL_MANT_DIG_113
+      OR target MATCHES "^(x86_64|aarch64)")
+    set(${result} TRUE PARENT_SCOPE)
+  else()
+    set(${result} FALSE PARENT_SCOPE)
+  endif()
+endfunction()
+
 # Check if we have any runtimes to build.
 if(runtimes)
   set(build_runtimes TRUE)
@@ -671,18 +682,29 @@ if(build_runtimes)
     if ("openmp" IN_LIST LLVM_ENABLE_RUNTIMES OR "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
       list(APPEND extra_args ENABLE_FORTRAN)
     endif()
-    # Ensure REAL(16) support in runtimes to be consistent with compiler
-    if(FLANG_RUNTIME_F128_MATH_LIB OR HAVE_LDBL_MANT_DIG_113)
-      list(APPEND extra_cmake_args "-DFORTRAN_SUPPORTS_REAL16=1")
+    # Ensure REAL(16) support in runtimes to be consistent with compiler.
+    # Keep intrinsic module generation consistent with targets for which
+    # the Flang frontend currently enables REAL(16) through backend support.
+    if(LLVM_RUNTIME_TARGETS)
+      foreach(name ${LLVM_RUNTIME_TARGETS})
+        if(name STREQUAL "default")
+          check_real16_support("${LLVM_TARGET_TRIPLE}" supports_real16)
+          set(default_fortran_cmake_args "-DFORTRAN_SUPPORTS_REAL16=${supports_real16}")
+        else()
+          check_real16_support("${name}" supports_real16)
+          set(${name}_fortran_cmake_args "-DFORTRAN_SUPPORTS_REAL16=${supports_real16}")
+        endif()
+      endforeach()
     else()
-      list(APPEND extra_cmake_args "-DFORTRAN_SUPPORTS_REAL16=0")
+      check_real16_support("${LLVM_TARGET_TRIPLE}" supports_real16)
+      set(default_fortran_cmake_args "-DFORTRAN_SUPPORTS_REAL16=${supports_real16}")
     endif()
   endif()
 
   if(NOT LLVM_RUNTIME_TARGETS)
     runtime_default_target(
       DEPENDS ${builtins_dep} ${extra_deps}
-      CMAKE_ARGS ${extra_cmake_args}
+      CMAKE_ARGS ${extra_cmake_args} ${default_fortran_cmake_args}
       PREFIXES ${prefixes}
       EXTRA_ARGS ${extra_args})
     set(test_targets check-runtimes)
@@ -690,7 +712,7 @@ if(build_runtimes)
     if("default" IN_LIST LLVM_RUNTIME_TARGETS)
       runtime_default_target(
         DEPENDS ${builtins_dep} ${extra_deps}
-        CMAKE_ARGS ${extra_cmake_args}
+        CMAKE_ARGS ${extra_cmake_args} ${default_fortran_cmake_args}
         PREFIXES ${prefixes}
         EXTRA_ARGS ${extra_args})
       list(REMOVE_ITEM LLVM_RUNTIME_TARGETS "default")
@@ -749,7 +771,7 @@ if(build_runtimes)
 
       runtime_register_target(${name}
         DEPENDS ${builtins_dep_name} ${extra_deps}
-        CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name} ${extra_cmake_args}
+        CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name} ${extra_cmake_args} ${${name}_fortran_cmake_args}
         EXTRA_ARGS TARGET_TRIPLE ${name} ${extra_args})
     endforeach()
 

>From 1c2d53a93229f784665b96a4166a6b89a99b1de7 Mon Sep 17 00:00:00 2001
From: s-watanabe314 <watanabe.shu-06 at fujitsu.com>
Date: Tue, 8 Sep 2026 18:20:27 +0900
Subject: [PATCH 2/2] fix python format

---
 flang/test/lit.cfg.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py
index d3fabb57ae77c..bd12c935ee1e0 100644
--- a/flang/test/lit.cfg.py
+++ b/flang/test/lit.cfg.py
@@ -265,6 +265,7 @@ def get_resource_module_intrinsic_dir(modfile):
 
 config.substitutions.append(("%openmp_flags", "-fopenmp"))
 
+
 def flang_supports_f128():
     flang_exe = lit.util.which("flang", config.clang_tools_dir)
 
@@ -285,6 +286,7 @@ def flang_supports_f128():
     if flang_cmd.returncode == 0:
         return True
 
+
 # Add features and substitutions to test F128 math support.
 # %f128-lib substitution may be used to generate check prefixes
 # for LIT tests checking for F128 library support.



More information about the flang-commits mailing list