[flang-commits] [flang] [flang] Implement !DIR$ [NO]INLINE directives (PR #134350)

via flang-commits flang-commits at lists.llvm.org
Thu Apr 3 23:46:28 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics

@llvm/pr-subscribers-flang-parser

Author: Jean-Didier PAILLEUX (JDPailleux)

<details>
<summary>Changes</summary>

This patch adds the support of these two directives : `!dir$ inline` and `!dir$ noinline`. 
- `!dir$ noinline` tells to the compiler to not perform inlining on specific function calls by adding the `noinline` metadata on the call.
- `!dir$ inline` tells to the compiler to not perform inlining on specific function calls by adding the `alwaysinline` metadata on the call.

Currently, these directives can be placed before a `DO LOOP`, call functions or assignments. Maybe other statements can be added in the future if needed.

For the `inline` directive the correct name might be `forceinline` but I'm not sure ?

---

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


15 Files Affected:

- (modified) flang/docs/Directives.md (+6) 
- (modified) flang/include/flang/Evaluate/call.h (+7) 
- (modified) flang/include/flang/Optimizer/Dialect/FIROps.td (+2) 
- (modified) flang/include/flang/Parser/dump-parse-tree.h (+2) 
- (modified) flang/include/flang/Parser/parse-tree.h (+5-1) 
- (modified) flang/lib/Lower/Bridge.cpp (+113-7) 
- (modified) flang/lib/Lower/ConvertCall.cpp (+7-1) 
- (modified) flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp (+3-1) 
- (modified) flang/lib/Parser/Fortran-parsers.cpp (+5) 
- (modified) flang/lib/Parser/unparse.cpp (+4) 
- (modified) flang/lib/Semantics/canonicalize-directives.cpp (+3-1) 
- (modified) flang/lib/Semantics/resolve-names.cpp (+3-1) 
- (added) flang/test/Integration/inline_directive.f90 (+51) 
- (added) flang/test/Lower/inline_directive.f90 (+51) 
- (modified) flang/test/Parser/compiler-directives.f90 (+20) 


``````````diff
diff --git a/flang/docs/Directives.md b/flang/docs/Directives.md
index 91c27cb510ea0..4f3748bf79722 100644
--- a/flang/docs/Directives.md
+++ b/flang/docs/Directives.md
@@ -53,6 +53,12 @@ A list of non-standard directives supported by Flang
 * `!dir$ novector` disabling vectorization on the following loop.
 * `!dir$ nounroll` disabling unrolling on the following loop.
 * `!dir$ nounroll_and_jam` disabling unrolling and jamming on the following loop.
+* `!dir$ inline` tells the compiler to attempt to inline routines if 
+  this directive is specified before a call statement or for all call function statements
+  within a DO LOOP. This directive can be improved later to support other place(s) for  
+  inlining function calls.
+* `!dir$ noinline` works in the same way as the `inline` directive, but prevents 
+  any attempt of inlining by the compiler on a function call statement.
 
 # Directive Details
 
diff --git a/flang/include/flang/Evaluate/call.h b/flang/include/flang/Evaluate/call.h
index 2a5929b873d74..7a1bad030c88f 100644
--- a/flang/include/flang/Evaluate/call.h
+++ b/flang/include/flang/Evaluate/call.h
@@ -254,6 +254,11 @@ class ProcedureRef {
   bool IsElemental() const { return proc_.IsElemental(); }
   bool hasAlternateReturns() const { return hasAlternateReturns_; }
 
+  bool hasNoInline() const { return noInline_; }
+  void set_noInline(bool ni) { noInline_ = ni; }
+  bool hasAlwaysInline() const { return alwaysInline_; }
+  void set_alwaysInline(bool ai) { alwaysInline_ = ai; }
+
   Expr<SomeType> *UnwrapArgExpr(int n) {
     if (static_cast<std::size_t>(n) < arguments_.size() && arguments_[n]) {
       return arguments_[n]->UnwrapExpr();
@@ -277,6 +282,8 @@ class ProcedureRef {
   ActualArguments arguments_;
   Chevrons chevrons_;
   bool hasAlternateReturns_;
+  bool noInline_{false};
+  bool alwaysInline_{false};
 };
 
 template <typename A> class FunctionRef : public ProcedureRef {
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 753e4bd18dc6d..18a198ca061b7 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -2490,6 +2490,8 @@ def fir_CallOp : fir_Op<"call",
     OptionalAttr<DictArrayAttr>:$arg_attrs,
     OptionalAttr<DictArrayAttr>:$res_attrs,
     OptionalAttr<fir_FortranProcedureFlagsAttr>:$procedure_attrs,
+    OptionalAttr<UnitAttr>:$no_inline,
+    OptionalAttr<UnitAttr>:$always_inline,
     DefaultValuedAttr<Arith_FastMathAttr,
                       "::mlir::arith::FastMathFlags::none">:$fastmath
   );
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index c66f0735f33f0..4e6e2aa4f0f8d 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -204,8 +204,10 @@ class ParseTreeDumper {
   NODE(parser, CompilerDirective)
   NODE(CompilerDirective, AssumeAligned)
   NODE(CompilerDirective, IgnoreTKR)
+  NODE(CompilerDirective, Inline)
   NODE(CompilerDirective, LoopCount)
   NODE(CompilerDirective, NameValue)
+  NODE(CompilerDirective, NoInline)
   NODE(CompilerDirective, Unrecognized)
   NODE(CompilerDirective, VectorAlways)
   NODE(CompilerDirective, Unroll)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index eeb438991feee..e86da56bb9d3d 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3354,6 +3354,8 @@ struct StmtFunctionStmt {
 // !DIR$ NOVECTOR
 // !DIR$ NOUNROLL
 // !DIR$ NOUNROLL_AND_JAM
+// !DIR$ INLINE
+// !DIR$ NOINLINE
 // !DIR$ <anything else>
 struct CompilerDirective {
   UNION_CLASS_BOILERPLATE(CompilerDirective);
@@ -3382,11 +3384,13 @@ struct CompilerDirective {
   EMPTY_CLASS(NoVector);
   EMPTY_CLASS(NoUnroll);
   EMPTY_CLASS(NoUnrollAndJam);
+  EMPTY_CLASS(Inline);
+  EMPTY_CLASS(NoInline);
   EMPTY_CLASS(Unrecognized);
   CharBlock source;
   std::variant<std::list<IgnoreTKR>, LoopCount, std::list<AssumeAligned>,
       VectorAlways, std::list<NameValue>, Unroll, UnrollAndJam, Unrecognized,
-      NoVector, NoUnroll, NoUnrollAndJam>
+      NoVector, NoUnroll, NoUnrollAndJam, Inline, NoInline>
       u;
 };
 
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 65edf1cea8761..9bad56448a3ea 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -1828,6 +1828,23 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     setCurrentPosition(stmt.source);
     assert(stmt.typedCall && "Call was not analyzed");
     mlir::Value res{};
+
+    // Set 'no_inline' or 'always_inline' to true on the ProcedureRef.
+    // The NoInline and AlwaysInline attribute will be set in genProcedureRef
+    // later.
+    for (const auto *dir : eval.dirs) {
+      Fortran::common::visit(
+          Fortran::common::visitors{
+              [&](const Fortran::parser::CompilerDirective::Inline &) {
+                stmt.typedCall->set_alwaysInline(true);
+              },
+              [&](const Fortran::parser::CompilerDirective::NoInline &) {
+                stmt.typedCall->set_noInline(true);
+              },
+              [&](const auto &) {}},
+          dir->u);
+    }
+
     if (lowerToHighLevelFIR()) {
       std::optional<mlir::Type> resultType;
       if (stmt.typedCall->hasAlternateReturns())
@@ -2053,6 +2070,47 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     // so no clean-up needs to be generated for these entities.
   }
 
+  void attachInlineAttributes(
+      mlir::Operation &op,
+      const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs) {
+    if (dirs.empty())
+      return;
+
+    for (mlir::Value operand : op.getOperands()) {
+      if (operand.getDefiningOp())
+        attachInlineAttributes(*operand.getDefiningOp(), dirs);
+    }
+
+    if (fir::CallOp callOp = mlir::dyn_cast<fir::CallOp>(op)) {
+      for (const auto *dir : dirs) {
+        Fortran::common::visit(
+            Fortran::common::visitors{
+                [&](const Fortran::parser::CompilerDirective::NoInline &) {
+                  callOp.setNoInlineAttr(builder->getUnitAttr());
+                },
+                [&](const Fortran::parser::CompilerDirective::Inline &) {
+                  callOp.setAlwaysInlineAttr(builder->getUnitAttr());
+                },
+                [&](const auto &) {}},
+            dir->u);
+      }
+    }
+  }
+
+  void attachAttributesToDoLoopOperations(
+      fir::DoLoopOp &doLoop,
+      llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
+    if (!doLoop.getOperation() || dirs.empty())
+      return;
+
+    for (mlir::Block &block : doLoop.getRegion()) {
+      for (mlir::Operation &op : block.getOperations()) {
+        if (!dirs.empty())
+          attachInlineAttributes(op, dirs);
+      }
+    }
+  }
+
   /// Generate FIR for a DO construct. There are six variants:
   ///  - unstructured infinite and while loops
   ///  - structured and unstructured increment loops
@@ -2162,6 +2220,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
 
     // This call may generate a branch in some contexts.
     genFIR(endDoEval, unstructuredContext);
+
+    // Add attribute(s) on operations in fir::DoLoopOp if necessary
+    for (IncrementLoopInfo &info : incrementLoopNestInfo)
+      attachAttributesToDoLoopOperations(info.doLoop, doStmtEval.dirs);
   }
 
   /// Generate FIR to evaluate loop control values (lower, upper and step).
@@ -2935,6 +2997,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
       e->dirs.push_back(&dir);
   }
 
+  void
+  attachInliningDirectiveToStmt(const Fortran::parser::CompilerDirective &dir,
+                                Fortran::lower::pft::Evaluation *e) {
+    while (e->isDirective())
+      e = e->lexicalSuccessor;
+
+    // If the successor is a statement or a do loop, the compiler
+    // will perform inlining.
+    if (e->isA<Fortran::parser::CallStmt>() ||
+        e->isA<Fortran::parser::NonLabelDoStmt>() ||
+        e->isA<Fortran::parser::AssignmentStmt>()) {
+      e->dirs.push_back(&dir);
+    } else {
+      mlir::Location loc = toLocation();
+      mlir::emitWarning(loc,
+                        "Inlining directive not in front of loops, function"
+                        "call or assignment.\n");
+    }
+  }
+
   void genFIR(const Fortran::parser::CompilerDirective &dir) {
     Fortran::lower::pft::Evaluation &eval = getEval();
 
@@ -2958,6 +3040,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
             [&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
               attachDirectiveToLoop(dir, &eval);
             },
+            [&](const Fortran::parser::CompilerDirective::Inline &) {
+              attachInliningDirectiveToStmt(dir, &eval);
+            },
+            [&](const Fortran::parser::CompilerDirective::NoInline &) {
+              attachInliningDirectiveToStmt(dir, &eval);
+            },
             [&](const auto &) {}},
         dir.u);
   }
@@ -4763,7 +4851,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
 
   void genDataAssignment(
       const Fortran::evaluate::Assignment &assign,
-      const Fortran::evaluate::ProcedureRef *userDefinedAssignment) {
+      const Fortran::evaluate::ProcedureRef *userDefinedAssignment,
+      const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs =
+          {}) {
     mlir::Location loc = getCurrentLocation();
     fir::FirOpBuilder &builder = getFirOpBuilder();
 
@@ -4836,12 +4926,22 @@ class FirConverter : public Fortran::lower::AbstractConverter {
       Fortran::lower::StatementContext localStmtCtx;
       hlfir::Entity rhs = evaluateRhs(localStmtCtx);
       hlfir::Entity lhs = evaluateLhs(localStmtCtx);
-      if (isCUDATransfer && !hasCUDAImplicitTransfer)
+      if (isCUDATransfer && !hasCUDAImplicitTransfer) {
         genCUDADataTransfer(builder, loc, assign, lhs, rhs);
-      else
+      } else {
+        // If RHS or LHS have a CallOp in their expression, this operation will
+        // have the 'no_inline' or 'always_inline' attribute if there is a
+        // directive just before the assignement.
+        if (!dirs.empty()) {
+          if (rhs.getDefiningOp())
+            attachInlineAttributes(*rhs.getDefiningOp(), dirs);
+          if (lhs.getDefiningOp())
+            attachInlineAttributes(*lhs.getDefiningOp(), dirs);
+        }
         builder.create<hlfir::AssignOp>(loc, rhs, lhs,
                                         isWholeAllocatableAssignment,
                                         keepLhsLengthInAllocatableAssignment);
+      }
       if (hasCUDAImplicitTransfer && !isInDeviceContext) {
         localSymbols.popScope();
         for (mlir::Value temp : implicitTemps)
@@ -4909,16 +5009,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
   }
 
   /// Shared for both assignments and pointer assignments.
-  void genAssignment(const Fortran::evaluate::Assignment &assign) {
+  void
+  genAssignment(const Fortran::evaluate::Assignment &assign,
+                const llvm::ArrayRef<const Fortran::parser::CompilerDirective *>
+                    &dirs = {}) {
     mlir::Location loc = toLocation();
     if (lowerToHighLevelFIR()) {
       Fortran::common::visit(
           Fortran::common::visitors{
               [&](const Fortran::evaluate::Assignment::Intrinsic &) {
-                genDataAssignment(assign, /*userDefinedAssignment=*/nullptr);
+                genDataAssignment(assign, /*userDefinedAssignment=*/nullptr,
+                                  dirs);
               },
               [&](const Fortran::evaluate::ProcedureRef &procRef) {
-                genDataAssignment(assign, /*userDefinedAssignment=*/&procRef);
+                genDataAssignment(assign, /*userDefinedAssignment=*/&procRef,
+                                  dirs);
               },
               [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
                 if (isInsideHlfirForallOrWhere())
@@ -5323,7 +5428,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
   }
 
   void genFIR(const Fortran::parser::AssignmentStmt &stmt) {
-    genAssignment(*stmt.typedAssignment->v);
+    Fortran::lower::pft::Evaluation &eval = getEval();
+    genAssignment(*stmt.typedAssignment->v, eval.dirs);
   }
 
   void genFIR(const Fortran::parser::SyncAllStmt &stmt) {
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 6a0f4d1090adc..fe8d84c2c8c37 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -647,9 +647,15 @@ Fortran::lower::genCallOpAndResult(
       callResult = dispatch.getResult(0);
   } else {
     // Standard procedure call with fir.call.
+    mlir::UnitAttr noinlineAttr, alwaysinlineAttr;
+    if (caller.getCallDescription().hasNoInline())
+      noinlineAttr = builder.getUnitAttr();
+    else if (caller.getCallDescription().hasAlwaysInline())
+      alwaysinlineAttr = builder.getUnitAttr();
     auto call = builder.create<fir::CallOp>(
         loc, funcType.getResults(), funcSymbolAttr, operands,
-        /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, procAttrs);
+        /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, procAttrs, noinlineAttr,
+        alwaysinlineAttr);
 
     callNumResults = call.getNumResults();
     if (callNumResults != 0)
diff --git a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
index 0c78a878cdc53..eff623d983535 100644
--- a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
@@ -207,7 +207,9 @@ struct DispatchOpConv : public OpConversionPattern<fir::DispatchOp> {
     args.append(dispatch.getArgs().begin(), dispatch.getArgs().end());
     rewriter.replaceOpWithNewOp<fir::CallOp>(
         dispatch, resTypes, nullptr, args, dispatch.getArgAttrsAttr(),
-        dispatch.getResAttrsAttr(), dispatch.getProcedureAttrsAttr());
+        dispatch.getResAttrsAttr(), dispatch.getProcedureAttrsAttr(),
+        /*no_inline*/ mlir::UnitAttr{},
+        /*alwais_inline*/ mlir::UnitAttr{});
     return mlir::success();
   }
 
diff --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp
index fbe629ab52935..ef9d4b191ad15 100644
--- a/flang/lib/Parser/Fortran-parsers.cpp
+++ b/flang/lib/Parser/Fortran-parsers.cpp
@@ -1314,6 +1314,9 @@ constexpr auto novector{"NOVECTOR" >> construct<CompilerDirective::NoVector>()};
 constexpr auto nounroll{"NOUNROLL" >> construct<CompilerDirective::NoUnroll>()};
 constexpr auto nounrollAndJam{
     "NOUNROLL_AND_JAM" >> construct<CompilerDirective::NoUnrollAndJam>()};
+constexpr auto inlineDir{"INLINE" >> construct<CompilerDirective::Inline>()};
+constexpr auto noinlineDir{
+    "NOINLINE" >> construct<CompilerDirective::NoInline>()};
 TYPE_PARSER(beginDirective >> "DIR$ "_tok >>
     sourced((construct<CompilerDirective>(ignore_tkr) ||
                 construct<CompilerDirective>(loopCount) ||
@@ -1324,6 +1327,8 @@ TYPE_PARSER(beginDirective >> "DIR$ "_tok >>
                 construct<CompilerDirective>(novector) ||
                 construct<CompilerDirective>(nounrollAndJam) ||
                 construct<CompilerDirective>(nounroll) ||
+                construct<CompilerDirective>(noinlineDir) ||
+                construct<CompilerDirective>(inlineDir) ||
                 construct<CompilerDirective>(
                     many(construct<CompilerDirective::NameValue>(
                         name, maybe(("="_tok || ":"_tok) >> digitString64))))) /
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 47dae0ae753d2..f7eaab45fb77b 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -1864,6 +1864,10 @@ class UnparseVisitor {
             [&](const CompilerDirective::NoUnrollAndJam &) {
               Word("!DIR$ NOUNROLL_AND_JAM");
             },
+            [&](const CompilerDirective::Inline &) { Word("!DIR$ INLINE"); },
+            [&](const CompilerDirective::NoInline &) {
+              Word("!DIR$ NOINLINE");
+            },
             [&](const CompilerDirective::Unrecognized &) {
               Word("!DIR$ ");
               Word(x.source.ToString());
diff --git a/flang/lib/Semantics/canonicalize-directives.cpp b/flang/lib/Semantics/canonicalize-directives.cpp
index 104df253ab642..ab6f801a6d350 100644
--- a/flang/lib/Semantics/canonicalize-directives.cpp
+++ b/flang/lib/Semantics/canonicalize-directives.cpp
@@ -60,7 +60,9 @@ static bool IsExecutionDirective(const parser::CompilerDirective &dir) {
       std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(dir.u) ||
       std::holds_alternative<parser::CompilerDirective::NoVector>(dir.u) ||
       std::holds_alternative<parser::CompilerDirective::NoUnroll>(dir.u) ||
-      std::holds_alternative<parser::CompilerDirective::NoUnrollAndJam>(dir.u);
+      std::holds_alternative<parser::CompilerDirective::NoUnrollAndJam>(dir.u) ||
+      std::holds_alternative<parser::CompilerDirective::Inline>(dir.u) ||
+      std::holds_alternative<parser::CompilerDirective::NoInline>(dir.u);
 }
 
 void CanonicalizationOfDirectives::Post(parser::SpecificationPart &spec) {
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 11c0ecc9e8410..1b67f351b7433 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -9576,7 +9576,9 @@ void ResolveNamesVisitor::Post(const parser::CompilerDirective &x) {
       std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(x.u) ||
       std::holds_alternative<parser::CompilerDirective::NoVector>(x.u) ||
       std::holds_alternative<parser::CompilerDirective::NoUnroll>(x.u) ||
-      std::holds_alternative<parser::CompilerDirective::NoUnrollAndJam>(x.u)) {
+      std::holds_alternative<parser::CompilerDirective::NoUnrollAndJam>(x.u) ||
+      std::holds_alternative<parser::CompilerDirective::Inline>(x.u) ||
+      std::holds_alternative<parser::CompilerDirective::NoInline>(x.u)) {
     return;
   }
   if (const auto *tkr{
diff --git a/flang/test/Integration/inline_directive.f90 b/flang/test/Integration/inline_directive.f90
new file mode 100644
index 0000000000000..6e55227e74b9a
--- /dev/null
+++ b/flang/test/Integration/inline_directive.f90
@@ -0,0 +1,51 @@
+! RUN: %flang_fc1 -emit-llvm -o - %s | FileCheck %s
+
+! CHECK-LABEL: test_inline
+subroutine test_inline()
+  integer :: x, y
+!CHECK:  %[[VAL_1:.*]] = alloca i32, i64 1, align 4
+!CHECK:  %[[VAL_2:.*]] = alloca i32, i64 1, align 4
+!CHECK:  %[[VAL_3:.*]] = alloca i32, i64 1, align 4
+!CHECK:  %[[VAL_4:.*]] = alloca i32, i64 1, align 4
+
+  !dir$ inline
+  y = g(x)
+  !dir$ inline
+  call f(x, y)
+!CHECK:  %[[VAL_5:.*]] = load i32, ptr %[[VAL_3]], align 4
+!CHECK:  %[[VAL_6:.*]] = mul i32 %[[VAL_5]], 2
+!CHECK:  store i32 %6, ptr %[[VAL_1]], align 4
+!CHECK:  %[[VAL_7:.*]] = load i32, ptr %[[VAL_1]], align 4
+!CHECK:  store i32 %7, ptr %[[VAL_2]], align 4
+!CHECK:  %[[VAL_8:.]] = load i32, ptr %[[VAL_3]], align 4
+!CHECK:  %[[VAL_9:.]] = mul i32 %[[VAL_8]], 2
+!CHECK:  store i32 %9, ptr %[[VAL_2]], align 4
+
+  !dir$ noinline
+  y = g(x)
+  !dir$ noinline
+  call f(x, y)
+!CHECK:  %[[VAL_10:.*]] = call i32 @_QFtest_inlinePg(ptr %[[VAL_3]]) #[[NOINLINE:.*]]
+!CHECK:  store i32 %[[VAL_10]], ptr %[[VAL_2]], align 4
+!CHECK:  call void @_QFtest_inlinePf(ptr %[[VAL_3]], ptr %[[VAL_2]]) #[[NOINLINE]]
+
+  !dir$ noinline
+  do i = 1, 100
+    call f(x, y)
+    !CHECK: br i1 %[[VAL_14:.*]], label %[[VAL_15:.*]], label %[[VAL_19:.*]]
+    !CHECK: call void @_QFtest_inlinePf(ptr %[[VAL_3]], ptr %[[VAL_2]]) #[[NOINLINE]]
+  enddo
+
+  contains
+    subroutine f(x, y)
+      integer, intent(in) :: x
+      integer, intent(out) :: y
+      y = x*2
+    end subroutine f
+    integer function g(x)
+      integer :: x
+      g = x*2
+    end function g
+end subroutine test_inline
+
+!CHECK: attributes #[[NOINLINE]] = { noinline }
diff --git a/flang/test/Lower/inline_directive.f90 b/flang/test/Lower/inline_directive.f90
new file mode 100644
index 0000000000000..a6b8300f59efe
--- /dev/null
+++ b/flang/test/Lower/inline_directive.f90
@@ -0,0 +1,51 @@
+! RUN: %flang_...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/134350


More information about the flang-commits mailing list