From 459c9263aeb7576e3206d3ff52d822cdad7321ea Mon Sep 17 00:00:00 2001 From: Volodymyr Turanskyy Date: Fri, 19 Dec 2025 10:13:19 +0000 Subject: [PATCH 1/3] [ATfE] Make use of baremetal compiler_rt profile library https://github.com/llvm/llvm-project/pull/167998 enabled baremetal builds of compiler_rt profile runtime, so replace ATfE downstream minimal profile implementation (proflib.c) with compiler_rt one. proflib.c file is kept to provide the code needed to interface compiler_rt profile library to keep it clear in one place. This depends on adding supported Arm architecture in upstream LLVM runtimes CMake file. --- .../embedded/arm-runtimes/CMakeLists.txt | 54 +++ .../cpp-baremetal-semihosting-prof/Makefile | 2 +- .../cpp-baremetal-semihosting-prof/README.md | 3 - .../cpp-baremetal-semihosting-prof/proflib.c | 419 ++---------------- 4 files changed, 87 insertions(+), 391 deletions(-) diff --git a/arm-software/embedded/arm-runtimes/CMakeLists.txt b/arm-software/embedded/arm-runtimes/CMakeLists.txt index 86313d98a6e8..3744838f84dc 100644 --- a/arm-software/embedded/arm-runtimes/CMakeLists.txt +++ b/arm-software/embedded/arm-runtimes/CMakeLists.txt @@ -387,6 +387,60 @@ if(ENABLE_COMPILER_RT_TESTS) add_dependencies(check-compiler-rt compiler_rt-check-compiler-rt) endif() +# Build compiler-rt profile library after the C library is available. +ExternalProject_Add( + compiler_rt_profile + STAMP_DIR ${PROJECT_PREFIX}/compiler_rt_profile/${VARIANT_BUILD_ID}/stamp + BINARY_DIR ${PROJECT_PREFIX}/compiler_rt_profile/${VARIANT_BUILD_ID}/build + DOWNLOAD_DIR ${PROJECT_PREFIX}/compiler_rt_profile/${VARIANT_BUILD_ID}/dl + TMP_DIR ${PROJECT_PREFIX}/compiler_rt_profile/${VARIANT_BUILD_ID}/tmp + SOURCE_DIR ${llvmproject_src_dir}/runtimes + INSTALL_DIR compiler-rt-profile/install + DEPENDS compiler_rt-install clib-install + CMAKE_ARGS + ${compiler_launcher_cmake_args} + -DCMAKE_AR=${LLVM_BINARY_DIR}/bin/llvm-ar${CMAKE_EXECUTABLE_SUFFIX} + -DCMAKE_ASM_COMPILER_TARGET=${target_triple} + -DCMAKE_ASM_FLAGS=${lib_compile_flags} + -DCMAKE_BUILD_TYPE=${LIBRARY_CMAKE_BUILD_TYPE} + -DCMAKE_CXX_COMPILER=${LLVM_BINARY_DIR}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX} + -DCMAKE_CXX_COMPILER_TARGET=${target_triple} + -DCMAKE_CXX_FLAGS=${lib_compile_flags} + -DCMAKE_C_COMPILER=${LLVM_BINARY_DIR}/bin/clang${CMAKE_EXECUTABLE_SUFFIX} + -DCMAKE_C_COMPILER_TARGET=${target_triple} + -DCMAKE_C_FLAGS=${lib_compile_flags} + -DCMAKE_INSTALL_MESSAGE=${CMAKE_INSTALL_MESSAGE} + -DCMAKE_INSTALL_PREFIX= + -DCMAKE_NM=${LLVM_BINARY_DIR}/bin/llvm-nm${CMAKE_EXECUTABLE_SUFFIX} + -DCMAKE_RANLIB=${LLVM_BINARY_DIR}/bin/llvm-ranlib${CMAKE_EXECUTABLE_SUFFIX} + -DCMAKE_SYSTEM_NAME=Generic + -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY + ${compiler_rt_cmake_args} + -DCOMPILER_RT_BAREMETAL_BUILD=ON + -DCOMPILER_RT_BUILD_BUILTINS=OFF + -DCOMPILER_RT_BUILD_LIBFUZZER=OFF + -DCOMPILER_RT_BUILD_PROFILE=ON + -DCOMPILER_RT_PROFILE_BAREMETAL=ON + -DCOMPILER_RT_BUILD_SANITIZERS=OFF + -DCOMPILER_RT_BUILD_XRAY=OFF + -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON + -DLLVM_ENABLE_RUNTIMES=compiler-rt + -DRUNTIME_VARIANT_NAME=${VARIANT} + -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON + STEP_TARGETS configure build install + USES_TERMINAL_CONFIGURE TRUE + USES_TERMINAL_BUILD TRUE + USES_TERMINAL_INSTALL TRUE + LIST_SEPARATOR , + CONFIGURE_HANDLED_BY_BUILD TRUE + INSTALL_COMMAND ${CMAKE_COMMAND} --install . + COMMAND + ${CMAKE_COMMAND} + -E copy_directory + /lib/${normalized_target_triple} + "${TEMP_LIB_DIR}/lib" +) + ############################################################################### # picolibc ############################################################################### diff --git a/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/Makefile b/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/Makefile index 2755cf0e4954..d6268823d719 100644 --- a/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/Makefile +++ b/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/Makefile @@ -12,7 +12,7 @@ build: hello.elf hello.elf: *.cpp $(BIN_PATH)/clang -E -P -x c -DLIBC_LD_FILE=$(LIBC_LD_FILE) ../../ldscripts/microbit.ld.in -o microbit.ld $(BIN_PATH)/clang $(CFG_FILE) $(MICROBIT_TARGET) -g -c proflib.c - $(BIN_PATH)/clang++ $(CFG_FILE) $(MICROBIT_TARGET) $(CRT_SEMIHOST) $(CPP_FLAGS) -g -T microbit.ld -fprofile-instr-generate -fcoverage-mapping -o hello.elf hello.cpp proflib.o + $(BIN_PATH)/clang++ $(CFG_FILE) $(MICROBIT_TARGET) $(CRT_SEMIHOST) $(CPP_FLAGS) -g -T microbit.ld -fprofile-instr-generate -fcoverage-mapping -o hello.elf hello.cpp proflib.o -lclang_rt.profile %.hex: %.elf $(BIN_PATH)/llvm-objcopy -O ihex $< $@ diff --git a/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/README.md b/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/README.md index c2fcd48ea5e0..9e80fb9b37d9 100644 --- a/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/README.md +++ b/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/README.md @@ -5,6 +5,3 @@ and use it to show code coverage. Use `make run` to build with instrumentation, run and collect the raw profile data, then output a visualization of the code coverage. - -NOTE: The upstream runtime implementation changes regularly, -thus `proflib.c` file needs to be updated to keep in sync. diff --git a/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/proflib.c b/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/proflib.c index b391638162cd..b0e4b197cedd 100644 --- a/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/proflib.c +++ b/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/proflib.c @@ -1,409 +1,54 @@ -/*===-- InstrProfData.inc - instr profiling runtime structures -*- C++ -*-=== *\ -|* -|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -|* See https://llvm.org/LICENSE.txt for license information. -|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -|* -\*===----------------------------------------------------------------------===*/ - // Copyright (c) 2023-2025, Arm Limited and affiliates. // This file is derived from various files in compiler-rt of the llvm-project, // see https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/profile -// NOTE: The profile format changes regularly. See INSTR_PROF_RAW_VERSION. -// This runtime will need updating if the version changes. - // This C file should be compiled without -fprofile-instr-generate. // It will provide enough of the runtime for files compiled with // -fprofile-instr-generate and, optionally, -fcoverage-mapping -#include #include #include #include -// Structures are derived from InstrProfData.inc -// Macros and __llvm functions derived from -// compiler_rt/lib/profile. - -#define INSTR_PROF_RAW_VERSION 10 -#define INSTR_PROF_RAW_VERSION_VAR __llvm_profile_raw_version -#define INSTR_PROF_PROFILE_RUNTIME_VAR __llvm_profile_runtime - -uint64_t INSTR_PROF_RAW_VERSION_VAR = INSTR_PROF_RAW_VERSION; -uint64_t INSTR_PROF_PROFILE_RUNTIME_VAR; - -enum ValueKind { - IPVK_IndirectCallTarget = 0, - IPVK_MemOPSize = 1, - IPVK_First = IPVK_IndirectCallTarget, - IPVK_Last = IPVK_MemOPSize, -}; - -typedef void *IntPtrT; -typedef struct __attribute__((aligned(8))) __llvm_profile_data { - const uint64_t NameRef; - const uint64_t FuncHash; - const IntPtrT CounterPtr; - const IntPtrT BitmapPtr; - const IntPtrT FunctionPointer; - IntPtrT Values; - const uint32_t NumCounters; - const uint16_t NumValueSites[IPVK_Last + 1]; - const uint32_t NumBitmapBytes; -} __llvm_profile_data; - -typedef struct __llvm_profile_header { - uint64_t Magic; - uint64_t Version; - uint64_t BinaryIdsSize; - uint64_t NumData; - uint64_t PaddingBytesBeforeCounters; - uint64_t NumCounters; - uint64_t PaddingBytesAfterCounters; - uint64_t NumBitmapBytes; - uint64_t PaddingBytesAfterBitmapBytes; - uint64_t NamesSize; - uint64_t CountersDelta; - uint64_t BitmapDelta; - uint64_t NamesDelta; - uint64_t NumVTables; - uint64_t VNamesSize; - uint64_t ValueKindLast; -} __llvm_profile_header; - -typedef struct VTableProfData { - uint64_t VTableNameHash; - IntPtrT VTablePointer; - uint32_t VTableSize; -} VTableProfData; - -#define INSTR_PROF_SIMPLE_CONCAT(x, y) x##y -#define INSTR_PROF_CONCAT(x, y) INSTR_PROF_SIMPLE_CONCAT(x, y) - -/* Macros to define start/stop section symbol for a given - * section on Linux. For instance - * INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) will - * expand to __start___llvm_prof_data - */ -#define INSTR_PROF_SECT_START(Sect) INSTR_PROF_CONCAT(__start_, Sect) -#define INSTR_PROF_SECT_STOP(Sect) INSTR_PROF_CONCAT(__stop_, Sect) - -/* section name strings common to all targets other - than WIN32 */ -#define INSTR_PROF_DATA_COMMON __llvm_prf_data -#define INSTR_PROF_NAME_COMMON __llvm_prf_names -#define INSTR_PROF_VNAME_COMMON __llvm_prf_vns -#define INSTR_PROF_CNTS_COMMON __llvm_prf_cnts -#define INSTR_PROF_BITS_COMMON __llvm_prf_bits -#define INSTR_PROF_VALS_COMMON __llvm_prf_vals -#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds -#define INSTR_PROF_VTAB_COMMON __llvm_prf_vtab -#define INSTR_PROF_COVMAP_COMMON __llvm_covmap -#define INSTR_PROF_COVFUN_COMMON __llvm_covfun -#define INSTR_PROF_COVDATA_COMMON __llvm_covdata -#define INSTR_PROF_COVNAME_COMMON __llvm_covnames -#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile - -/* Declare section start and stop symbols for various sections - * generated by compiler instrumentation. - */ -#define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_COMMON) -#define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_COMMON) -#define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_COMMON) -#define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_COMMON) -#define PROF_VNAME_START INSTR_PROF_SECT_START(INSTR_PROF_VNAME_COMMON) -#define PROF_VNAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNAME_COMMON) -#define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_COMMON) -#define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_COMMON) -#define PROF_VTABLE_START INSTR_PROF_SECT_START(INSTR_PROF_VTAB_COMMON) -#define PROF_VTABLE_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VTAB_COMMON) -#define PROF_BITS_START INSTR_PROF_SECT_START(INSTR_PROF_BITS_COMMON) -#define PROF_BITS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_BITS_COMMON) -#define PROF_ORDERFILE_START INSTR_PROF_SECT_START(INSTR_PROF_ORDERFILE_COMMON) -#define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_COMMON) -#define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_COMMON) - -#define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden"))) -#define COMPILER_RT_WEAK __attribute__((weak)) - -/* Declare section start and stop symbols for various sections - * generated by compiler instrumentation. - */ -extern __llvm_profile_data PROF_DATA_START COMPILER_RT_VISIBILITY - COMPILER_RT_WEAK; -extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY - COMPILER_RT_WEAK; -extern char PROF_CNTS_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern char PROF_CNTS_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern VTableProfData PROF_VTABLE_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern VTableProfData PROF_VTABLE_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern char PROF_VNAME_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern char PROF_VNAME_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern char PROF_BITS_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern char PROF_BITS_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern uint32_t PROF_ORDERFILE_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern char PROF_NAME_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; -extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK; +// Callsbacks into the profile runtime +extern uint64_t __llvm_profile_get_size_for_buffer(void); +extern int __llvm_profile_write_buffer(char *buffer); -void __llvm_profile_dump(void); +// Declare this to disable the default profile runtime initialization +uint64_t __llvm_profile_runtime; -static size_t __llvm_profile_counter_entry_size() { return sizeof(uint64_t); } - -/* Register an atexit handler to dump the profile after main has exited - * If this is omitted, a program must manually call __llvm_profile_dump - * to write the profile - */ -__attribute__((constructor)) void __proflib_initialize() { - atexit(__llvm_profile_dump); -} - -/* Runtime registration has been disabled for ELF platforms. Runtime - * registration can be used to find the bounds of the counter sections - * when linker defined symbols are unavailable. This implementation - * will always use linker defined symbols so we do not need to implement - * this function. Provide a definition in case runtime registration is - * enabled, as the compiler will generate references to it. - */ -COMPILER_RT_VISIBILITY void __llvm_profile_register_function(void *Data_) { - (void)Data_; -} - -COMPILER_RT_VISIBILITY void -__llvm_profile_register_names_function(void *NamesStart, uint64_t NamesSize) { - (void)NamesStart; - (void)NamesSize; -} - -/* Magic number to detect file format and endianness. - * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0, - * so that utilities, like strings, don't grab it as a string. 129 is also - * invalid UTF-8, and high enough to be interesting. - * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR" - * for 32-bit platforms. - */ -#define INSTR_PROF_RAW_MAGIC_64 \ - (uint64_t)255 << 56 | (uint64_t)'l' << 48 | (uint64_t)'p' << 40 | \ - (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | \ - (uint64_t)'r' << 8 | (uint64_t)129 -#define INSTR_PROF_RAW_MAGIC_32 \ - (uint64_t)255 << 56 | (uint64_t)'l' << 48 | (uint64_t)'p' << 40 | \ - (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | \ - (uint64_t)'R' << 8 | (uint64_t)129 -static uint64_t __llvm_profile_get_magic(void) { - return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64) - : (INSTR_PROF_RAW_MAGIC_32); -} -static uint64_t __llvm_profile_get_version(void) { - return __llvm_profile_raw_version; -} -static uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin, - const __llvm_profile_data *End) { - intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End; - return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) / - sizeof(__llvm_profile_data); -} -uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin, - const __llvm_profile_data *End) { - intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End; - return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) / - sizeof(__llvm_profile_data); -} -static const __llvm_profile_data *__llvm_profile_begin_data(void) { - return &PROF_DATA_START; -} -static const __llvm_profile_data *__llvm_profile_end_data(void) { - return &PROF_DATA_STOP; -} -static const char *__llvm_profile_begin_names(void) { return &PROF_NAME_START; } -static const char *__llvm_profile_end_names(void) { return &PROF_NAME_STOP; } -static char *__llvm_profile_begin_counters(void) { return &PROF_CNTS_START; } -static char *__llvm_profile_end_counters(void) { return &PROF_CNTS_STOP; } -static char *__llvm_profile_begin_bitmap(void) { return &PROF_BITS_START; } -static char *__llvm_profile_end_bitmap(void) { return &PROF_BITS_STOP; } -static uint64_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes) { - return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t)); -} -static uint64_t __llvm_profile_get_num_bitmap_bytes(const char *Begin, - const char *End) { - return (End - Begin); -} -static uint64_t __llvm_profile_get_name_size(const char *Begin, - const char *End) { - return End - Begin; -} -static int __llvm_write_binary_ids(void) { return 0; } -static uint64_t __llvm_profile_get_num_counters(const char *Begin, - const char *End) { - intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End; - return ((EndI + __llvm_profile_counter_entry_size() - 1) - BeginI) / - __llvm_profile_counter_entry_size(); -} -static uint64_t __llvm_profile_get_counters_size(const char *Begin, - const char *End) { - return __llvm_profile_get_num_counters(Begin, End) * - __llvm_profile_counter_entry_size(); -} -static const VTableProfData *__llvm_profile_begin_vtables(void) { - return &PROF_VTABLE_START; -} -static const VTableProfData *__llvm_profile_end_vtables(void) { - return &PROF_VTABLE_STOP; -} -static const char *__llvm_profile_begin_vtabnames(void) { - return &PROF_VNAME_START; -} -static const char *__llvm_profile_end_vtabnames(void) { - return &PROF_VNAME_STOP; -} -static uint64_t __llvm_profile_get_num_vtable(const VTableProfData *Begin, - const VTableProfData *End) { - // Convert pointers to intptr_t to use integer arithmetic. - intptr_t EndI = (intptr_t)End, BeginI = (intptr_t)Begin; - return (EndI - BeginI) / sizeof(VTableProfData); -} -static uint64_t -__llvm_profile_get_vtable_section_size(const VTableProfData *Begin, - const VTableProfData *End) { - return (intptr_t)(End) - (intptr_t)(Begin); -} - -/* At exit, the file is written out using semihosting using the default - * filename of "default.profraw" - */ +// The profile file is written out using semihosting void __llvm_profile_dump(void) { - FILE *Fd; - /* Header: __llvm_profile_header from InstrProfData.inc */ - const char *FileName = "default.profraw"; - /* Calculate size of sections. */ - const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); - const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); - const char *CountersBegin = __llvm_profile_begin_counters(); - const char *CountersEnd = __llvm_profile_end_counters(); - const char *BitmapBegin = __llvm_profile_begin_bitmap(); - const char *BitmapEnd = __llvm_profile_end_bitmap(); - const char *NamesBegin = __llvm_profile_begin_names(); - const char *NamesEnd = __llvm_profile_end_names(); - const VTableProfData *VTableBegin = __llvm_profile_begin_vtables(); - const VTableProfData *VTableEnd = __llvm_profile_end_vtables(); - const char *VNamesBegin = __llvm_profile_begin_vtabnames(); - const char *VNamesEnd = __llvm_profile_end_vtabnames(); - const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); - const uint64_t NumCounters = - __llvm_profile_get_num_counters(CountersBegin, CountersEnd); - const uint64_t CountersSize = - __llvm_profile_get_counters_size(CountersBegin, CountersEnd); - const uint64_t NamesSize = __llvm_profile_get_name_size(NamesBegin, NamesEnd); - const uint64_t NumBitmapBytes = - __llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd); - const uint64_t NumVTables = - __llvm_profile_get_num_vtable(VTableBegin, VTableEnd); - const uint64_t VTableSectionSize = - __llvm_profile_get_vtable_section_size(VTableBegin, VTableEnd); - const uint64_t VNamesSize = - __llvm_profile_get_name_size(VNamesBegin, VNamesEnd); - uint64_t PaddingBytesAfterNames = - __llvm_profile_get_num_padding_bytes(NamesSize); - uint64_t PaddingBytesAfterVTable = - __llvm_profile_get_num_padding_bytes(VTableSectionSize); - uint64_t PaddingBytesAfterVNames = - __llvm_profile_get_num_padding_bytes(VNamesSize); - -#ifdef PROFLIB_DEBUG - fprintf(stderr, "__llvm_profile_dump\n"); - fprintf(stderr, "NumCounters %" PRIu64 "\n", NumCounters); -#endif // PROFLIB_DEBUG - - __llvm_profile_header Hdr; - Hdr.Magic = __llvm_profile_get_magic(); - Hdr.Version = __llvm_profile_get_version(); - Hdr.BinaryIdsSize = __llvm_write_binary_ids(); - Hdr.NumData = __llvm_profile_get_num_data(DataBegin, DataEnd); - Hdr.PaddingBytesBeforeCounters = 0; - Hdr.NumCounters = NumCounters; - Hdr.PaddingBytesAfterCounters = 0; - Hdr.NumBitmapBytes = NumBitmapBytes; - Hdr.PaddingBytesAfterBitmapBytes = 0; - Hdr.NamesSize = NamesSize; - Hdr.CountersDelta = (uintptr_t)CountersBegin - (uintptr_t)DataBegin; - Hdr.BitmapDelta = (uintptr_t)BitmapBegin - (uintptr_t)DataBegin; - Hdr.NamesDelta = (uintptr_t)NamesBegin; - Hdr.NumVTables = NumVTables; - Hdr.VNamesSize = VNamesSize; - Hdr.ValueKindLast = IPVK_Last; - - Fd = fopen(FileName, "wb"); - if (!Fd) { - perror("fopen default.profraw failed"); + const char *file_name = "default.profraw"; + FILE *fd = fopen(file_name, "wb"); + + if (!fd) { + printf("proflib: fopen default.profraw failed."); return; } - /* Header */ - fwrite(&Hdr, sizeof Hdr, 1, Fd); - - /* Data */ -#ifdef PROFLIB_DEBUG - fprintf(stderr, "DataSize: %" PRIu64 "\n", - DataSize * sizeof(__llvm_profile_data)); -#endif // PROFLIB_DEBUG - fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, Fd); - - /* Counters */ -#ifdef PROFLIB_DEBUG - fprintf(stderr, "CountersBegin: %p\n", CountersBegin); - fprintf(stderr, "CountersEnd: %p\n", CountersEnd); - fprintf(stderr, "NumCounters: %" PRIu64 "\n", NumCounters); - fprintf(stderr, "CountersSize: %" PRIu64 "\n", CountersSize); -#endif // PROFLIB_DEBUG - fwrite(CountersBegin, sizeof(uint8_t), CountersSize, Fd); - - /* Bitmap */ -#ifdef PROFLIB_DEBUG - fprintf(stderr, "NumBitmapBytes: %" PRIu64 "\n", NumBitmapBytes); -#endif // PROFLIB_DEBUG - fwrite(BitmapBegin, sizeof(uint8_t), NumBitmapBytes, Fd); - - /* Names */ -#ifdef PROFLIB_DEBUG - fprintf(stderr, "NamesSize: %" PRIu64 "\n", NamesSize); -#endif // PROFLIB_DEBUG - fwrite(NamesBegin, sizeof(uint8_t), NamesSize, Fd); - - /* Padding */ -#ifdef PROFLIB_DEBUG - fprintf(stderr, "PaddingBytesAfterNames: %" PRIu64 "\n", - PaddingBytesAfterNames); -#endif // PROFLIB_DEBUG - for (; PaddingBytesAfterNames != 0; --PaddingBytesAfterNames) - fputc(0, Fd); - - /* VTables */ -#ifdef PROFLIB_DEBUG - fprintf(stderr, "VTableSectionSize: %" PRIu64 "\n", VTableSectionSize); -#endif // PROFLIB_DEBUG - fwrite(VTableBegin, sizeof(uint8_t), VTableSectionSize, Fd); - - /* Padding */ -#ifdef PROFLIB_DEBUG - fprintf(stderr, "PaddingBytesAfterVTable: %" PRIu64 "\n", - PaddingBytesAfterVTable); -#endif // PROFLIB_DEBUG - for (; PaddingBytesAfterVTable != 0; --PaddingBytesAfterVTable) - fputc(0, Fd); + + uint64_t size = __llvm_profile_get_size_for_buffer(); + char* buffer = (char*) malloc(size); + + if (buffer) { + if (__llvm_profile_write_buffer(buffer) == -1) { + printf("proflib: Getting profile data failed.\n"); + } else { + fwrite(buffer, size, 1, fd); + } + free(buffer); + } else { + printf("proflib: malloc for profile data failed.\n"); + } - /* VNames */ -#ifdef PROFLIB_DEBUG - fprintf(stderr, "VNamesSize: %" PRIu64 "\n", VNamesSize); -#endif // PROFLIB_DEBUG - fwrite(VNamesBegin, sizeof(uint8_t), VNamesSize, Fd); + fclose(fd); +} - /* Padding */ -#ifdef PROFLIB_DEBUG - fprintf(stderr, "PaddingBytesAfterVNames: %" PRIu64 "\n", - PaddingBytesAfterVNames); -#endif // PROFLIB_DEBUG - for (; PaddingBytesAfterVNames != 0; --PaddingBytesAfterVNames) - fputc(0, Fd); +// Register an atexit handler to dump the profile after main has exited +// If this is omitted, a program must manually call __llvm_profile_dump +// to write the profile - fclose(Fd); +__attribute__((constructor)) void __proflib_initialize() { + atexit(__llvm_profile_dump); } From cf6e18f49b259c868bc2e16a861a0e60dd806f40 Mon Sep 17 00:00:00 2001 From: Volodymyr Turanskyy Date: Fri, 19 Dec 2025 11:01:52 +0000 Subject: [PATCH 2/3] Fix typo --- .../samples/src/cpp-baremetal-semihosting-prof/proflib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/proflib.c b/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/proflib.c index b0e4b197cedd..162b655a1e0f 100644 --- a/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/proflib.c +++ b/arm-software/embedded/samples/src/cpp-baremetal-semihosting-prof/proflib.c @@ -11,7 +11,7 @@ #include #include -// Callsbacks into the profile runtime +// Callbacks into the profile runtime extern uint64_t __llvm_profile_get_size_for_buffer(void); extern int __llvm_profile_write_buffer(char *buffer); From 8a390d3c43accc8a1ef314466f1c8d175416487d Mon Sep 17 00:00:00 2001 From: Volodymyr Turanskyy Date: Fri, 2 Jan 2026 14:30:29 +0000 Subject: [PATCH 3/3] Collect common builtins and profile flags --- .../embedded/arm-runtimes/CMakeLists.txt | 56 +++++++------------ 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/arm-software/embedded/arm-runtimes/CMakeLists.txt b/arm-software/embedded/arm-runtimes/CMakeLists.txt index 3744838f84dc..9f648c44ddd0 100644 --- a/arm-software/embedded/arm-runtimes/CMakeLists.txt +++ b/arm-software/embedded/arm-runtimes/CMakeLists.txt @@ -308,16 +308,9 @@ if(NOT C_LIBRARY STREQUAL "llvmlibc") ) endif() -ExternalProject_Add( - compiler_rt - STAMP_DIR ${PROJECT_PREFIX}/compiler_rt/${VARIANT_BUILD_ID}/stamp - BINARY_DIR ${PROJECT_PREFIX}/compiler_rt/${VARIANT_BUILD_ID}/build - DOWNLOAD_DIR ${PROJECT_PREFIX}/compiler_rt/${VARIANT_BUILD_ID}/dl - TMP_DIR ${PROJECT_PREFIX}/compiler_rt/${VARIANT_BUILD_ID}/tmp - SOURCE_DIR ${llvmproject_src_dir}/runtimes - INSTALL_DIR compiler-rt/install - CMAKE_ARGS - ${compiler_launcher_cmake_args} +# Common compiler_rt flags used by both builtins and profile builds +set( + compiler_rt_common_flags -DCMAKE_AR=${LLVM_BINARY_DIR}/bin/llvm-ar${CMAKE_EXECUTABLE_SUFFIX} -DCMAKE_ASM_COMPILER_TARGET=${target_triple} -DCMAKE_ASM_FLAGS=${lib_compile_flags} @@ -334,17 +327,31 @@ ExternalProject_Add( -DCMAKE_RANLIB=${LLVM_BINARY_DIR}/bin/llvm-ranlib${CMAKE_EXECUTABLE_SUFFIX} -DCMAKE_SYSTEM_NAME=Generic -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY - ${compiler_rt_cmake_args} -DCOMPILER_RT_BAREMETAL_BUILD=ON -DCOMPILER_RT_BUILD_LIBFUZZER=OFF - -DCOMPILER_RT_BUILD_PROFILE=OFF -DCOMPILER_RT_BUILD_SANITIZERS=OFF -DCOMPILER_RT_BUILD_XRAY=OFF -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON -DLLVM_ENABLE_RUNTIMES=compiler-rt -DRUNTIME_VARIANT_NAME=${VARIANT} -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON +) + +ExternalProject_Add( + compiler_rt + STAMP_DIR ${PROJECT_PREFIX}/compiler_rt/${VARIANT_BUILD_ID}/stamp + BINARY_DIR ${PROJECT_PREFIX}/compiler_rt/${VARIANT_BUILD_ID}/build + DOWNLOAD_DIR ${PROJECT_PREFIX}/compiler_rt/${VARIANT_BUILD_ID}/dl + TMP_DIR ${PROJECT_PREFIX}/compiler_rt/${VARIANT_BUILD_ID}/tmp + SOURCE_DIR ${llvmproject_src_dir}/runtimes + INSTALL_DIR compiler-rt/install + CMAKE_ARGS + ${compiler_rt_common_flags} + ${compiler_launcher_cmake_args} + ${compiler_rt_cmake_args} ${compiler_rt_test_cmake_args} + -DCOMPILER_RT_BUILD_BUILTINS=ON + -DCOMPILER_RT_BUILD_PROFILE=OFF STEP_TARGETS configure build install USES_TERMINAL_CONFIGURE TRUE USES_TERMINAL_BUILD TRUE @@ -398,35 +405,12 @@ ExternalProject_Add( INSTALL_DIR compiler-rt-profile/install DEPENDS compiler_rt-install clib-install CMAKE_ARGS + ${compiler_rt_common_flags} ${compiler_launcher_cmake_args} - -DCMAKE_AR=${LLVM_BINARY_DIR}/bin/llvm-ar${CMAKE_EXECUTABLE_SUFFIX} - -DCMAKE_ASM_COMPILER_TARGET=${target_triple} - -DCMAKE_ASM_FLAGS=${lib_compile_flags} - -DCMAKE_BUILD_TYPE=${LIBRARY_CMAKE_BUILD_TYPE} - -DCMAKE_CXX_COMPILER=${LLVM_BINARY_DIR}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX} - -DCMAKE_CXX_COMPILER_TARGET=${target_triple} - -DCMAKE_CXX_FLAGS=${lib_compile_flags} - -DCMAKE_C_COMPILER=${LLVM_BINARY_DIR}/bin/clang${CMAKE_EXECUTABLE_SUFFIX} - -DCMAKE_C_COMPILER_TARGET=${target_triple} - -DCMAKE_C_FLAGS=${lib_compile_flags} - -DCMAKE_INSTALL_MESSAGE=${CMAKE_INSTALL_MESSAGE} - -DCMAKE_INSTALL_PREFIX= - -DCMAKE_NM=${LLVM_BINARY_DIR}/bin/llvm-nm${CMAKE_EXECUTABLE_SUFFIX} - -DCMAKE_RANLIB=${LLVM_BINARY_DIR}/bin/llvm-ranlib${CMAKE_EXECUTABLE_SUFFIX} - -DCMAKE_SYSTEM_NAME=Generic - -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY ${compiler_rt_cmake_args} - -DCOMPILER_RT_BAREMETAL_BUILD=ON -DCOMPILER_RT_BUILD_BUILTINS=OFF - -DCOMPILER_RT_BUILD_LIBFUZZER=OFF -DCOMPILER_RT_BUILD_PROFILE=ON -DCOMPILER_RT_PROFILE_BAREMETAL=ON - -DCOMPILER_RT_BUILD_SANITIZERS=OFF - -DCOMPILER_RT_BUILD_XRAY=OFF - -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON - -DLLVM_ENABLE_RUNTIMES=compiler-rt - -DRUNTIME_VARIANT_NAME=${VARIANT} - -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON STEP_TARGETS configure build install USES_TERMINAL_CONFIGURE TRUE USES_TERMINAL_BUILD TRUE