Index: compiler-rt/trunk/cmake/base-config-ix.cmake =================================================================== --- compiler-rt/trunk/cmake/base-config-ix.cmake +++ compiler-rt/trunk/cmake/base-config-ix.cmake @@ -47,15 +47,11 @@ ${LLVM_INCLUDE_TESTS}) option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered" ${LLVM_ENABLE_WERROR}) - # Use just-built Clang to compile/link tests on all platforms, except for - # Windows where we need to use clang-cl instead. - if(NOT MSVC) - set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang) - set(COMPILER_RT_TEST_CXX_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++) - else() - set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang.exe) - set(COMPILER_RT_TEST_CXX_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++.exe) - endif() + # Use just-built Clang to compile/link tests on all platforms. + set(COMPILER_RT_TEST_COMPILER + ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}) + set(COMPILER_RT_TEST_CXX_COMPILER + ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}) else() # Take output dir and install path from the user. set(COMPILER_RT_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH Index: compiler-rt/trunk/lib/profile/CMakeLists.txt =================================================================== --- compiler-rt/trunk/lib/profile/CMakeLists.txt +++ compiler-rt/trunk/lib/profile/CMakeLists.txt @@ -62,6 +62,7 @@ InstrProfilingPlatformFuchsia.c InstrProfilingPlatformLinux.c InstrProfilingPlatformOther.c + InstrProfilingPlatformWindows.c InstrProfilingRuntime.cc InstrProfilingUtil.c) Index: compiler-rt/trunk/lib/profile/InstrProfData.inc =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfData.inc +++ compiler-rt/trunk/lib/profile/InstrProfData.inc @@ -249,22 +249,22 @@ #define INSTR_PROF_DATA_DEFINED INSTR_PROF_SECT_ENTRY(IPSK_data, \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_DATA_COFF), "__DATA,") + INSTR_PROF_DATA_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_cnts, \ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COFF), "__DATA,") + INSTR_PROF_CNTS_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_name, \ INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_NAME_COFF), "__DATA,") + INSTR_PROF_NAME_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_vals, \ INSTR_PROF_QUOTE(INSTR_PROF_VALS_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_VALS_COFF), "__DATA,") + INSTR_PROF_VALS_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_vnodes, \ INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COFF), "__DATA,") + INSTR_PROF_VNODES_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_covmap, \ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COFF), "__LLVM_COV,") + INSTR_PROF_COVMAP_COFF, "__LLVM_COV,") #undef INSTR_PROF_SECT_ENTRY #endif @@ -654,13 +654,15 @@ #define INSTR_PROF_VALS_COMMON __llvm_prf_vals #define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds #define INSTR_PROF_COVMAP_COMMON __llvm_covmap -/* Win32 */ -#define INSTR_PROF_DATA_COFF .lprfd -#define INSTR_PROF_NAME_COFF .lprfn -#define INSTR_PROF_CNTS_COFF .lprfc -#define INSTR_PROF_VALS_COFF .lprfv -#define INSTR_PROF_VNODES_COFF .lprfnd -#define INSTR_PROF_COVMAP_COFF .lcovmap +/* Windows section names. Because these section names contain dollar characters, + * they must be quoted. + */ +#define INSTR_PROF_DATA_COFF ".lprfd$M" +#define INSTR_PROF_NAME_COFF ".lprfn$M" +#define INSTR_PROF_CNTS_COFF ".lprfc$M" +#define INSTR_PROF_VALS_COFF ".lprfv$M" +#define INSTR_PROF_VNODES_COFF ".lprfnd$M" +#define INSTR_PROF_COVMAP_COFF ".lcovmap$M" #ifdef _WIN32 /* Runtime section names and name strings. */ @@ -676,31 +678,18 @@ #define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF #else /* Runtime section names and name strings. */ -#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COMMON -#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COMMON -#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COMMON +#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON) +#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON) +#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON) /* Array of pointers. Each pointer points to a list * of value nodes associated with one value site. */ -#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_VALS_COMMON +#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VALS_COMMON) /* Value profile nodes section. */ -#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COMMON -#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COMMON +#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON) +#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON) #endif -#define INSTR_PROF_DATA_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME) -#define INSTR_PROF_NAME_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME) -#define INSTR_PROF_CNTS_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME) -#define INSTR_PROF_COVMAP_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME) -#define INSTR_PROF_VALS_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_VALS_SECT_NAME) -#define INSTR_PROF_VNODES_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_VNODES_SECT_NAME) - /* 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 Index: compiler-rt/trunk/lib/profile/InstrProfilingPlatformLinux.c =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfilingPlatformLinux.c +++ compiler-rt/trunk/lib/profile/InstrProfilingPlatformLinux.c @@ -13,14 +13,14 @@ #include "InstrProfiling.h" -#define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) -#define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_SECT_NAME) -#define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_SECT_NAME) -#define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_SECT_NAME) -#define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_SECT_NAME) -#define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_SECT_NAME) -#define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_SECT_NAME) -#define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_SECT_NAME) +#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_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_COMMON) +#define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_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) /* Declare section start and stop symbols for various sections * generated by compiler instrumentation. @@ -36,11 +36,11 @@ /* Add dummy data to ensure the section is always created. */ __llvm_profile_data - __prof_data_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_DATA_SECT_NAME_STR); + __prof_data_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_DATA_SECT_NAME); uint64_t - __prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME_STR); -char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME_STR); -ValueProfNode __prof_vnodes_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_VNODES_SECT_NAME_STR); + __prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME); +char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME); +ValueProfNode __prof_vnodes_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_VNODES_SECT_NAME); COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_begin_data(void) { Index: compiler-rt/trunk/lib/profile/InstrProfilingPlatformOther.c =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfilingPlatformOther.c +++ compiler-rt/trunk/lib/profile/InstrProfilingPlatformOther.c @@ -6,10 +6,12 @@ |* \*===----------------------------------------------------------------------===*/ -#if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) && \ - !(defined(__sun__) && defined(__svr4__)) && !defined(__NetBSD__) +#if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) && \ + !(defined(__sun__) && defined(__svr4__)) && !defined(__NetBSD__) && \ + !defined(_WIN32) #include +#include #include "InstrProfiling.h" @@ -91,13 +93,4 @@ COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = 0; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = 0; -#if defined(_WIN32) -// Put read-write sections in .data. -#pragma comment(linker, "/MERGE:.lprfc=.data") -#pragma comment(linker, "/MERGE:.lprfd=.data") -// Put read-write sections in .rdata. -#pragma comment(linker, "/MERGE:.lcovmap=.rdata") -#pragma comment(linker, "/MERGE:.lprfn=.rdata") -#endif - #endif Index: compiler-rt/trunk/lib/profile/InstrProfilingPlatformWindows.c =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfilingPlatformWindows.c +++ compiler-rt/trunk/lib/profile/InstrProfilingPlatformWindows.c @@ -0,0 +1,65 @@ +/*===- InstrProfilingPlatformWindows.c - Profile data on Windows ----------===*\ +|* +|* 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 +|* +\*===----------------------------------------------------------------------===*/ + +#include "InstrProfiling.h" + +#if defined(_WIN32) + +#if defined(_MSC_VER) +/* Merge read-write sections into .data. */ +#pragma comment(linker, "/MERGE:.lprfc=.data") +#pragma comment(linker, "/MERGE:.lprfd=.data") +#pragma comment(linker, "/MERGE:.lprfv=.data") +#pragma comment(linker, "/MERGE:.lprfnd=.data") +/* Merge read-only sections into .rdata. */ +#pragma comment(linker, "/MERGE:.lprfn=.rdata") +#pragma comment(linker, "/MERGE:.lcovmap=.rdata") + +/* Allocate read-only section bounds. */ +#pragma section(".lprfn$A", read) +#pragma section(".lprfn$Z", read) + +/* Allocate read-write section bounds. */ +#pragma section(".lprfd$A", read, write) +#pragma section(".lprfd$Z", read, write) +#pragma section(".lprfc$A", read, write) +#pragma section(".lprfc$Z", read, write) +#pragma section(".lprfnd$A", read, write) +#pragma section(".lprfnd$Z", read, write) +#endif + +__llvm_profile_data COMPILER_RT_SECTION(".lprfd$A") DataStart = {0}; +__llvm_profile_data COMPILER_RT_SECTION(".lprfd$Z") DataEnd = {0}; + +const char COMPILER_RT_SECTION(".lprfn$A") NamesStart = '\0'; +const char COMPILER_RT_SECTION(".lprfn$Z") NamesEnd = '\0'; + +uint64_t COMPILER_RT_SECTION(".lprfc$A") CountersStart; +uint64_t COMPILER_RT_SECTION(".lprfc$Z") CountersEnd; + +ValueProfNode COMPILER_RT_SECTION(".lprfnd$A") VNodesStart; +ValueProfNode COMPILER_RT_SECTION(".lprfnd$Z") VNodesEnd; + +const __llvm_profile_data *__llvm_profile_begin_data(void) { + return &DataStart + 1; +} +const __llvm_profile_data *__llvm_profile_end_data(void) { return &DataEnd; } + +const char *__llvm_profile_begin_names(void) { return &NamesStart + 1; } +const char *__llvm_profile_end_names(void) { return &NamesEnd; } + +uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart + 1; } +uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; } + +ValueProfNode *__llvm_profile_begin_vnodes(void) { return &VNodesStart + 1; } +ValueProfNode *__llvm_profile_end_vnodes(void) { return &VNodesEnd; } + +ValueProfNode *CurrentVNode = &VNodesStart + 1; +ValueProfNode *EndVNode = &VNodesEnd; + +#endif Index: compiler-rt/trunk/lib/profile/InstrProfilingValue.c =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfilingValue.c +++ compiler-rt/trunk/lib/profile/InstrProfilingValue.c @@ -31,7 +31,7 @@ * allocated by the compiler. */ COMPILER_RT_VISIBILITY ValueProfNode lprofValueProfNodes[INSTR_PROF_VNODE_POOL_SIZE] COMPILER_RT_SECTION( - COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME_STR); + COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME); #endif COMPILER_RT_VISIBILITY uint32_t VPMaxNumValsPerSite = Index: compiler-rt/trunk/test/profile/coverage-inline.cpp =================================================================== --- compiler-rt/trunk/test/profile/coverage-inline.cpp +++ compiler-rt/trunk/test/profile/coverage-inline.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_profgen -g -fcoverage-mapping -c -o %t1.o %s -DOBJECT_1 +// RUN: %clang_profgen -g -fcoverage-mapping -c -o %t2.o %s +// RUN: %clang_profgen -g -fcoverage-mapping %t1.o %t2.o -o %t.exe +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.exe +// RUN: llvm-profdata show %t.profraw -all-functions | FileCheck %s + +// Test that the instrumentation puts the right linkage on the profile data for +// inline functions. + +// CHECK: {{.*}}foo{{.*}}: +// CHECK-NEXT: Hash: +// CHECK-NEXT: Counters: 1 +// CHECK-NEXT: Function count: 1 +// CHECK: {{.*}}inline_wrapper{{.*}}: +// CHECK-NEXT: Hash: +// CHECK-NEXT: Counters: 1 +// CHECK-NEXT: Function count: 2 +// CHECK: main: +// CHECK-NEXT: Hash: +// CHECK-NEXT: Counters: 1 +// CHECK-NEXT: Function count: 1 + +extern "C" int puts(const char *); + +inline void inline_wrapper(const char *msg) { + puts(msg); +} + +void foo(); + +#ifdef OBJECT_1 +void foo() { + inline_wrapper("foo"); +} +#else +int main() { + inline_wrapper("main"); + foo(); +} +#endif Index: compiler-rt/trunk/test/profile/lit.cfg =================================================================== --- compiler-rt/trunk/test/profile/lit.cfg +++ compiler-rt/trunk/test/profile/lit.cfg @@ -24,6 +24,10 @@ if config.host_os in ['Linux']: extra_link_flags = ["-ldl"] +elif config.host_os in ['Windows']: + # InstrProf is incompatible with incremental linking. Disable it as a + # workaround. + extra_link_flags = ["-Wl,-incremental:no"] else: extra_link_flags = [] Index: llvm/trunk/include/llvm/ProfileData/InstrProfData.inc =================================================================== --- llvm/trunk/include/llvm/ProfileData/InstrProfData.inc +++ llvm/trunk/include/llvm/ProfileData/InstrProfData.inc @@ -249,22 +249,22 @@ #define INSTR_PROF_DATA_DEFINED INSTR_PROF_SECT_ENTRY(IPSK_data, \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_DATA_COFF), "__DATA,") + INSTR_PROF_DATA_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_cnts, \ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COFF), "__DATA,") + INSTR_PROF_CNTS_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_name, \ INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_NAME_COFF), "__DATA,") + INSTR_PROF_NAME_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_vals, \ INSTR_PROF_QUOTE(INSTR_PROF_VALS_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_VALS_COFF), "__DATA,") + INSTR_PROF_VALS_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_vnodes, \ INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COFF), "__DATA,") + INSTR_PROF_VNODES_COFF, "__DATA,") INSTR_PROF_SECT_ENTRY(IPSK_covmap, \ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON), \ - INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COFF), "__LLVM_COV,") + INSTR_PROF_COVMAP_COFF, "__LLVM_COV,") #undef INSTR_PROF_SECT_ENTRY #endif @@ -654,13 +654,15 @@ #define INSTR_PROF_VALS_COMMON __llvm_prf_vals #define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds #define INSTR_PROF_COVMAP_COMMON __llvm_covmap -/* Win32 */ -#define INSTR_PROF_DATA_COFF .lprfd -#define INSTR_PROF_NAME_COFF .lprfn -#define INSTR_PROF_CNTS_COFF .lprfc -#define INSTR_PROF_VALS_COFF .lprfv -#define INSTR_PROF_VNODES_COFF .lprfnd -#define INSTR_PROF_COVMAP_COFF .lcovmap +/* Windows section names. Because these section names contain dollar characters, + * they must be quoted. + */ +#define INSTR_PROF_DATA_COFF ".lprfd$M" +#define INSTR_PROF_NAME_COFF ".lprfn$M" +#define INSTR_PROF_CNTS_COFF ".lprfc$M" +#define INSTR_PROF_VALS_COFF ".lprfv$M" +#define INSTR_PROF_VNODES_COFF ".lprfnd$M" +#define INSTR_PROF_COVMAP_COFF ".lcovmap$M" #ifdef _WIN32 /* Runtime section names and name strings. */ @@ -676,31 +678,18 @@ #define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF #else /* Runtime section names and name strings. */ -#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COMMON -#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COMMON -#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COMMON +#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON) +#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON) +#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON) /* Array of pointers. Each pointer points to a list * of value nodes associated with one value site. */ -#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_VALS_COMMON +#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VALS_COMMON) /* Value profile nodes section. */ -#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COMMON -#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COMMON +#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON) +#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON) #endif -#define INSTR_PROF_DATA_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME) -#define INSTR_PROF_NAME_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME) -#define INSTR_PROF_CNTS_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME) -#define INSTR_PROF_COVMAP_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME) -#define INSTR_PROF_VALS_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_VALS_SECT_NAME) -#define INSTR_PROF_VNODES_SECT_NAME_STR \ - INSTR_PROF_QUOTE(INSTR_PROF_VNODES_SECT_NAME) - /* 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 Index: llvm/trunk/lib/Transforms/Instrumentation/InstrProfiling.cpp =================================================================== --- llvm/trunk/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ llvm/trunk/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -677,22 +677,6 @@ return F->hasAddressTaken() || F->hasLinkOnceLinkage(); } -static inline Comdat *getOrCreateProfileComdat(Module &M, Function &F, - InstrProfIncrementInst *Inc, - const Triple &TT) { - if (!needsComdatForCounter(F, M)) - return nullptr; - - // COFF format requires a COMDAT section to have a key symbol with the same - // name. The linker targeting COFF also requires that the COMDAT - // a section is associated to must precede the associating section. For this - // reason, we must choose the counter var's name as the name of the comdat. - StringRef ComdatPrefix = - (TT.isOSBinFormatCOFF() ? getInstrProfCountersVarPrefix() - : getInstrProfComdatPrefix()); - return M.getOrInsertComdat(StringRef(getVarName(Inc, ComdatPrefix))); -} - static bool needsRuntimeRegistrationOfSectionRange(const Triple &TT) { // Don't do this for Darwin. compiler-rt uses linker magic. if (TT.isOSDarwin()) @@ -700,7 +684,7 @@ // Use linker script magic to get data/cnts/name start/end. if (TT.isOSLinux() || TT.isOSFreeBSD() || TT.isOSNetBSD() || - TT.isOSFuchsia() || TT.isPS4CPU()) + TT.isOSFuchsia() || TT.isPS4CPU() || TT.isOSWindows()) return false; return true; @@ -717,13 +701,44 @@ PD = It->second; } - // Move the name variable to the right section. Place them in a COMDAT group - // if the associated function is a COMDAT. This will make sure that - // only one copy of counters of the COMDAT function will be emitted after - // linking. + // Match the linkage and visibility of the name global, except on COFF, where + // the linkage must be local and consequentially the visibility must be + // default. Function *Fn = Inc->getParent()->getParent(); - Comdat *ProfileVarsComdat = nullptr; - ProfileVarsComdat = getOrCreateProfileComdat(*M, *Fn, Inc, TT); + GlobalValue::LinkageTypes Linkage = NamePtr->getLinkage(); + GlobalValue::VisibilityTypes Visibility = NamePtr->getVisibility(); + if (TT.isOSBinFormatCOFF()) { + Linkage = GlobalValue::InternalLinkage; + Visibility = GlobalValue::DefaultVisibility; + } + + // Move the name variable to the right section. Place them in a COMDAT group + // if the associated function is a COMDAT. This will make sure that only one + // copy of counters of the COMDAT function will be emitted after linking. + Comdat *Cmdt = nullptr; + GlobalValue::LinkageTypes CounterLinkage = Linkage; + if (needsComdatForCounter(*Fn, *M)) { + if (TT.isOSBinFormatCOFF()) { + // There are two cases that need a comdat on COFF: + // 1. Functions that already have comdats (standard case) + // 2. available_externally functions (dllimport and C99 inline) + // In the first case, put all the data in the original function comdat. In + // the second case, create a new comdat group using the counter as the + // leader. It's linkage must be external, so use linkonce_odr linkage in + // that case. + if (Comdat *C = Fn->getComdat()) { + Cmdt = C; + } else { + Cmdt = M->getOrInsertComdat( + getVarName(Inc, getInstrProfCountersVarPrefix())); + CounterLinkage = GlobalValue::LinkOnceODRLinkage; + } + } else { + // For other platforms that use comdats (ELF), make a new comdat group for + // all the profile data. It will be deduplicated within the current DSO. + Cmdt = M->getOrInsertComdat(getVarName(Inc, getInstrProfComdatPrefix())); + } + } uint64_t NumCounters = Inc->getNumCounters()->getZExtValue(); LLVMContext &Ctx = M->getContext(); @@ -731,14 +746,15 @@ // Create the counters variable. auto *CounterPtr = - new GlobalVariable(*M, CounterTy, false, NamePtr->getLinkage(), + new GlobalVariable(*M, CounterTy, false, Linkage, Constant::getNullValue(CounterTy), getVarName(Inc, getInstrProfCountersVarPrefix())); - CounterPtr->setVisibility(NamePtr->getVisibility()); + CounterPtr->setVisibility(Visibility); CounterPtr->setSection( getInstrProfSectionName(IPSK_cnts, TT.getObjectFormat())); CounterPtr->setAlignment(8); - CounterPtr->setComdat(ProfileVarsComdat); + CounterPtr->setComdat(Cmdt); + CounterPtr->setLinkage(CounterLinkage); auto *Int8PtrTy = Type::getInt8PtrTy(Ctx); // Allocate statically the array of pointers to value profile nodes for @@ -752,14 +768,14 @@ ArrayType *ValuesTy = ArrayType::get(Type::getInt64Ty(Ctx), NS); auto *ValuesVar = - new GlobalVariable(*M, ValuesTy, false, NamePtr->getLinkage(), + new GlobalVariable(*M, ValuesTy, false, Linkage, Constant::getNullValue(ValuesTy), getVarName(Inc, getInstrProfValuesVarPrefix())); - ValuesVar->setVisibility(NamePtr->getVisibility()); + ValuesVar->setVisibility(Visibility); ValuesVar->setSection( getInstrProfSectionName(IPSK_vals, TT.getObjectFormat())); ValuesVar->setAlignment(8); - ValuesVar->setComdat(ProfileVarsComdat); + ValuesVar->setComdat(Cmdt); ValuesPtrExpr = ConstantExpr::getBitCast(ValuesVar, Type::getInt8PtrTy(Ctx)); } @@ -786,13 +802,13 @@ #define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Init, #include "llvm/ProfileData/InstrProfData.inc" }; - auto *Data = new GlobalVariable(*M, DataTy, false, NamePtr->getLinkage(), + auto *Data = new GlobalVariable(*M, DataTy, false, Linkage, ConstantStruct::get(DataTy, DataVals), getVarName(Inc, getInstrProfDataVarPrefix())); - Data->setVisibility(NamePtr->getVisibility()); + Data->setVisibility(Visibility); Data->setSection(getInstrProfSectionName(IPSK_data, TT.getObjectFormat())); Data->setAlignment(INSTR_PROF_DATA_ALIGNMENT); - Data->setComdat(ProfileVarsComdat); + Data->setComdat(Cmdt); PD.RegionCounters = CounterPtr; PD.DataVar = Data; @@ -878,6 +894,10 @@ NamesSize = CompressedNameStr.size(); NamesVar->setSection( getInstrProfSectionName(IPSK_name, TT.getObjectFormat())); + // On COFF, it's important to reduce the alignment down to 1 to prevent the + // linker from inserting padding before the start of the names section or + // between names entries. + NamesVar->setAlignment(1); UsedVars.push_back(NamesVar); for (auto *NamePtr : ReferencedNames) Index: llvm/trunk/test/Instrumentation/InstrProfiling/PR23499.ll =================================================================== --- llvm/trunk/test/Instrumentation/InstrProfiling/PR23499.ll +++ llvm/trunk/test/Instrumentation/InstrProfiling/PR23499.ll @@ -20,8 +20,8 @@ ; COFF-NOT: __profn__Z3barIvEvv -; COFF: @__profc__Z3barIvEvv = linkonce_odr hidden global [1 x i64] zeroinitializer, section "{{.*}}prfc", comdat, align 8 -; COFF: @__profd__Z3barIvEvv = linkonce_odr hidden global { i64, i64, i64*, i8*, i8*, i32, [2 x i16] } { i64 4947693190065689389, i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc__Z3barIvEvv, i32 0, i32 0), i8*{{.*}}, i8* null, i32 1, [2 x i16] zeroinitializer }, section "{{.*}}prfd{{.*}}", comdat($__profc__Z3barIvEvv), align 8 +; COFF: @__profc__Z3barIvEvv = internal global [1 x i64] zeroinitializer, section "{{.*}}prfc$M", comdat($_Z3barIvEvv), align 8 +; COFF: @__profd__Z3barIvEvv = internal global { i64, i64, i64*, i8*, i8*, i32, [2 x i16] } { i64 4947693190065689389, i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc__Z3barIvEvv, i32 0, i32 0), i8*{{.*}}, i8* null, i32 1, [2 x i16] zeroinitializer }, section "{{.*}}prfd{{.*}}", comdat($_Z3barIvEvv), align 8 declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #1 Index: llvm/trunk/test/Instrumentation/InstrProfiling/comdat.ll =================================================================== --- llvm/trunk/test/Instrumentation/InstrProfiling/comdat.ll +++ llvm/trunk/test/Instrumentation/InstrProfiling/comdat.ll @@ -0,0 +1,38 @@ +; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s --check-prefixes=ELF +; RUN: opt < %s -mtriple=x86_64-pc-win32-coff -instrprof -S | FileCheck %s --check-prefixes=COFF +; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes=instrprof -S | FileCheck %s --check-prefixes=ELF +; RUN: opt < %s -mtriple=x86_64-pc-win32-coff -passes=instrprof -S | FileCheck %s --check-prefixes=COFF + +; There are two main cases where comdats are necessary: +; 1. standard inline functions (weak_odr / linkonce_odr) +; 2. available externally functions (C99 inline / extern template / dllimport) +; Check that we do the right thing for the two object formats with comdats, ELF +; and COFF. + +declare void @llvm.instrprof.increment(i8*, i64, i32, i32) + +$foo_inline = comdat any + +@__profn_foo_inline = linkonce_odr hidden constant [10 x i8] c"foo_inline" + +; ELF: @__profc_foo_inline = linkonce_odr hidden global{{.*}}, section "__llvm_prf_cnts", comdat($__profv_foo_inline), align 8 +; ELF: @__profd_foo_inline = linkonce_odr hidden global{{.*}}, section "__llvm_prf_data", comdat($__profv_foo_inline), align 8 +; COFF: @__profc_foo_inline = internal global{{.*}}, section ".lprfc$M", comdat($foo_inline), align 8 +; COFF: @__profd_foo_inline = internal global{{.*}}, section ".lprfd$M", comdat($foo_inline), align 8 +define weak_odr void @foo_inline() comdat { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__profn_foo_inline, i32 0, i32 0), i64 0, i32 1, i32 0) + ret void +} + +$foo_extern = comdat any + +@__profn_foo_extern = linkonce_odr hidden constant [10 x i8] c"foo_extern" + +; ELF: @__profc_foo_extern = linkonce_odr hidden global{{.*}}, section "__llvm_prf_cnts", comdat($__profv_foo_extern) +; ELF: @__profd_foo_extern = linkonce_odr hidden global{{.*}}, section "__llvm_prf_data", comdat($__profv_foo_extern) +; COFF: @__profc_foo_extern = linkonce_odr dso_local global{{.*}}, section ".lprfc$M", comdat, align 8 +; COFF: @__profd_foo_extern = internal global{{.*}}, section ".lprfd$M", comdat($__profc_foo_extern), align 8 +define available_externally void @foo_extern() { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__profn_foo_extern, i32 0, i32 0), i64 0, i32 1, i32 0) + ret void +} Index: llvm/trunk/test/Instrumentation/InstrProfiling/linkage.ll =================================================================== --- llvm/trunk/test/Instrumentation/InstrProfiling/linkage.ll +++ llvm/trunk/test/Instrumentation/InstrProfiling/linkage.ll @@ -1,11 +1,11 @@ ;; Check that runtime symbols get appropriate linkage. -; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s --check-prefixes=COMMON,MACHO -; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s --check-prefixes=COMMON,LINUX -; RUN: opt < %s -mtriple=x86_64-pc-win32-coff -instrprof -S | FileCheck %s --check-prefixes=COMMON,COFF -; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -passes=instrprof -S | FileCheck %s --check-prefixes=COMMON,MACHO -; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes=instrprof -S | FileCheck %s --check-prefixes=COMMON,LINUX -; RUN: opt < %s -mtriple=x86_64-pc-win32-coff -passes=instrprof -S | FileCheck %s --check-prefixes=COMMON,COFF +; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s --check-prefixes=POSIX,MACHO +; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s --check-prefixes=POSIX,LINUX +; RUN: opt < %s -mtriple=x86_64-pc-win32-coff -instrprof -S | FileCheck %s --check-prefixes=COFF +; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -passes=instrprof -S | FileCheck %s --check-prefixes=POSIX,MACHO +; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes=instrprof -S | FileCheck %s --check-prefixes=POSIX,LINUX +; RUN: opt < %s -mtriple=x86_64-pc-win32-coff -passes=instrprof -S | FileCheck %s --check-prefixes=COFF ; MACHO: @__llvm_profile_runtime = external global i32 ; LINUX-NOT: @__llvm_profile_runtime = external global i32 @@ -16,31 +16,38 @@ @__profn_foo_inline = linkonce_odr hidden constant [10 x i8] c"foo_inline" @__profn_foo_extern = linkonce_odr hidden constant [10 x i8] c"foo_extern" -; COMMON: @__profc_foo = hidden global -; COMMON: @__profd_foo = hidden global +; POSIX: @__profc_foo = hidden global +; POSIX: @__profd_foo = hidden global +; COFF: @__profc_foo = internal global +; COFF-NOT: comdat +; COFF: @__profd_foo = internal global define void @foo() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } -; COMMON: @__profc_foo_weak = weak hidden global -; COMMON: @__profd_foo_weak = weak hidden global +; POSIX: @__profc_foo_weak = weak hidden global +; POSIX: @__profd_foo_weak = weak hidden global +; COFF: @__profc_foo_weak = internal global +; COFF: @__profd_foo_weak = internal global define weak void @foo_weak() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @__profn_foo_weak, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } -; COMMON: @"__profc_linkage.ll:foo_internal" = internal global -; COMMON: @"__profd_linkage.ll:foo_internal" = internal global +; POSIX: @"__profc_linkage.ll:foo_internal" = internal global +; POSIX: @"__profd_linkage.ll:foo_internal" = internal global +; COFF: @"__profc_linkage.ll:foo_internal" = internal global +; COFF: @"__profd_linkage.ll:foo_internal" = internal global define internal void @foo_internal() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @"__profn_linkage.ll:foo_internal", i32 0, i32 0), i64 0, i32 1, i32 0) ret void } -; COMMON: @__profc_foo_inline = linkonce_odr hidden global -; COFF-SAME: section ".lprfc", align 8 -; COMMON: @__profd_foo_inline = linkonce_odr hidden global -; COFF-SAME: section ".lprfd", align 8 +; POSIX: @__profc_foo_inline = linkonce_odr hidden global +; POSIX: @__profd_foo_inline = linkonce_odr hidden global +; COFF: @__profc_foo_inline = internal global{{.*}} section ".lprfc$M", align 8 +; COFF: @__profd_foo_inline = internal global{{.*}} section ".lprfd$M", align 8 define linkonce_odr void @foo_inline() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__profn_foo_inline, i32 0, i32 0), i64 0, i32 1, i32 0) ret void @@ -50,8 +57,8 @@ ; LINUX: @__profd_foo_extern = linkonce_odr hidden global {{.*}}section "__llvm_prf_data", comdat($__profv_foo_extern), align 8 ; MACHO: @__profc_foo_extern = linkonce_odr hidden global ; MACHO: @__profd_foo_extern = linkonce_odr hidden global -; COFF: @__profc_foo_extern = linkonce_odr hidden global {{.*}}section ".lprfc", comdat, align 8 -; COFF: @__profd_foo_extern = linkonce_odr hidden global {{.*}}section ".lprfd", comdat($__profc_foo_extern), align 8 +; COFF: @__profc_foo_extern = linkonce_odr dso_local global {{.*}}section ".lprfc$M", comdat, align 8 +; COFF: @__profd_foo_extern = internal global {{.*}}section ".lprfd$M", comdat($__profc_foo_extern), align 8 define available_externally void @foo_extern() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__profn_foo_extern, i32 0, i32 0), i64 0, i32 1, i32 0) ret void Index: llvm/trunk/test/Instrumentation/InstrProfiling/platform.ll =================================================================== --- llvm/trunk/test/Instrumentation/InstrProfiling/platform.ll +++ llvm/trunk/test/Instrumentation/InstrProfiling/platform.ll @@ -20,13 +20,14 @@ ; MACHO: @__profc_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 ; ELF: @__profc_foo = hidden global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8 -; WINDOWS: @__profc_foo = hidden global [1 x i64] zeroinitializer, section ".lprfc", align 8 +; WINDOWS: @__profc_foo = internal global [1 x i64] zeroinitializer, section ".lprfc$M", align 8 ; MACHO: @__profd_foo = hidden {{.*}}, section "__DATA,__llvm_prf_data,regular,live_support", align 8 ; ELF: @__profd_foo = hidden {{.*}}, section "__llvm_prf_data", align 8 -; WINDOWS: @__profd_foo = hidden {{.*}}, section ".lprfd", align 8 +; WINDOWS: @__profd_foo = internal global {{.*}}, section ".lprfd$M", align 8 -; ELF: @__llvm_prf_nm = private constant [{{.*}} x i8] c"{{.*}}", section "{{.*}}__llvm_prf_names" +; ELF: @__llvm_prf_nm = private constant [{{.*}} x i8] c"{{.*}}", section "{{.*}}__llvm_prf_names", align 1 +; WINDOWS: @__llvm_prf_nm = private constant [{{.*}} x i8] c"{{.*}}", section "{{.*}}lprfn$M", align 1 define void @foo() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 0, i32 1, i32 0) @@ -42,14 +43,11 @@ ; LINUX-NOT: define internal void @__llvm_profile_register_functions ; FREEBSD-NOT: define internal void @__llvm_profile_register_functions ; PS4-NOT: define internal void @__llvm_profile_register_functions +; WINDOWS-NOT: define internal void @__llvm_profile_register_functions ;; PR38340: When dynamic registration is used, we had a bug where we'd register ;; something that's not a __profd_* variable. -; WINDOWS: define internal void @__llvm_profile_register_functions() -; WINDOWS-NOT: __llvm_profile_runtime_user -; WINDOWS: ret void - ; SOLARIS: define internal void @__llvm_profile_register_functions ; SOLARIS-NOT: __llvm_profile_runtime_user ; SOLARIS: ret void @@ -58,5 +56,5 @@ ; LINUX-NOT: define internal void @__llvm_profile_init ; FREEBSD-NOT: define internal void @__llvm_profile_init ; PS4-NOT: define internal void @__llvm_profile_init +; WINDOWS-NOT: define internal void @__llvm_profile_init ; SOLARIS: define internal void @__llvm_profile_init -; WINDOWS: define internal void @__llvm_profile_init