Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- `clang --target=aarch64-linux-gnu`
- The prebuilt arm64/universal macOS packages additionally bundle the arm64 iOS-*simulator* libraries, for out-of-the-box cross-compilation support via e.g. `-mtriple=arm64-apple-ios12.0-simulator`. (#4974)
- New `--fdebug-prefix-map` command-line option and changed debuginfo file/directory name splitting logic (both now similar to clang), to aid reproducible builds. (#5039)
- New `--funified-lto` command-line option, same as clang.

#### Platform support
- Supports LLVM 15 - 21.
Expand Down
2 changes: 2 additions & 0 deletions driver/cl_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,8 @@ cl::opt<bool> ltoFatObjects(
"ffat-lto-objects", cl::ZeroOrMore,
cl::desc("Include both IR and object code in object file output; only "
"effective when compiling with -flto."));
cl::opt<bool> ltoUnified("funified-lto", cl::ZeroOrMore,
cl::desc("Use unified LTO pipeline."));

cl::opt<std::string>
saveOptimizationRecord("fsave-optimization-record",
Expand Down
4 changes: 3 additions & 1 deletion driver/cl_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,11 @@ enum LTOKind {
LTO_Thin,
};
extern cl::opt<LTOKind> ltoMode;
extern cl::opt<bool> ltoFatObjects;
extern cl::opt<bool> ltoUnified;
inline bool isUsingLTO() { return ltoMode != LTO_None; }
inline bool isUsingThinLTO() { return ltoMode == LTO_Thin; }
extern cl::opt<bool> ltoFatObjects;
inline bool prepareForThinLTO() { return isUsingThinLTO() || opts::ltoUnified; }

extern cl::opt<std::string> saveOptimizationRecord;

Expand Down
72 changes: 54 additions & 18 deletions gen/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,24 @@
//
//===----------------------------------------------------------------------===//

#ifdef IN_JITRT
#include "runtime/jit-rt/cpp-so/optimizer.h"
#include "runtime/jit-rt/cpp-so/valueparser.h"
#include "runtime/jit-rt/cpp-so/utils.h"
#endif

#include "gen/optimizer.h"

#ifndef IN_JITRT
#include "dmd/errors.h"
#include "gen/logger.h"
#endif

#include "gen/passes/GarbageCollect2Stack.h"
#include "gen/passes/StripExternals.h"
#include "gen/passes/SimplifyDRuntimeCalls.h"
#include "gen/passes/Passes.h"

#ifndef IN_JITRT
#ifdef IN_JITRT
#include "runtime/jit-rt/cpp-so/optimizer.h"
#include "runtime/jit-rt/cpp-so/valueparser.h"
#include "runtime/jit-rt/cpp-so/utils.h"
#else
#include "dmd/errors.h"
#include "driver/cl_options.h"
#include "driver/cl_options_instrumentation.h"
#include "driver/cl_options_sanitizers.h"
#include "driver/plugins.h"
#include "driver/targetmachine.h"
#include "gen/logger.h"
#endif

#if LDC_LLVM_VER < 1700
Expand Down Expand Up @@ -355,7 +349,9 @@ static void addGarbageCollect2StackPass(ModulePassManager &mpm,
}
}

// Exclude these functions, that access cmdline options, from the JIT RT.
#ifndef IN_JITRT

static llvm::Optional<PGOOptions> getPGOOptions() {
// FIXME: Do we have these anywhere?
bool debugInfoForProfiling = false;
Expand Down Expand Up @@ -409,6 +405,44 @@ static llvm::Optional<PGOOptions> getPGOOptions() {
return std::nullopt;
#endif
}

// Imitate behavior of clang
static bool shouldEmitRegularLTOSummary(llvm::Module const &M) {
return opts::isUsingLTO() &&
llvm::Triple(M.getTargetTriple()).getVendor() != llvm::Triple::Apple;
}

/// Check whether we should emit a flag for UnifiedLTO.
/// The UnifiedLTO module flag should be set when UnifiedLTO is enabled for
/// ThinLTO or Full LTO with module summaries.
static bool shouldEmitUnifiedLTOModuleFlag(llvm::Module const &M) {
return opts::ltoUnified &&
(opts::prepareForThinLTO() || shouldEmitRegularLTOSummary(M));
}

static void addLTOModuleFlags(llvm::Module *M) {
if (opts::ltoFatObjects) {
if (opts::prepareForThinLTO()) {
// TODO: implement support for EnableSplitLTOUnit
// if (!M->getModuleFlag("EnableSplitLTOUnit"))
// M->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit",
// CodeGenOpts.EnableSplitLTOUnit);
} else {
if (shouldEmitRegularLTOSummary(*M)) {
if (!M->getModuleFlag("ThinLTO") && !opts::ltoUnified)
M->addModuleFlag(llvm::Module::Error, "ThinLTO", uint32_t(0));
if (!M->getModuleFlag("EnableSplitLTOUnit"))
M->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit",
uint32_t(1));
}
}

if (shouldEmitUnifiedLTOModuleFlag(*M) &&
!M->getModuleFlag("UnifiedLTO"))
M->addModuleFlag(llvm::Module::Error, "UnifiedLTO", uint32_t(1));
}
}

#endif // !IN_JITRT

static PipelineTuningOptions getPipelineTuningOptions(unsigned optLevelVal, unsigned sizeLevelVal) {
Expand Down Expand Up @@ -585,12 +619,11 @@ void runOptimizationPasses(llvm::Module *M, llvm::TargetMachine *TM) {
mpm = pb.buildO0DefaultPipeline(level, ltoPrelink);
#if LDC_LLVM_VER >= 1700
} else if (opts::ltoFatObjects && opts::isUsingLTO()) {
mpm = pb.buildFatLTODefaultPipeline(level,
opts::isUsingThinLTO(),
opts::isUsingThinLTO()
);
mpm = pb.buildFatLTODefaultPipeline(level, opts::prepareForThinLTO(),
opts::prepareForThinLTO() ||
shouldEmitRegularLTOSummary(*M));
#endif
} else if (opts::isUsingThinLTO()) {
} else if (opts::prepareForThinLTO()) {
mpm = pb.buildThinLTOPreLinkDefaultPipeline(level);
} else if (opts::isUsingLTO()) {
mpm = pb.buildLTOPreLinkDefaultPipeline(level);
Expand All @@ -599,6 +632,9 @@ void runOptimizationPasses(llvm::Module *M, llvm::TargetMachine *TM) {
mpm = pb.buildPerModuleDefaultPipeline(level);
}

#ifndef IN_JITRT
addLTOModuleFlags(M);
#endif

mpm.run(*M,mam);
}
Expand Down
25 changes: 25 additions & 0 deletions tests/linking/lto_unified.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Test unified lto commandline flag

// REQUIRES: LTO
// REQUIRES: atleast_llvm1800

// RUN: split-file %s %t

// RUN: %ldc %t/second.d -of=%t/second_thin%obj -c -flto=thin
// RUN: %ldc %t/third.d -of=%t/third_full%obj -c -flto=full
// RUN: %ldc -I%t %t/main.d %t/second_thin%obj %t/third_full%obj -flto=full -O

//--- main.d
import second;
import third;
void main()
{
foo();
g();
}

//--- second.d
void foo() {}

//--- third.d
void g() {}
Loading