@@ -1828,6 +1828,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
18281828 setCurrentPosition (stmt.source );
18291829 assert (stmt.typedCall && " Call was not analyzed" );
18301830 mlir::Value res{};
1831+
1832+ // Set 'no_inline', 'inline_hint' or 'always_inline' to true on the
1833+ // ProcedureRef. The NoInline and AlwaysInline attribute will be set in
1834+ // genProcedureRef later.
1835+ for (const auto *dir : eval.dirs ) {
1836+ Fortran::common::visit (
1837+ Fortran::common::visitors{
1838+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
1839+ stmt.typedCall ->set_alwaysInline (true );
1840+ },
1841+ [&](const Fortran::parser::CompilerDirective::Inline &) {
1842+ stmt.typedCall ->set_inlineHint (true );
1843+ },
1844+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
1845+ stmt.typedCall ->set_noInline (true );
1846+ },
1847+ [&](const auto &) {}},
1848+ dir->u );
1849+ }
1850+
18311851 if (lowerToHighLevelFIR ()) {
18321852 std::optional<mlir::Type> resultType;
18331853 if (stmt.typedCall ->hasAlternateReturns ())
@@ -2053,6 +2073,50 @@ class FirConverter : public Fortran::lower::AbstractConverter {
20532073 // so no clean-up needs to be generated for these entities.
20542074 }
20552075
2076+ void attachInlineAttributes (
2077+ mlir::Operation &op,
2078+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs) {
2079+ if (dirs.empty ())
2080+ return ;
2081+
2082+ for (mlir::Value operand : op.getOperands ()) {
2083+ if (operand.getDefiningOp ())
2084+ attachInlineAttributes (*operand.getDefiningOp (), dirs);
2085+ }
2086+
2087+ if (fir::CallOp callOp = mlir::dyn_cast<fir::CallOp>(op)) {
2088+ for (const auto *dir : dirs) {
2089+ Fortran::common::visit (
2090+ Fortran::common::visitors{
2091+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
2092+ callOp.setInlineAttr (fir::FortranInlineEnum::no_inline);
2093+ },
2094+ [&](const Fortran::parser::CompilerDirective::Inline &) {
2095+ callOp.setInlineAttr (fir::FortranInlineEnum::inline_hint);
2096+ },
2097+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
2098+ callOp.setInlineAttr (fir::FortranInlineEnum::always_inline);
2099+ },
2100+ [&](const auto &) {}},
2101+ dir->u );
2102+ }
2103+ }
2104+ }
2105+
2106+ void attachAttributesToDoLoopOperations (
2107+ fir::DoLoopOp &doLoop,
2108+ llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
2109+ if (!doLoop.getOperation () || dirs.empty ())
2110+ return ;
2111+
2112+ for (mlir::Block &block : doLoop.getRegion ()) {
2113+ for (mlir::Operation &op : block.getOperations ()) {
2114+ if (!dirs.empty ())
2115+ attachInlineAttributes (op, dirs);
2116+ }
2117+ }
2118+ }
2119+
20562120 // / Generate FIR for a DO construct. There are six variants:
20572121 // / - unstructured infinite and while loops
20582122 // / - structured and unstructured increment loops
@@ -2162,6 +2226,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
21622226
21632227 // This call may generate a branch in some contexts.
21642228 genFIR (endDoEval, unstructuredContext);
2229+
2230+ // Add attribute(s) on operations in fir::DoLoopOp if necessary
2231+ for (IncrementLoopInfo &info : incrementLoopNestInfo)
2232+ attachAttributesToDoLoopOperations (info.doLoop , doStmtEval.dirs );
21652233 }
21662234
21672235 // / Generate FIR to evaluate loop control values (lower, upper and step).
@@ -2935,6 +3003,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
29353003 e->dirs .push_back (&dir);
29363004 }
29373005
3006+ void
3007+ attachInliningDirectiveToStmt (const Fortran::parser::CompilerDirective &dir,
3008+ Fortran::lower::pft::Evaluation *e) {
3009+ while (e->isDirective ())
3010+ e = e->lexicalSuccessor ;
3011+
3012+ // If the successor is a statement or a do loop, the compiler
3013+ // will perform inlining.
3014+ if (e->isA <Fortran::parser::CallStmt>() ||
3015+ e->isA <Fortran::parser::NonLabelDoStmt>() ||
3016+ e->isA <Fortran::parser::AssignmentStmt>()) {
3017+ e->dirs .push_back (&dir);
3018+ } else {
3019+ mlir::Location loc = toLocation ();
3020+ mlir::emitWarning (loc,
3021+ " Inlining directive not in front of loops, function"
3022+ " call or assignment.\n " );
3023+ }
3024+ }
3025+
29383026 void genFIR (const Fortran::parser::CompilerDirective &dir) {
29393027 Fortran::lower::pft::Evaluation &eval = getEval ();
29403028
@@ -2958,6 +3046,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
29583046 [&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
29593047 attachDirectiveToLoop (dir, &eval);
29603048 },
3049+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
3050+ attachInliningDirectiveToStmt (dir, &eval);
3051+ },
3052+ [&](const Fortran::parser::CompilerDirective::Inline &) {
3053+ attachInliningDirectiveToStmt (dir, &eval);
3054+ },
3055+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
3056+ attachInliningDirectiveToStmt (dir, &eval);
3057+ },
29613058 [&](const auto &) {}},
29623059 dir.u );
29633060 }
@@ -4761,7 +4858,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
47614858
47624859 void genDataAssignment (
47634860 const Fortran::evaluate::Assignment &assign,
4764- const Fortran::evaluate::ProcedureRef *userDefinedAssignment) {
4861+ const Fortran::evaluate::ProcedureRef *userDefinedAssignment,
4862+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs =
4863+ {}) {
47654864 mlir::Location loc = getCurrentLocation ();
47664865 fir::FirOpBuilder &builder = getFirOpBuilder ();
47674866
@@ -4834,12 +4933,22 @@ class FirConverter : public Fortran::lower::AbstractConverter {
48344933 Fortran::lower::StatementContext localStmtCtx;
48354934 hlfir::Entity rhs = evaluateRhs (localStmtCtx);
48364935 hlfir::Entity lhs = evaluateLhs (localStmtCtx);
4837- if (isCUDATransfer && !hasCUDAImplicitTransfer)
4936+ if (isCUDATransfer && !hasCUDAImplicitTransfer) {
48384937 genCUDADataTransfer (builder, loc, assign, lhs, rhs);
4839- else
4938+ } else {
4939+ // If RHS or LHS have a CallOp in their expression, this operation will
4940+ // have the 'no_inline' or 'always_inline' attribute if there is a
4941+ // directive just before the assignement.
4942+ if (!dirs.empty ()) {
4943+ if (rhs.getDefiningOp ())
4944+ attachInlineAttributes (*rhs.getDefiningOp (), dirs);
4945+ if (lhs.getDefiningOp ())
4946+ attachInlineAttributes (*lhs.getDefiningOp (), dirs);
4947+ }
48404948 builder.create <hlfir::AssignOp>(loc, rhs, lhs,
48414949 isWholeAllocatableAssignment,
48424950 keepLhsLengthInAllocatableAssignment);
4951+ }
48434952 if (hasCUDAImplicitTransfer && !isInDeviceContext) {
48444953 localSymbols.popScope ();
48454954 for (mlir::Value temp : implicitTemps)
@@ -4907,16 +5016,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
49075016 }
49085017
49095018 // / Shared for both assignments and pointer assignments.
4910- void genAssignment (const Fortran::evaluate::Assignment &assign) {
5019+ void
5020+ genAssignment (const Fortran::evaluate::Assignment &assign,
5021+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *>
5022+ &dirs = {}) {
49115023 mlir::Location loc = toLocation ();
49125024 if (lowerToHighLevelFIR ()) {
49135025 Fortran::common::visit (
49145026 Fortran::common::visitors{
49155027 [&](const Fortran::evaluate::Assignment::Intrinsic &) {
4916- genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr );
5028+ genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr ,
5029+ dirs);
49175030 },
49185031 [&](const Fortran::evaluate::ProcedureRef &procRef) {
4919- genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef);
5032+ genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef,
5033+ dirs);
49205034 },
49215035 [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
49225036 if (isInsideHlfirForallOrWhere ())
@@ -5321,7 +5435,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
53215435 }
53225436
53235437 void genFIR (const Fortran::parser::AssignmentStmt &stmt) {
5324- genAssignment (*stmt.typedAssignment ->v );
5438+ Fortran::lower::pft::Evaluation &eval = getEval ();
5439+ genAssignment (*stmt.typedAssignment ->v , eval.dirs );
53255440 }
53265441
53275442 void genFIR (const Fortran::parser::SyncAllStmt &stmt) {
0 commit comments