[flang-commits] [flang] [flang] Set LLVM specific attributes to fir.call's of Fortran runtime. (PR #128093)
Tom Eccles via flang-commits
flang-commits at lists.llvm.org
Mon Feb 24 06:14:40 PST 2025
================
@@ -0,0 +1,252 @@
+//===- SetRuntimeCallAttributes.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
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+/// \file
+/// SetRuntimeCallAttributesPass looks for fir.call operations
+/// that are calling into Fortran runtime, and tries to set different
+/// attributes on them to enable more optimizations in LLVM backend
+/// (granted that they are preserved all the way to LLVM IR).
+/// This pass is currently only attaching fir.call wide atttributes,
+/// such as ones corresponding to llvm.memory, nosync, nocallbac, etc.
+/// It is not designed to attach attributes to the arguments and the results
+/// of a call.
+//===----------------------------------------------------------------------===//
+#include "flang/Common/static-multimap-view.h"
+#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIROpsSupport.h"
+#include "flang/Optimizer/Support/InternalNames.h"
+#include "flang/Optimizer/Transforms/Passes.h"
+#include "flang/Runtime/io-api-consts.h"
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
+
+namespace fir {
+#define GEN_PASS_DEF_SETRUNTIMECALLATTRIBUTES
+#include "flang/Optimizer/Transforms/Passes.h.inc"
+} // namespace fir
+
+#define DEBUG_TYPE "set-runtime-call-attrs"
+
+using namespace Fortran::runtime;
+using namespace Fortran::runtime::io;
+
+#define mkIOKey(X) FirmkKey(IONAME(X))
+#define mkRTKey(X) FirmkKey(RTNAME(X))
+
+// Return LLVM dialect MemoryEffectsAttr for the given Fortran runtime call.
+// This function is computing a generic value of this attribute
+// by analyzing the arguments and their types.
+// It tries to figure out if an "indirect" memory access is possible
+// during this call. If it is not possible, then the memory effects
+// are:
+// * other = NoModRef
+// * argMem = ModRef
+// * inaccessibleMem = ModRef
+//
+// Otherwise, it returns an empty attribute meaning ModRef for all kinds
+// of memory.
+//
+// The attribute deduction is conservative in a sense that it applies
+// to most of the runtime calls, but it may still be incorrect for some
+// runtime calls.
+static mlir::LLVM::MemoryEffectsAttr getGenericMemoryAttr(fir::CallOp callOp) {
+ bool maybeIndirectAccess = false;
+ for (auto arg : callOp.getArgOperands()) {
+ mlir::Type argType = arg.getType();
+ if (mlir::isa<fir::BaseBoxType>(argType)) {
+ // If it is a null box, then this particular call
+ // cannot access memory indirectly through the box's
+ // base_addr.
+ auto def = arg.getDefiningOp();
+ if (!def || !mlir::isa<fir::ZeroOp>(def)) {
+ maybeIndirectAccess = true;
+ break;
+ }
+ }
+ if (auto refType = mlir::dyn_cast<fir::ReferenceType>(argType)) {
+ if (!fir::isa_trivial(refType.getElementType())) {
+ maybeIndirectAccess = true;
+ break;
+ }
+ }
+ if (auto ptrType = mlir::dyn_cast<mlir::LLVM::LLVMPointerType>(argType)) {
+ maybeIndirectAccess = true;
+ break;
+ }
+ }
+ if (!maybeIndirectAccess) {
+ return mlir::LLVM::MemoryEffectsAttr::get(
+ callOp->getContext(),
+ {/*other=*/mlir::LLVM::ModRefInfo::NoModRef,
+ /*argMem=*/mlir::LLVM::ModRefInfo::ModRef,
+ /*inaccessibleMem=*/mlir::LLVM::ModRefInfo::ModRef});
+ }
+
+ return {};
+}
+
+namespace {
+class SetRuntimeCallAttributesPass
+ : public fir::impl::SetRuntimeCallAttributesBase<
+ SetRuntimeCallAttributesPass> {
+public:
+ void runOnOperation() override;
+};
+
+// A helper to match a type against a list of types.
+template <typename T, typename... Ts>
+constexpr bool IsAny = std::disjunction_v<std::is_same<T, Ts>...>;
+} // end anonymous namespace
+
+// MemoryAttrDesc type provides get() method for computing
+// mlir::LLVM::MemoryEffectsAttr for the given Fortran runtime call.
+// If needed, add specializations for particular runtime calls.
+namespace {
+// Default implementation just uses getGenericMemoryAttr().
+// Note that it may be incorrect for some runtime calls.
+template <typename KEY, typename Enable = void>
+struct MemoryAttrDesc {
+ static mlir::LLVM::MemoryEffectsAttr get(fir::CallOp callOp) {
+ return getGenericMemoryAttr(callOp);
+ }
+};
+} // end anonymous namespace
+
+// NosyncAttrDesc type provides get() method for computing
+// LLVM nosync attribute for the given call.
+namespace {
+// Default implementation always returns LLVM nosync.
+// This should be true for the majority of the Fortran runtime calls.
+template <typename KEY, typename Enable = void>
+struct NosyncAttrDesc {
+ static std::optional<mlir::NamedAttribute> get(fir::CallOp callOp) {
+ // TODO: replace llvm.nosync with an LLVM dialect callback.
+ return mlir::NamedAttribute("llvm.nosync",
+ mlir::UnitAttr::get(callOp->getContext()));
+ }
+};
+} // end anonymous namespace
+
+// NocallbackAttrDesc type provides get() method for computing
+// LLVM nocallback attribute for the given call.
+namespace {
+// Default implementation always returns LLVM nocallback.
+// It must be specialized for Fortran runtime functions that may call
+// user functions during their execution (e.g. defined IO, assignment).
+template <typename KEY, typename Enable = void>
+struct NocallbackAttrDesc {
+ static std::optional<mlir::NamedAttribute> get(fir::CallOp callOp) {
+ // TODO: replace llvm.nocallback with an LLVM dialect callback.
+ return mlir::NamedAttribute("llvm.nocallback",
+ mlir::UnitAttr::get(callOp->getContext()));
+ }
+};
+
+// Derived types IO may call back into a Fortran module.
----------------
tblah wrote:
Couldn't derived type allocation and assignment also call back in the module?
Edit: It looks like this is only enabled for I/O functions for now?
https://github.com/llvm/llvm-project/pull/128093
More information about the flang-commits
mailing list