-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[flang] Implement !DIR$ [NO]INLINE and FORCEINLINE directives #134350
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-flang-semantics @llvm/pr-subscribers-flang-parser Author: Jean-Didier PAILLEUX (JDPailleux) ChangesThis patch adds the support of these two directives :
Currently, these directives can be placed before a For the Patch is 22.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/134350.diff 15 Files Affected:
diff --git a/flang/docs/Directives.md b/flang/docs/Directives.md
index 91c27cb510ea0..4f3748bf79722 100644
--- a/flang/docs/Directives.md
+++ b/flang/docs/Directives.md
@@ -53,6 +53,12 @@ A list of non-standard directives supported by Flang
* `!dir$ novector` disabling vectorization on the following loop.
* `!dir$ nounroll` disabling unrolling on the following loop.
* `!dir$ nounroll_and_jam` disabling unrolling and jamming on the following loop.
+* `!dir$ inline` tells the compiler to attempt to inline routines if
+ this directive is specified before a call statement or for all call function statements
+ within a DO LOOP. This directive can be improved later to support other place(s) for
+ inlining function calls.
+* `!dir$ noinline` works in the same way as the `inline` directive, but prevents
+ any attempt of inlining by the compiler on a function call statement.
# Directive Details
diff --git a/flang/include/flang/Evaluate/call.h b/flang/include/flang/Evaluate/call.h
index 2a5929b873d74..7a1bad030c88f 100644
--- a/flang/include/flang/Evaluate/call.h
+++ b/flang/include/flang/Evaluate/call.h
@@ -254,6 +254,11 @@ class ProcedureRef {
bool IsElemental() const { return proc_.IsElemental(); }
bool hasAlternateReturns() const { return hasAlternateReturns_; }
+ bool hasNoInline() const { return noInline_; }
+ void set_noInline(bool ni) { noInline_ = ni; }
+ bool hasAlwaysInline() const { return alwaysInline_; }
+ void set_alwaysInline(bool ai) { alwaysInline_ = ai; }
+
Expr<SomeType> *UnwrapArgExpr(int n) {
if (static_cast<std::size_t>(n) < arguments_.size() && arguments_[n]) {
return arguments_[n]->UnwrapExpr();
@@ -277,6 +282,8 @@ class ProcedureRef {
ActualArguments arguments_;
Chevrons chevrons_;
bool hasAlternateReturns_;
+ bool noInline_{false};
+ bool alwaysInline_{false};
};
template <typename A> class FunctionRef : public ProcedureRef {
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 753e4bd18dc6d..18a198ca061b7 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -2490,6 +2490,8 @@ def fir_CallOp : fir_Op<"call",
OptionalAttr<DictArrayAttr>:$arg_attrs,
OptionalAttr<DictArrayAttr>:$res_attrs,
OptionalAttr<fir_FortranProcedureFlagsAttr>:$procedure_attrs,
+ OptionalAttr<UnitAttr>:$no_inline,
+ OptionalAttr<UnitAttr>:$always_inline,
DefaultValuedAttr<Arith_FastMathAttr,
"::mlir::arith::FastMathFlags::none">:$fastmath
);
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index c66f0735f33f0..4e6e2aa4f0f8d 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -204,8 +204,10 @@ class ParseTreeDumper {
NODE(parser, CompilerDirective)
NODE(CompilerDirective, AssumeAligned)
NODE(CompilerDirective, IgnoreTKR)
+ NODE(CompilerDirective, Inline)
NODE(CompilerDirective, LoopCount)
NODE(CompilerDirective, NameValue)
+ NODE(CompilerDirective, NoInline)
NODE(CompilerDirective, Unrecognized)
NODE(CompilerDirective, VectorAlways)
NODE(CompilerDirective, Unroll)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index eeb438991feee..e86da56bb9d3d 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3354,6 +3354,8 @@ struct StmtFunctionStmt {
// !DIR$ NOVECTOR
// !DIR$ NOUNROLL
// !DIR$ NOUNROLL_AND_JAM
+// !DIR$ INLINE
+// !DIR$ NOINLINE
// !DIR$ <anything else>
struct CompilerDirective {
UNION_CLASS_BOILERPLATE(CompilerDirective);
@@ -3382,11 +3384,13 @@ struct CompilerDirective {
EMPTY_CLASS(NoVector);
EMPTY_CLASS(NoUnroll);
EMPTY_CLASS(NoUnrollAndJam);
+ EMPTY_CLASS(Inline);
+ EMPTY_CLASS(NoInline);
EMPTY_CLASS(Unrecognized);
CharBlock source;
std::variant<std::list<IgnoreTKR>, LoopCount, std::list<AssumeAligned>,
VectorAlways, std::list<NameValue>, Unroll, UnrollAndJam, Unrecognized,
- NoVector, NoUnroll, NoUnrollAndJam>
+ NoVector, NoUnroll, NoUnrollAndJam, Inline, NoInline>
u;
};
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 65edf1cea8761..9bad56448a3ea 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -1828,6 +1828,23 @@ class FirConverter : public Fortran::lower::AbstractConverter {
setCurrentPosition(stmt.source);
assert(stmt.typedCall && "Call was not analyzed");
mlir::Value res{};
+
+ // Set 'no_inline' 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::Inline &) {
+ stmt.typedCall->set_alwaysInline(true);
+ },
+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
+ stmt.typedCall->set_noInline(true);
+ },
+ [&](const auto &) {}},
+ dir->u);
+ }
+
if (lowerToHighLevelFIR()) {
std::optional<mlir::Type> resultType;
if (stmt.typedCall->hasAlternateReturns())
@@ -2053,6 +2070,47 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// 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.setNoInlineAttr(builder->getUnitAttr());
+ },
+ [&](const Fortran::parser::CompilerDirective::Inline &) {
+ callOp.setAlwaysInlineAttr(builder->getUnitAttr());
+ },
+ [&](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
@@ -2162,6 +2220,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// This call may generate a branch in some contexts.
genFIR(endDoEval, unstructuredContext);
+
+ // Add attribute(s) on operations in fir::DoLoopOp if necessary
+ for (IncrementLoopInfo &info : incrementLoopNestInfo)
+ attachAttributesToDoLoopOperations(info.doLoop, doStmtEval.dirs);
}
/// Generate FIR to evaluate loop control values (lower, upper and step).
@@ -2935,6 +2997,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
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();
@@ -2958,6 +3040,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
[&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
attachDirectiveToLoop(dir, &eval);
},
+ [&](const Fortran::parser::CompilerDirective::Inline &) {
+ attachInliningDirectiveToStmt(dir, &eval);
+ },
+ [&](const Fortran::parser::CompilerDirective::NoInline &) {
+ attachInliningDirectiveToStmt(dir, &eval);
+ },
[&](const auto &) {}},
dir.u);
}
@@ -4763,7 +4851,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
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();
@@ -4836,12 +4926,22 @@ class FirConverter : public Fortran::lower::AbstractConverter {
Fortran::lower::StatementContext localStmtCtx;
hlfir::Entity rhs = evaluateRhs(localStmtCtx);
hlfir::Entity lhs = evaluateLhs(localStmtCtx);
- if (isCUDATransfer && !hasCUDAImplicitTransfer)
+ if (isCUDATransfer && !hasCUDAImplicitTransfer) {
genCUDADataTransfer(builder, loc, assign, lhs, rhs);
- 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);
+ }
builder.create<hlfir::AssignOp>(loc, rhs, lhs,
isWholeAllocatableAssignment,
keepLhsLengthInAllocatableAssignment);
+ }
if (hasCUDAImplicitTransfer && !isInDeviceContext) {
localSymbols.popScope();
for (mlir::Value temp : implicitTemps)
@@ -4909,16 +5009,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
/// 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())
@@ -5323,7 +5428,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
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) {
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 6a0f4d1090adc..fe8d84c2c8c37 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -647,9 +647,15 @@ Fortran::lower::genCallOpAndResult(
callResult = dispatch.getResult(0);
} else {
// Standard procedure call with fir.call.
+ mlir::UnitAttr noinlineAttr, alwaysinlineAttr;
+ if (caller.getCallDescription().hasNoInline())
+ noinlineAttr = builder.getUnitAttr();
+ else if (caller.getCallDescription().hasAlwaysInline())
+ alwaysinlineAttr = builder.getUnitAttr();
auto call = builder.create<fir::CallOp>(
loc, funcType.getResults(), funcSymbolAttr, operands,
- /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, procAttrs);
+ /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, procAttrs, noinlineAttr,
+ alwaysinlineAttr);
callNumResults = call.getNumResults();
if (callNumResults != 0)
diff --git a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
index 0c78a878cdc53..eff623d983535 100644
--- a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
@@ -207,7 +207,9 @@ struct DispatchOpConv : public OpConversionPattern<fir::DispatchOp> {
args.append(dispatch.getArgs().begin(), dispatch.getArgs().end());
rewriter.replaceOpWithNewOp<fir::CallOp>(
dispatch, resTypes, nullptr, args, dispatch.getArgAttrsAttr(),
- dispatch.getResAttrsAttr(), dispatch.getProcedureAttrsAttr());
+ dispatch.getResAttrsAttr(), dispatch.getProcedureAttrsAttr(),
+ /*no_inline*/ mlir::UnitAttr{},
+ /*alwais_inline*/ mlir::UnitAttr{});
return mlir::success();
}
diff --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp
index fbe629ab52935..ef9d4b191ad15 100644
--- a/flang/lib/Parser/Fortran-parsers.cpp
+++ b/flang/lib/Parser/Fortran-parsers.cpp
@@ -1314,6 +1314,9 @@ constexpr auto novector{"NOVECTOR" >> construct<CompilerDirective::NoVector>()};
constexpr auto nounroll{"NOUNROLL" >> construct<CompilerDirective::NoUnroll>()};
constexpr auto nounrollAndJam{
"NOUNROLL_AND_JAM" >> construct<CompilerDirective::NoUnrollAndJam>()};
+constexpr auto inlineDir{"INLINE" >> construct<CompilerDirective::Inline>()};
+constexpr auto noinlineDir{
+ "NOINLINE" >> construct<CompilerDirective::NoInline>()};
TYPE_PARSER(beginDirective >> "DIR$ "_tok >>
sourced((construct<CompilerDirective>(ignore_tkr) ||
construct<CompilerDirective>(loopCount) ||
@@ -1324,6 +1327,8 @@ TYPE_PARSER(beginDirective >> "DIR$ "_tok >>
construct<CompilerDirective>(novector) ||
construct<CompilerDirective>(nounrollAndJam) ||
construct<CompilerDirective>(nounroll) ||
+ construct<CompilerDirective>(noinlineDir) ||
+ construct<CompilerDirective>(inlineDir) ||
construct<CompilerDirective>(
many(construct<CompilerDirective::NameValue>(
name, maybe(("="_tok || ":"_tok) >> digitString64))))) /
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 47dae0ae753d2..f7eaab45fb77b 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -1864,6 +1864,10 @@ class UnparseVisitor {
[&](const CompilerDirective::NoUnrollAndJam &) {
Word("!DIR$ NOUNROLL_AND_JAM");
},
+ [&](const CompilerDirective::Inline &) { Word("!DIR$ INLINE"); },
+ [&](const CompilerDirective::NoInline &) {
+ Word("!DIR$ NOINLINE");
+ },
[&](const CompilerDirective::Unrecognized &) {
Word("!DIR$ ");
Word(x.source.ToString());
diff --git a/flang/lib/Semantics/canonicalize-directives.cpp b/flang/lib/Semantics/canonicalize-directives.cpp
index 104df253ab642..ab6f801a6d350 100644
--- a/flang/lib/Semantics/canonicalize-directives.cpp
+++ b/flang/lib/Semantics/canonicalize-directives.cpp
@@ -60,7 +60,9 @@ static bool IsExecutionDirective(const parser::CompilerDirective &dir) {
std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(dir.u) ||
std::holds_alternative<parser::CompilerDirective::NoVector>(dir.u) ||
std::holds_alternative<parser::CompilerDirective::NoUnroll>(dir.u) ||
- std::holds_alternative<parser::CompilerDirective::NoUnrollAndJam>(dir.u);
+ std::holds_alternative<parser::CompilerDirective::NoUnrollAndJam>(dir.u) ||
+ std::holds_alternative<parser::CompilerDirective::Inline>(dir.u) ||
+ std::holds_alternative<parser::CompilerDirective::NoInline>(dir.u);
}
void CanonicalizationOfDirectives::Post(parser::SpecificationPart &spec) {
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 11c0ecc9e8410..1b67f351b7433 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -9576,7 +9576,9 @@ void ResolveNamesVisitor::Post(const parser::CompilerDirective &x) {
std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(x.u) ||
std::holds_alternative<parser::CompilerDirective::NoVector>(x.u) ||
std::holds_alternative<parser::CompilerDirective::NoUnroll>(x.u) ||
- std::holds_alternative<parser::CompilerDirective::NoUnrollAndJam>(x.u)) {
+ std::holds_alternative<parser::CompilerDirective::NoUnrollAndJam>(x.u) ||
+ std::holds_alternative<parser::CompilerDirective::Inline>(x.u) ||
+ std::holds_alternative<parser::CompilerDirective::NoInline>(x.u)) {
return;
}
if (const auto *tkr{
diff --git a/flang/test/Integration/inline_directive.f90 b/flang/test/Integration/inline_directive.f90
new file mode 100644
index 0000000000000..6e55227e74b9a
--- /dev/null
+++ b/flang/test/Integration/inline_directive.f90
@@ -0,0 +1,51 @@
+! RUN: %flang_fc1 -emit-llvm -o - %s | FileCheck %s
+
+! CHECK-LABEL: test_inline
+subroutine test_inline()
+ integer :: x, y
+!CHECK: %[[VAL_1:.*]] = alloca i32, i64 1, align 4
+!CHECK: %[[VAL_2:.*]] = alloca i32, i64 1, align 4
+!CHECK: %[[VAL_3:.*]] = alloca i32, i64 1, align 4
+!CHECK: %[[VAL_4:.*]] = alloca i32, i64 1, align 4
+
+ !dir$ inline
+ y = g(x)
+ !dir$ inline
+ call f(x, y)
+!CHECK: %[[VAL_5:.*]] = load i32, ptr %[[VAL_3]], align 4
+!CHECK: %[[VAL_6:.*]] = mul i32 %[[VAL_5]], 2
+!CHECK: store i32 %6, ptr %[[VAL_1]], align 4
+!CHECK: %[[VAL_7:.*]] = load i32, ptr %[[VAL_1]], align 4
+!CHECK: store i32 %7, ptr %[[VAL_2]], align 4
+!CHECK: %[[VAL_8:.]] = load i32, ptr %[[VAL_3]], align 4
+!CHECK: %[[VAL_9:.]] = mul i32 %[[VAL_8]], 2
+!CHECK: store i32 %9, ptr %[[VAL_2]], align 4
+
+ !dir$ noinline
+ y = g(x)
+ !dir$ noinline
+ call f(x, y)
+!CHECK: %[[VAL_10:.*]] = call i32 @_QFtest_inlinePg(ptr %[[VAL_3]]) #[[NOINLINE:.*]]
+!CHECK: store i32 %[[VAL_10]], ptr %[[VAL_2]], align 4
+!CHECK: call void @_QFtest_inlinePf(ptr %[[VAL_3]], ptr %[[VAL_2]]) #[[NOINLINE]]
+
+ !dir$ noinline
+ do i = 1, 100
+ call f(x, y)
+ !CHECK: br i1 %[[VAL_14:.*]], label %[[VAL_15:.*]], label %[[VAL_19:.*]]
+ !CHECK: call void @_QFtest_inlinePf(ptr %[[VAL_3]], ptr %[[VAL_2]]) #[[NOINLINE]]
+ enddo
+
+ contains
+ subroutine f(x, y)
+ integer, intent(in) :: x
+ integer, intent(out) :: y
+ y = x*2
+ end subroutine f
+ integer function g(x)
+ integer :: x
+ g = x*2
+ end function g
+end subroutine test_inline
+
+!CHECK: attributes #[[NOINLINE]] = { noinline }
diff --git a/flang/test/Lower/inline_directive.f90 b/flang/test/Lower/inline_directive.f90
new file mode 100644
index 0000000000000..a6b8300f59efe
--- /dev/null
+++ b/flang/test/Lower/inline_directive.f90
@@ -0,0 +1,51 @@
+! RUN: %flang_...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
02e9631
to
5ae8ca3
Compare
Thanks for the patch @JDPailleux !dir$ inline This matches the pragma's supported by intel compiler as well [Below snippet from intel website] |
Thanks for your reply ! I'll rename the |
5ae8ca3
to
038819a
Compare
038819a
to
7faed13
Compare
This patch adds the support of these two directives :
!dir$ inline
and!dir$ noinline
.!dir$ noinline
tells to the compiler to not perform inlining on specific function calls by adding thenoinline
metadata on the call.!dir$ inline
tells to the compiler to not perform inlining on specific function calls by adding theinlinehint
metadata on the call.!dir$ forceinline
tells to the compiler to not perform inlining on specific function calls by adding thealwaysinline
metadata on the call.Currently, these directives can be placed before a
DO LOOP
, call functions or assignments. Maybe other statements can be added in the future if needed.For the
inline
directive the correct name might beforceinline
but I'm not sure ?