@@ -1828,6 +1828,23 @@ class FirConverter : public Fortran::lower::AbstractConverter {
1828
1828
setCurrentPosition (stmt.source );
1829
1829
assert (stmt.typedCall && " Call was not analyzed" );
1830
1830
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
+
1831
1848
if (lowerToHighLevelFIR ()) {
1832
1849
std::optional<mlir::Type> resultType;
1833
1850
if (stmt.typedCall ->hasAlternateReturns ())
@@ -2053,6 +2070,47 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2053
2070
// so no clean-up needs to be generated for these entities.
2054
2071
}
2055
2072
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
+
2056
2114
// / Generate FIR for a DO construct. There are six variants:
2057
2115
// / - unstructured infinite and while loops
2058
2116
// / - structured and unstructured increment loops
@@ -2162,6 +2220,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2162
2220
2163
2221
// This call may generate a branch in some contexts.
2164
2222
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 );
2165
2227
}
2166
2228
2167
2229
// / Generate FIR to evaluate loop control values (lower, upper and step).
@@ -2935,6 +2997,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2935
2997
e->dirs .push_back (&dir);
2936
2998
}
2937
2999
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
+
2938
3020
void genFIR (const Fortran::parser::CompilerDirective &dir) {
2939
3021
Fortran::lower::pft::Evaluation &eval = getEval ();
2940
3022
@@ -2958,6 +3040,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2958
3040
[&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
2959
3041
attachDirectiveToLoop (dir, &eval);
2960
3042
},
3043
+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
3044
+ attachInliningDirectiveToStmt (dir, &eval);
3045
+ },
3046
+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
3047
+ attachInliningDirectiveToStmt (dir, &eval);
3048
+ },
2961
3049
[&](const auto &) {}},
2962
3050
dir.u );
2963
3051
}
@@ -4763,7 +4851,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
4763
4851
4764
4852
void genDataAssignment (
4765
4853
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
+ {}) {
4767
4857
mlir::Location loc = getCurrentLocation ();
4768
4858
fir::FirOpBuilder &builder = getFirOpBuilder ();
4769
4859
@@ -4836,12 +4926,22 @@ class FirConverter : public Fortran::lower::AbstractConverter {
4836
4926
Fortran::lower::StatementContext localStmtCtx;
4837
4927
hlfir::Entity rhs = evaluateRhs (localStmtCtx);
4838
4928
hlfir::Entity lhs = evaluateLhs (localStmtCtx);
4839
- if (isCUDATransfer && !hasCUDAImplicitTransfer)
4929
+ if (isCUDATransfer && !hasCUDAImplicitTransfer) {
4840
4930
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
+ }
4842
4941
builder.create <hlfir::AssignOp>(loc, rhs, lhs,
4843
4942
isWholeAllocatableAssignment,
4844
4943
keepLhsLengthInAllocatableAssignment);
4944
+ }
4845
4945
if (hasCUDAImplicitTransfer && !isInDeviceContext) {
4846
4946
localSymbols.popScope ();
4847
4947
for (mlir::Value temp : implicitTemps)
@@ -4909,16 +5009,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
4909
5009
}
4910
5010
4911
5011
// / 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 = {}) {
4913
5016
mlir::Location loc = toLocation ();
4914
5017
if (lowerToHighLevelFIR ()) {
4915
5018
Fortran::common::visit (
4916
5019
Fortran::common::visitors{
4917
5020
[&](const Fortran::evaluate::Assignment::Intrinsic &) {
4918
- genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr );
5021
+ genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr ,
5022
+ dirs);
4919
5023
},
4920
5024
[&](const Fortran::evaluate::ProcedureRef &procRef) {
4921
- genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef);
5025
+ genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef,
5026
+ dirs);
4922
5027
},
4923
5028
[&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
4924
5029
if (isInsideHlfirForallOrWhere ())
@@ -5323,7 +5428,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
5323
5428
}
5324
5429
5325
5430
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 );
5327
5433
}
5328
5434
5329
5435
void genFIR (const Fortran::parser::SyncAllStmt &stmt) {
0 commit comments