https://github.com/ivanradanov updated 
https://github.com/llvm/llvm-project/pull/208098

>From ef030255af3f253a71a4bbed912d2917cff31b15 Mon Sep 17 00:00:00 2001
From: Ivan Radanov Ivanov <[email protected]>
Date: Tue, 7 Jul 2026 12:29:36 -0700
Subject: [PATCH 1/2] [flang][acc] Emit acc.on_device operation for
 acc_on_device call

It is important we recognize acc_on_device calls as they need to be
folded during compilation. Emitting this operation helps with the
recognition of the runtime call in the optimizer.
---
 .../Optimizer/Builder/CUDAIntrinsicCall.h     |  3 +-
 .../flang/Optimizer/Builder/IntrinsicCall.h   | 16 +++++-
 .../Optimizer/Builder/OpenACCIntrinsicCall.h  | 32 ++++++++++++
 .../Optimizer/Builder/PPCIntrinsicCall.h      |  3 +-
 flang/lib/Lower/ConvertCall.cpp               | 15 +++---
 flang/lib/Optimizer/Builder/CMakeLists.txt    |  1 +
 .../Optimizer/Builder/CUDAIntrinsicCall.cpp   | 20 ++------
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 42 ++++++++-------
 .../Builder/OpenACCIntrinsicCall.cpp          | 51 +++++++++++++++++++
 .../Optimizer/Builder/PPCIntrinsicCall.cpp    |  6 ++-
 flang/test/Lower/OpenACC/acc-on-device.f90    | 14 +++++
 11 files changed, 158 insertions(+), 45 deletions(-)
 create mode 100644 flang/include/flang/Optimizer/Builder/OpenACCIntrinsicCall.h
 create mode 100644 flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp
 create mode 100644 flang/test/Lower/OpenACC/acc-on-device.f90

diff --git a/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h 
b/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h
index 6167a876f7b62..2974d774b2d1a 100644
--- a/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h
@@ -108,7 +108,8 @@ struct CUDAIntrinsicLibrary : IntrinsicLibrary {
   mlir::Value genVoteSync(mlir::Type, llvm::ArrayRef<mlir::Value>);
 };
 
-const IntrinsicHandler *findCUDAIntrinsicHandler(llvm::StringRef name);
+const IntrinsicHandler *findCUDAIntrinsicHandler(llvm::StringRef name,
+                                                 bool isBindcCall = false);
 
 } // namespace fir
 
diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h 
b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index ca14b62c2ed48..53c975e4b3f66 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -796,7 +796,8 @@ mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder 
&builder,
 /// \p intrinsicName.
 std::optional<IntrinsicHandlerEntry>
 lookupIntrinsicHandler(fir::FirOpBuilder &, llvm::StringRef intrinsicName,
-                       std::optional<mlir::Type> resultType);
+                       std::optional<mlir::Type> resultType,
+                       bool isBindcCall = false);
 
 /// Generate a TODO error message for an as yet unimplemented intrinsic.
 void crashOnMissingIntrinsic(mlir::Location loc, llvm::StringRef name);
@@ -846,6 +847,19 @@ mlir::Value genDivC(fir::FirOpBuilder &builder, 
mlir::Location loc,
 mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType,
                    mlir::Value x, mlir::Value y);
 
+template <std::size_t N>
+static constexpr bool isSorted(const IntrinsicHandler (&array)[N]) {
+  // Replace by std::sorted when C++20 is default (will be constexpr).
+  const IntrinsicHandler *lastSeen{nullptr};
+  bool isSorted{true};
+  for (const auto &x : array) {
+    if (lastSeen)
+      isSorted &= std::string_view{lastSeen->name} < std::string_view{x.name};
+    lastSeen = &x;
+  }
+  return isSorted;
+}
+
 } // namespace fir
 
 #endif // FORTRAN_LOWER_INTRINSICCALL_H
diff --git a/flang/include/flang/Optimizer/Builder/OpenACCIntrinsicCall.h 
b/flang/include/flang/Optimizer/Builder/OpenACCIntrinsicCall.h
new file mode 100644
index 0000000000000..585c50bf12edc
--- /dev/null
+++ b/flang/include/flang/Optimizer/Builder/OpenACCIntrinsicCall.h
@@ -0,0 +1,32 @@
+//===-- Builder/OpenACCIntrinsicCall.h - OpenACC intrinsics -----*- C++ 
-*-===//
+//
+// Part of the LLVM 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_LOWER_OPENACCINTRINSICCALL_H
+#define FORTRAN_LOWER_OPENACCINTRINSICCALL_H
+
+#include "flang/Optimizer/Builder/IntrinsicCall.h"
+
+namespace fir {
+
+struct OpenACCIntrinsicLibrary : IntrinsicLibrary {
+
+  explicit OpenACCIntrinsicLibrary(fir::FirOpBuilder &builder,
+                                   mlir::Location loc)
+      : IntrinsicLibrary(builder, loc) {}
+  OpenACCIntrinsicLibrary() = delete;
+  OpenACCIntrinsicLibrary(const OpenACCIntrinsicLibrary &) = delete;
+
+  mlir::Value genACCOnDevice(mlir::Type, llvm::ArrayRef<mlir::Value>);
+};
+
+const IntrinsicHandler *findOpenACCIntrinsicHandler(llvm::StringRef name,
+                                                    bool isBindcCall = false);
+
+} // namespace fir
+
+#endif // FORTRAN_LOWER_OPENACCINTRINSICCALL_H
diff --git a/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h 
b/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h
index 5ae32f70a11a7..75d69c89636ea 100644
--- a/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h
@@ -320,7 +320,8 @@ struct PPCIntrinsicLibrary : IntrinsicLibrary {
                                 llvm::ArrayRef<fir::ExtendedValue> args);
 };
 
-const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name);
+const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name,
+                                                bool isBindcCall = false);
 
 std::pair<const MathOperation *, const MathOperation *>
 checkPPCMathOperationsRange(llvm::StringRef name);
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 4e862e8ece18a..92547cd982288 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -3135,16 +3135,17 @@ genProcedureRef(CallContext &callContext) {
   fir::FirOpBuilder &builder = callContext.getBuilder();
   if (auto *intrinsic = callContext.procRef.proc().GetSpecificIntrinsic())
     return genIntrinsicRef(intrinsic, callContext);
-  // Intercept non BIND(C) module procedure reference that have lowering
-  // handlers defined for there name. Otherwise, lower them as user
-  // procedure calls and expect the implementation to be part of
-  // runtime libraries with the proper name mangling.
-  if (Fortran::lower::isIntrinsicModuleProcRef(callContext.procRef) &&
-      !callContext.isBindcCall())
+  // Intercept module procedure references that have lowering handlers defined
+  // for their name. Otherwise, lower them as user procedure calls and expect
+  // the implementation to be part of runtime libraries with the proper name
+  // mangling.
+  if (Fortran::lower::isIntrinsicModuleProcRef(callContext.procRef)) {
+    const bool isBindcCall = callContext.isBindcCall();
     if (std::optional<fir::IntrinsicHandlerEntry> intrinsicEntry =
             fir::lookupIntrinsicHandler(builder, 
callContext.getProcedureName(),
-                                        callContext.resultType))
+                                        callContext.resultType, isBindcCall))
       return genIntrinsicRef(nullptr, *intrinsicEntry, callContext);
+  }
 
   if (callContext.isStatementFunctionCall())
     return genStmtFunctionRef(loc, callContext.converter, callContext.symMap,
diff --git a/flang/lib/Optimizer/Builder/CMakeLists.txt 
b/flang/lib/Optimizer/Builder/CMakeLists.txt
index c82ad8e9160f4..6a710977a5e02 100644
--- a/flang/lib/Optimizer/Builder/CMakeLists.txt
+++ b/flang/lib/Optimizer/Builder/CMakeLists.txt
@@ -14,6 +14,7 @@ add_flang_library(FIRBuilder
   LowLevelIntrinsics.cpp
   MIFCommon.cpp
   MutableBox.cpp
+  OpenACCIntrinsicCall.cpp
   PPCIntrinsicCall.cpp
   Runtime/Allocatable.cpp
   Runtime/ArrayConstructor.cpp
diff --git a/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp 
b/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp
index 0e0cb4cd5bc19..61c5e8131216e 100644
--- a/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp
@@ -640,22 +640,12 @@ static constexpr IntrinsicHandler cudaHandlers[]{
      {{}},
      /*isElemental=*/false},
 };
+static_assert(fir::isSorted(cudaHandlers) && "map must be sorted");
 
-template <std::size_t N>
-static constexpr bool isSorted(const IntrinsicHandler (&array)[N]) {
-  // Replace by std::sorted when C++20 is default (will be constexpr).
-  const IntrinsicHandler *lastSeen{nullptr};
-  bool isSorted{true};
-  for (const auto &x : array) {
-    if (lastSeen)
-      isSorted &= std::string_view{lastSeen->name} < std::string_view{x.name};
-    lastSeen = &x;
-  }
-  return isSorted;
-}
-static_assert(isSorted(cudaHandlers) && "map must be sorted");
-
-const IntrinsicHandler *findCUDAIntrinsicHandler(llvm::StringRef name) {
+const IntrinsicHandler *findCUDAIntrinsicHandler(llvm::StringRef name,
+                                                 bool isBindcCall) {
+  if (isBindcCall)
+    return nullptr;
   auto compare = [](const IntrinsicHandler &cudaHandler, llvm::StringRef name) 
{
     return name.compare(cudaHandler.name) > 0;
   };
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp 
b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index a2abcba0b81f2..bff561064bc70 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -22,6 +22,7 @@
 #include "flang/Optimizer/Builder/Complex.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/MutableBox.h"
+#include "flang/Optimizer/Builder/OpenACCIntrinsicCall.h"
 #include "flang/Optimizer/Builder/PPCIntrinsicCall.h"
 #include "flang/Optimizer/Builder/Runtime/Allocatable.h"
 #include "flang/Optimizer/Builder/Runtime/CUDA/Descriptor.h"
@@ -881,22 +882,12 @@ static constexpr IntrinsicHandler handlers[]{
        {"kind", asValue}}},
      /*isElemental=*/true},
 };
+static_assert(fir::isSorted(handlers) && "map must be sorted");
 
-template <std::size_t N>
-static constexpr bool isSorted(const IntrinsicHandler (&array)[N]) {
-  // Replace by std::sorted when C++20 is default (will be constexpr).
-  const IntrinsicHandler *lastSeen{nullptr};
-  bool isSorted{true};
-  for (const auto &x : array) {
-    if (lastSeen)
-      isSorted &= std::string_view{lastSeen->name} < std::string_view{x.name};
-    lastSeen = &x;
-  }
-  return isSorted;
-}
-static_assert(isSorted(handlers) && "map must be sorted");
-
-static const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name) {
+static const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name,
+                                                    bool isBindcCall = false) {
+  if (isBindcCall)
+    return nullptr;
   auto compare = [](const IntrinsicHandler &handler, llvm::StringRef name) {
     return name.compare(handler.name) > 0;
   };
@@ -1931,21 +1922,30 @@ lookupRuntimeGenerator(llvm::StringRef name, bool 
isPPCTarget) {
 std::optional<IntrinsicHandlerEntry>
 lookupIntrinsicHandler(fir::FirOpBuilder &builder,
                        llvm::StringRef intrinsicName,
-                       std::optional<mlir::Type> resultType) {
+                       std::optional<mlir::Type> resultType, bool isBindcCall) 
{
   llvm::StringRef name = genericName(intrinsicName);
-  if (const IntrinsicHandler *handler = findIntrinsicHandler(name))
+  if (const IntrinsicHandler *handler = findIntrinsicHandler(name, 
isBindcCall))
     return std::make_optional<IntrinsicHandlerEntry>(handler);
   bool isPPCTarget = fir::getTargetTriple(builder.getModule()).isPPC();
   // If targeting PowerPC, check PPC intrinsic handlers.
   if (isPPCTarget)
-    if (const IntrinsicHandler *ppcHandler = findPPCIntrinsicHandler(name))
+    if (const IntrinsicHandler *ppcHandler =
+            findPPCIntrinsicHandler(name, isBindcCall))
       return std::make_optional<IntrinsicHandlerEntry>(ppcHandler);
   // TODO: Look for CUDA intrinsic handlers only if CUDA is enabled.
-  if (const IntrinsicHandler *cudaHandler = findCUDAIntrinsicHandler(name))
+  if (const IntrinsicHandler *cudaHandler =
+          findCUDAIntrinsicHandler(name, isBindcCall))
     return std::make_optional<IntrinsicHandlerEntry>(cudaHandler);
+  // TODO: Look for OpenACC intrinsic handlers only if OpenACC is enabled.
+  if (const IntrinsicHandler *openaccHandler =
+          findOpenACCIntrinsicHandler(name, isBindcCall))
+    return std::make_optional<IntrinsicHandlerEntry>(openaccHandler);
   // Subroutines should have a handler.
   if (!resultType)
     return std::nullopt;
+  // BIND(C) intrinsic module procedures must not fall back to runtime lookup.
+  if (isBindcCall)
+    return std::nullopt;
   // Try the runtime if no special handler was defined for the
   // intrinsic being called. Maths runtime only has numerical elemental.
   if (auto runtimeGeneratorRange = lookupRuntimeGenerator(name, isPPCTarget))
@@ -9381,6 +9381,10 @@ getIntrinsicArgumentLowering(llvm::StringRef 
specificName) {
   if (const IntrinsicHandler *cudaHandler = findCUDAIntrinsicHandler(name))
     if (!cudaHandler->argLoweringRules.hasDefaultRules())
       return &cudaHandler->argLoweringRules;
+  if (const IntrinsicHandler *openaccHandler =
+          findOpenACCIntrinsicHandler(name))
+    if (!openaccHandler->argLoweringRules.hasDefaultRules())
+      return &openaccHandler->argLoweringRules;
   return nullptr;
 }
 
diff --git a/flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp 
b/flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp
new file mode 100644
index 0000000000000..684eda58652ed
--- /dev/null
+++ b/flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp
@@ -0,0 +1,51 @@
+//===-- OpenACCIntrinsicCall.cpp 
------------------------------------------===//
+//
+// Part of the LLVM 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/OpenACCIntrinsicCall.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+
+namespace fir {
+
+using OAI = OpenACCIntrinsicLibrary;
+
+static constexpr IntrinsicHandler openaccHandlers[]{
+    {"acc_on_device",
+     static_cast<OpenACCIntrinsicLibrary::ElementalGenerator>(
+         &OAI::genACCOnDevice),
+     {{{"devtype", asValue}}},
+     /*isElemental=*/false},
+};
+static_assert(fir::isSorted(openaccHandlers) && "map must be sorted");
+
+const IntrinsicHandler *findOpenACCIntrinsicHandler(llvm::StringRef name,
+                                                    bool isBindcCall) {
+  if (!isBindcCall)
+    return nullptr;
+  auto compare = [](const IntrinsicHandler &openaccHandler,
+                    llvm::StringRef name) {
+    return name.compare(openaccHandler.name) > 0;
+  };
+  auto result = llvm::lower_bound(openaccHandlers, name, compare);
+  return result != std::end(openaccHandlers) && result->name == name ? result
+                                                                     : nullptr;
+}
+
+mlir::Value
+OpenACCIntrinsicLibrary::genACCOnDevice(mlir::Type resultType,
+                                        llvm::ArrayRef<mlir::Value> args) {
+  assert(args.size() == 1);
+  mlir::Value deviceType = args[0];
+  if (deviceType.getType() != builder.getI32Type())
+    deviceType = builder.createConvert(loc, builder.getI32Type(), deviceType);
+  mlir::Value onDevice =
+      mlir::acc::OnDeviceOp::create(builder, loc, deviceType).getResult();
+  return builder.createConvert(loc, resultType, onDevice);
+}
+
+} // namespace fir
diff --git a/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp 
b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp
index c17ca6112218b..cf8c7ce4f8d4e 100644
--- a/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp
@@ -777,6 +777,7 @@ static constexpr IntrinsicHandler ppcHandlers[]{
      {{{"arg1", asValue}, {"arg2", asValue}, {"arg3", asAddr}}},
      /*isElemental=*/false},
 };
+static_assert(fir::isSorted(ppcHandlers) && "map must be sorted");
 
 static constexpr MathOperation ppcMathOperations[] = {
     // fcfi is just another name for fcfid, there is no llvm.ppc.fcfi.
@@ -932,7 +933,10 @@ static constexpr MathOperation ppcMathOperations[] = {
      genLibCall},
 };
 
-const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name) {
+const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name,
+                                                bool isBindcCall) {
+  if (isBindcCall)
+    return nullptr;
   auto compare = [](const IntrinsicHandler &ppcHandler, llvm::StringRef name) {
     return name.compare(ppcHandler.name) > 0;
   };
diff --git a/flang/test/Lower/OpenACC/acc-on-device.f90 
b/flang/test/Lower/OpenACC/acc-on-device.f90
new file mode 100644
index 0000000000000..b41959496d0af
--- /dev/null
+++ b/flang/test/Lower/OpenACC/acc-on-device.f90
@@ -0,0 +1,14 @@
+! This test checks lowering of the OpenACC acc_on_device intrinsic.
+
+! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s
+
+subroutine acc_on_device_test
+  use openacc
+  implicit none
+  logical :: on_host
+
+  on_host = acc_on_device(acc_device_host)
+!CHECK: [[HOST:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
+!CHECK: acc.on_device [[HOST]] : i32 -> i1
+!CHECK-NOT: fir.call @acc_on_device
+end subroutine acc_on_device_test

>From 5824ebcf030b00846e56c244abc60d9589e33c02 Mon Sep 17 00:00:00 2001
From: Ivan Radanov Ivanov <[email protected]>
Date: Wed, 8 Jul 2026 07:56:12 -0700
Subject: [PATCH 2/2] simplify builder

---
 flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp 
b/flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp
index 684eda58652ed..7e023b0ae419a 100644
--- a/flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp
@@ -40,11 +40,8 @@ mlir::Value
 OpenACCIntrinsicLibrary::genACCOnDevice(mlir::Type resultType,
                                         llvm::ArrayRef<mlir::Value> args) {
   assert(args.size() == 1);
-  mlir::Value deviceType = args[0];
-  if (deviceType.getType() != builder.getI32Type())
-    deviceType = builder.createConvert(loc, builder.getI32Type(), deviceType);
   mlir::Value onDevice =
-      mlir::acc::OnDeviceOp::create(builder, loc, deviceType).getResult();
+      mlir::acc::OnDeviceOp::create(builder, loc, args[0]).getResult();
   return builder.createConvert(loc, resultType, onDevice);
 }
 

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to