@@ -1828,6 +1828,26 @@ 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', '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
+
1831
1851
if (lowerToHighLevelFIR ()) {
1832
1852
std::optional<mlir::Type> resultType;
1833
1853
if (stmt.typedCall ->hasAlternateReturns ())
@@ -2053,6 +2073,50 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2053
2073
// so no clean-up needs to be generated for these entities.
2054
2074
}
2055
2075
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.setNoInlineAttr (builder->getUnitAttr ());
2093
+ },
2094
+ [&](const Fortran::parser::CompilerDirective::Inline &) {
2095
+ callOp.setInlineHintAttr (builder->getUnitAttr ());
2096
+ },
2097
+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
2098
+ callOp.setAlwaysInlineAttr (builder->getUnitAttr ());
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
+
2056
2120
// / Generate FIR for a DO construct. There are six variants:
2057
2121
// / - unstructured infinite and while loops
2058
2122
// / - structured and unstructured increment loops
@@ -2162,6 +2226,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2162
2226
2163
2227
// This call may generate a branch in some contexts.
2164
2228
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 );
2165
2233
}
2166
2234
2167
2235
// / Generate FIR to evaluate loop control values (lower, upper and step).
@@ -2935,6 +3003,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2935
3003
e->dirs .push_back (&dir);
2936
3004
}
2937
3005
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
+
2938
3026
void genFIR (const Fortran::parser::CompilerDirective &dir) {
2939
3027
Fortran::lower::pft::Evaluation &eval = getEval ();
2940
3028
@@ -2958,6 +3046,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2958
3046
[&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
2959
3047
attachDirectiveToLoop (dir, &eval);
2960
3048
},
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
+ },
2961
3058
[&](const auto &) {}},
2962
3059
dir.u );
2963
3060
}
@@ -4761,7 +4858,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
4761
4858
4762
4859
void genDataAssignment (
4763
4860
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
+ {}) {
4765
4864
mlir::Location loc = getCurrentLocation ();
4766
4865
fir::FirOpBuilder &builder = getFirOpBuilder ();
4767
4866
@@ -4834,12 +4933,22 @@ class FirConverter : public Fortran::lower::AbstractConverter {
4834
4933
Fortran::lower::StatementContext localStmtCtx;
4835
4934
hlfir::Entity rhs = evaluateRhs (localStmtCtx);
4836
4935
hlfir::Entity lhs = evaluateLhs (localStmtCtx);
4837
- if (isCUDATransfer && !hasCUDAImplicitTransfer)
4936
+ if (isCUDATransfer && !hasCUDAImplicitTransfer) {
4838
4937
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
+ }
4840
4948
builder.create <hlfir::AssignOp>(loc, rhs, lhs,
4841
4949
isWholeAllocatableAssignment,
4842
4950
keepLhsLengthInAllocatableAssignment);
4951
+ }
4843
4952
if (hasCUDAImplicitTransfer && !isInDeviceContext) {
4844
4953
localSymbols.popScope ();
4845
4954
for (mlir::Value temp : implicitTemps)
@@ -4907,16 +5016,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
4907
5016
}
4908
5017
4909
5018
// / 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 = {}) {
4911
5023
mlir::Location loc = toLocation ();
4912
5024
if (lowerToHighLevelFIR ()) {
4913
5025
Fortran::common::visit (
4914
5026
Fortran::common::visitors{
4915
5027
[&](const Fortran::evaluate::Assignment::Intrinsic &) {
4916
- genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr );
5028
+ genDataAssignment (assign, /* userDefinedAssignment=*/ nullptr ,
5029
+ dirs);
4917
5030
},
4918
5031
[&](const Fortran::evaluate::ProcedureRef &procRef) {
4919
- genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef);
5032
+ genDataAssignment (assign, /* userDefinedAssignment=*/ &procRef,
5033
+ dirs);
4920
5034
},
4921
5035
[&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
4922
5036
if (isInsideHlfirForallOrWhere ())
@@ -5321,7 +5435,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
5321
5435
}
5322
5436
5323
5437
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 );
5325
5440
}
5326
5441
5327
5442
void genFIR (const Fortran::parser::SyncAllStmt &stmt) {
0 commit comments