diff --git a/llvm/include/llvm-c/Transforms/PassBuilder.h b/llvm/include/llvm-c/Transforms/PassBuilder.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm-c/Transforms/PassBuilder.h @@ -0,0 +1,123 @@ +/*===-- llvm-c/Transform/PassBuilder.h - PassBuilder for LLVM C ---*- 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 *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header contains the LLVM-C interface into the new pass manager *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TRANSFORMS_PASSBUILDER_H +#define LLVM_C_TRANSFORMS_PASSBUILDER_H + +#include "llvm-c/Error.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Types.h" + +LLVM_C_EXTERN_C_BEGIN + +/** + * A reference to an llvm::PipelineTuningOptions instance + */ +typedef struct LLVMOpaquePipelineTuningOptions *LLVMPipelineTuningOptionsRef; + +/** + * A set of options passed which are attached to the Pass Manager upon run. + * + * This corresponds to an llvm::LLVMPassBuilderOptions instance + * + * The details for how the different properties of this structure are used can + * be found in the source for LLVMRunPasses + */ +typedef struct LLVMOpaquePassBuilderOptions *LLVMPassBuilderOptionsRef; + +/** + * Construct and run a set of passes over a module + * + * This function takes a string with the passes that should be used. The format + * of this string is the same as opt's -passes argument for the new pass + * manager. Individual passes can be specified, separated by commas. Full + * pipelines may also be invoked using `default` and friends. See opt for + * full reference of the Passes format. + * + * If Debug is enabled, then debug logging from the analysis managers and + * standard instrumentation will be printed to stderr. + * + * If VerifyEach is enabled, then a module verification pass will be ran in + * addition to the other passes. + */ +LLVMErrorRef LLVMRunPasses(LLVMTargetMachineRef TM, LLVMModuleRef M, + LLVMPassBuilderOptionsRef Options, + const char *Passes); + +/** + * Create a new set of options for a PassBuilder + * + * Ownership of the returned instance is given to the client, and they are + * responsible for it. The client should call LLVMDisposePassBuilderOptions + * to free the pass builder options. + */ +LLVMPassBuilderOptionsRef LLVMCreatePassBuilderOptions(); + +void LLVMPassBuilderOptionsSetPipelineTuningOptions( + LLVMPassBuilderOptionsRef Options, LLVMPipelineTuningOptionsRef PTO); + +void LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options, + LLVMBool VerifyEach); + +void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options, + LLVMBool DebugLogging); + +/** + * Dispose of a heap-allocated PassBuilderOptions instance + */ +void LLVMDisposePassBuilderOptions(LLVMPassBuilderOptionsRef Options); + +/** + * Create a new set of tunable pipeline options for a PassBuilder instance + * + * Ownership of the returned instance is given to the client, and they are + * responsible for it. The client should call LLVMDisposePipelineTuningOptions + * to free the pipeline tuning options. + */ +LLVMPipelineTuningOptionsRef LLVMCreatePipelineTuningOptions(); + +void LLVMPipelineTuningOptionsSetLoopInterleaving( + LLVMPipelineTuningOptionsRef PTO, LLVMBool LoopInterleaving); + +void LLVMPipelineTuningOptionsSetLoopVectorization( + LLVMPipelineTuningOptionsRef PTO, LLVMBool LoopVectorization); + +void LLVMPipelineTuningOptionsSetSLPVectorization( + LLVMPipelineTuningOptionsRef PTO, LLVMBool SLPVectorization); + +void LLVMPipelineTuningOptionsSetLoopUnrolling(LLVMPipelineTuningOptionsRef PTO, + LLVMBool LoopUnrolling); + +void LLVMPipelineTuningOptionsSetForgetAllSCEVInLoopUnroll( + LLVMPipelineTuningOptionsRef PTO, LLVMBool ForgetAllSCEVInLoopUnroll); + +void LLVMPipelineTuningOptionsSetLicmMssaOptCap( + LLVMPipelineTuningOptionsRef PTO, unsigned LicmMssaOptCap); + +void LLVMPipelineTuningOptionsSetLicmMssaNoAccForPromotionCap( + LLVMPipelineTuningOptionsRef PTO, unsigned LicmMssaNoAccForPromotionCap); + +void LLVMPipelineTuningOptionsSetCallGraphProfile( + LLVMPipelineTuningOptionsRef PTO, LLVMBool CallGraphProfile); + +void LLVMPipelineTuningOptionsSetMergeFunctions( + LLVMPipelineTuningOptionsRef PTO, LLVMBool MergeFunctions); + +/** + * Dispose of a heap-allocated PipelineTuningOptions instance + */ +void LLVMDisposePipelineTuningOptions(LLVMPipelineTuningOptionsRef PTO); + +LLVM_C_EXTERN_C_END + +#endif // LLVM_C_TRANSFORMS_PASSBUILDER_H diff --git a/llvm/lib/Passes/CMakeLists.txt b/llvm/lib/Passes/CMakeLists.txt --- a/llvm/lib/Passes/CMakeLists.txt +++ b/llvm/lib/Passes/CMakeLists.txt @@ -1,5 +1,6 @@ add_llvm_component_library(LLVMPasses PassBuilder.cpp + PassBuilderBindings.cpp PassPlugin.cpp StandardInstrumentations.cpp diff --git a/llvm/lib/Passes/PassBuilderBindings.cpp b/llvm/lib/Passes/PassBuilderBindings.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Passes/PassBuilderBindings.cpp @@ -0,0 +1,161 @@ +//===-------------- PassBuilder bindings for LLVM-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 +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the C bindings to the new pass manager +/// +//===----------------------------------------------------------------------===// + +#include "llvm-c/Transforms/PassBuilder.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/StandardInstrumentations.h" +#include "llvm/Support/CBindingWrapping.h" + +using namespace llvm; + +namespace llvm { +/// Helper struct for holding a set of builder options for LLVMRunPasses. This +/// structure is used to keep LLVMRunPasses backwards compatible with future +/// versions in case we modify the options the new Pass Manager utilizes. +class LLVMPassBuilderOptions { +public: + explicit LLVMPassBuilderOptions(bool DebugLogging = false, + bool VerifyEach = false, + PipelineTuningOptions *PTO = nullptr) + : DebugLogging(DebugLogging), VerifyEach(VerifyEach), PTO(PTO) {} + + bool DebugLogging; + bool VerifyEach; + PipelineTuningOptions *PTO; +}; +} // namespace llvm + +static TargetMachine *unwrap(LLVMTargetMachineRef P) { + return reinterpret_cast(P); +} + +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(PipelineTuningOptions, + LLVMPipelineTuningOptionsRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMPassBuilderOptions, + LLVMPassBuilderOptionsRef) + +LLVMErrorRef LLVMRunPasses(LLVMTargetMachineRef TM, LLVMModuleRef M, + LLVMPassBuilderOptionsRef Options, + const char *Passes) { + TargetMachine *Machine = unwrap(TM); + LLVMPassBuilderOptions *PassOpts = unwrap(Options); + assert(PassOpts->PTO && + "PipelineTuningOptions is null, did you forget to set it?"); + PipelineTuningOptions *Opts = PassOpts->PTO; + bool Debug = PassOpts->DebugLogging; + bool VerifyEach = PassOpts->VerifyEach; + + Module *Mod = unwrap(M); + PassInstrumentationCallbacks PIC; + PassBuilder PB(Debug, Machine, *Opts, None, &PIC); + + LoopAnalysisManager LAM(Debug); + FunctionAnalysisManager FAM(Debug); + CGSCCAnalysisManager CGAM(Debug); + ModuleAnalysisManager MAM(Debug); + PB.registerLoopAnalyses(LAM); + PB.registerFunctionAnalyses(FAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerModuleAnalyses(MAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + StandardInstrumentations SI(Debug, VerifyEach); + SI.registerCallbacks(PIC, &FAM); + ModulePassManager MPM(Debug); + if (VerifyEach) { + MPM.addPass(VerifierPass()); + } + if (auto Err = PB.parsePassPipeline(MPM, Passes)) { + return wrap(std::move(Err)); + } + + MPM.run(*Mod, MAM); + return LLVMErrorSuccess; +} + +LLVMPassBuilderOptionsRef LLVMCreatePassBuilderOptions() { + return wrap(new LLVMPassBuilderOptions()); +} + +void LLVMPassBuilderOptionsSetPipelineTuningOptions( + LLVMPassBuilderOptionsRef Options, LLVMPipelineTuningOptionsRef PTO) { + unwrap(Options)->PTO = unwrap(PTO); +} + +void LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options, + LLVMBool VerifyEach) { + unwrap(Options)->VerifyEach = VerifyEach; +} + +void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options, + LLVMBool DebugLogging) { + unwrap(Options)->DebugLogging = DebugLogging; +} + +void LLVMDisposePassBuilderOptions(LLVMPassBuilderOptionsRef Options) { + delete unwrap(Options); +} + +LLVMPipelineTuningOptionsRef LLVMCreatePipelineTuningOptions() { + return wrap(new PipelineTuningOptions()); +} + +void LLVMPipelineTuningOptionsSetLoopInterleaving( + LLVMPipelineTuningOptionsRef PTO, LLVMBool LoopInterleaving) { + unwrap(PTO)->LoopInterleaving = LoopInterleaving; +} + +void LLVMPipelineTuningOptionsSetLoopVectorization( + LLVMPipelineTuningOptionsRef PTO, LLVMBool LoopVectorization) { + unwrap(PTO)->LoopVectorization = LoopVectorization; +} + +void LLVMPipelineTuningOptionsSetSLPVectorization( + LLVMPipelineTuningOptionsRef PTO, LLVMBool SLPVectorization) { + unwrap(PTO)->SLPVectorization = SLPVectorization; +} + +void LLVMPipelineTuningOptionsSetLoopUnrolling(LLVMPipelineTuningOptionsRef PTO, + LLVMBool LoopUnrolling) { + unwrap(PTO)->LoopUnrolling = LoopUnrolling; +} + +void LLVMPipelineTuningOptionsSetForgetAllSCEVInLoopUnroll( + LLVMPipelineTuningOptionsRef PTO, LLVMBool ForgetAllSCEVInLoopUnroll) { + unwrap(PTO)->ForgetAllSCEVInLoopUnroll = ForgetAllSCEVInLoopUnroll; +} + +void LLVMPipelineTuningOptionsSetLicmMssaOptCap( + LLVMPipelineTuningOptionsRef PTO, unsigned LicmMssaOptCap) { + unwrap(PTO)->LicmMssaOptCap = LicmMssaOptCap; +} + +void LLVMPipelineTuningOptionsSetLicmMssaNoAccForPromotionCap( + LLVMPipelineTuningOptionsRef PTO, unsigned LicmMssaNoAccForPromotionCap) { + unwrap(PTO)->LicmMssaNoAccForPromotionCap = LicmMssaNoAccForPromotionCap; +} + +void LLVMPipelineTuningOptionsSetCallGraphProfile( + LLVMPipelineTuningOptionsRef PTO, LLVMBool CallGraphProfile) { + unwrap(PTO)->CallGraphProfile = CallGraphProfile; +} + +void LLVMPipelineTuningOptionsSetMergeFunctions( + LLVMPipelineTuningOptionsRef PTO, LLVMBool MergeFunctions) { + unwrap(PTO)->MergeFunctions = MergeFunctions; +} + +void LLVMDisposePipelineTuningOptions(LLVMPipelineTuningOptionsRef PTO) { + delete unwrap(PTO); +} \ No newline at end of file diff --git a/llvm/unittests/Passes/CMakeLists.txt b/llvm/unittests/Passes/CMakeLists.txt --- a/llvm/unittests/Passes/CMakeLists.txt +++ b/llvm/unittests/Passes/CMakeLists.txt @@ -1,5 +1,5 @@ # Needed by LLVM's CMake checks because this file defines multiple targets. -set(LLVM_OPTIONAL_SOURCES PluginsTest.cpp TestPlugin.cpp) +set(LLVM_OPTIONAL_SOURCES PluginsTest.cpp TestPlugin.cpp PassBuilderBindingsTest.cpp) # If plugins are disabled, this test will disable itself at runtime. Otherwise, # reconfiguring with plugins disabled will leave behind a stale executable. @@ -34,3 +34,7 @@ add_dependencies(TestPlugin intrinsics_gen) add_dependencies(PluginsTests TestPlugin) endif() + +set(LLVM_LINK_COMPONENTS Support Passes Core Target native) +add_llvm_unittest(PassesBindingsTests PassBuilderBindingsTest.cpp) +target_link_libraries(PassesBindingsTests PRIVATE LLVMTestingSupport) \ No newline at end of file diff --git a/llvm/unittests/Passes/PassBuilderBindingsTest.cpp b/llvm/unittests/Passes/PassBuilderBindingsTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/Passes/PassBuilderBindingsTest.cpp @@ -0,0 +1,71 @@ +//===- unittests/Passes/PassBuilderBindingsTest.cpp -----------------------===// +// +// 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 "llvm-c/Core.h" +#include "llvm-c/Transforms/PassBuilder.h" +#include "llvm-c/Types.h" +#include "gtest/gtest.h" + +using namespace llvm; + +class PassBuilderCTest : public testing::Test { + void SetUp() override { + LLVMInitializeNativeTarget(); + const char *Triple = LLVMGetDefaultTargetTriple(); + char *Err; + LLVMTargetRef Target; + if (LLVMGetTargetFromTriple(Triple, &Target, &Err)) { + FAIL() << "Failed to create target from default triple: " << Err; + } + TM = LLVMCreateTargetMachine(Target, Triple, "generic", "", + LLVMCodeGenLevelDefault, LLVMRelocDefault, + LLVMCodeModelDefault); + PTO = LLVMCreatePipelineTuningOptions(); + Context = LLVMContextCreate(); + Module = LLVMModuleCreateWithNameInContext("test", Context); + } + + void TearDown() override { + LLVMDisposeTargetMachine(TM); + LLVMDisposePipelineTuningOptions(PTO); + LLVMDisposeModule(Module); + LLVMContextDispose(Context); + } + +public: + LLVMTargetMachineRef TM; + LLVMPipelineTuningOptionsRef PTO; + LLVMModuleRef Module; + LLVMContextRef Context; +}; + +TEST_F(PassBuilderCTest, Basic) { + LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions(); + LLVMPassBuilderOptionsSetPipelineTuningOptions(Options, PTO); + LLVMPassBuilderOptionsSetVerifyEach(Options, 1); + LLVMPassBuilderOptionsSetDebugLogging(Options, 0); + if (LLVMErrorRef E = LLVMRunPasses(TM, Module, Options, "default")) { + char *Msg = LLVMGetErrorMessage(E); + LLVMConsumeError(E); + LLVMDisposePassBuilderOptions(Options); + FAIL() << "Failed to run passes: " << Msg; + } + LLVMDisposePassBuilderOptions(Options); +} + +TEST_F(PassBuilderCTest, InvalidPassIsError) { + LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions(); + LLVMPassBuilderOptionsSetPipelineTuningOptions(Options, PTO); + LLVMErrorRef E1 = LLVMRunPasses(TM, Module, Options, ""); + LLVMErrorRef E2 = LLVMRunPasses(TM, Module, Options, "does-not-exist-pass"); + ASSERT_TRUE(E1); + ASSERT_TRUE(E2); + LLVMConsumeError(E1); + LLVMConsumeError(E2); + LLVMDisposePassBuilderOptions(Options); +}