@@ -1828,6 +1828,23 @@ 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' or 'always_inline' to true on the ProcedureRef.
1833+ // The NoInline and AlwaysInline attribute will be set in genProcedureRef
1834+ // 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::NoInline &) {
1842+ stmt.typedCall ->set_noInline (true );
1843+ },
1844+ [&](const auto &) {}},
1845+ dir->u );
1846+ }
1847+
18311848 if (lowerToHighLevelFIR ()) {
18321849 std::optional<mlir::Type> resultType;
18331850 if (stmt.typedCall ->hasAlternateReturns ())
@@ -2053,6 +2070,47 @@ class FirConverter : public Fortran::lower::AbstractConverter {
20532070 // so no clean-up needs to be generated for these entities.
20542071 }
20552072
2073+ void attachInlineAttributes (
2074+ mlir::Operation &op,
2075+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs) {
2076+ if (dirs.empty ())
2077+ return ;
2078+
2079+ for (mlir::Value operand : op.getOperands ()) {
2080+ if (operand.getDefiningOp ())
2081+ attachInlineAttributes (*operand.getDefiningOp (), dirs);
2082+ }
2083+
2084+ if (fir::CallOp callOp = mlir::dyn_cast<fir::CallOp>(op)) {
2085+ for (const auto *dir : dirs) {
2086+ Fortran::common::visit (
2087+ Fortran::common::visitors{
2088+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
2089+ callOp.setNoInlineAttr (builder->getUnitAttr ());
2090+ },
2091+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
2092+ callOp.setAlwaysInlineAttr (builder->getUnitAttr ());
2093+ },
2094+ [&](const auto &) {}},
2095+ dir->u );
2096+ }
2097+ }
2098+ }
2099+
2100+ void attachAttributesToDoLoopOperations (
2101+ fir::DoLoopOp &doLoop,
2102+ llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
2103+ if (!doLoop.getOperation () || dirs.empty ())
2104+ return ;
2105+
2106+ for (mlir::Block &block : doLoop.getRegion ()) {
2107+ for (mlir::Operation &op : block.getOperations ()) {
2108+ if (!dirs.empty ())
2109+ attachInlineAttributes (op, dirs);
2110+ }
2111+ }
2112+ }
2113+
20562114 // / Generate FIR for a DO construct. There are six variants:
20572115 // / - unstructured infinite and while loops
20582116 // / - structured and unstructured increment loops
@@ -2162,6 +2220,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
21622220
21632221 // This call may generate a branch in some contexts.
21642222 genFIR (endDoEval, unstructuredContext);
2223+
2224+ // Add attribute(s) on operations in fir::DoLoopOp if necessary
2225+ for (IncrementLoopInfo &info : incrementLoopNestInfo)
2226+ attachAttributesToDoLoopOperations (info.doLoop , doStmtEval.dirs );
21652227 }
21662228
21672229 // / Generate FIR to evaluate loop control values (lower, upper and step).
@@ -2935,6 +2997,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
29352997 e->dirs .push_back (&dir);
29362998 }
29372999
3000+ void
3001+ attachInliningDirectiveToStmt (const Fortran::parser::CompilerDirective &dir,
3002+ Fortran::lower::pft::Evaluation *e) {
3003+ while (e->isDirective ())
3004+ e = e->lexicalSuccessor ;
3005+
3006+ // If the successor is a statement or a do loop, the compiler
3007+ // will perform inlining.
3008+ if (e->isA <Fortran::parser::CallStmt>() ||
3009+ e->isA <Fortran::parser::NonLabelDoStmt>() ||
3010+ e->isA <Fortran::parser::AssignmentStmt>()) {
3011+ e->dirs .push_back (&dir);
3012+ } else {
3013+ mlir::Location loc = toLocation ();
3014+ mlir::emitWarning (loc,
3015+ " Inlining directive not in front of loops, function"
3016+ " call or assignment.\n " );
3017+ }
3018+ }
3019+
29383020 void genFIR (const Fortran::parser::CompilerDirective &dir) {
29393021 Fortran::lower::pft::Evaluation &eval = getEval ();
29403022
@@ -2958,6 +3040,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
29583040 [&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
29593041 attachDirectiveToLoop (dir, &eval);
29603042 },
3043+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
3044+ attachInliningDirectiveToStmt (dir, &eval);
3045+ },
3046+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
3047+ attachInliningDirectiveToStmt (dir, &eval);
3048+ },
29613049 [&](const auto &) {}},
29623050 dir.u );
29633051 }
@@ -4763,7 +4851,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
47634851
47644852 void genDataAssignment (
47654853 const Fortran::evaluate::Assignment &assign,
4766- const Fortran::evaluate::ProcedureRef *userDefinedAssignment) {
4854+ const Fortran::evaluate::ProcedureRef *userDefinedAssignment,
4855+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs =
4856+ {}) {
47674857 mlir::Location loc = getCurrentLocation ();
47684858 fir::FirOpBuilder &builder = getFirOpBuilder ();
47694859
@@ -4836,12 +4926,22 @@ class FirConverter : public Fortran::lower::AbstractConverter {
48364926 Fortran::lower::StatementContext localStmtCtx;
48374927 hlfir::Entity rhs = evaluateRhs (localStmtCtx);
48384928 hlfir::Entity lhs = evaluateLhs (localStmtCtx);
4839- if (isCUDATransfer && !hasCUDAImplicitTransfer)
4929+ if (isCUDATransfer && !hasCUDAImplicitTransfer) {
48404930 genCUDADataTransfer (builder, loc, assign, lhs, rhs);
4841- else
4931+ } else {
4932+ // If RHS or LHS have a CallOp in their expression, this operation will
4933+ // have the 'no_inline' or 'always_inline' attribute if there is a
4934+ // directive just before the assignement.
4935+ if (!dirs.empty ()) {
4936+ if (rhs.getDefiningOp ())
4937+ attachInlineAttributes (*rhs.getDefiningOp (), dirs);
4938+ if (lhs.getDefiningOp ())
4939+ attachInlineAttributes (*lhs.getDefiningOp (), dirs);
4940+ }
48424941 builder.create <hlfir::AssignOp>(loc, rhs, lhs,
48434942 isWholeAllocatableAssignment,
48444943 keepLhsLengthInAllocatableAssignment);
4944+ }
48454945 if (hasCUDAImplicitTransfer && !isInDeviceContext) {
48464946 localSymbols.popScope ();
48474947 for (mlir::Value temp : implicitTemps)
@@ -4909,16 +5009,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
49095009 }
49105010
49115011 // / Shared for both assignments and pointer assignments.
4912- void genAssignment (const Fortran::evaluate::Assignment &assign) {
5012+ void
5013+ genAssignment (const Fortran::evaluate::Assignment &assign,
5014+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *>
5015+ &dirs = {}) {
49135016 mlir::Location loc = toLocation ();
49145017 if (lowerToHighLevelFIR ()) {
49155018 Fortran::common::visit (
49165019 Fortran::common::visitors{
49175020 [&](const Fortran::evaluate::Assignment::Intrinsic &) {
4918- genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr );
5021+ genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr ,
5022+ dirs);
49195023 },
49205024 [&](const Fortran::evaluate::ProcedureRef &procRef) {
4921- genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef);
5025+ genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef,
5026+ dirs);
49225027 },
49235028 [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
49245029 if (isInsideHlfirForallOrWhere ())
@@ -5323,7 +5428,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
53235428 }
53245429
53255430 void genFIR (const Fortran::parser::AssignmentStmt &stmt) {
5326- genAssignment (*stmt.typedAssignment ->v );
5431+ Fortran::lower::pft::Evaluation &eval = getEval ();
5432+ genAssignment (*stmt.typedAssignment ->v , eval.dirs );
53275433 }
53285434
53295435 void genFIR (const Fortran::parser::SyncAllStmt &stmt) {
0 commit comments