Skip to content

Commit c5463bd

Browse files
Merge pull request #68985 from antoniofrighetto/feature/load-pass-plugin
[Driver][Frontend] Introduce `load-pass-plugin` option
2 parents 990d62c + 377c03f commit c5463bd

File tree

10 files changed

+119
-18
lines changed

10 files changed

+119
-18
lines changed

include/swift/AST/DiagnosticsIRGen.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,8 @@ ERROR(attr_objc_implementation_resilient_property_deployment_target, none,
7777
"target to %0 %2 or store this value in an object or 'any' type",
7878
(StringRef, const llvm::VersionTuple, const llvm::VersionTuple))
7979

80+
ERROR(unable_to_load_pass_plugin,none,
81+
"unable to load plugin '%0': '%1'", (StringRef, StringRef))
82+
8083
#define UNDEFINE_DIAGNOSTIC_MACROS
8184
#include "DefineDiagnosticMacros.h"

include/swift/AST/IRGenOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,9 @@ class IRGenOptions {
551551
/// Emit a .casid file next to the object file if CAS Backend is used.
552552
bool EmitCASIDFile;
553553

554+
/// Paths to the pass plugins registered via -load-pass-plugin.
555+
std::vector<std::string> LLVMPassPlugins;
556+
554557
IRGenOptions()
555558
: OutputKind(IRGenOutputKind::LLVMAssemblyAfterOptimization),
556559
Verify(true), OptMode(OptimizationMode::NotSet),

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,6 +1888,11 @@ def use_interface_for_module: Separate<["-", "--"], "use-interface-for-module">,
18881888
HelpText<"Prefer loading these modules via interface">,
18891889
MetaVarName<"<name>">;
18901890

1891+
def load_pass_plugin_EQ : Joined<["-"], "load-pass-plugin=">,
1892+
Flags<[FrontendOption, ArgumentIsPath]>,
1893+
HelpText<"Load LLVM pass plugin from a dynamic shared object file.">,
1894+
MetaVarName<"<path>">;
1895+
18911896
// ONLY SUPPORTED IN NEW DRIVER
18921897

18931898
// These flags only exist here so that the old driver doesn't fail with unknown

include/swift/Subsystems.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,10 @@ namespace swift {
266266
/// Given an already created LLVM module, construct a pass pipeline and run
267267
/// the Swift LLVM Pipeline upon it. This will include the emission of LLVM IR
268268
/// if requested (\out is not null).
269-
void performLLVMOptimizations(const IRGenOptions &Opts, llvm::Module *Module,
269+
void performLLVMOptimizations(const IRGenOptions &Opts,
270+
DiagnosticEngine &Diags,
271+
llvm::sys::Mutex *DiagMutex,
272+
llvm::Module *Module,
270273
llvm::TargetMachine *TargetMachine,
271274
llvm::raw_pwrite_stream *out);
272275

lib/Driver/ToolChains.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
349349
inputArgs.AddLastArg(arguments, options::OPT_cxx_interoperability_mode);
350350
inputArgs.AddLastArg(arguments, options::OPT_enable_builtin_module);
351351
inputArgs.AddLastArg(arguments, options::OPT_compiler_assertions);
352+
inputArgs.AddLastArg(arguments, options::OPT_load_pass_plugin_EQ);
352353

353354
// Pass on any build config options
354355
inputArgs.AddAllArgs(arguments, options::OPT_D);

lib/DriverTool/swift_llvm_opt_main.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,10 @@ int swift_llvm_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
214214
Opts.OutputKind = IRGenOutputKind::LLVMAssemblyAfterOptimization;
215215

216216
// Then perform the optimizations.
217-
performLLVMOptimizations(Opts, M.get(), TM.get(), &Out->os());
217+
SourceManager SM;
218+
DiagnosticEngine Diags(SM);
219+
performLLVMOptimizations(Opts, Diags, nullptr, M.get(), TM.get(),
220+
&Out->os());
218221
} else {
219222
std::string Pipeline = PassPipeline;
220223
llvm::TargetLibraryInfoImpl TLII(ModuleTriple);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3233,6 +3233,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
32333233
}
32343234
}
32353235

3236+
for (const Arg *A : Args.filtered(OPT_load_pass_plugin_EQ)) {
3237+
Opts.LLVMPassPlugins.push_back(A->getValue());
3238+
}
3239+
32363240
for (const Arg *A : Args.filtered(OPT_verify_type_layout)) {
32373241
Opts.VerifyTypeLayoutNames.push_back(A->getValue());
32383242
}

lib/IRGen/IRGen.cpp

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#include "llvm/MC/TargetRegistry.h"
7070
#include "llvm/Object/ObjectFile.h"
7171
#include "llvm/Passes/PassBuilder.h"
72+
#include "llvm/Passes/PassPlugin.h"
7273
#include "llvm/Passes/StandardInstrumentations.h"
7374
#include "llvm/Support/CommandLine.h"
7475
#include "llvm/Support/Debug.h"
@@ -233,7 +234,21 @@ static void populatePGOOptions(std::optional<PGOOptions> &Out,
233234
}
234235
}
235236

237+
template <typename... ArgTypes>
238+
void diagnoseSync(
239+
DiagnosticEngine &Diags, llvm::sys::Mutex *DiagMutex, SourceLoc Loc,
240+
Diag<ArgTypes...> ID,
241+
typename swift::detail::PassArgument<ArgTypes>::type... Args) {
242+
std::optional<llvm::sys::ScopedLock> Lock;
243+
if (DiagMutex)
244+
Lock.emplace(*DiagMutex);
245+
246+
Diags.diagnose(Loc, ID, std::move(Args)...);
247+
}
248+
236249
void swift::performLLVMOptimizations(const IRGenOptions &Opts,
250+
DiagnosticEngine &Diags,
251+
llvm::sys::Mutex *DiagMutex,
237252
llvm::Module *Module,
238253
llvm::TargetMachine *TargetMachine,
239254
llvm::raw_pwrite_stream *out) {
@@ -279,6 +294,18 @@ void swift::performLLVMOptimizations(const IRGenOptions &Opts,
279294

280295
PassBuilder PB(TargetMachine, PTO, PGOOpt, &PIC);
281296

297+
// Attempt to load pass plugins and register their callbacks with PB.
298+
for (const auto &PluginFile : Opts.LLVMPassPlugins) {
299+
Expected<PassPlugin> PassPlugin = PassPlugin::Load(PluginFile);
300+
if (PassPlugin) {
301+
PassPlugin->registerPassBuilderCallbacks(PB);
302+
} else {
303+
diagnoseSync(Diags, DiagMutex, SourceLoc(),
304+
diag::unable_to_load_pass_plugin, PluginFile,
305+
toString(PassPlugin.takeError()));
306+
}
307+
}
308+
282309
// Register the AA manager first so that our version is the one used.
283310
FAM.registerPass([&] {
284311
auto AA = PB.buildDefaultAAPipeline();
@@ -565,20 +592,6 @@ static void countStatsPostIRGen(UnifiedStatsReporter &Stats,
565592
}
566593
}
567594

568-
template<typename ...ArgTypes>
569-
void
570-
diagnoseSync(DiagnosticEngine &Diags, llvm::sys::Mutex *DiagMutex,
571-
SourceLoc Loc, Diag<ArgTypes...> ID,
572-
typename swift::detail::PassArgument<ArgTypes>::type... Args) {
573-
if (DiagMutex)
574-
DiagMutex->lock();
575-
576-
Diags.diagnose(Loc, ID, std::move(Args)...);
577-
578-
if (DiagMutex)
579-
DiagMutex->unlock();
580-
}
581-
582595
/// Run the LLVM passes. In multi-threaded compilation this will be done for
583596
/// multiple LLVM modules in parallel.
584597
bool swift::performLLVM(const IRGenOptions &Opts,
@@ -647,7 +660,7 @@ bool swift::performLLVM(const IRGenOptions &Opts,
647660
assert(Opts.OutputKind == IRGenOutputKind::Module && "no output specified");
648661
}
649662

650-
performLLVMOptimizations(Opts, Module, TargetMachine,
663+
performLLVMOptimizations(Opts, Diags, DiagMutex, Module, TargetMachine,
651664
OutputFile ? &OutputFile->getOS() : nullptr);
652665

653666
if (Stats) {
@@ -1779,7 +1792,7 @@ GeneratedModule OptimizedIRRequest::evaluate(Evaluator &evaluator,
17791792
if (!irMod)
17801793
return irMod;
17811794

1782-
performLLVMOptimizations(desc.Opts, irMod.getModule(),
1795+
performLLVMOptimizations(desc.Opts, ctx.Diags, nullptr, irMod.getModule(),
17831796
irMod.getTargetMachine(), desc.out);
17841797
return irMod;
17851798
}

test/Frontend/Inputs/TestPlugin.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===---------------------- TestPlugin.cpp --------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// Used by -load-pass-plugin
14+
15+
#include "llvm/Pass.h"
16+
#include "llvm/Passes/PassBuilder.h"
17+
#include "llvm/Passes/PassPlugin.h"
18+
19+
using namespace llvm;
20+
21+
namespace {
22+
23+
void runTestPlugin(Function &F) {
24+
errs() << "TestPlugin: ";
25+
errs().write_escaped(F.getName()) << '\n';
26+
}
27+
28+
struct TestPluginPass : PassInfoMixin<TestPluginPass> {
29+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
30+
runTestPlugin(F);
31+
return PreservedAnalyses::all();
32+
}
33+
};
34+
35+
} // namespace
36+
37+
PassPluginLibraryInfo getTestPluginInfo() {
38+
return {LLVM_PLUGIN_API_VERSION, "TestPlugin", LLVM_VERSION_STRING,
39+
[](PassBuilder &PB) {
40+
PB.registerVectorizerStartEPCallback(
41+
[](llvm::FunctionPassManager &PM, OptimizationLevel Level) {
42+
PM.addPass(TestPluginPass());
43+
});
44+
}};
45+
}
46+
47+
extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
48+
llvmGetPassPluginInfo() {
49+
return getTestPluginInfo();
50+
}

test/Frontend/load-pass-plugin.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// REQUIRES: OS=macosx
2+
3+
// RUN: %target-swift-frontend -load-pass-plugin=nonexistent.dylib %s -emit-ir -o /dev/null 2>&1 | %FileCheck -check-prefix=CHECK-UNABLE-LOAD %s
4+
// CHECK-UNABLE-LOAD: error: unable to load plugin 'nonexistent.dylib': 'Could not load library{{.*}}'
5+
6+
// RUN: %empty-directory(%t)
7+
// RUN: %target-clangxx %S/Inputs/TestPlugin.cpp -std=c++17 -stdlib=libc++ \
8+
// RUN: -isysroot %sdk -I %llvm_src_root/include -I %llvm_obj_root/include -L %llvm_obj_root/lib -lLLVMSupport \
9+
// RUN: -Wl,-undefined -Wl,suppress -Wl,-flat_namespace \
10+
// RUN: -dynamiclib -o %t/libTestPlugin.dylib
11+
12+
// RUN: %target-swift-frontend -load-pass-plugin=%t/libTestPlugin.dylib %s -emit-ir -o /dev/null 2>&1 | %swift-demangle | %FileCheck %s
13+
// CHECK: TestPlugin: main
14+
// CHECK: TestPlugin: null.empty() -> ()
15+
16+
func empty() {}

0 commit comments

Comments
 (0)