Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);

// 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
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

#endif
}

[[noreturn]] void RTNAME(Abort)() {
// TODO: Add backtrace call, unless with `-fno-backtrace`.
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