Merge pull request #4320 from kinke/dead_strip

Be less conservative wrt. linker dead code elimination
This commit is contained in:
Martin Kinkelin 2023-02-22 16:10:19 +01:00 committed by GitHub
commit aa9b2783bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 66 additions and 50 deletions

View file

@ -1,6 +1,7 @@
# LDC master
#### Big news
- Linker-level dead code elimination is enabled by default for Apple, wasm and *all* ELF targets too now. (#4320)
#### Platform support

View file

@ -635,33 +635,6 @@ if(LDC_WITH_LLD)
endif()
endif()
# Plugin support
if(UNIX)
set(LDC_ENABLE_PLUGINS_DEFAULT ON)
else()
set(LDC_ENABLE_PLUGINS_DEFAULT OFF)
endif()
set(LDC_ENABLE_PLUGINS ${LDC_ENABLE_PLUGINS_DEFAULT} CACHE BOOL "Build LDC with plugin support (increases binary size)")
if(LDC_ENABLE_PLUGINS)
add_definitions(-DLDC_ENABLE_PLUGINS)
if(APPLE)
# No extra link flags needed.
elseif(UNIX)
# For plugin support, we need to link with --export-dynamic on Unix.
# Make sure the linker supports --export-dynamic (on Solaris it is not supported and also not needed).
set(CMAKE_REQUIRED_QUIET_BAK ${CMAKE_REQUIRED_QUIET})
set(CMAKE_REQUIRED_QUIET ON) # suppress status messages
CHECK_LINK_FLAG("--export-dynamic" LINKER_ACCEPTS_EXPORT_DYNAMIC_FLAG)
set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_BAK})
if(LINKER_ACCEPTS_EXPORT_DYNAMIC_FLAG)
set(LDC_LINKERFLAG_LIST "${LDC_LINKERFLAG_LIST};-Wl,--export-dynamic")
endif()
endif()
endif()
message(STATUS "-- Building LDC with plugin support (LDC_ENABLE_PLUGINS): ${LDC_ENABLE_PLUGINS}")
if(NOT DEFINED LDC_LINK_MANUALLY)
if(MSVC)
# Use the D host compiler for linking D executables.
@ -678,6 +651,42 @@ if(LDC_LINK_MANUALLY AND NOT DEFINED D_LINKER_ARGS)
message(STATUS "Host D compiler linker flags: ${D_LINKER_ARGS}")
endif()
# Plugin support
if(UNIX)
set(LDC_ENABLE_PLUGINS_DEFAULT ON)
else()
set(LDC_ENABLE_PLUGINS_DEFAULT OFF)
endif()
set(LDC_ENABLE_PLUGINS ${LDC_ENABLE_PLUGINS_DEFAULT} CACHE BOOL "Build LDC with plugin support (increases binary size)")
if(LDC_ENABLE_PLUGINS)
add_definitions(-DLDC_ENABLE_PLUGINS)
if(APPLE)
# Need to disable dead_strip with LDC host compilers.
if("${D_COMPILER_ID}" STREQUAL "LDMD")
if(LDC_LINK_MANUALLY)
# suboptimal - applies to all D executables (incl. ldmd2, ldc-build-runtime, ldc-prune-cache)
list(REMOVE_ITEM D_LINKER_ARGS "-Wl,-dead_strip")
else()
# just for ldc2 (and ldc2-unittest)
append("-disable-linker-strip-dead" DFLAGS_LDC)
endif()
endif()
elseif(UNIX)
# For plugin support, we need to link with --export-dynamic on Unix.
# Make sure the linker supports --export-dynamic (on Solaris it is not supported and also not needed).
set(CMAKE_REQUIRED_QUIET_BAK ${CMAKE_REQUIRED_QUIET})
set(CMAKE_REQUIRED_QUIET ON) # suppress status messages
CHECK_LINK_FLAG("--export-dynamic" LINKER_ACCEPTS_EXPORT_DYNAMIC_FLAG)
set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_BAK})
if(LINKER_ACCEPTS_EXPORT_DYNAMIC_FLAG)
set(LDC_LINKERFLAG_LIST "${LDC_LINKERFLAG_LIST};-Wl,--export-dynamic")
endif()
endif()
endif()
message(STATUS "-- Building LDC with plugin support (LDC_ENABLE_PLUGINS): ${LDC_ENABLE_PLUGINS}")
build_d_executable(
"${LDC_EXE}"
"${LDC_EXE_FULL}"

View file

@ -479,6 +479,8 @@ void ArgsBuilder::addSanitizers(const llvm::Triple &triple) {
void ArgsBuilder::build(llvm::StringRef outputPath,
const std::vector<std::string> &defaultLibNames) {
const auto &triple = *global.params.targetTriple;
// object files
for (auto objfile : global.params.objfiles) {
args.push_back(objfile);
@ -494,7 +496,7 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
// Link with profile-rt library when generating an instrumented binary.
if (opts::isInstrumentingForPGO()) {
addProfileRuntimeLinkFlags(*global.params.targetTriple);
addProfileRuntimeLinkFlags(triple);
}
if (opts::enableDynamicCompile) {
@ -521,10 +523,10 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
args.push_back("-o");
args.push_back(std::string(outputPath));
addSanitizers(*global.params.targetTriple);
addSanitizers(triple);
if (opts::fXRayInstrument) {
addXRayLinkFlags(*global.params.targetTriple);
addXRayLinkFlags(triple);
}
// Add LTO link flags before adding the user link switches, such that the user
@ -559,16 +561,14 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
addLdFlag("-rpath", rpath);
}
if (global.params.targetTriple->getOS() == llvm::Triple::Linux ||
(global.params.targetTriple->getOS() == llvm::Triple::FreeBSD &&
(useInternalLLDForLinking() ||
(!opts::linker.empty() && opts::linker != "bfd") ||
(opts::linker.empty() && isLldDefaultLinker())))) {
// Make sure we don't do --gc-sections when generating a profile-
// instrumented binary. The runtime relies on magic sections, which
// would be stripped by gc-section on older version of ld, see bug:
// https://sourceware.org/bugzilla/show_bug.cgi?id=19161
if (!opts::disableLinkerStripDead && !opts::isInstrumentingForPGO()) {
// Make sure we don't do --gc-sections when generating a profile-
// instrumented binary. The runtime relies on magic sections, which
// would be stripped by gc-section on older version of ld, see bug:
// https://sourceware.org/bugzilla/show_bug.cgi?id=19161
if (!opts::disableLinkerStripDead && !opts::isInstrumentingForPGO()) {
if (triple.isOSBinFormatMachO()) {
addLdFlag("-dead_strip");
} else {
addLdFlag("--gc-sections");
}
}

View file

@ -505,14 +505,14 @@ createTargetMachine(const std::string targetTriple, const std::string arch,
break;
}
// Right now, we only support linker-level dead code elimination on Linux
// and FreeBSD using GNU or LLD linkers (based on the --gc-sections flag).
// The Apple ld on OS X supports a similar flag (-dead_strip) that doesn't
// require emitting the symbols into different sections. The MinGW ld doesn't
// seem to support --gc-sections at all.
if (!noLinkerStripDead && (triple.getOS() == llvm::Triple::Linux ||
triple.getOS() == llvm::Triple::FreeBSD ||
triple.getOS() == llvm::Triple::Win32)) {
// Linker-level dead code elimination for ELF/wasm binaries using GNU or LLD
// linkers (based on the --gc-sections flag) requires a separate section per
// symbol.
// The Apple ld64 on macOS supports a similar flag (-dead_strip) that doesn't
// require emitting the symbols into different sections.
// On Windows, the MSVC link.exe / lld-link.exe has `/REF`; LLD enforces
// separate sections with LTO, so do the same here.
if (!noLinkerStripDead && !triple.isOSBinFormatMachO()) {
targetOptions.FunctionSections = true;
targetOptions.DataSections = true;
}

View file

@ -150,7 +150,12 @@ void IrGlobal::define() {
// If this global is used from a naked function, we need to create an
// artificial "use" for it, or it could be removed by the optimizer if
// the only reference to it is in inline asm.
if (nakedUse) {
// Also prevent linker-level dead-symbol-elimination from stripping
// special `rt_*` druntime symbol overrides (e.g., from executables linked
// against *shared* druntime; required at least for Apple's ld64 linker).
const auto name = gvar->getName();
if (nakedUse || name == "rt_options" || name == "rt_envvars_enabled" ||
name == "rt_cmdline_enabled") {
gIR->usedArray.push_back(gvar);
}

View file

@ -10,7 +10,8 @@ GREP:=grep
.PHONY: all clean
all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS)))
$(ROOT)/profile.done: DFLAGS+=-profile
# LDC: enable assertions for BUILD=RELEASE (=> `-O -release`)
$(ROOT)/profile.done: DFLAGS+=-profile -check=assert=on
$(ROOT)/profile.done: $(ROOT)/%.done: $(ROOT)/%
@echo Testing $*
@rm -f $(ROOT)/mytrace.log $(ROOT)/mytrace.def