https://github.com/ivanradanov updated https://github.com/llvm/llvm-project/pull/208098
>From 74459791fdc38bbc5f51e9be358e5c2c6b2275c1 Mon Sep 17 00:00:00 2001 From: Ivan Radanov Ivanov <[email protected]> Date: Wed, 8 Jul 2026 08:17:23 -0700 Subject: [PATCH 1/3] test --- mlir/test/Dialect/OpenACC/ops.mlir | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mlir/test/Dialect/OpenACC/ops.mlir b/mlir/test/Dialect/OpenACC/ops.mlir index c696cefb94600..a2775390bf12b 100644 --- a/mlir/test/Dialect/OpenACC/ops.mlir +++ b/mlir/test/Dialect/OpenACC/ops.mlir @@ -1188,9 +1188,9 @@ acc.shutdown device_num(%idxValue : index) if(%ifCond) // ----- %devTypeInt = arith.constant 2 : i32 -%onHostInt = acc.on_device %devType : i32 -> i1 +%onHostInt = acc.on_device %devTypeInt : i32 -> i1 %devTypeIndex = arith.constant 2 : index -%onHostIndex = acc.on_device %devType : index -> i1 +%onHostIndex = acc.on_device %devTypeIndex : index -> i1 // CHECK: [[DEVTYPEINT:%.*]] = arith.constant 2 : i32 // CHECK: %[[ONHOSTINT:.*]] = acc.on_device [[DEVTYPEINT]] : i32 -> i1 >From fcdae160d2a6bb931501cb21fe460d4bc60c1c92 Mon Sep 17 00:00:00 2001 From: Ivan Radanov Ivanov <[email protected]> Date: Tue, 7 Jul 2026 12:29:36 -0700 Subject: [PATCH 2/3] [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 ++- 10 files changed, 144 insertions(+), 45 deletions(-) create mode 100644 flang/include/flang/Optimizer/Builder/OpenACCIntrinsicCall.h create mode 100644 flang/lib/Optimizer/Builder/OpenACCIntrinsicCall.cpp 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; }; >From cf02cbc9a9f98d7339f17ce8b54d7c6845c096e2 Mon Sep 17 00:00:00 2001 From: Ivan Radanov Ivanov <[email protected]> Date: Wed, 8 Jul 2026 07:56:12 -0700 Subject: [PATCH 3/3] 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
