@@ -1884,6 +1884,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
18841884 setCurrentPosition (stmt.source );
18851885 assert (stmt.typedCall && " Call was not analyzed" );
18861886 mlir::Value res{};
1887+
1888+ // Set 'no_inline', 'inline_hint' or 'always_inline' to true on the
1889+ // ProcedureRef. The NoInline and AlwaysInline attribute will be set in
1890+ // genProcedureRef later.
1891+ for (const auto *dir : eval.dirs ) {
1892+ Fortran::common::visit (
1893+ Fortran::common::visitors{
1894+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
1895+ stmt.typedCall ->setAlwaysInline (true );
1896+ },
1897+ [&](const Fortran::parser::CompilerDirective::Inline &) {
1898+ stmt.typedCall ->setInlineHint (true );
1899+ },
1900+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
1901+ stmt.typedCall ->setNoInline (true );
1902+ },
1903+ [&](const auto &) {}},
1904+ dir->u );
1905+ }
1906+
18871907 if (lowerToHighLevelFIR ()) {
18881908 std::optional<mlir::Type> resultType;
18891909 if (stmt.typedCall ->hasAlternateReturns ())
@@ -2200,6 +2220,50 @@ class FirConverter : public Fortran::lower::AbstractConverter {
22002220 // so no clean-up needs to be generated for these entities.
22012221 }
22022222
2223+ void attachInlineAttributes (
2224+ mlir::Operation &op,
2225+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs) {
2226+ if (dirs.empty ())
2227+ return ;
2228+
2229+ for (mlir::Value operand : op.getOperands ()) {
2230+ if (operand.getDefiningOp ())
2231+ attachInlineAttributes (*operand.getDefiningOp (), dirs);
2232+ }
2233+
2234+ if (fir::CallOp callOp = mlir::dyn_cast<fir::CallOp>(op)) {
2235+ for (const auto *dir : dirs) {
2236+ Fortran::common::visit (
2237+ Fortran::common::visitors{
2238+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
2239+ callOp.setInlineAttr (fir::FortranInlineEnum::no_inline);
2240+ },
2241+ [&](const Fortran::parser::CompilerDirective::Inline &) {
2242+ callOp.setInlineAttr (fir::FortranInlineEnum::inline_hint);
2243+ },
2244+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
2245+ callOp.setInlineAttr (fir::FortranInlineEnum::always_inline);
2246+ },
2247+ [&](const auto &) {}},
2248+ dir->u );
2249+ }
2250+ }
2251+ }
2252+
2253+ void attachAttributesToDoLoopOperations (
2254+ fir::DoLoopOp &doLoop,
2255+ llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
2256+ if (!doLoop.getOperation () || dirs.empty ())
2257+ return ;
2258+
2259+ for (mlir::Block &block : doLoop.getRegion ()) {
2260+ for (mlir::Operation &op : block.getOperations ()) {
2261+ if (!dirs.empty ())
2262+ attachInlineAttributes (op, dirs);
2263+ }
2264+ }
2265+ }
2266+
22032267 // / Generate FIR for a DO construct. There are six variants:
22042268 // / - unstructured infinite and while loops
22052269 // / - structured and unstructured increment loops
@@ -2351,6 +2415,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
23512415 if (!incrementLoopNestInfo.empty () &&
23522416 incrementLoopNestInfo.back ().isConcurrent )
23532417 localSymbols.popScope ();
2418+
2419+ // Add attribute(s) on operations in fir::DoLoopOp if necessary
2420+ for (IncrementLoopInfo &info : incrementLoopNestInfo)
2421+ if (auto loopOp = mlir::dyn_cast_if_present<fir::DoLoopOp>(info.loopOp ))
2422+ attachAttributesToDoLoopOperations (loopOp, doStmtEval.dirs );
23542423 }
23552424
23562425 // / Generate FIR to evaluate loop control values (lower, upper and step).
@@ -3154,6 +3223,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
31543223 e->dirs .push_back (&dir);
31553224 }
31563225
3226+ void
3227+ attachInliningDirectiveToStmt (const Fortran::parser::CompilerDirective &dir,
3228+ Fortran::lower::pft::Evaluation *e) {
3229+ while (e->isDirective ())
3230+ e = e->lexicalSuccessor ;
3231+
3232+ // If the successor is a statement or a do loop, the compiler
3233+ // will perform inlining.
3234+ if (e->isA <Fortran::parser::CallStmt>() ||
3235+ e->isA <Fortran::parser::NonLabelDoStmt>() ||
3236+ e->isA <Fortran::parser::AssignmentStmt>()) {
3237+ e->dirs .push_back (&dir);
3238+ } else {
3239+ mlir::Location loc = toLocation ();
3240+ mlir::emitWarning (loc,
3241+ " Inlining directive not in front of loops, function"
3242+ " call or assignment.\n " );
3243+ }
3244+ }
3245+
31573246 void genFIR (const Fortran::parser::CompilerDirective &dir) {
31583247 Fortran::lower::pft::Evaluation &eval = getEval ();
31593248
@@ -3177,6 +3266,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
31773266 [&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
31783267 attachDirectiveToLoop (dir, &eval);
31793268 },
3269+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
3270+ attachInliningDirectiveToStmt (dir, &eval);
3271+ },
3272+ [&](const Fortran::parser::CompilerDirective::Inline &) {
3273+ attachInliningDirectiveToStmt (dir, &eval);
3274+ },
3275+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
3276+ attachInliningDirectiveToStmt (dir, &eval);
3277+ },
31803278 [&](const auto &) {}},
31813279 dir.u );
31823280 }
@@ -5086,7 +5184,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
50865184
50875185 void genDataAssignment (
50885186 const Fortran::evaluate::Assignment &assign,
5089- const Fortran::evaluate::ProcedureRef *userDefinedAssignment) {
5187+ const Fortran::evaluate::ProcedureRef *userDefinedAssignment,
5188+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs =
5189+ {}) {
50905190 mlir::Location loc = getCurrentLocation ();
50915191 fir::FirOpBuilder &builder = getFirOpBuilder ();
50925192
@@ -5166,10 +5266,20 @@ class FirConverter : public Fortran::lower::AbstractConverter {
51665266 genCUDADataTransfer (builder, loc, assign, lhs, rhs,
51675267 isWholeAllocatableAssignment,
51685268 keepLhsLengthInAllocatableAssignment);
5169- else
5269+ else {
5270+ // If RHS or LHS have a CallOp in their expression, this operation will
5271+ // have the 'no_inline' or 'always_inline' attribute if there is a
5272+ // directive just before the assignement.
5273+ if (!dirs.empty ()) {
5274+ if (rhs.getDefiningOp ())
5275+ attachInlineAttributes (*rhs.getDefiningOp (), dirs);
5276+ if (lhs.getDefiningOp ())
5277+ attachInlineAttributes (*lhs.getDefiningOp (), dirs);
5278+ }
51705279 hlfir::AssignOp::create (builder, loc, rhs, lhs,
51715280 isWholeAllocatableAssignment,
51725281 keepLhsLengthInAllocatableAssignment);
5282+ }
51735283 if (hasCUDAImplicitTransfer && !isInDeviceContext) {
51745284 localSymbols.popScope ();
51755285 for (mlir::Value temp : implicitTemps)
@@ -5237,16 +5347,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
52375347 }
52385348
52395349 // / Shared for both assignments and pointer assignments.
5240- void genAssignment (const Fortran::evaluate::Assignment &assign) {
5350+ void
5351+ genAssignment (const Fortran::evaluate::Assignment &assign,
5352+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *>
5353+ &dirs = {}) {
52415354 mlir::Location loc = toLocation ();
52425355 if (lowerToHighLevelFIR ()) {
52435356 Fortran::common::visit (
52445357 Fortran::common::visitors{
52455358 [&](const Fortran::evaluate::Assignment::Intrinsic &) {
5246- genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr );
5359+ genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr ,
5360+ dirs);
52475361 },
52485362 [&](const Fortran::evaluate::ProcedureRef &procRef) {
5249- genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef);
5363+ genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef,
5364+ dirs);
52505365 },
52515366 [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
52525367 if (isInsideHlfirForallOrWhere ())
@@ -5651,7 +5766,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
56515766 }
56525767
56535768 void genFIR (const Fortran::parser::AssignmentStmt &stmt) {
5654- genAssignment (*stmt.typedAssignment ->v );
5769+ Fortran::lower::pft::Evaluation &eval = getEval ();
5770+ genAssignment (*stmt.typedAssignment ->v , eval.dirs );
56555771 }
56565772
56575773 void genFIR (const Fortran::parser::SyncAllStmt &stmt) {
0 commit comments