Skip to content

[flang] Set LLVM specific attributes to fir.call's of Fortran runtime. #128093

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

Merged
merged 3 commits into from
Feb 24, 2025

Conversation

vzakhari
Copy link
Contributor

This change is inspired by a case in facerec benchmark, where performance
of scalar code may improve by about 6%@aarch64 due to getting rid of redundant
loads from Fortran descriptors. These descriptors are corresponding
to subroutine local ALLOCATABLE, SAVE variables. The scalar loop nest
in LocalMove subroutine contains call to Fortran runtime IO functions,
and LLVM globals-aa analysis cannot prove that these calls do not modify
the globalized descriptors with internal linkage.

This patch sets and propagates llvm.memory_effects attribute for fir.call
operations calling Fortran runtime functions. In particular, it tries
to set the Other memory effect to NoModRef. The Other memory effect
includes accesses to globals and captured pointers, so we cannot set
it for functions taking Fortran descriptors with one exception
for calls where the Fortran descriptor arguments are all null.

As long as different calls to the same Fortran runtime function may have
different attributes, I decided to attach the attributes to the calls
rather than functions. Moreover, attaching the attributes to func.func
will require propagating these attributes to llvm.func, which is not
happening right now.

In addition to llvm.memory_effects, the new pass sets llvm.nosync
and llvm.nocallback attributes that may also help LLVM alias analysis
(e.g. see #127707). These attributes are ignored currently.
I will support them in LLVM IR dialect in a separate patch.

I also added another pass for developers to be able to print
declarations/calls of all Fortran runtime functions that are recognized
by the attributes setting pass. It should help with maintenance
of the LIT tests.

This change is inspired by a case in facerec benchmark, where performance
of scalar code may improve by about 6%@aarch64 due to getting rid of redundant
loads from Fortran descriptors. These descriptors are corresponding
to subroutine local ALLOCATABLE, SAVE variables. The scalar loop nest
in LocalMove subroutine contains call to Fortran runtime IO functions,
and LLVM globals-aa analysis cannot prove that these calls do not modify
the globalized descriptors with internal linkage.

This patch sets and propagates llvm.memory_effects attribute for fir.call
operations calling Fortran runtime functions. In particular, it tries
to set the Other memory effect to NoModRef. The Other memory effect
includes accesses to globals and captured pointers, so we cannot set
it for functions taking Fortran descriptors with one exception
for calls where the Fortran descriptor arguments are all null.

As long as different calls to the same Fortran runtime function may have
different attributes, I decided to attach the attributes to the calls
rather than functions. Moreover, attaching the attributes to func.func
will require propagating these attributes to llvm.func, which is not
happening right now.

In addition to llvm.memory_effects, the new pass sets llvm.nosync
and llvm.nocallback attributes that may also help LLVM alias analysis
(e.g. see llvm#127707). These attributes are ignored currently.
I will support them in LLVM IR dialect in a separate patch.

I also added another pass for developers to be able to print
declarations/calls of all Fortran runtime functions that are recognized
by the attributes setting pass. It should help with maintenance
of the LIT tests.
@llvmbot llvmbot added flang:driver flang Flang issues not falling into any other category flang:fir-hlfir flang:codegen labels Feb 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 21, 2025

@llvm/pr-subscribers-flang-driver

Author: Slava Zakharin (vzakhari)

Changes

This change is inspired by a case in facerec benchmark, where performance
of scalar code may improve by about 6%@aarch64 due to getting rid of redundant
loads from Fortran descriptors. These descriptors are corresponding
to subroutine local ALLOCATABLE, SAVE variables. The scalar loop nest
in LocalMove subroutine contains call to Fortran runtime IO functions,
and LLVM globals-aa analysis cannot prove that these calls do not modify
the globalized descriptors with internal linkage.

This patch sets and propagates llvm.memory_effects attribute for fir.call
operations calling Fortran runtime functions. In particular, it tries
to set the Other memory effect to NoModRef. The Other memory effect
includes accesses to globals and captured pointers, so we cannot set
it for functions taking Fortran descriptors with one exception
for calls where the Fortran descriptor arguments are all null.

As long as different calls to the same Fortran runtime function may have
different attributes, I decided to attach the attributes to the calls
rather than functions. Moreover, attaching the attributes to func.func
will require propagating these attributes to llvm.func, which is not
happening right now.

In addition to llvm.memory_effects, the new pass sets llvm.nosync
and llvm.nocallback attributes that may also help LLVM alias analysis
(e.g. see #127707). These attributes are ignored currently.
I will support them in LLVM IR dialect in a separate patch.

I also added another pass for developers to be able to print
declarations/calls of all Fortran runtime functions that are recognized
by the attributes setting pass. It should help with maintenance
of the LIT tests.


Patch is 183.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128093.diff

19 Files Affected:

  • (modified) flang/include/flang/Optimizer/Builder/FIRBuilder.h (+9)
  • (modified) flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h (+38-4)
  • (modified) flang/include/flang/Optimizer/Dialect/FIRDialect.td (+12)
  • (modified) flang/include/flang/Optimizer/Transforms/Passes.h (+2)
  • (modified) flang/include/flang/Optimizer/Transforms/Passes.td (+33)
  • (added) flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc (+111)
  • (modified) flang/lib/Lower/IO.cpp (+147-149)
  • (modified) flang/lib/Optimizer/Builder/FIRBuilder.cpp (+12)
  • (modified) flang/lib/Optimizer/CodeGen/CodeGen.cpp (+10)
  • (modified) flang/lib/Optimizer/Passes/Pipelines.cpp (+3)
  • (modified) flang/lib/Optimizer/Transforms/CMakeLists.txt (+2)
  • (added) flang/lib/Optimizer/Transforms/GenRuntimeCallsForTest.cpp (+106)
  • (added) flang/lib/Optimizer/Transforms/SetRuntimeCallAttributes.cpp (+252)
  • (modified) flang/test/Driver/mlir-pass-pipeline.f90 (+2)
  • (modified) flang/test/Fir/basic-program.fir (+2)
  • (modified) flang/test/Lower/array-temp.f90 (+9-9)
  • (added) flang/test/Transforms/set-runtime-call-attributes.fir (+1039)
  • (added) flang/test/Transforms/verify-known-runtime-functions.fir (+101)
  • (added) flang/test/Utils/generate-checks-for-runtime-funcs.py (+79)
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index 93eca78424775..1675c15363868 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -385,6 +385,15 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
                                            mlir::FunctionType ty,
                                            mlir::SymbolTable *);
 
+  /// Returns a named function for a Fortran runtime API, creating
+  /// it, if it does not exist in the module yet.
+  /// If \p isIO is set to true, then the function corresponds
+  /// to one of Fortran runtime IO APIs.
+  mlir::func::FuncOp createRuntimeFunction(mlir::Location loc,
+                                           llvm::StringRef name,
+                                           mlir::FunctionType ty,
+                                           bool isIO = false);
+
   /// Cast the input value to IndexType.
   mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
     return createConvert(loc, getIndexType(), val);
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
index 1ffc354d6b80f..5158abaa31ed1 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
@@ -21,6 +21,7 @@
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Runtime/io-api-consts.h"
 #include "flang/Runtime/reduce.h"
 #include "flang/Support/Fortran.h"
 #include "mlir/IR/BuiltinTypes.h"
@@ -586,6 +587,33 @@ constexpr TypeBuilderFunc getModel<void>() {
   };
 }
 
+// Define additional runtime type models specific to IO.
+template <>
+constexpr TypeBuilderFunc getModel<Fortran::runtime::io::IoStatementState *>() {
+  return getModel<char *>();
+}
+template <>
+constexpr TypeBuilderFunc getModel<Fortran::runtime::io::Iostat>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return mlir::IntegerType::get(context,
+                                  8 * sizeof(Fortran::runtime::io::Iostat));
+  };
+}
+template <>
+constexpr TypeBuilderFunc
+getModel<const Fortran::runtime::io::NamelistGroup &>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return fir::ReferenceType::get(mlir::TupleType::get(context));
+  };
+}
+template <>
+constexpr TypeBuilderFunc
+getModel<const Fortran::runtime::io::NonTbpDefinedIoTable *>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return fir::ReferenceType::get(mlir::TupleType::get(context));
+  };
+}
+
 REDUCTION_REF_OPERATION_MODEL(std::int8_t)
 REDUCTION_VALUE_OPERATION_MODEL(std::int8_t)
 REDUCTION_REF_OPERATION_MODEL(std::int16_t)
@@ -778,16 +806,22 @@ struct RuntimeTableEntry<RuntimeTableKey<KT>, RuntimeIdentifier<Cs...>> {
 /// argument is intended to be of the form: <mkRTKey(runtime function name)>.
 template <typename RuntimeEntry>
 static mlir::func::FuncOp getRuntimeFunc(mlir::Location loc,
-                                         fir::FirOpBuilder &builder) {
+                                         fir::FirOpBuilder &builder,
+                                         bool isIO = false) {
   using namespace Fortran::runtime;
   auto name = RuntimeEntry::name;
   auto func = builder.getNamedFunction(name);
   if (func)
     return func;
   auto funTy = RuntimeEntry::getTypeModel()(builder.getContext());
-  func = builder.createFunction(loc, name, funTy);
-  func->setAttr(FIROpsDialect::getFirRuntimeAttrName(), builder.getUnitAttr());
-  return func;
+  return builder.createRuntimeFunction(loc, name, funTy, isIO);
+}
+
+/// Get (or generate) the MLIR FuncOp for a given IO runtime function.
+template <typename E>
+static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
+                                           fir::FirOpBuilder &builder) {
+  return getRuntimeFunc<E>(loc, builder, /*isIO=*/true);
 }
 
 namespace helper {
diff --git a/flang/include/flang/Optimizer/Dialect/FIRDialect.td b/flang/include/flang/Optimizer/Dialect/FIRDialect.td
index 0dfb3eda585ce..b05f4e731bc73 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRDialect.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRDialect.td
@@ -56,6 +56,18 @@ def FIROpsDialect : Dialect {
     static constexpr llvm::StringRef getFirRuntimeAttrName() {
       return "fir.runtime";
     }
+    // Return string name of fir.memory attributes.
+    // It is attached to fir.call operations to convey
+    // llvm.memory attributes to LLVM IR.
+    // Its value is intended to be mlir::LLVM::MemoryEffectsAttr.
+    // TODO: we should probably make it an inherent attribute
+    // of fir.call, though, it is supposed to be a short-lived
+    // attribute that appears right before CodeGen and only
+    // meaningful for LLVM, so it is unclear if embedding
+    // it into fir.call makes sense.
+    static constexpr llvm::StringRef getFirCallMemoryAttrName() {
+      return "fir.llvm_memory";
+    }
   }];
 }
 
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h
index 10e1c999d4533..afbbeb55632f1 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.h
+++ b/flang/include/flang/Optimizer/Transforms/Passes.h
@@ -60,6 +60,8 @@ namespace fir {
 #define GEN_PASS_DECL_FUNCTIONATTR
 #define GEN_PASS_DECL_CONSTANTARGUMENTGLOBALISATIONOPT
 #define GEN_PASS_DECL_COMPILERGENERATEDNAMESCONVERSION
+#define GEN_PASS_DECL_SETRUNTIMECALLATTRIBUTES
+#define GEN_PASS_DECL_GENRUNTIMECALLSFORTEST
 
 #include "flang/Optimizer/Transforms/Passes.h.inc"
 
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index 0b6e0119c16c3..64341b42bd1e4 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -453,4 +453,37 @@ def CUFGPUToLLVMConversion : Pass<"cuf-gpu-convert-to-llvm", "mlir::ModuleOp"> {
   ];
 }
 
+def SetRuntimeCallAttributes
+    : Pass<"set-runtime-call-attrs", "mlir::func::FuncOp"> {
+  let summary = "Set Fortran runtime fir.call attributes targeting LLVM IR";
+  let description = [{
+    This pass sets different attributes for Fortran runtime calls
+    that enable more optimizations in LLVM backend.
+    For the time being, the meaning of these attributes is not
+    strictly defined for HLFIR/FIR.
+  }];
+  let dependentDialects = ["fir::FIROpsDialect", "mlir::LLVM::LLVMDialect"];
+}
+
+def GenRuntimeCallsForTest
+    : Pass<"gen-runtime-calls-for-test", "mlir::ModuleOp"> {
+  let summary =
+      "Print FIR containing declarations/calls of Fortran runtime functions";
+  let description = [{
+    This pass is only for developers to be able to print FIR
+    that declares and calls Fortran runtime functions.
+    It helps producing/updating tests for passes that modify
+    the func/call operations based on some knowledge of
+    Fortran runtime.
+  }];
+  let options =
+      [Option<"doGenerateCalls", "do-generate-calls", "bool",
+              /*default=*/"false",
+              "Generate thin wrapper functions that call Fortran runtime "
+              "functions. If it is set to false, then only the declarations "
+              "are generated.">,
+  ];
+  let dependentDialects = ["fir::FIROpsDialect", "mlir::func::FuncDialect"];
+}
+
 #endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES
diff --git a/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc b/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc
new file mode 100644
index 0000000000000..cb4bf4ecf559d
--- /dev/null
+++ b/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc
@@ -0,0 +1,111 @@
+//===-- Optimizer/Transforms/RuntimeFunctions.inc ---------------*- 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 KNOWN_IO_FUNC
+#error "Define KNOWN_IO_FUNC before including this file"
+#endif
+#ifndef KNOWN_RUNTIME_FUNC
+#error "Define KNOWN_RUNTIME_FUNC before including this file"
+#endif
+
+// Fortran runtime functions that SetRuntimeCallAttributesPass recognizes.
+// WARNING: if you add a function entry here, you must make sure
+// that the attribute computation callbacks that end up being
+// used are correct for this function. If needed, add
+// specializations for the types that provide attribute
+// computation callbacks in SetRuntimeCallAttributesPass.
+
+// clang-format off
+KNOWN_IO_FUNC(BeginBackspace),
+KNOWN_IO_FUNC(BeginClose),
+KNOWN_IO_FUNC(BeginEndfile),
+KNOWN_IO_FUNC(BeginExternalFormattedInput),
+KNOWN_IO_FUNC(BeginExternalFormattedOutput),
+KNOWN_IO_FUNC(BeginExternalListInput),
+KNOWN_IO_FUNC(BeginExternalListOutput),
+KNOWN_IO_FUNC(BeginFlush),
+KNOWN_IO_FUNC(BeginInquireFile),
+KNOWN_IO_FUNC(BeginInquireIoLength),
+KNOWN_IO_FUNC(BeginInquireUnit),
+KNOWN_IO_FUNC(BeginInternalArrayFormattedInput),
+KNOWN_IO_FUNC(BeginInternalArrayFormattedOutput),
+KNOWN_IO_FUNC(BeginInternalArrayListInput),
+KNOWN_IO_FUNC(BeginInternalArrayListOutput),
+KNOWN_IO_FUNC(BeginInternalFormattedInput),
+KNOWN_IO_FUNC(BeginInternalFormattedOutput),
+KNOWN_IO_FUNC(BeginInternalListInput),
+KNOWN_IO_FUNC(BeginInternalListOutput),
+KNOWN_IO_FUNC(BeginOpenNewUnit),
+KNOWN_IO_FUNC(BeginOpenUnit),
+KNOWN_IO_FUNC(BeginRewind),
+KNOWN_IO_FUNC(BeginUnformattedInput),
+KNOWN_IO_FUNC(BeginUnformattedOutput),
+KNOWN_IO_FUNC(BeginWait),
+KNOWN_IO_FUNC(BeginWaitAll),
+KNOWN_IO_FUNC(CheckUnitNumberInRange128),
+KNOWN_IO_FUNC(CheckUnitNumberInRange64),
+KNOWN_IO_FUNC(EnableHandlers),
+KNOWN_IO_FUNC(EndIoStatement),
+KNOWN_IO_FUNC(GetAsynchronousId),
+KNOWN_IO_FUNC(GetIoLength),
+KNOWN_IO_FUNC(GetIoMsg),
+KNOWN_IO_FUNC(GetNewUnit),
+KNOWN_IO_FUNC(GetSize),
+KNOWN_IO_FUNC(InputAscii),
+KNOWN_IO_FUNC(InputComplex32),
+KNOWN_IO_FUNC(InputComplex64),
+KNOWN_IO_FUNC(InputDerivedType),
+KNOWN_IO_FUNC(InputDescriptor),
+KNOWN_IO_FUNC(InputInteger),
+KNOWN_IO_FUNC(InputLogical),
+KNOWN_IO_FUNC(InputNamelist),
+KNOWN_IO_FUNC(InputReal32),
+KNOWN_IO_FUNC(InputReal64),
+KNOWN_IO_FUNC(InquireCharacter),
+KNOWN_IO_FUNC(InquireInteger64),
+KNOWN_IO_FUNC(InquireLogical),
+KNOWN_IO_FUNC(InquirePendingId),
+KNOWN_IO_FUNC(OutputAscii),
+KNOWN_IO_FUNC(OutputComplex32),
+KNOWN_IO_FUNC(OutputComplex64),
+KNOWN_IO_FUNC(OutputDerivedType),
+KNOWN_IO_FUNC(OutputDescriptor),
+KNOWN_IO_FUNC(OutputInteger128),
+KNOWN_IO_FUNC(OutputInteger16),
+KNOWN_IO_FUNC(OutputInteger32),
+KNOWN_IO_FUNC(OutputInteger64),
+KNOWN_IO_FUNC(OutputInteger8),
+KNOWN_IO_FUNC(OutputLogical),
+KNOWN_IO_FUNC(OutputNamelist),
+KNOWN_IO_FUNC(OutputReal32),
+KNOWN_IO_FUNC(OutputReal64),
+KNOWN_IO_FUNC(SetAccess),
+KNOWN_IO_FUNC(SetAction),
+KNOWN_IO_FUNC(SetAdvance),
+KNOWN_IO_FUNC(SetAsynchronous),
+KNOWN_IO_FUNC(SetBlank),
+KNOWN_IO_FUNC(SetCarriagecontrol),
+KNOWN_IO_FUNC(SetConvert),
+KNOWN_IO_FUNC(SetDecimal),
+KNOWN_IO_FUNC(SetDelim),
+KNOWN_IO_FUNC(SetEncoding),
+KNOWN_IO_FUNC(SetFile),
+KNOWN_IO_FUNC(SetForm),
+KNOWN_IO_FUNC(SetPad),
+KNOWN_IO_FUNC(SetPos),
+KNOWN_IO_FUNC(SetPosition),
+KNOWN_IO_FUNC(SetRec),
+KNOWN_IO_FUNC(SetRecl),
+KNOWN_IO_FUNC(SetRound),
+KNOWN_IO_FUNC(SetSign),
+KNOWN_IO_FUNC(SetStatus)
+
+// clang-format on
+
+#undef KNOWN_IO_FUNC
+#undef KNOWN_RUNTIME_FUNC
diff --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index 75453721d91a2..35068f0519cbd 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -43,35 +43,6 @@
 
 #define DEBUG_TYPE "flang-lower-io"
 
-// Define additional runtime type models specific to IO.
-namespace fir::runtime {
-template <>
-constexpr TypeBuilderFunc getModel<Fortran::runtime::io::IoStatementState *>() {
-  return getModel<char *>();
-}
-template <>
-constexpr TypeBuilderFunc getModel<Fortran::runtime::io::Iostat>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return mlir::IntegerType::get(context,
-                                  8 * sizeof(Fortran::runtime::io::Iostat));
-  };
-}
-template <>
-constexpr TypeBuilderFunc
-getModel<const Fortran::runtime::io::NamelistGroup &>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return fir::ReferenceType::get(mlir::TupleType::get(context));
-  };
-}
-template <>
-constexpr TypeBuilderFunc
-getModel<const Fortran::runtime::io::NonTbpDefinedIoTable *>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return fir::ReferenceType::get(mlir::TupleType::get(context));
-  };
-}
-} // namespace fir::runtime
-
 using namespace Fortran::runtime::io;
 
 #define mkIOKey(X) FirmkKey(IONAME(X))
@@ -172,22 +143,6 @@ inline int64_t getLength(mlir::Type argTy) {
   return mlir::cast<fir::SequenceType>(argTy).getShape()[0];
 }
 
-/// Get (or generate) the MLIR FuncOp for a given IO runtime function.
-template <typename E>
-static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
-                                           fir::FirOpBuilder &builder) {
-  llvm::StringRef name = getName<E>();
-  mlir::func::FuncOp func = builder.getNamedFunction(name);
-  if (func)
-    return func;
-  auto funTy = getTypeModel<E>()(builder.getContext());
-  func = builder.createFunction(loc, name, funTy);
-  func->setAttr(fir::FIROpsDialect::getFirRuntimeAttrName(),
-                builder.getUnitAttr());
-  func->setAttr("fir.io", builder.getUnitAttr());
-  return func;
-}
-
 /// Generate calls to end an IO statement. Return the IOSTAT value, if any.
 /// It is the caller's responsibility to generate branches on that value.
 static mlir::Value genEndIO(Fortran::lower::AbstractConverter &converter,
@@ -197,7 +152,7 @@ static mlir::Value genEndIO(Fortran::lower::AbstractConverter &converter,
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
   if (csi.ioMsg) {
     mlir::func::FuncOp getIoMsg =
-        getIORuntimeFunc<mkIOKey(GetIoMsg)>(loc, builder);
+        fir::runtime::getIORuntimeFunc<mkIOKey(GetIoMsg)>(loc, builder);
     builder.create<fir::CallOp>(
         loc, getIoMsg,
         mlir::ValueRange{
@@ -208,7 +163,7 @@ static mlir::Value genEndIO(Fortran::lower::AbstractConverter &converter,
                                   fir::getLen(*csi.ioMsg))});
   }
   mlir::func::FuncOp endIoStatement =
-      getIORuntimeFunc<mkIOKey(EndIoStatement)>(loc, builder);
+      fir::runtime::getIORuntimeFunc<mkIOKey(EndIoStatement)>(loc, builder);
   auto call = builder.create<fir::CallOp>(loc, endIoStatement,
                                           mlir::ValueRange{cookie});
   mlir::Value iostat = call.getResult(0);
@@ -659,45 +614,57 @@ static mlir::func::FuncOp getOutputFunc(mlir::Location loc,
                                         fir::FirOpBuilder &builder,
                                         mlir::Type type, bool isFormatted) {
   if (mlir::isa<fir::RecordType>(fir::unwrapPassByRefType(type)))
-    return getIORuntimeFunc<mkIOKey(OutputDerivedType)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(OutputDerivedType)>(loc,
+                                                                      builder);
   if (!isFormatted)
-    return getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc,
+                                                                     builder);
   if (auto ty = mlir::dyn_cast<mlir::IntegerType>(type)) {
     if (!ty.isUnsigned()) {
       switch (ty.getWidth()) {
       case 1:
-        return getIORuntimeFunc<mkIOKey(OutputLogical)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputLogical)>(loc,
+                                                                      builder);
       case 8:
-        return getIORuntimeFunc<mkIOKey(OutputInteger8)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger8)>(loc,
+                                                                       builder);
       case 16:
-        return getIORuntimeFunc<mkIOKey(OutputInteger16)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger16)>(
+            loc, builder);
       case 32:
-        return getIORuntimeFunc<mkIOKey(OutputInteger32)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger32)>(
+            loc, builder);
       case 64:
-        return getIORuntimeFunc<mkIOKey(OutputInteger64)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger64)>(
+            loc, builder);
       case 128:
-        return getIORuntimeFunc<mkIOKey(OutputInteger128)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger128)>(
+            loc, builder);
       }
       llvm_unreachable("unknown OutputInteger kind");
     }
   }
   if (auto ty = mlir::dyn_cast<mlir::FloatType>(type)) {
     if (auto width = ty.getWidth(); width == 32)
-      return getIORuntimeFunc<mkIOKey(OutputReal32)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputReal32)>(loc,
+                                                                   builder);
     else if (width == 64)
-      return getIORuntimeFunc<mkIOKey(OutputReal64)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputReal64)>(loc,
+                                                                   builder);
   }
   auto kindMap = fir::getKindMapping(builder.getModule());
   if (auto ty = mlir::dyn_cast<mlir::ComplexType>(type)) {
     // COMPLEX(KIND=k) corresponds to a pair of REAL(KIND=k).
     auto width = mlir::cast<mlir::FloatType>(ty.getElementType()).getWidth();
     if (width == 32)
-      return getIORuntimeFunc<mkIOKey(OutputComplex32)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputComplex32)>(loc,
+                                                                      builder);
     else if (width == 64)
-      return getIORuntimeFunc<mkIOKey(OutputComplex64)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputComplex64)>(loc,
+                                                                      builder);
   }
   if (mlir::isa<fir::LogicalType>(type))
-    return getIORuntimeFunc<mkIOKey(OutputLogical)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(OutputLogical)>(loc, builder);
   if (fir::factory::CharacterExprHelper::isCharacterScalar(type)) {
     // TODO: What would it mean if the default CHARACTER KIND is set to a wide
     // character encoding scheme? How do we handle UTF-8? Is it a distinct KIND
@@ -706,9 +673,10 @@ static mlir::func::FuncOp getOutputFunc(mlir::Location loc,
     auto asciiKind = kindMap.defaultCharacterKind();
     if (kindMap.getCharacterBitsize(asciiKind) == 8 &&
         fir::factory::CharacterExprHelper::getCharacterKind(type) == asciiKind)
-      return getIORuntimeFunc<mkIOKey(OutputAscii)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputAscii)>(loc, builder);
   }
-  return getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc, builder);
+  return fir::runtime::getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc,
+                                                                   builder);
 }
 
 /// Generate a sequence of output data transfer calls.
@@ -778,39 +746,46 @@ static mlir::func::FuncOp getInputFunc(mlir::Location loc,
                                        fir::FirOpBuilder &builder,
                                        mlir::Type type, bool isFormatted) {
   if (mlir::isa<fir::RecordType>(fir::unwrapPassByRefType(type)))
-    return getIORuntimeFunc<mkIOKey(InputDerivedType)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(InputDerivedType)>(loc,
+                                                                     builder);
   if (!isFormatted)
-    return getIORuntimeFunc<mkIOKey(InputDescriptor)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(InputDescriptor)>(loc,
+                                                                    builder);
   if (auto ty = mlir::dyn_cast<mlir::IntegerType>(type)) {
     if (type.isUnsignedInteger())
-  ...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Feb 21, 2025

@llvm/pr-subscribers-flang-fir-hlfir

Author: Slava Zakharin (vzakhari)

Changes

This change is inspired by a case in facerec benchmark, where performance
of scalar code may improve by about 6%@aarch64 due to getting rid of redundant
loads from Fortran descriptors. These descriptors are corresponding
to subroutine local ALLOCATABLE, SAVE variables. The scalar loop nest
in LocalMove subroutine contains call to Fortran runtime IO functions,
and LLVM globals-aa analysis cannot prove that these calls do not modify
the globalized descriptors with internal linkage.

This patch sets and propagates llvm.memory_effects attribute for fir.call
operations calling Fortran runtime functions. In particular, it tries
to set the Other memory effect to NoModRef. The Other memory effect
includes accesses to globals and captured pointers, so we cannot set
it for functions taking Fortran descriptors with one exception
for calls where the Fortran descriptor arguments are all null.

As long as different calls to the same Fortran runtime function may have
different attributes, I decided to attach the attributes to the calls
rather than functions. Moreover, attaching the attributes to func.func
will require propagating these attributes to llvm.func, which is not
happening right now.

In addition to llvm.memory_effects, the new pass sets llvm.nosync
and llvm.nocallback attributes that may also help LLVM alias analysis
(e.g. see #127707). These attributes are ignored currently.
I will support them in LLVM IR dialect in a separate patch.

I also added another pass for developers to be able to print
declarations/calls of all Fortran runtime functions that are recognized
by the attributes setting pass. It should help with maintenance
of the LIT tests.


Patch is 183.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128093.diff

19 Files Affected:

  • (modified) flang/include/flang/Optimizer/Builder/FIRBuilder.h (+9)
  • (modified) flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h (+38-4)
  • (modified) flang/include/flang/Optimizer/Dialect/FIRDialect.td (+12)
  • (modified) flang/include/flang/Optimizer/Transforms/Passes.h (+2)
  • (modified) flang/include/flang/Optimizer/Transforms/Passes.td (+33)
  • (added) flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc (+111)
  • (modified) flang/lib/Lower/IO.cpp (+147-149)
  • (modified) flang/lib/Optimizer/Builder/FIRBuilder.cpp (+12)
  • (modified) flang/lib/Optimizer/CodeGen/CodeGen.cpp (+10)
  • (modified) flang/lib/Optimizer/Passes/Pipelines.cpp (+3)
  • (modified) flang/lib/Optimizer/Transforms/CMakeLists.txt (+2)
  • (added) flang/lib/Optimizer/Transforms/GenRuntimeCallsForTest.cpp (+106)
  • (added) flang/lib/Optimizer/Transforms/SetRuntimeCallAttributes.cpp (+252)
  • (modified) flang/test/Driver/mlir-pass-pipeline.f90 (+2)
  • (modified) flang/test/Fir/basic-program.fir (+2)
  • (modified) flang/test/Lower/array-temp.f90 (+9-9)
  • (added) flang/test/Transforms/set-runtime-call-attributes.fir (+1039)
  • (added) flang/test/Transforms/verify-known-runtime-functions.fir (+101)
  • (added) flang/test/Utils/generate-checks-for-runtime-funcs.py (+79)
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index 93eca78424775..1675c15363868 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -385,6 +385,15 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
                                            mlir::FunctionType ty,
                                            mlir::SymbolTable *);
 
+  /// Returns a named function for a Fortran runtime API, creating
+  /// it, if it does not exist in the module yet.
+  /// If \p isIO is set to true, then the function corresponds
+  /// to one of Fortran runtime IO APIs.
+  mlir::func::FuncOp createRuntimeFunction(mlir::Location loc,
+                                           llvm::StringRef name,
+                                           mlir::FunctionType ty,
+                                           bool isIO = false);
+
   /// Cast the input value to IndexType.
   mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
     return createConvert(loc, getIndexType(), val);
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
index 1ffc354d6b80f..5158abaa31ed1 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
@@ -21,6 +21,7 @@
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Runtime/io-api-consts.h"
 #include "flang/Runtime/reduce.h"
 #include "flang/Support/Fortran.h"
 #include "mlir/IR/BuiltinTypes.h"
@@ -586,6 +587,33 @@ constexpr TypeBuilderFunc getModel<void>() {
   };
 }
 
+// Define additional runtime type models specific to IO.
+template <>
+constexpr TypeBuilderFunc getModel<Fortran::runtime::io::IoStatementState *>() {
+  return getModel<char *>();
+}
+template <>
+constexpr TypeBuilderFunc getModel<Fortran::runtime::io::Iostat>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return mlir::IntegerType::get(context,
+                                  8 * sizeof(Fortran::runtime::io::Iostat));
+  };
+}
+template <>
+constexpr TypeBuilderFunc
+getModel<const Fortran::runtime::io::NamelistGroup &>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return fir::ReferenceType::get(mlir::TupleType::get(context));
+  };
+}
+template <>
+constexpr TypeBuilderFunc
+getModel<const Fortran::runtime::io::NonTbpDefinedIoTable *>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return fir::ReferenceType::get(mlir::TupleType::get(context));
+  };
+}
+
 REDUCTION_REF_OPERATION_MODEL(std::int8_t)
 REDUCTION_VALUE_OPERATION_MODEL(std::int8_t)
 REDUCTION_REF_OPERATION_MODEL(std::int16_t)
@@ -778,16 +806,22 @@ struct RuntimeTableEntry<RuntimeTableKey<KT>, RuntimeIdentifier<Cs...>> {
 /// argument is intended to be of the form: <mkRTKey(runtime function name)>.
 template <typename RuntimeEntry>
 static mlir::func::FuncOp getRuntimeFunc(mlir::Location loc,
-                                         fir::FirOpBuilder &builder) {
+                                         fir::FirOpBuilder &builder,
+                                         bool isIO = false) {
   using namespace Fortran::runtime;
   auto name = RuntimeEntry::name;
   auto func = builder.getNamedFunction(name);
   if (func)
     return func;
   auto funTy = RuntimeEntry::getTypeModel()(builder.getContext());
-  func = builder.createFunction(loc, name, funTy);
-  func->setAttr(FIROpsDialect::getFirRuntimeAttrName(), builder.getUnitAttr());
-  return func;
+  return builder.createRuntimeFunction(loc, name, funTy, isIO);
+}
+
+/// Get (or generate) the MLIR FuncOp for a given IO runtime function.
+template <typename E>
+static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
+                                           fir::FirOpBuilder &builder) {
+  return getRuntimeFunc<E>(loc, builder, /*isIO=*/true);
 }
 
 namespace helper {
diff --git a/flang/include/flang/Optimizer/Dialect/FIRDialect.td b/flang/include/flang/Optimizer/Dialect/FIRDialect.td
index 0dfb3eda585ce..b05f4e731bc73 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRDialect.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRDialect.td
@@ -56,6 +56,18 @@ def FIROpsDialect : Dialect {
     static constexpr llvm::StringRef getFirRuntimeAttrName() {
       return "fir.runtime";
     }
+    // Return string name of fir.memory attributes.
+    // It is attached to fir.call operations to convey
+    // llvm.memory attributes to LLVM IR.
+    // Its value is intended to be mlir::LLVM::MemoryEffectsAttr.
+    // TODO: we should probably make it an inherent attribute
+    // of fir.call, though, it is supposed to be a short-lived
+    // attribute that appears right before CodeGen and only
+    // meaningful for LLVM, so it is unclear if embedding
+    // it into fir.call makes sense.
+    static constexpr llvm::StringRef getFirCallMemoryAttrName() {
+      return "fir.llvm_memory";
+    }
   }];
 }
 
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h
index 10e1c999d4533..afbbeb55632f1 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.h
+++ b/flang/include/flang/Optimizer/Transforms/Passes.h
@@ -60,6 +60,8 @@ namespace fir {
 #define GEN_PASS_DECL_FUNCTIONATTR
 #define GEN_PASS_DECL_CONSTANTARGUMENTGLOBALISATIONOPT
 #define GEN_PASS_DECL_COMPILERGENERATEDNAMESCONVERSION
+#define GEN_PASS_DECL_SETRUNTIMECALLATTRIBUTES
+#define GEN_PASS_DECL_GENRUNTIMECALLSFORTEST
 
 #include "flang/Optimizer/Transforms/Passes.h.inc"
 
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index 0b6e0119c16c3..64341b42bd1e4 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -453,4 +453,37 @@ def CUFGPUToLLVMConversion : Pass<"cuf-gpu-convert-to-llvm", "mlir::ModuleOp"> {
   ];
 }
 
+def SetRuntimeCallAttributes
+    : Pass<"set-runtime-call-attrs", "mlir::func::FuncOp"> {
+  let summary = "Set Fortran runtime fir.call attributes targeting LLVM IR";
+  let description = [{
+    This pass sets different attributes for Fortran runtime calls
+    that enable more optimizations in LLVM backend.
+    For the time being, the meaning of these attributes is not
+    strictly defined for HLFIR/FIR.
+  }];
+  let dependentDialects = ["fir::FIROpsDialect", "mlir::LLVM::LLVMDialect"];
+}
+
+def GenRuntimeCallsForTest
+    : Pass<"gen-runtime-calls-for-test", "mlir::ModuleOp"> {
+  let summary =
+      "Print FIR containing declarations/calls of Fortran runtime functions";
+  let description = [{
+    This pass is only for developers to be able to print FIR
+    that declares and calls Fortran runtime functions.
+    It helps producing/updating tests for passes that modify
+    the func/call operations based on some knowledge of
+    Fortran runtime.
+  }];
+  let options =
+      [Option<"doGenerateCalls", "do-generate-calls", "bool",
+              /*default=*/"false",
+              "Generate thin wrapper functions that call Fortran runtime "
+              "functions. If it is set to false, then only the declarations "
+              "are generated.">,
+  ];
+  let dependentDialects = ["fir::FIROpsDialect", "mlir::func::FuncDialect"];
+}
+
 #endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES
diff --git a/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc b/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc
new file mode 100644
index 0000000000000..cb4bf4ecf559d
--- /dev/null
+++ b/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc
@@ -0,0 +1,111 @@
+//===-- Optimizer/Transforms/RuntimeFunctions.inc ---------------*- 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 KNOWN_IO_FUNC
+#error "Define KNOWN_IO_FUNC before including this file"
+#endif
+#ifndef KNOWN_RUNTIME_FUNC
+#error "Define KNOWN_RUNTIME_FUNC before including this file"
+#endif
+
+// Fortran runtime functions that SetRuntimeCallAttributesPass recognizes.
+// WARNING: if you add a function entry here, you must make sure
+// that the attribute computation callbacks that end up being
+// used are correct for this function. If needed, add
+// specializations for the types that provide attribute
+// computation callbacks in SetRuntimeCallAttributesPass.
+
+// clang-format off
+KNOWN_IO_FUNC(BeginBackspace),
+KNOWN_IO_FUNC(BeginClose),
+KNOWN_IO_FUNC(BeginEndfile),
+KNOWN_IO_FUNC(BeginExternalFormattedInput),
+KNOWN_IO_FUNC(BeginExternalFormattedOutput),
+KNOWN_IO_FUNC(BeginExternalListInput),
+KNOWN_IO_FUNC(BeginExternalListOutput),
+KNOWN_IO_FUNC(BeginFlush),
+KNOWN_IO_FUNC(BeginInquireFile),
+KNOWN_IO_FUNC(BeginInquireIoLength),
+KNOWN_IO_FUNC(BeginInquireUnit),
+KNOWN_IO_FUNC(BeginInternalArrayFormattedInput),
+KNOWN_IO_FUNC(BeginInternalArrayFormattedOutput),
+KNOWN_IO_FUNC(BeginInternalArrayListInput),
+KNOWN_IO_FUNC(BeginInternalArrayListOutput),
+KNOWN_IO_FUNC(BeginInternalFormattedInput),
+KNOWN_IO_FUNC(BeginInternalFormattedOutput),
+KNOWN_IO_FUNC(BeginInternalListInput),
+KNOWN_IO_FUNC(BeginInternalListOutput),
+KNOWN_IO_FUNC(BeginOpenNewUnit),
+KNOWN_IO_FUNC(BeginOpenUnit),
+KNOWN_IO_FUNC(BeginRewind),
+KNOWN_IO_FUNC(BeginUnformattedInput),
+KNOWN_IO_FUNC(BeginUnformattedOutput),
+KNOWN_IO_FUNC(BeginWait),
+KNOWN_IO_FUNC(BeginWaitAll),
+KNOWN_IO_FUNC(CheckUnitNumberInRange128),
+KNOWN_IO_FUNC(CheckUnitNumberInRange64),
+KNOWN_IO_FUNC(EnableHandlers),
+KNOWN_IO_FUNC(EndIoStatement),
+KNOWN_IO_FUNC(GetAsynchronousId),
+KNOWN_IO_FUNC(GetIoLength),
+KNOWN_IO_FUNC(GetIoMsg),
+KNOWN_IO_FUNC(GetNewUnit),
+KNOWN_IO_FUNC(GetSize),
+KNOWN_IO_FUNC(InputAscii),
+KNOWN_IO_FUNC(InputComplex32),
+KNOWN_IO_FUNC(InputComplex64),
+KNOWN_IO_FUNC(InputDerivedType),
+KNOWN_IO_FUNC(InputDescriptor),
+KNOWN_IO_FUNC(InputInteger),
+KNOWN_IO_FUNC(InputLogical),
+KNOWN_IO_FUNC(InputNamelist),
+KNOWN_IO_FUNC(InputReal32),
+KNOWN_IO_FUNC(InputReal64),
+KNOWN_IO_FUNC(InquireCharacter),
+KNOWN_IO_FUNC(InquireInteger64),
+KNOWN_IO_FUNC(InquireLogical),
+KNOWN_IO_FUNC(InquirePendingId),
+KNOWN_IO_FUNC(OutputAscii),
+KNOWN_IO_FUNC(OutputComplex32),
+KNOWN_IO_FUNC(OutputComplex64),
+KNOWN_IO_FUNC(OutputDerivedType),
+KNOWN_IO_FUNC(OutputDescriptor),
+KNOWN_IO_FUNC(OutputInteger128),
+KNOWN_IO_FUNC(OutputInteger16),
+KNOWN_IO_FUNC(OutputInteger32),
+KNOWN_IO_FUNC(OutputInteger64),
+KNOWN_IO_FUNC(OutputInteger8),
+KNOWN_IO_FUNC(OutputLogical),
+KNOWN_IO_FUNC(OutputNamelist),
+KNOWN_IO_FUNC(OutputReal32),
+KNOWN_IO_FUNC(OutputReal64),
+KNOWN_IO_FUNC(SetAccess),
+KNOWN_IO_FUNC(SetAction),
+KNOWN_IO_FUNC(SetAdvance),
+KNOWN_IO_FUNC(SetAsynchronous),
+KNOWN_IO_FUNC(SetBlank),
+KNOWN_IO_FUNC(SetCarriagecontrol),
+KNOWN_IO_FUNC(SetConvert),
+KNOWN_IO_FUNC(SetDecimal),
+KNOWN_IO_FUNC(SetDelim),
+KNOWN_IO_FUNC(SetEncoding),
+KNOWN_IO_FUNC(SetFile),
+KNOWN_IO_FUNC(SetForm),
+KNOWN_IO_FUNC(SetPad),
+KNOWN_IO_FUNC(SetPos),
+KNOWN_IO_FUNC(SetPosition),
+KNOWN_IO_FUNC(SetRec),
+KNOWN_IO_FUNC(SetRecl),
+KNOWN_IO_FUNC(SetRound),
+KNOWN_IO_FUNC(SetSign),
+KNOWN_IO_FUNC(SetStatus)
+
+// clang-format on
+
+#undef KNOWN_IO_FUNC
+#undef KNOWN_RUNTIME_FUNC
diff --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index 75453721d91a2..35068f0519cbd 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -43,35 +43,6 @@
 
 #define DEBUG_TYPE "flang-lower-io"
 
-// Define additional runtime type models specific to IO.
-namespace fir::runtime {
-template <>
-constexpr TypeBuilderFunc getModel<Fortran::runtime::io::IoStatementState *>() {
-  return getModel<char *>();
-}
-template <>
-constexpr TypeBuilderFunc getModel<Fortran::runtime::io::Iostat>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return mlir::IntegerType::get(context,
-                                  8 * sizeof(Fortran::runtime::io::Iostat));
-  };
-}
-template <>
-constexpr TypeBuilderFunc
-getModel<const Fortran::runtime::io::NamelistGroup &>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return fir::ReferenceType::get(mlir::TupleType::get(context));
-  };
-}
-template <>
-constexpr TypeBuilderFunc
-getModel<const Fortran::runtime::io::NonTbpDefinedIoTable *>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return fir::ReferenceType::get(mlir::TupleType::get(context));
-  };
-}
-} // namespace fir::runtime
-
 using namespace Fortran::runtime::io;
 
 #define mkIOKey(X) FirmkKey(IONAME(X))
@@ -172,22 +143,6 @@ inline int64_t getLength(mlir::Type argTy) {
   return mlir::cast<fir::SequenceType>(argTy).getShape()[0];
 }
 
-/// Get (or generate) the MLIR FuncOp for a given IO runtime function.
-template <typename E>
-static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
-                                           fir::FirOpBuilder &builder) {
-  llvm::StringRef name = getName<E>();
-  mlir::func::FuncOp func = builder.getNamedFunction(name);
-  if (func)
-    return func;
-  auto funTy = getTypeModel<E>()(builder.getContext());
-  func = builder.createFunction(loc, name, funTy);
-  func->setAttr(fir::FIROpsDialect::getFirRuntimeAttrName(),
-                builder.getUnitAttr());
-  func->setAttr("fir.io", builder.getUnitAttr());
-  return func;
-}
-
 /// Generate calls to end an IO statement. Return the IOSTAT value, if any.
 /// It is the caller's responsibility to generate branches on that value.
 static mlir::Value genEndIO(Fortran::lower::AbstractConverter &converter,
@@ -197,7 +152,7 @@ static mlir::Value genEndIO(Fortran::lower::AbstractConverter &converter,
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
   if (csi.ioMsg) {
     mlir::func::FuncOp getIoMsg =
-        getIORuntimeFunc<mkIOKey(GetIoMsg)>(loc, builder);
+        fir::runtime::getIORuntimeFunc<mkIOKey(GetIoMsg)>(loc, builder);
     builder.create<fir::CallOp>(
         loc, getIoMsg,
         mlir::ValueRange{
@@ -208,7 +163,7 @@ static mlir::Value genEndIO(Fortran::lower::AbstractConverter &converter,
                                   fir::getLen(*csi.ioMsg))});
   }
   mlir::func::FuncOp endIoStatement =
-      getIORuntimeFunc<mkIOKey(EndIoStatement)>(loc, builder);
+      fir::runtime::getIORuntimeFunc<mkIOKey(EndIoStatement)>(loc, builder);
   auto call = builder.create<fir::CallOp>(loc, endIoStatement,
                                           mlir::ValueRange{cookie});
   mlir::Value iostat = call.getResult(0);
@@ -659,45 +614,57 @@ static mlir::func::FuncOp getOutputFunc(mlir::Location loc,
                                         fir::FirOpBuilder &builder,
                                         mlir::Type type, bool isFormatted) {
   if (mlir::isa<fir::RecordType>(fir::unwrapPassByRefType(type)))
-    return getIORuntimeFunc<mkIOKey(OutputDerivedType)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(OutputDerivedType)>(loc,
+                                                                      builder);
   if (!isFormatted)
-    return getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc,
+                                                                     builder);
   if (auto ty = mlir::dyn_cast<mlir::IntegerType>(type)) {
     if (!ty.isUnsigned()) {
       switch (ty.getWidth()) {
       case 1:
-        return getIORuntimeFunc<mkIOKey(OutputLogical)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputLogical)>(loc,
+                                                                      builder);
       case 8:
-        return getIORuntimeFunc<mkIOKey(OutputInteger8)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger8)>(loc,
+                                                                       builder);
       case 16:
-        return getIORuntimeFunc<mkIOKey(OutputInteger16)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger16)>(
+            loc, builder);
       case 32:
-        return getIORuntimeFunc<mkIOKey(OutputInteger32)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger32)>(
+            loc, builder);
       case 64:
-        return getIORuntimeFunc<mkIOKey(OutputInteger64)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger64)>(
+            loc, builder);
       case 128:
-        return getIORuntimeFunc<mkIOKey(OutputInteger128)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger128)>(
+            loc, builder);
       }
       llvm_unreachable("unknown OutputInteger kind");
     }
   }
   if (auto ty = mlir::dyn_cast<mlir::FloatType>(type)) {
     if (auto width = ty.getWidth(); width == 32)
-      return getIORuntimeFunc<mkIOKey(OutputReal32)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputReal32)>(loc,
+                                                                   builder);
     else if (width == 64)
-      return getIORuntimeFunc<mkIOKey(OutputReal64)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputReal64)>(loc,
+                                                                   builder);
   }
   auto kindMap = fir::getKindMapping(builder.getModule());
   if (auto ty = mlir::dyn_cast<mlir::ComplexType>(type)) {
     // COMPLEX(KIND=k) corresponds to a pair of REAL(KIND=k).
     auto width = mlir::cast<mlir::FloatType>(ty.getElementType()).getWidth();
     if (width == 32)
-      return getIORuntimeFunc<mkIOKey(OutputComplex32)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputComplex32)>(loc,
+                                                                      builder);
     else if (width == 64)
-      return getIORuntimeFunc<mkIOKey(OutputComplex64)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputComplex64)>(loc,
+                                                                      builder);
   }
   if (mlir::isa<fir::LogicalType>(type))
-    return getIORuntimeFunc<mkIOKey(OutputLogical)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(OutputLogical)>(loc, builder);
   if (fir::factory::CharacterExprHelper::isCharacterScalar(type)) {
     // TODO: What would it mean if the default CHARACTER KIND is set to a wide
     // character encoding scheme? How do we handle UTF-8? Is it a distinct KIND
@@ -706,9 +673,10 @@ static mlir::func::FuncOp getOutputFunc(mlir::Location loc,
     auto asciiKind = kindMap.defaultCharacterKind();
     if (kindMap.getCharacterBitsize(asciiKind) == 8 &&
         fir::factory::CharacterExprHelper::getCharacterKind(type) == asciiKind)
-      return getIORuntimeFunc<mkIOKey(OutputAscii)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputAscii)>(loc, builder);
   }
-  return getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc, builder);
+  return fir::runtime::getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc,
+                                                                   builder);
 }
 
 /// Generate a sequence of output data transfer calls.
@@ -778,39 +746,46 @@ static mlir::func::FuncOp getInputFunc(mlir::Location loc,
                                        fir::FirOpBuilder &builder,
                                        mlir::Type type, bool isFormatted) {
   if (mlir::isa<fir::RecordType>(fir::unwrapPassByRefType(type)))
-    return getIORuntimeFunc<mkIOKey(InputDerivedType)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(InputDerivedType)>(loc,
+                                                                     builder);
   if (!isFormatted)
-    return getIORuntimeFunc<mkIOKey(InputDescriptor)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(InputDescriptor)>(loc,
+                                                                    builder);
   if (auto ty = mlir::dyn_cast<mlir::IntegerType>(type)) {
     if (type.isUnsignedInteger())
-  ...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Feb 21, 2025

@llvm/pr-subscribers-flang-codegen

Author: Slava Zakharin (vzakhari)

Changes

This change is inspired by a case in facerec benchmark, where performance
of scalar code may improve by about 6%@aarch64 due to getting rid of redundant
loads from Fortran descriptors. These descriptors are corresponding
to subroutine local ALLOCATABLE, SAVE variables. The scalar loop nest
in LocalMove subroutine contains call to Fortran runtime IO functions,
and LLVM globals-aa analysis cannot prove that these calls do not modify
the globalized descriptors with internal linkage.

This patch sets and propagates llvm.memory_effects attribute for fir.call
operations calling Fortran runtime functions. In particular, it tries
to set the Other memory effect to NoModRef. The Other memory effect
includes accesses to globals and captured pointers, so we cannot set
it for functions taking Fortran descriptors with one exception
for calls where the Fortran descriptor arguments are all null.

As long as different calls to the same Fortran runtime function may have
different attributes, I decided to attach the attributes to the calls
rather than functions. Moreover, attaching the attributes to func.func
will require propagating these attributes to llvm.func, which is not
happening right now.

In addition to llvm.memory_effects, the new pass sets llvm.nosync
and llvm.nocallback attributes that may also help LLVM alias analysis
(e.g. see #127707). These attributes are ignored currently.
I will support them in LLVM IR dialect in a separate patch.

I also added another pass for developers to be able to print
declarations/calls of all Fortran runtime functions that are recognized
by the attributes setting pass. It should help with maintenance
of the LIT tests.


Patch is 183.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128093.diff

19 Files Affected:

  • (modified) flang/include/flang/Optimizer/Builder/FIRBuilder.h (+9)
  • (modified) flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h (+38-4)
  • (modified) flang/include/flang/Optimizer/Dialect/FIRDialect.td (+12)
  • (modified) flang/include/flang/Optimizer/Transforms/Passes.h (+2)
  • (modified) flang/include/flang/Optimizer/Transforms/Passes.td (+33)
  • (added) flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc (+111)
  • (modified) flang/lib/Lower/IO.cpp (+147-149)
  • (modified) flang/lib/Optimizer/Builder/FIRBuilder.cpp (+12)
  • (modified) flang/lib/Optimizer/CodeGen/CodeGen.cpp (+10)
  • (modified) flang/lib/Optimizer/Passes/Pipelines.cpp (+3)
  • (modified) flang/lib/Optimizer/Transforms/CMakeLists.txt (+2)
  • (added) flang/lib/Optimizer/Transforms/GenRuntimeCallsForTest.cpp (+106)
  • (added) flang/lib/Optimizer/Transforms/SetRuntimeCallAttributes.cpp (+252)
  • (modified) flang/test/Driver/mlir-pass-pipeline.f90 (+2)
  • (modified) flang/test/Fir/basic-program.fir (+2)
  • (modified) flang/test/Lower/array-temp.f90 (+9-9)
  • (added) flang/test/Transforms/set-runtime-call-attributes.fir (+1039)
  • (added) flang/test/Transforms/verify-known-runtime-functions.fir (+101)
  • (added) flang/test/Utils/generate-checks-for-runtime-funcs.py (+79)
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index 93eca78424775..1675c15363868 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -385,6 +385,15 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
                                            mlir::FunctionType ty,
                                            mlir::SymbolTable *);
 
+  /// Returns a named function for a Fortran runtime API, creating
+  /// it, if it does not exist in the module yet.
+  /// If \p isIO is set to true, then the function corresponds
+  /// to one of Fortran runtime IO APIs.
+  mlir::func::FuncOp createRuntimeFunction(mlir::Location loc,
+                                           llvm::StringRef name,
+                                           mlir::FunctionType ty,
+                                           bool isIO = false);
+
   /// Cast the input value to IndexType.
   mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
     return createConvert(loc, getIndexType(), val);
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
index 1ffc354d6b80f..5158abaa31ed1 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
@@ -21,6 +21,7 @@
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Runtime/io-api-consts.h"
 #include "flang/Runtime/reduce.h"
 #include "flang/Support/Fortran.h"
 #include "mlir/IR/BuiltinTypes.h"
@@ -586,6 +587,33 @@ constexpr TypeBuilderFunc getModel<void>() {
   };
 }
 
+// Define additional runtime type models specific to IO.
+template <>
+constexpr TypeBuilderFunc getModel<Fortran::runtime::io::IoStatementState *>() {
+  return getModel<char *>();
+}
+template <>
+constexpr TypeBuilderFunc getModel<Fortran::runtime::io::Iostat>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return mlir::IntegerType::get(context,
+                                  8 * sizeof(Fortran::runtime::io::Iostat));
+  };
+}
+template <>
+constexpr TypeBuilderFunc
+getModel<const Fortran::runtime::io::NamelistGroup &>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return fir::ReferenceType::get(mlir::TupleType::get(context));
+  };
+}
+template <>
+constexpr TypeBuilderFunc
+getModel<const Fortran::runtime::io::NonTbpDefinedIoTable *>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return fir::ReferenceType::get(mlir::TupleType::get(context));
+  };
+}
+
 REDUCTION_REF_OPERATION_MODEL(std::int8_t)
 REDUCTION_VALUE_OPERATION_MODEL(std::int8_t)
 REDUCTION_REF_OPERATION_MODEL(std::int16_t)
@@ -778,16 +806,22 @@ struct RuntimeTableEntry<RuntimeTableKey<KT>, RuntimeIdentifier<Cs...>> {
 /// argument is intended to be of the form: <mkRTKey(runtime function name)>.
 template <typename RuntimeEntry>
 static mlir::func::FuncOp getRuntimeFunc(mlir::Location loc,
-                                         fir::FirOpBuilder &builder) {
+                                         fir::FirOpBuilder &builder,
+                                         bool isIO = false) {
   using namespace Fortran::runtime;
   auto name = RuntimeEntry::name;
   auto func = builder.getNamedFunction(name);
   if (func)
     return func;
   auto funTy = RuntimeEntry::getTypeModel()(builder.getContext());
-  func = builder.createFunction(loc, name, funTy);
-  func->setAttr(FIROpsDialect::getFirRuntimeAttrName(), builder.getUnitAttr());
-  return func;
+  return builder.createRuntimeFunction(loc, name, funTy, isIO);
+}
+
+/// Get (or generate) the MLIR FuncOp for a given IO runtime function.
+template <typename E>
+static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
+                                           fir::FirOpBuilder &builder) {
+  return getRuntimeFunc<E>(loc, builder, /*isIO=*/true);
 }
 
 namespace helper {
diff --git a/flang/include/flang/Optimizer/Dialect/FIRDialect.td b/flang/include/flang/Optimizer/Dialect/FIRDialect.td
index 0dfb3eda585ce..b05f4e731bc73 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRDialect.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRDialect.td
@@ -56,6 +56,18 @@ def FIROpsDialect : Dialect {
     static constexpr llvm::StringRef getFirRuntimeAttrName() {
       return "fir.runtime";
     }
+    // Return string name of fir.memory attributes.
+    // It is attached to fir.call operations to convey
+    // llvm.memory attributes to LLVM IR.
+    // Its value is intended to be mlir::LLVM::MemoryEffectsAttr.
+    // TODO: we should probably make it an inherent attribute
+    // of fir.call, though, it is supposed to be a short-lived
+    // attribute that appears right before CodeGen and only
+    // meaningful for LLVM, so it is unclear if embedding
+    // it into fir.call makes sense.
+    static constexpr llvm::StringRef getFirCallMemoryAttrName() {
+      return "fir.llvm_memory";
+    }
   }];
 }
 
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h
index 10e1c999d4533..afbbeb55632f1 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.h
+++ b/flang/include/flang/Optimizer/Transforms/Passes.h
@@ -60,6 +60,8 @@ namespace fir {
 #define GEN_PASS_DECL_FUNCTIONATTR
 #define GEN_PASS_DECL_CONSTANTARGUMENTGLOBALISATIONOPT
 #define GEN_PASS_DECL_COMPILERGENERATEDNAMESCONVERSION
+#define GEN_PASS_DECL_SETRUNTIMECALLATTRIBUTES
+#define GEN_PASS_DECL_GENRUNTIMECALLSFORTEST
 
 #include "flang/Optimizer/Transforms/Passes.h.inc"
 
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index 0b6e0119c16c3..64341b42bd1e4 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -453,4 +453,37 @@ def CUFGPUToLLVMConversion : Pass<"cuf-gpu-convert-to-llvm", "mlir::ModuleOp"> {
   ];
 }
 
+def SetRuntimeCallAttributes
+    : Pass<"set-runtime-call-attrs", "mlir::func::FuncOp"> {
+  let summary = "Set Fortran runtime fir.call attributes targeting LLVM IR";
+  let description = [{
+    This pass sets different attributes for Fortran runtime calls
+    that enable more optimizations in LLVM backend.
+    For the time being, the meaning of these attributes is not
+    strictly defined for HLFIR/FIR.
+  }];
+  let dependentDialects = ["fir::FIROpsDialect", "mlir::LLVM::LLVMDialect"];
+}
+
+def GenRuntimeCallsForTest
+    : Pass<"gen-runtime-calls-for-test", "mlir::ModuleOp"> {
+  let summary =
+      "Print FIR containing declarations/calls of Fortran runtime functions";
+  let description = [{
+    This pass is only for developers to be able to print FIR
+    that declares and calls Fortran runtime functions.
+    It helps producing/updating tests for passes that modify
+    the func/call operations based on some knowledge of
+    Fortran runtime.
+  }];
+  let options =
+      [Option<"doGenerateCalls", "do-generate-calls", "bool",
+              /*default=*/"false",
+              "Generate thin wrapper functions that call Fortran runtime "
+              "functions. If it is set to false, then only the declarations "
+              "are generated.">,
+  ];
+  let dependentDialects = ["fir::FIROpsDialect", "mlir::func::FuncDialect"];
+}
+
 #endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES
diff --git a/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc b/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc
new file mode 100644
index 0000000000000..cb4bf4ecf559d
--- /dev/null
+++ b/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc
@@ -0,0 +1,111 @@
+//===-- Optimizer/Transforms/RuntimeFunctions.inc ---------------*- 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 KNOWN_IO_FUNC
+#error "Define KNOWN_IO_FUNC before including this file"
+#endif
+#ifndef KNOWN_RUNTIME_FUNC
+#error "Define KNOWN_RUNTIME_FUNC before including this file"
+#endif
+
+// Fortran runtime functions that SetRuntimeCallAttributesPass recognizes.
+// WARNING: if you add a function entry here, you must make sure
+// that the attribute computation callbacks that end up being
+// used are correct for this function. If needed, add
+// specializations for the types that provide attribute
+// computation callbacks in SetRuntimeCallAttributesPass.
+
+// clang-format off
+KNOWN_IO_FUNC(BeginBackspace),
+KNOWN_IO_FUNC(BeginClose),
+KNOWN_IO_FUNC(BeginEndfile),
+KNOWN_IO_FUNC(BeginExternalFormattedInput),
+KNOWN_IO_FUNC(BeginExternalFormattedOutput),
+KNOWN_IO_FUNC(BeginExternalListInput),
+KNOWN_IO_FUNC(BeginExternalListOutput),
+KNOWN_IO_FUNC(BeginFlush),
+KNOWN_IO_FUNC(BeginInquireFile),
+KNOWN_IO_FUNC(BeginInquireIoLength),
+KNOWN_IO_FUNC(BeginInquireUnit),
+KNOWN_IO_FUNC(BeginInternalArrayFormattedInput),
+KNOWN_IO_FUNC(BeginInternalArrayFormattedOutput),
+KNOWN_IO_FUNC(BeginInternalArrayListInput),
+KNOWN_IO_FUNC(BeginInternalArrayListOutput),
+KNOWN_IO_FUNC(BeginInternalFormattedInput),
+KNOWN_IO_FUNC(BeginInternalFormattedOutput),
+KNOWN_IO_FUNC(BeginInternalListInput),
+KNOWN_IO_FUNC(BeginInternalListOutput),
+KNOWN_IO_FUNC(BeginOpenNewUnit),
+KNOWN_IO_FUNC(BeginOpenUnit),
+KNOWN_IO_FUNC(BeginRewind),
+KNOWN_IO_FUNC(BeginUnformattedInput),
+KNOWN_IO_FUNC(BeginUnformattedOutput),
+KNOWN_IO_FUNC(BeginWait),
+KNOWN_IO_FUNC(BeginWaitAll),
+KNOWN_IO_FUNC(CheckUnitNumberInRange128),
+KNOWN_IO_FUNC(CheckUnitNumberInRange64),
+KNOWN_IO_FUNC(EnableHandlers),
+KNOWN_IO_FUNC(EndIoStatement),
+KNOWN_IO_FUNC(GetAsynchronousId),
+KNOWN_IO_FUNC(GetIoLength),
+KNOWN_IO_FUNC(GetIoMsg),
+KNOWN_IO_FUNC(GetNewUnit),
+KNOWN_IO_FUNC(GetSize),
+KNOWN_IO_FUNC(InputAscii),
+KNOWN_IO_FUNC(InputComplex32),
+KNOWN_IO_FUNC(InputComplex64),
+KNOWN_IO_FUNC(InputDerivedType),
+KNOWN_IO_FUNC(InputDescriptor),
+KNOWN_IO_FUNC(InputInteger),
+KNOWN_IO_FUNC(InputLogical),
+KNOWN_IO_FUNC(InputNamelist),
+KNOWN_IO_FUNC(InputReal32),
+KNOWN_IO_FUNC(InputReal64),
+KNOWN_IO_FUNC(InquireCharacter),
+KNOWN_IO_FUNC(InquireInteger64),
+KNOWN_IO_FUNC(InquireLogical),
+KNOWN_IO_FUNC(InquirePendingId),
+KNOWN_IO_FUNC(OutputAscii),
+KNOWN_IO_FUNC(OutputComplex32),
+KNOWN_IO_FUNC(OutputComplex64),
+KNOWN_IO_FUNC(OutputDerivedType),
+KNOWN_IO_FUNC(OutputDescriptor),
+KNOWN_IO_FUNC(OutputInteger128),
+KNOWN_IO_FUNC(OutputInteger16),
+KNOWN_IO_FUNC(OutputInteger32),
+KNOWN_IO_FUNC(OutputInteger64),
+KNOWN_IO_FUNC(OutputInteger8),
+KNOWN_IO_FUNC(OutputLogical),
+KNOWN_IO_FUNC(OutputNamelist),
+KNOWN_IO_FUNC(OutputReal32),
+KNOWN_IO_FUNC(OutputReal64),
+KNOWN_IO_FUNC(SetAccess),
+KNOWN_IO_FUNC(SetAction),
+KNOWN_IO_FUNC(SetAdvance),
+KNOWN_IO_FUNC(SetAsynchronous),
+KNOWN_IO_FUNC(SetBlank),
+KNOWN_IO_FUNC(SetCarriagecontrol),
+KNOWN_IO_FUNC(SetConvert),
+KNOWN_IO_FUNC(SetDecimal),
+KNOWN_IO_FUNC(SetDelim),
+KNOWN_IO_FUNC(SetEncoding),
+KNOWN_IO_FUNC(SetFile),
+KNOWN_IO_FUNC(SetForm),
+KNOWN_IO_FUNC(SetPad),
+KNOWN_IO_FUNC(SetPos),
+KNOWN_IO_FUNC(SetPosition),
+KNOWN_IO_FUNC(SetRec),
+KNOWN_IO_FUNC(SetRecl),
+KNOWN_IO_FUNC(SetRound),
+KNOWN_IO_FUNC(SetSign),
+KNOWN_IO_FUNC(SetStatus)
+
+// clang-format on
+
+#undef KNOWN_IO_FUNC
+#undef KNOWN_RUNTIME_FUNC
diff --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index 75453721d91a2..35068f0519cbd 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -43,35 +43,6 @@
 
 #define DEBUG_TYPE "flang-lower-io"
 
-// Define additional runtime type models specific to IO.
-namespace fir::runtime {
-template <>
-constexpr TypeBuilderFunc getModel<Fortran::runtime::io::IoStatementState *>() {
-  return getModel<char *>();
-}
-template <>
-constexpr TypeBuilderFunc getModel<Fortran::runtime::io::Iostat>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return mlir::IntegerType::get(context,
-                                  8 * sizeof(Fortran::runtime::io::Iostat));
-  };
-}
-template <>
-constexpr TypeBuilderFunc
-getModel<const Fortran::runtime::io::NamelistGroup &>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return fir::ReferenceType::get(mlir::TupleType::get(context));
-  };
-}
-template <>
-constexpr TypeBuilderFunc
-getModel<const Fortran::runtime::io::NonTbpDefinedIoTable *>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return fir::ReferenceType::get(mlir::TupleType::get(context));
-  };
-}
-} // namespace fir::runtime
-
 using namespace Fortran::runtime::io;
 
 #define mkIOKey(X) FirmkKey(IONAME(X))
@@ -172,22 +143,6 @@ inline int64_t getLength(mlir::Type argTy) {
   return mlir::cast<fir::SequenceType>(argTy).getShape()[0];
 }
 
-/// Get (or generate) the MLIR FuncOp for a given IO runtime function.
-template <typename E>
-static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
-                                           fir::FirOpBuilder &builder) {
-  llvm::StringRef name = getName<E>();
-  mlir::func::FuncOp func = builder.getNamedFunction(name);
-  if (func)
-    return func;
-  auto funTy = getTypeModel<E>()(builder.getContext());
-  func = builder.createFunction(loc, name, funTy);
-  func->setAttr(fir::FIROpsDialect::getFirRuntimeAttrName(),
-                builder.getUnitAttr());
-  func->setAttr("fir.io", builder.getUnitAttr());
-  return func;
-}
-
 /// Generate calls to end an IO statement. Return the IOSTAT value, if any.
 /// It is the caller's responsibility to generate branches on that value.
 static mlir::Value genEndIO(Fortran::lower::AbstractConverter &converter,
@@ -197,7 +152,7 @@ static mlir::Value genEndIO(Fortran::lower::AbstractConverter &converter,
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
   if (csi.ioMsg) {
     mlir::func::FuncOp getIoMsg =
-        getIORuntimeFunc<mkIOKey(GetIoMsg)>(loc, builder);
+        fir::runtime::getIORuntimeFunc<mkIOKey(GetIoMsg)>(loc, builder);
     builder.create<fir::CallOp>(
         loc, getIoMsg,
         mlir::ValueRange{
@@ -208,7 +163,7 @@ static mlir::Value genEndIO(Fortran::lower::AbstractConverter &converter,
                                   fir::getLen(*csi.ioMsg))});
   }
   mlir::func::FuncOp endIoStatement =
-      getIORuntimeFunc<mkIOKey(EndIoStatement)>(loc, builder);
+      fir::runtime::getIORuntimeFunc<mkIOKey(EndIoStatement)>(loc, builder);
   auto call = builder.create<fir::CallOp>(loc, endIoStatement,
                                           mlir::ValueRange{cookie});
   mlir::Value iostat = call.getResult(0);
@@ -659,45 +614,57 @@ static mlir::func::FuncOp getOutputFunc(mlir::Location loc,
                                         fir::FirOpBuilder &builder,
                                         mlir::Type type, bool isFormatted) {
   if (mlir::isa<fir::RecordType>(fir::unwrapPassByRefType(type)))
-    return getIORuntimeFunc<mkIOKey(OutputDerivedType)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(OutputDerivedType)>(loc,
+                                                                      builder);
   if (!isFormatted)
-    return getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc,
+                                                                     builder);
   if (auto ty = mlir::dyn_cast<mlir::IntegerType>(type)) {
     if (!ty.isUnsigned()) {
       switch (ty.getWidth()) {
       case 1:
-        return getIORuntimeFunc<mkIOKey(OutputLogical)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputLogical)>(loc,
+                                                                      builder);
       case 8:
-        return getIORuntimeFunc<mkIOKey(OutputInteger8)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger8)>(loc,
+                                                                       builder);
       case 16:
-        return getIORuntimeFunc<mkIOKey(OutputInteger16)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger16)>(
+            loc, builder);
       case 32:
-        return getIORuntimeFunc<mkIOKey(OutputInteger32)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger32)>(
+            loc, builder);
       case 64:
-        return getIORuntimeFunc<mkIOKey(OutputInteger64)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger64)>(
+            loc, builder);
       case 128:
-        return getIORuntimeFunc<mkIOKey(OutputInteger128)>(loc, builder);
+        return fir::runtime::getIORuntimeFunc<mkIOKey(OutputInteger128)>(
+            loc, builder);
       }
       llvm_unreachable("unknown OutputInteger kind");
     }
   }
   if (auto ty = mlir::dyn_cast<mlir::FloatType>(type)) {
     if (auto width = ty.getWidth(); width == 32)
-      return getIORuntimeFunc<mkIOKey(OutputReal32)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputReal32)>(loc,
+                                                                   builder);
     else if (width == 64)
-      return getIORuntimeFunc<mkIOKey(OutputReal64)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputReal64)>(loc,
+                                                                   builder);
   }
   auto kindMap = fir::getKindMapping(builder.getModule());
   if (auto ty = mlir::dyn_cast<mlir::ComplexType>(type)) {
     // COMPLEX(KIND=k) corresponds to a pair of REAL(KIND=k).
     auto width = mlir::cast<mlir::FloatType>(ty.getElementType()).getWidth();
     if (width == 32)
-      return getIORuntimeFunc<mkIOKey(OutputComplex32)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputComplex32)>(loc,
+                                                                      builder);
     else if (width == 64)
-      return getIORuntimeFunc<mkIOKey(OutputComplex64)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputComplex64)>(loc,
+                                                                      builder);
   }
   if (mlir::isa<fir::LogicalType>(type))
-    return getIORuntimeFunc<mkIOKey(OutputLogical)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(OutputLogical)>(loc, builder);
   if (fir::factory::CharacterExprHelper::isCharacterScalar(type)) {
     // TODO: What would it mean if the default CHARACTER KIND is set to a wide
     // character encoding scheme? How do we handle UTF-8? Is it a distinct KIND
@@ -706,9 +673,10 @@ static mlir::func::FuncOp getOutputFunc(mlir::Location loc,
     auto asciiKind = kindMap.defaultCharacterKind();
     if (kindMap.getCharacterBitsize(asciiKind) == 8 &&
         fir::factory::CharacterExprHelper::getCharacterKind(type) == asciiKind)
-      return getIORuntimeFunc<mkIOKey(OutputAscii)>(loc, builder);
+      return fir::runtime::getIORuntimeFunc<mkIOKey(OutputAscii)>(loc, builder);
   }
-  return getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc, builder);
+  return fir::runtime::getIORuntimeFunc<mkIOKey(OutputDescriptor)>(loc,
+                                                                   builder);
 }
 
 /// Generate a sequence of output data transfer calls.
@@ -778,39 +746,46 @@ static mlir::func::FuncOp getInputFunc(mlir::Location loc,
                                        fir::FirOpBuilder &builder,
                                        mlir::Type type, bool isFormatted) {
   if (mlir::isa<fir::RecordType>(fir::unwrapPassByRefType(type)))
-    return getIORuntimeFunc<mkIOKey(InputDerivedType)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(InputDerivedType)>(loc,
+                                                                     builder);
   if (!isFormatted)
-    return getIORuntimeFunc<mkIOKey(InputDescriptor)>(loc, builder);
+    return fir::runtime::getIORuntimeFunc<mkIOKey(InputDescriptor)>(loc,
+                                                                    builder);
   if (auto ty = mlir::dyn_cast<mlir::IntegerType>(type)) {
     if (type.isUnsignedInteger())
-  ...
[truncated]

Copy link

github-actions bot commented Feb 21, 2025

✅ With the latest revision this PR passed the Python code formatter.

Copy link
Contributor

@vdonaldson vdonaldson left a comment

Choose a reason for hiding this comment

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

Looks ok to me. You might want to get additional review.

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

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

Looks great, thanks

// cannot access memory indirectly through the box's
// base_addr.
auto def = arg.getDefiningOp();
if (!def || !mlir::isa<fir::ZeroOp>(def)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe worth adding fir::AbsentOp here that is also used in some context to create null box.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! Will do.

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.

This is really nice, Slava :)

Just one question, if it turns out not to be relevant then this LGTM.

}
};

// Derived types IO may call back into a Fortran module.
Copy link
Contributor

Choose a reason for hiding this comment

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

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right, Tom. I will have to provide specializations for those non-I/O APIs.

Another point is that distinguishing these cases from trivial ones (when no callback may happen) might be not qutie reliable that late in the pipeline, so I think it may be worth introducing separate APIs for trivial and non-trivial cases of assignment/etc. For the trivial cases, this will also help to avoid generating Fortran runtime calls that end up using call recursion, which is a problem for some offload devices.

If we split the APIs in such a way, then we will be able to set the attributes based on the APIs name rather than based on the recognition of the actual arguments.

@vzakhari vzakhari merged commit 36fdeb2 into llvm:main Feb 24, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Feb 24, 2025

LLVM Buildbot has detected a new failure on builder openmp-offload-sles-build-only running on rocm-worker-hw-04-sles while building flang at step 5 "compile-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/140/builds/17587

Here is the relevant piece of the build log for the reference
Step 5 (compile-openmp) failure: build (failure)
...
168.238 [113/18/6972] Linking CXX executable bin/llvm-opt-fuzzer
168.363 [113/17/6973] Linking CXX executable bin/llvm-split
168.517 [113/16/6974] Linking CXX executable bin/llvm-reduce
168.619 [113/15/6975] Building CXX object tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/AddDebugInfo.cpp.o
168.623 [113/14/6976] Building CXX object tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/SimplifyIntrinsics.cpp.o
169.039 [113/13/6977] Linking CXX executable bin/opt
169.113 [113/12/6978] Building CXX object tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/VScaleAttr.cpp.o
169.874 [113/11/6979] Building CXX object tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/DebugTypeGenerator.cpp.o
170.289 [113/10/6980] Building CXX object tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/FunctionAttr.cpp.o
170.907 [113/9/6981] Building CXX object tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/SetRuntimeCallAttributes.cpp.o
FAILED: tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/SetRuntimeCallAttributes.cpp.o 
ccache /usr/bin/c++ -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools/flang/lib/Optimizer/Transforms -I/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/lib/Optimizer/Transforms -I/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include -Itools/flang/include -Iinclude -I/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/include -isystem /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/../mlir/include -isystem tools/mlir/include -isystem tools/clang/include -isystem /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/../clang/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -fno-lifetime-dse -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wno-uninitialized -Wno-nonnull -Wno-noexcept-type -Wdelete-non-virtual-dtor -Wno-comment -Wno-misleading-indentation -fdiagnostics-color -ffunction-sections -fdata-sections -Wno-deprecated-copy -Wno-ctad-maybe-unsupported -fno-strict-aliasing -fno-semantic-interposition -O3 -DNDEBUG  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -std=c++1z -MD -MT tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/SetRuntimeCallAttributes.cpp.o -MF tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/SetRuntimeCallAttributes.cpp.o.d -o tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/SetRuntimeCallAttributes.cpp.o -c /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/lib/Optimizer/Transforms/SetRuntimeCallAttributes.cpp
In file included from /usr/include/c++/7/bits/basic_string.h:48:0,
                 from /usr/include/c++/7/string:52,
                 from /usr/include/c++/7/stdexcept:39,
                 from /usr/include/c++/7/optional:38,
                 from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include/flang/Common/constexpr-bitset.h:20,
                 from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include/flang/Common/enum-set.h:17,
                 from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include/flang/Common/Fortran-consts.h:12,
                 from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include/flang/Support/Fortran.h:15,
                 from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include/flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h:16,
                 from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include/flang/Optimizer/Dialect/FIROps.h:12,
                 from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include/flang/Optimizer/Builder/FIRBuilder.h:19,
                 from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h:21,
                 from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/lib/Optimizer/Transforms/SetRuntimeCallAttributes.cpp:21:
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc:24:1:   in constexpr expansion of ‘std::basic_string_view<char>(((const char*)(& fir::runtime::RuntimeTableEntry<fir::runtime::RuntimeTableKey<Fortran::runtime::io::IoStatementState*(int, const char*, int)>, std::integer_sequence<char, '_', 'F', 'o', 'r', 't', 'r', 'a', 'n', 'A', 'i', 'o', 'B', 'e', 'g', 'i', 'n', 'B', 'a', 'c', 'k', 's', 'p', 'a', 'c', 'e'> >::name)))’
/usr/include/c++/7/string_view:100:22: error: ‘(((const char*)(& fir::runtime::RuntimeTableEntry<fir::runtime::RuntimeTableKey<Fortran::runtime::io::IoStatementState*(int, const char*, int)>, std::integer_sequence<char, '_', 'F', 'o', 'r', 't', 'r', 'a', 'n', 'A', 'i', 'o', 'B', 'e', 'g', 'i', 'n', 'B', 'a', 'c', 'k', 's', 'p', 'a', 'c', 'e'> >::name)) != 0)’ is not a constant expression
       : _M_len{__str == nullptr ? 0 : traits_type::length(__str)},
                ~~~~~~^~~~~~~~~~
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/lib/Optimizer/Transforms/SetRuntimeCallAttributes.cpp:205:1: error: non-constant condition for static assertion
 static_assert(runtimeFuncs.Verify() && "map must be sorted");
 ^~~~~~~~~~~~~
cc1plus: warning: unrecognized command line option ‘-Wno-ctad-maybe-unsupported’
cc1plus: warning: unrecognized command line option ‘-Wno-deprecated-copy’
171.799 [113/8/6982] Building CXX object tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/GenRuntimeCallsForTest.cpp.o
176.239 [113/7/6983] Building CXX object tools/flang/lib/Optimizer/Transforms/CMakeFiles/FIRTransforms.dir/PolymorphicOpConversion.cpp.o
180.129 [113/6/6984] Building CXX object tools/flang/lib/Optimizer/Support/CMakeFiles/FIRSupport.dir/InitFIR.cpp.o
185.352 [113/5/6985] Building CXX object tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/PFTBuilder.cpp.o
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/lib/Lower/PFTBuilder.cpp: In member function ‘void {anonymous}::SymbolVisitor::visitSymbol(const Fortran::semantics::Symbol&)’:
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/lib/Lower/PFTBuilder.cpp:2055:37: warning: unused variable ‘_’ [-Wunused-variable]
           for (const auto &[_, param] : derivedTypeSpec->parameters())
                                     ^
At global scope:
cc1plus: warning: unrecognized command line option ‘-Wno-ctad-maybe-unsupported’
cc1plus: warning: unrecognized command line option ‘-Wno-deprecated-copy’
189.415 [113/4/6986] Building CXX object tools/flang/tools/fir-opt/CMakeFiles/fir-opt.dir/fir-opt.cpp.o
195.012 [113/3/6987] Building CXX object tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/ConvertExpr.cpp.o
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/lib/Lower/ConvertExpr.cpp: In lambda function:
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/flang/lib/Lower/ConvertExpr.cpp:4677:33: warning: unused variable ‘_’ [-Wunused-variable]

vzakhari added a commit that referenced this pull request Feb 24, 2025
vzakhari added a commit that referenced this pull request Feb 24, 2025
… runtime. (#128093)"

This change is inspired by a case in facerec benchmark, where
performance
of scalar code may improve by about 6%@aarch64 due to getting rid of
redundant
loads from Fortran descriptors. These descriptors are corresponding
to subroutine local ALLOCATABLE, SAVE variables. The scalar loop nest
in LocalMove subroutine contains call to Fortran runtime IO functions,
and LLVM globals-aa analysis cannot prove that these calls do not modify
the globalized descriptors with internal linkage.

This patch sets and propagates llvm.memory_effects attribute for
fir.call
operations calling Fortran runtime functions. In particular, it tries
to set the Other memory effect to NoModRef. The Other memory effect
includes accesses to globals and captured pointers, so we cannot set
it for functions taking Fortran descriptors with one exception
for calls where the Fortran descriptor arguments are all null.

As long as different calls to the same Fortran runtime function may have
different attributes, I decided to attach the attributes to the calls
rather than functions. Moreover, attaching the attributes to func.func
will require propagating these attributes to llvm.func, which is not
happening right now.

In addition to llvm.memory_effects, the new pass sets llvm.nosync
and llvm.nocallback attributes that may also help LLVM alias analysis
(e.g. see #127707). These attributes are ignored currently.
I will support them in LLVM IR dialect in a separate patch.

I also added another pass for developers to be able to print
declarations/calls of all Fortran runtime functions that are recognized
by the attributes setting pass. It should help with maintenance
of the LIT tests.
@llvm-ci
Copy link
Collaborator

llvm-ci commented Feb 24, 2025

LLVM Buildbot has detected a new failure on builder premerge-monolithic-windows running on premerge-windows-1 while building flang at step 5 "clean-build-dir".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/35/builds/7581

Here is the relevant piece of the build log for the reference
Step 5 (clean-build-dir) failure: Delete failed. (failure)
Step 7 (build-unified-tree) failure: build (failure)
...
[8525/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-if-stmt.cpp.obj
[8526/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-io.cpp.obj
[8527/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-namelist.cpp.obj
[8528/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-omp-structure.cpp.obj
[8529/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-nullify.cpp.obj
[8530/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-purity.cpp.obj
[8531/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-select-rank.cpp.obj
[8532/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-return.cpp.obj
[8533/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-select-type.cpp.obj
[8534/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-stop.cpp.obj
FAILED: tools/flang/lib/Semantics/CMakeFiles/FortranSemantics.dir/check-stop.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Semantics -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Semantics -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\check-stop.cpp.obj /Fdtools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\FortranSemantics.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Semantics\check-stop.cpp
[8535/13500] Building CXX object tools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\compute-offsets.cpp.obj
FAILED: tools/flang/lib/Semantics/CMakeFiles/FortranSemantics.dir/compute-offsets.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Semantics -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Semantics -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\compute-offsets.cpp.obj /Fdtools\flang\lib\Semantics\CMakeFiles\FortranSemantics.dir\FortranSemantics.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Semantics\compute-offsets.cpp
[8536/13500] Building CXX object tools\flang\lib\Lower\CMakeFiles\FortranLower.dir\VectorSubscripts.cpp.obj
FAILED: tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/VectorSubscripts.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Lower\CMakeFiles\FortranLower.dir\VectorSubscripts.cpp.obj /Fdtools\flang\lib\Lower\CMakeFiles\FortranLower.dir\FortranLower.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower\VectorSubscripts.cpp
C:\BuildTools\VC\Tools\MSVC\14.29.30133\include\utility(504): fatal error C1060: compiler is out of heap space
[8537/13500] Building CXX object tools\flang\lib\Lower\CMakeFiles\FortranLower.dir\Support\Utils.cpp.obj
FAILED: tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/Support/Utils.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Lower\CMakeFiles\FortranLower.dir\Support\Utils.cpp.obj /Fdtools\flang\lib\Lower\CMakeFiles\FortranLower.dir\FortranLower.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower\Support\Utils.cpp
C:\BuildTools\VC\Tools\MSVC\14.29.30133\include\variant(1529): fatal error C1060: compiler is out of heap space
[8538/13500] Building CXX object tools\flang\lib\Lower\CMakeFiles\FortranLower.dir\OpenMP\ClauseProcessor.cpp.obj
FAILED: tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/OpenMP/ClauseProcessor.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Lower\CMakeFiles\FortranLower.dir\OpenMP\ClauseProcessor.cpp.obj /Fdtools\flang\lib\Lower\CMakeFiles\FortranLower.dir\FortranLower.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower\OpenMP\ClauseProcessor.cpp
C:\BuildTools\VC\Tools\MSVC\14.29.30133\include\tuple(800): fatal error C1060: compiler is out of heap space
[8539/13500] Building CXX object tools\flang\lib\Lower\CMakeFiles\FortranLower.dir\Runtime.cpp.obj
FAILED: tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/Runtime.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Lower\CMakeFiles\FortranLower.dir\Runtime.cpp.obj /Fdtools\flang\lib\Lower\CMakeFiles\FortranLower.dir\FortranLower.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower\Runtime.cpp
C:\BuildTools\VC\Tools\MSVC\14.29.30133\include\variant(758): fatal error C1060: compiler is out of heap space
[8540/13500] Building CXX object tools\flang\lib\Lower\CMakeFiles\FortranLower.dir\ConvertExpr.cpp.obj
FAILED: tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/ConvertExpr.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Lower\CMakeFiles\FortranLower.dir\ConvertExpr.cpp.obj /Fdtools\flang\lib\Lower\CMakeFiles\FortranLower.dir\FortranLower.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower\ConvertExpr.cpp
C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower\ConvertExpr.cpp(3017): fatal error C1060: compiler is out of heap space
[8541/13500] Building CXX object tools\flang\lib\Lower\CMakeFiles\FortranLower.dir\Bridge.cpp.obj
FAILED: tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/Bridge.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Lower\CMakeFiles\FortranLower.dir\Bridge.cpp.obj /Fdtools\flang\lib\Lower\CMakeFiles\FortranLower.dir\FortranLower.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower\Bridge.cpp
C:\BuildTools\VC\Tools\MSVC\14.29.30133\include\tuple(819): fatal error C1060: compiler is out of heap space
[8542/13500] Building CXX object tools\flang\lib\Lower\CMakeFiles\FortranLower.dir\OpenMP\PrivateReductionUtils.cpp.obj
FAILED: tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/OpenMP/PrivateReductionUtils.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Lower\CMakeFiles\FortranLower.dir\OpenMP\PrivateReductionUtils.cpp.obj /Fdtools\flang\lib\Lower\CMakeFiles\FortranLower.dir\FortranLower.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower\OpenMP\PrivateReductionUtils.cpp
C:\BuildTools\VC\Tools\MSVC\14.29.30133\include\variant(777): fatal error C1060: compiler is out of heap space
[8543/13500] Building CXX object tools\flang\lib\Lower\CMakeFiles\FortranLower.dir\CustomIntrinsicCall.cpp.obj
FAILED: tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/CustomIntrinsicCall.cpp.obj 
sccache C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe  /nologo /TP -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\include -Itools\flang\include -Iinclude -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\..\mlir\include -Itools\mlir\include -Itools\clang\include -IC:\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\..\clang\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2  -MD  /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\flang\lib\Lower\CMakeFiles\FortranLower.dir\CustomIntrinsicCall.cpp.obj /Fdtools\flang\lib\Lower\CMakeFiles\FortranLower.dir\FortranLower.pdb /FS -c C:\ws\buildbot\premerge-monolithic-windows\llvm-project\flang\lib\Lower\CustomIntrinsicCall.cpp
C:\BuildTools\VC\Tools\MSVC\14.29.30133\include\variant(1504): fatal error C1060: compiler is out of heap space
[8544/13500] Building CXX object tools\flang\lib\Lower\CMakeFiles\FortranLower.dir\Allocatable.cpp.obj
FAILED: tools/flang/lib/Lower/CMakeFiles/FortranLower.dir/Allocatable.cpp.obj 

@llvm-ci
Copy link
Collaborator

llvm-ci commented Apr 11, 2025

LLVM Buildbot has detected a new failure on builder flang-x86_64-windows running on minipc-ryzen-win while building flang at step 6 "build-unified-tree".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/166/builds/889

Here is the relevant piece of the build log for the reference
Step 6 (build-unified-tree) failure: build (failure)
...
-- Looking for stddef.h
-- Looking for stddef.h - not found
-- Check size of unsigned short
-- Check size of unsigned short - failed
-- Check size of unsigned int
-- Check size of unsigned int - failed
-- Check size of unsigned long
-- Check size of unsigned long - failed
-- Configuring incomplete, errors occurred!
2909.499 [3/2/6802] Generating ../../../../include/flang/ieee_arithmetic.mod
FAILED: runtimes/runtimes-stamps/runtimes-configure C:/buildbot/flang-x86_64-windows/build/runtimes/runtimes-stamps/runtimes-configure 
C:\Windows\system32\cmd.exe /C "cd /D C:\buildbot\flang-x86_64-windows\build\runtimes\runtimes-bins && "C:\Program Files\CMake\bin\cmake.exe" --no-warn-unused-cli -DCMAKE_C_COMPILER=C:/buildbot/flang-x86_64-windows/build/./bin/clang-cl.exe -DCMAKE_CXX_COMPILER=C:/buildbot/flang-x86_64-windows/build/./bin/clang-cl.exe -DCMAKE_ASM_COMPILER=C:/buildbot/flang-x86_64-windows/build/./bin/clang-cl.exe -DCMAKE_Fortran_COMPILER=C:/buildbot/flang-x86_64-windows/build/./bin/flang.exe -DCMAKE_AR=C:/buildbot/flang-x86_64-windows/build/./bin/llvm-lib.exe -DCMAKE_RANLIB=C:/buildbot/flang-x86_64-windows/build/./bin/llvm-ranlib.exe -DCMAKE_NM=C:/buildbot/flang-x86_64-windows/build/./bin/llvm-nm.exe -DCMAKE_OBJDUMP=C:/buildbot/flang-x86_64-windows/build/./bin/llvm-objdump.exe -DCMAKE_RC_COMPILER=C:/buildbot/flang-x86_64-windows/build/./bin/llvm-rc.exe -DCMAKE_C_COMPILER_TARGET=x86_64-pc-windows-msvc -DCMAKE_CXX_COMPILER_TARGET=x86_64-pc-windows-msvc -DCMAKE_Fortran_COMPILER_TARGET=x86_64-pc-windows-msvc -DCMAKE_ASM_COMPILER_TARGET=x86_64-pc-windows-msvc -DCMAKE_INSTALL_PREFIX=C:/buildbot/flang-x86_64-windows/flang.install -DLLVM_BINARY_DIR=C:/buildbot/flang-x86_64-windows/build -DLLVM_CONFIG_PATH=C:/buildbot/flang-x86_64-windows/build/bin/llvm-config.exe -DLLVM_ENABLE_WERROR=OFF -DLLVM_HOST_TRIPLE=x86_64-pc-windows-msvc -DLLVM_HAVE_LINK_VERSION_SCRIPT=0 -DLLVM_USE_RELATIVE_PATHS_IN_DEBUG_INFO=OFF -DLLVM_USE_RELATIVE_PATHS_IN_FILES=OFF "-DLLVM_LIT_ARGS=-v -vv" -DLLVM_SOURCE_PREFIX= -DPACKAGE_VERSION=21.0.0git -DCMAKE_BUILD_TYPE=Release -DCMAKE_MAKE_PROGRAM=C:/ProgramData/chocolatey/bin/ninja.exe -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCOMPILER_RT_BUILD_BUILTINS=Off -DLLVM_INCLUDE_TESTS=ON -DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-pc-windows-msvc -DLLVM_ENABLE_PROJECTS_USED=ON -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF -DLLVM_BUILD_TOOLS=ON -DCMAKE_C_COMPILER_WORKS=ON -DCMAKE_CXX_COMPILER_WORKS=ON -DCMAKE_Fortran_COMPILER_WORKS=ON -DCMAKE_ASM_COMPILER_WORKS=ON -DHAVE_LLVM_LIT=ON -DCLANG_RESOURCE_DIR= -DLLVM_ENABLE_RUNTIMES=compiler-rt;flang-rt -DFFI_INCLUDE_DIR= -DFFI_LIBRARY_DIR= -DFLANG_RUNTIME_F128_MATH_LIB= -GNinja -CC:/buildbot/flang-x86_64-windows/build/projects/runtimes/tmp/runtimes-cache-Release.cmake -S C:/buildbot/flang-x86_64-windows/llvm-project/llvm/runtimes/../../runtimes -B C:/buildbot/flang-x86_64-windows/build/runtimes/runtimes-bins && "C:\Program Files\CMake\bin\cmake.exe" -E touch C:/buildbot/flang-x86_64-windows/build/runtimes/runtimes-stamps/runtimes-configure"
ninja: build stopped: subcommand failed.
CMake Error at C:/Program Files/CMake/share/cmake-3.31/Modules/TestBigEndian.cmake:72 (message):
  no suitable type found
Call Stack (most recent call first):
  C:/Program Files/CMake/share/cmake-3.31/Modules/TestBigEndian.cmake:37 (__TEST_BIG_ENDIAN_LEGACY_IMPL)
  C:/buildbot/flang-x86_64-windows/llvm-project/flang/cmake/modules/FlangCommon.cmake:38 (test_big_endian)
  C:/buildbot/flang-x86_64-windows/llvm-project/flang-rt/CMakeLists.txt:67 (include)



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:codegen flang:driver flang:fir-hlfir flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants