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,105 @@ +/*===-- 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 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 may be specified, separated by commas. Full + * pipelines may also be invoked using `default` and friends. See opt for + * full reference of the Passes format. + */ +LLVMErrorRef LLVMRunPasses(LLVMModuleRef M, const char *Passes, + LLVMTargetMachineRef TM, + LLVMPassBuilderOptionsRef Options); + +/** + * 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(); + +/** + * Toggle adding the VerifierPass for the PassBuilder, ensuring all functions + * inside the module is valid. + */ +void LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options, + LLVMBool VerifyEach); + +/** + * Toggle debug logging when running the PassBuilder + */ +void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options, + LLVMBool DebugLogging); + +void LLVMPassBuilderOptionsSetLoopInterleaving( + LLVMPassBuilderOptionsRef Options, LLVMBool LoopInterleaving); + +void LLVMPassBuilderOptionsSetLoopVectorization( + LLVMPassBuilderOptionsRef Options, LLVMBool LoopVectorization); + +void LLVMPassBuilderOptionsSetSLPVectorization( + LLVMPassBuilderOptionsRef Options, LLVMBool SLPVectorization); + +void LLVMPassBuilderOptionsSetLoopUnrolling(LLVMPassBuilderOptionsRef Options, + LLVMBool LoopUnrolling); + +void LLVMPassBuilderOptionsSetForgetAllSCEVInLoopUnroll( + LLVMPassBuilderOptionsRef Options, LLVMBool ForgetAllSCEVInLoopUnroll); + +void LLVMPassBuilderOptionsSetCoroutines(LLVMPassBuilderOptionsRef Options, + LLVMBool Coroutines); + +void LLVMPassBuilderOptionsSetLicmMssaOptCap(LLVMPassBuilderOptionsRef Options, + unsigned LicmMssaOptCap); + +void LLVMPassBuilderOptionsSetLicmMssaNoAccForPromotionCap( + LLVMPassBuilderOptionsRef Options, unsigned LicmMssaNoAccForPromotionCap); + +void LLVMPassBuilderOptionsSetCallGraphProfile( + LLVMPassBuilderOptionsRef Options, LLVMBool CallGraphProfile); + +void LLVMPassBuilderOptionsSetMergeFunctions(LLVMPassBuilderOptionsRef Options, + LLVMBool MergeFunctions); + +/** + * Dispose of a heap-allocated PassBuilderOptions instance + */ +void LLVMDisposePassBuilderOptions(LLVMPassBuilderOptionsRef Options); + +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,149 @@ +//===-------------- 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 = PipelineTuningOptions()) + : 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(LLVMPassBuilderOptions, + LLVMPassBuilderOptionsRef) + +LLVMErrorRef LLVMRunPasses(LLVMModuleRef M, const char *Passes, + LLVMTargetMachineRef TM, + LLVMPassBuilderOptionsRef Options) { + TargetMachine *Machine = unwrap(TM); + LLVMPassBuilderOptions *PassOpts = unwrap(Options); + bool Debug = PassOpts->DebugLogging; + bool VerifyEach = PassOpts->VerifyEach; + + Module *Mod = unwrap(M); + PassInstrumentationCallbacks PIC; + PassBuilder PB(Debug, Machine, PassOpts->PTO, 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 LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options, + LLVMBool VerifyEach) { + unwrap(Options)->VerifyEach = VerifyEach; +} + +void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options, + LLVMBool DebugLogging) { + unwrap(Options)->DebugLogging = DebugLogging; +} + +void LLVMPassBuilderOptionsSetLoopInterleaving( + LLVMPassBuilderOptionsRef Options, LLVMBool LoopInterleaving) { + unwrap(Options)->PTO.LoopInterleaving = LoopInterleaving; +} + +void LLVMPassBuilderOptionsSetLoopVectorization( + LLVMPassBuilderOptionsRef Options, LLVMBool LoopVectorization) { + unwrap(Options)->PTO.LoopVectorization = LoopVectorization; +} + +void LLVMPassBuilderOptionsSetSLPVectorization( + LLVMPassBuilderOptionsRef Options, LLVMBool SLPVectorization) { + unwrap(Options)->PTO.SLPVectorization = SLPVectorization; +} + +void LLVMPassBuilderOptionsSetLoopUnrolling(LLVMPassBuilderOptionsRef Options, + LLVMBool LoopUnrolling) { + unwrap(Options)->PTO.LoopUnrolling = LoopUnrolling; +} + +void LLVMPassBuilderOptionsSetForgetAllSCEVInLoopUnroll( + LLVMPassBuilderOptionsRef Options, LLVMBool ForgetAllSCEVInLoopUnroll) { + unwrap(Options)->PTO.ForgetAllSCEVInLoopUnroll = ForgetAllSCEVInLoopUnroll; +} + +void LLVMPassBuilderOptionsSetCoroutines(LLVMPassBuilderOptionsRef Options, + LLVMBool Coroutines) { + unwrap(Options)->PTO.Coroutines = Coroutines; +} + +void LLVMPassBuilderOptionsSetLicmMssaOptCap(LLVMPassBuilderOptionsRef Options, + unsigned LicmMssaOptCap) { + unwrap(Options)->PTO.LicmMssaOptCap = LicmMssaOptCap; +} + +void LLVMPassBuilderOptionsSetLicmMssaNoAccForPromotionCap( + LLVMPassBuilderOptionsRef Options, unsigned LicmMssaNoAccForPromotionCap) { + unwrap(Options)->PTO.LicmMssaNoAccForPromotionCap = + LicmMssaNoAccForPromotionCap; +} + +void LLVMPassBuilderOptionsSetCallGraphProfile( + LLVMPassBuilderOptionsRef Options, LLVMBool CallGraphProfile) { + unwrap(Options)->PTO.CallGraphProfile = CallGraphProfile; +} + +void LLVMPassBuilderOptionsSetMergeFunctions(LLVMPassBuilderOptionsRef Options, + LLVMBool MergeFunctions) { + unwrap(Options)->PTO.MergeFunctions = MergeFunctions; +} + +void LLVMDisposePassBuilderOptions(LLVMPassBuilderOptionsRef Options) { + delete unwrap(Options); +} 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,67 @@ +//===- 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); + Context = LLVMContextCreate(); + Module = LLVMModuleCreateWithNameInContext("test", Context); + } + + void TearDown() override { + LLVMDisposeTargetMachine(TM); + LLVMDisposeModule(Module); + LLVMContextDispose(Context); + } + +public: + LLVMTargetMachineRef TM; + LLVMModuleRef Module; + LLVMContextRef Context; +}; + +TEST_F(PassBuilderCTest, Basic) { + LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions(); + LLVMPassBuilderOptionsSetLoopUnrolling(Options, 1); + 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(); + 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); +}