Skip to content
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]Add new intrinsic function backtrace and complete the TODO of abort #117603

Merged
merged 13 commits into from
Nov 28, 2024
Merged
1 change: 1 addition & 0 deletions flang/include/flang/Optimizer/Builder/IntrinsicCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ struct IntrinsicLibrary {
fir::ExtendedValue genAssociated(mlir::Type,
llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genAtand(mlir::Type, llvm::ArrayRef<mlir::Value>);
void genBacktrace(llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genBesselJn(mlir::Type,
llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genBesselYn(mlir::Type,
Expand Down
3 changes: 3 additions & 0 deletions flang/include/flang/Optimizer/Builder/Runtime/Stop.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ void genExit(fir::FirOpBuilder &, mlir::Location, mlir::Value status);
/// Generate call to ABORT intrinsic runtime routine.
void genAbort(fir::FirOpBuilder &, mlir::Location);

/// Generate call to BACKTRACE intrinsic runtime routine.
void genBacktrace(fir::FirOpBuilder &builder, mlir::Location loc);

/// Generate call to crash the program with an error message when detecting
/// an invalid situation at runtime.
void genReportFatalUserError(fir::FirOpBuilder &, mlir::Location,
Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Runtime/stop.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ NORETURN void RTNAME(ProgramEndStatement)(NO_ARGUMENTS);
// Extensions
NORETURN void RTNAME(Exit)(int status DEFAULT_VALUE(EXIT_SUCCESS));
NORETURN void RTNAME(Abort)(NO_ARGUMENTS);
void RTNAME(Backtrace)(NO_ARGUMENTS);
clementval marked this conversation as resolved.
Show resolved Hide resolved

// Crash with an error message when the program dynamically violates a Fortran
// constraint.
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Evaluate/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,7 @@ static const IntrinsicInterface intrinsicSubroutine[]{
{"stat", AnyInt, Rank::scalar, Optionality::optional,
common::Intent::Out}},
{}, Rank::elemental, IntrinsicClass::atomicSubroutine},
{"backtrace", {}, {}, Rank::elemental, IntrinsicClass::pureSubroutine},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am late in the review, but since this has been reverted, I do not think "elemental" is correct here, and I would also debate the pure aspect since this is doing IO on the standard output which is forbidden for pure subroutine.

In fact, I am not quite sure that the front-end needs to know about backtrace since there are type resolution or argument requiring explicit interface.

It may just be simpler to deal with it like a user procedure for which the runtime provides an implementation (if the user has not). See FDATE implementation for instance.

Please also document the extension support in docs/Intrinsics.md.

Thanks for adding this, it is a great feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I understand what you said. I think you are right. But in this case, it seems to me that the built-in functions such as Abort and Exit need to be rewritten, because they can be regarded as user processes like backtrace. (If I understand correctly) I plan to complete backtrace in the original way first, and rewrite the built-in functions such as Abort and exit in the next new PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I temporarily changed pure to impure to match element (I saw the original Abort implementation was the same). Since the previous PR was problematic and had been rejected, I submitted a new PR after making modifications. You can follow this PR to follow the latest changes.#118179

Copy link
Contributor

@jeanPerier jeanPerier Dec 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think that Exit can be rewritten without front-end support because it has an OPTIONAL argument, so it requires an explicit interface. Maybe Abort could be handled without front-end support, however, I think its NORETURN aspect is something that may be valuable to lowering (not leveraged yet), so it may be worth keeping it like this. @klausler, do you agree Abort and Exit need or benefit from front-end support, while Backtrace does not?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.

{"co_broadcast",
{{"a", AnyData, Rank::anyOrAssumedRank, Optionality::required,
common::Intent::InOut},
Expand Down
7 changes: 7 additions & 0 deletions flang/lib/Optimizer/Builder/IntrinsicCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ static constexpr IntrinsicHandler handlers[]{
{"atan2pi", &I::genAtanpi},
{"atand", &I::genAtand},
{"atanpi", &I::genAtanpi},
{"backtrace", &I::genBacktrace},
{"bessel_jn",
&I::genBesselJn,
{{{"n1", asValue}, {"n2", asValue}, {"x", asValue}}},
Expand Down Expand Up @@ -2682,6 +2683,12 @@ IntrinsicLibrary::genBesselJn(mlir::Type resultType,
}
}

// Backtrace
void IntrinsicLibrary::genBacktrace(llvm::ArrayRef<fir::ExtendedValue> args) {
assert(args.size() == 0);
fir::runtime::genBacktrace(builder, loc);
}

// BESSEL_YN
fir::ExtendedValue
IntrinsicLibrary::genBesselYn(mlir::Type resultType,
Expand Down
7 changes: 7 additions & 0 deletions flang/lib/Optimizer/Builder/Runtime/Stop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ void fir::runtime::genAbort(fir::FirOpBuilder &builder, mlir::Location loc) {
builder.create<fir::CallOp>(loc, abortFunc, std::nullopt);
}

void fir::runtime::genBacktrace(fir::FirOpBuilder &builder,
mlir::Location loc) {
mlir::func::FuncOp backtraceFunc =
fir::runtime::getRuntimeFunc<mkRTKey(Backtrace)>(loc, builder);
builder.create<fir::CallOp>(loc, backtraceFunc, std::nullopt);
}

void fir::runtime::genReportFatalUserError(fir::FirOpBuilder &builder,
mlir::Location loc,
llvm::StringRef message) {
Expand Down
30 changes: 29 additions & 1 deletion flang/runtime/stop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
#include <cstdio>
#include <cstdlib>

#include "llvm/Config/config.h"
#ifdef HAVE_BACKTRACE
#include BACKTRACE_HEADER
#endif

extern "C" {

static void DescribeIEEESignaledExceptions() {
Expand Down Expand Up @@ -152,11 +157,34 @@ void RTNAME(PauseStatementText)(const char *code, std::size_t length) {
std::exit(status);
}

static void PrintBacktrace() {
#ifdef HAVE_BACKTRACE
// TODO: Need to parse DWARF information to print function line numbers
dty2 marked this conversation as resolved.
Show resolved Hide resolved
constexpr int MAX_CALL_STACK{999};
void *buffer[MAX_CALL_STACK];
int nptrs{backtrace(buffer, MAX_CALL_STACK)};

if (char **symbols{backtrace_symbols(buffer, nptrs)}) {
for (int i = 0; i < nptrs; i++) {
Fortran::runtime::Terminator{}.PrintCrashArgs("#%d %s\n", i, symbols[i]);
}
free(symbols);
}

#else

// TODO: Windows platform implementation
dty2 marked this conversation as resolved.
Show resolved Hide resolved

#endif
}

[[noreturn]] void RTNAME(Abort)() {
// TODO: Add backtrace call, unless with `-fno-backtrace`.
dty2 marked this conversation as resolved.
Show resolved Hide resolved
PrintBacktrace();
std::abort();
}

void RTNAME(Backtrace)() { PrintBacktrace(); }

[[noreturn]] void RTNAME(ReportFatalUserError)(
const char *message, const char *source, int line) {
Fortran::runtime::Terminator{source, line}.Crash(message);
Expand Down
10 changes: 10 additions & 0 deletions flang/test/Lower/Intrinsics/backtrace.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
! RUN: bbc -emit-fir %s -o - | FileCheck %s

! CHECK-LABEL: func.func @_QPbacktrace_test() {
! CHECK: %[[VAL_0:.*]] = fir.call @_FortranABacktrace() {{.*}}: () -> none
! CHECK: return
! CHECK: }

subroutine backtrace_test()
call backtrace
end subroutine