diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -133,6 +133,18 @@ check_library_exists(pthread pthread_create "" COMPILER_RT_HAS_LIBPTHREAD) check_library_exists(execinfo backtrace "" COMPILER_RT_HAS_LIBEXECINFO) +# system calls +check_c_source_compiles( +" +#include +void exit_handler() {} +int main() { + at_quick_exit(exit_handler); + return 0; +} +" COMPILER_RT_TARGET_HAS_AT_QUICK_EXIT) + + # Look for terminfo library, used in unittests that depend on LLVMSupport. if(LLVM_ENABLE_TERMINFO STREQUAL FORCE_ON) set(MAYBE_REQUIRED REQUIRED) diff --git a/compiler-rt/lib/profile/CMakeLists.txt b/compiler-rt/lib/profile/CMakeLists.txt --- a/compiler-rt/lib/profile/CMakeLists.txt +++ b/compiler-rt/lib/profile/CMakeLists.txt @@ -111,6 +111,12 @@ -DCOMPILER_RT_HAS_UNAME=1) endif() +if(COMPILER_RT_TARGET_HAS_AT_QUICK_EXIT) + set(EXTRA_FLAGS + ${EXTRA_FLAGS} + -DCOMPILER_RT_TARGET_HAS_AT_QUICK_EXIT=1) +endif() + # We don't use the C++ Standard Library here, so avoid including it by mistake. append_list_if(COMPILER_RT_HAS_NOSTDINCXX_FLAG -nostdinc++ EXTRA_FLAGS) # XRay uses C++ standard library headers. diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c --- a/compiler-rt/lib/profile/InstrProfilingFile.c +++ b/compiler-rt/lib/profile/InstrProfilingFile.c @@ -1166,7 +1166,11 @@ lprofSetupValueProfiler(); HasBeenRegistered = 1; - return atexit(writeFileWithoutReturn); + int rc = atexit(writeFileWithoutReturn); +#if defined(COMPILER_RT_TARGET_HAS_AT_QUICK_EXIT) + rc = rc || at_quick_exit(writeFileWithoutReturn); +#endif + return rc; } #endif diff --git a/compiler-rt/test/lit.common.configured.in b/compiler-rt/test/lit.common.configured.in --- a/compiler-rt/test/lit.common.configured.in +++ b/compiler-rt/test/lit.common.configured.in @@ -51,8 +51,12 @@ # and using `config.compiler_rt_libdir` instead. This only matters when the runtime # library paths differ. set_default("test_suite_supports_overriding_runtime_lib_path", False) +set_default("quick_exit_available", @COMPILER_RT_TARGET_HAS_AT_QUICK_EXIT@) config.available_features.add('target-is-%s' % config.target_arch) +if not config.quick_exit_available: + config.available_features.add("quick_exit_unavailable") + if config.enable_per_target_runtime_dir: set_default("target_suffix", "") elif config.android: diff --git a/compiler-rt/test/profile/instrprof-write-file-at-quick-exit-explicitly.c b/compiler-rt/test/profile/instrprof-write-file-at-quick-exit-explicitly.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/profile/instrprof-write-file-at-quick-exit-explicitly.c @@ -0,0 +1,20 @@ +// RUN: %clang_profgen -o %t -O3 %s +// RUN: %run %t %t.profraw +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s +// UNSUPPORTED: quick_exit_unavailable + +#include + +int __llvm_profile_runtime = 0; +int __llvm_profile_register_write_file_atexit(void); +void __llvm_profile_set_filename(const char *); +int main(int argc, const char *argv[]) { + __llvm_profile_register_write_file_atexit(); + // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + if (argc < 2) + return 1; + __llvm_profile_set_filename(argv[1]); + quick_exit(0); +} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2}