aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Lower/Bridge.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'flang/lib/Lower/Bridge.cpp')
-rw-r--r--flang/lib/Lower/Bridge.cpp128
1 files changed, 122 insertions, 6 deletions
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index a516a44..6e72987 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -1884,6 +1884,26 @@ private:
setCurrentPosition(stmt.source);
assert(stmt.typedCall && "Call was not analyzed");
mlir::Value res{};
+
+ // Set 'no_inline', 'inline_hint' or 'always_inline' to true on the
+ // ProcedureRef. The NoInline and AlwaysInline attribute will be set in
+ // genProcedureRef later.
+ for (const auto *dir : eval.dirs) {
+ Fortran::common::visit(
+ Fortran::common::visitors{
+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
+ stmt.typedCall->setAlwaysInline(true);
+ },
+ [&](const Fortran::parser::CompilerDirective::Inline &) {
+ stmt.typedCall->setInlineHint(true);
+ },
+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
+ stmt.typedCall->setNoInline(true);
+ },
+ [&](const auto &) {}},
+ dir->u);
+ }
+
if (lowerToHighLevelFIR()) {
std::optional<mlir::Type> resultType;
if (stmt.typedCall->hasAlternateReturns())
@@ -2200,6 +2220,50 @@ private:
// so no clean-up needs to be generated for these entities.
}
+ void attachInlineAttributes(
+ mlir::Operation &op,
+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs) {
+ if (dirs.empty())
+ return;
+
+ for (mlir::Value operand : op.getOperands()) {
+ if (operand.getDefiningOp())
+ attachInlineAttributes(*operand.getDefiningOp(), dirs);
+ }
+
+ if (fir::CallOp callOp = mlir::dyn_cast<fir::CallOp>(op)) {
+ for (const auto *dir : dirs) {
+ Fortran::common::visit(
+ Fortran::common::visitors{
+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
+ callOp.setInlineAttr(fir::FortranInlineEnum::no_inline);
+ },
+ [&](const Fortran::parser::CompilerDirective::Inline &) {
+ callOp.setInlineAttr(fir::FortranInlineEnum::inline_hint);
+ },
+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
+ callOp.setInlineAttr(fir::FortranInlineEnum::always_inline);
+ },
+ [&](const auto &) {}},
+ dir->u);
+ }
+ }
+ }
+
+ void attachAttributesToDoLoopOperations(
+ fir::DoLoopOp &doLoop,
+ llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
+ if (!doLoop.getOperation() || dirs.empty())
+ return;
+
+ for (mlir::Block &block : doLoop.getRegion()) {
+ for (mlir::Operation &op : block.getOperations()) {
+ if (!dirs.empty())
+ attachInlineAttributes(op, dirs);
+ }
+ }
+ }
+
/// Generate FIR for a DO construct. There are six variants:
/// - unstructured infinite and while loops
/// - structured and unstructured increment loops
@@ -2351,6 +2415,11 @@ private:
if (!incrementLoopNestInfo.empty() &&
incrementLoopNestInfo.back().isConcurrent)
localSymbols.popScope();
+
+ // Add attribute(s) on operations in fir::DoLoopOp if necessary
+ for (IncrementLoopInfo &info : incrementLoopNestInfo)
+ if (auto loopOp = mlir::dyn_cast_if_present<fir::DoLoopOp>(info.loopOp))
+ attachAttributesToDoLoopOperations(loopOp, doStmtEval.dirs);
}
/// Generate FIR to evaluate loop control values (lower, upper and step).
@@ -3154,6 +3223,26 @@ private:
e->dirs.push_back(&dir);
}
+ void
+ attachInliningDirectiveToStmt(const Fortran::parser::CompilerDirective &dir,
+ Fortran::lower::pft::Evaluation *e) {
+ while (e->isDirective())
+ e = e->lexicalSuccessor;
+
+ // If the successor is a statement or a do loop, the compiler
+ // will perform inlining.
+ if (e->isA<Fortran::parser::CallStmt>() ||
+ e->isA<Fortran::parser::NonLabelDoStmt>() ||
+ e->isA<Fortran::parser::AssignmentStmt>()) {
+ e->dirs.push_back(&dir);
+ } else {
+ mlir::Location loc = toLocation();
+ mlir::emitWarning(loc,
+ "Inlining directive not in front of loops, function"
+ "call or assignment.\n");
+ }
+ }
+
void genFIR(const Fortran::parser::CompilerDirective &dir) {
Fortran::lower::pft::Evaluation &eval = getEval();
@@ -3177,6 +3266,15 @@ private:
[&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
attachDirectiveToLoop(dir, &eval);
},
+ [&](const Fortran::parser::CompilerDirective::ForceInline &) {
+ attachInliningDirectiveToStmt(dir, &eval);
+ },
+ [&](const Fortran::parser::CompilerDirective::Inline &) {
+ attachInliningDirectiveToStmt(dir, &eval);
+ },
+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
+ attachInliningDirectiveToStmt(dir, &eval);
+ },
[&](const auto &) {}},
dir.u);
}
@@ -5086,7 +5184,9 @@ private:
void genDataAssignment(
const Fortran::evaluate::Assignment &assign,
- const Fortran::evaluate::ProcedureRef *userDefinedAssignment) {
+ const Fortran::evaluate::ProcedureRef *userDefinedAssignment,
+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *> &dirs =
+ {}) {
mlir::Location loc = getCurrentLocation();
fir::FirOpBuilder &builder = getFirOpBuilder();
@@ -5166,10 +5266,20 @@ private:
genCUDADataTransfer(builder, loc, assign, lhs, rhs,
isWholeAllocatableAssignment,
keepLhsLengthInAllocatableAssignment);
- else
+ else {
+ // If RHS or LHS have a CallOp in their expression, this operation will
+ // have the 'no_inline' or 'always_inline' attribute if there is a
+ // directive just before the assignement.
+ if (!dirs.empty()) {
+ if (rhs.getDefiningOp())
+ attachInlineAttributes(*rhs.getDefiningOp(), dirs);
+ if (lhs.getDefiningOp())
+ attachInlineAttributes(*lhs.getDefiningOp(), dirs);
+ }
hlfir::AssignOp::create(builder, loc, rhs, lhs,
isWholeAllocatableAssignment,
keepLhsLengthInAllocatableAssignment);
+ }
if (hasCUDAImplicitTransfer && !isInDeviceContext) {
localSymbols.popScope();
for (mlir::Value temp : implicitTemps)
@@ -5237,16 +5347,21 @@ private:
}
/// Shared for both assignments and pointer assignments.
- void genAssignment(const Fortran::evaluate::Assignment &assign) {
+ void
+ genAssignment(const Fortran::evaluate::Assignment &assign,
+ const llvm::ArrayRef<const Fortran::parser::CompilerDirective *>
+ &dirs = {}) {
mlir::Location loc = toLocation();
if (lowerToHighLevelFIR()) {
Fortran::common::visit(
Fortran::common::visitors{
[&](const Fortran::evaluate::Assignment::Intrinsic &) {
- genDataAssignment(assign, /*userDefinedAssignment=*/nullptr);
+ genDataAssignment(assign, /*userDefinedAssignment=*/nullptr,
+ dirs);
},
[&](const Fortran::evaluate::ProcedureRef &procRef) {
- genDataAssignment(assign, /*userDefinedAssignment=*/&procRef);
+ genDataAssignment(assign, /*userDefinedAssignment=*/&procRef,
+ dirs);
},
[&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
if (isInsideHlfirForallOrWhere())
@@ -5651,7 +5766,8 @@ private:
}
void genFIR(const Fortran::parser::AssignmentStmt &stmt) {
- genAssignment(*stmt.typedAssignment->v);
+ Fortran::lower::pft::Evaluation &eval = getEval();
+ genAssignment(*stmt.typedAssignment->v, eval.dirs);
}
void genFIR(const Fortran::parser::SyncAllStmt &stmt) {