@@ -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.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
+
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