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,95 @@ +/*===-- 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::PassBuilder instance + */ +typedef struct LLVMOpaquePassBuilder *LLVMPassBuilderRef; + +/** + * A reference to an llvm::PipelineTuningOptions instance + */ +typedef struct LLVMOpaquePipelineTuningOptions *LLVMPipelineTuningOptionsRef; + +/** + * Create a new pass builder + * + * Ownership of the returned instance is given to the client, and they are + * responsible for it. Unless the client hands the ownership of the PassBuilder + * to LLVMRunPassBuilder, they are responsible for freeing it with + * LLVMDisposePassBuilder. + * + * If DebugLogging is enabled, then debug logging will be printed to stderr. + */ +LLVMPassBuilderRef LLVMCreatePassBuilder(LLVMBool DebugLogging, + LLVMTargetMachineRef TM, + LLVMPipelineTuningOptionsRef); + +/** + * Run a pass builder over an entire 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. + * + * This function takes ownership of the provided PassBuilder. The PassBuilder + * should not be used again after calling this function. + * + * 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 LLVMRunPassBuilder(LLVMPassBuilderRef PB, LLVMModuleRef M, + LLVMBool Debug, LLVMBool VerifyEach, + const char *Passes); + +/** + * Dispose of a heap-allocated PassBuilder instance + */ +void LLVMDisposePassBuilder(LLVMPassBuilderRef PB); + +/** + * 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( + LLVMBool LoopInterleaving, LLVMBool LoopVectorization, + LLVMBool SLPVectorization, LLVMBool LoopUnrolling, + LLVMBool ForgetAllSCEVInLoopUnroll, unsigned LicmMssaOptCap, + unsigned LicmMssaNoAccForPromotionCap, LLVMBool CallGraphProfile, + 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,90 @@ +//===-------------- 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; + +static TargetMachine *unwrap(LLVMTargetMachineRef P) { + return reinterpret_cast(P); +} + +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(PassBuilder, LLVMPassBuilderRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(PipelineTuningOptions, + LLVMPipelineTuningOptionsRef) + +LLVMPassBuilderRef LLVMCreatePassBuilder(LLVMBool DebugLogging, + LLVMTargetMachineRef TM, + LLVMPipelineTuningOptionsRef PTO) { + TargetMachine *Machine = unwrap(TM); + PipelineTuningOptions *Opts = unwrap(PTO); + auto *PB = new PassBuilder(DebugLogging, Machine, *Opts); + return wrap(PB); +} + +LLVMErrorRef LLVMRunPassBuilder(LLVMPassBuilderRef PB, LLVMModuleRef M, + LLVMBool Debug, LLVMBool VerifyEach, + const char *Passes) { + PassBuilder *P = unwrap(PB); + Module *Mod = unwrap(M); + LoopAnalysisManager LAM(Debug); + FunctionAnalysisManager FAM(Debug); + CGSCCAnalysisManager CGAM(Debug); + ModuleAnalysisManager MAM(Debug); + P->registerLoopAnalyses(LAM); + P->registerFunctionAnalyses(FAM); + P->registerCGSCCAnalyses(CGAM); + P->registerModuleAnalyses(MAM); + P->crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM(Debug); + if (VerifyEach) { + MPM.addPass(VerifierPass()); + } + if (auto Err = P->parsePassPipeline(MPM, Passes)) { + return wrap(std::move(Err)); + } + + MPM.run(*Mod, MAM); + LLVMDisposePassBuilder(PB); + return LLVMErrorSuccess; +} + +void LLVMDisposePassBuilder(LLVMPassBuilderRef PB) { delete unwrap(PB); } + +LLVMPipelineTuningOptionsRef LLVMCreatePipelineTuningOptions( + LLVMBool LoopInterleaving, LLVMBool LoopVectorization, + LLVMBool SLPVectorization, LLVMBool LoopUnrolling, + LLVMBool ForgetAllSCEVInLoopUnroll, unsigned LicmMssaOptCap, + unsigned LicmMssaNoAccForPromotionCap, LLVMBool CallGraphProfile, + LLVMBool MergeFunctions) { + auto *Options = new PipelineTuningOptions(); + Options->LoopInterleaving = LoopInterleaving; + Options->LoopVectorization = LoopVectorization; + Options->SLPVectorization = SLPVectorization; + Options->LoopUnrolling = LoopUnrolling; + Options->ForgetAllSCEVInLoopUnroll = ForgetAllSCEVInLoopUnroll; + Options->LicmMssaOptCap = LicmMssaOptCap; + Options->LicmMssaNoAccForPromotionCap = LicmMssaNoAccForPromotionCap; + Options->CallGraphProfile = CallGraphProfile; + Options->MergeFunctions = MergeFunctions; + return wrap(Options); +} + +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,66 @@ +//===- 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; + } + LLVMTargetMachineRef TM = LLVMCreateTargetMachine( + Target, Triple, "generic", "", LLVMCodeGenLevelDefault, + LLVMRelocDefault, LLVMCodeModelDefault); + PTO = LLVMCreatePipelineTuningOptions(0, 0, 0, 0, 0, 0, 0, 0, 0); + PB = LLVMCreatePassBuilder(false, TM, PTO); + + Context = LLVMContextCreate(); + Module = LLVMModuleCreateWithNameInContext("test", Context); + } + + void TearDown() override { + LLVMDisposePipelineTuningOptions(PTO); + LLVMDisposeModule(Module); + LLVMContextDispose(Context); + } + +public: + LLVMPassBuilderRef PB; + LLVMPipelineTuningOptionsRef PTO; + LLVMModuleRef Module; + LLVMContextRef Context; +}; + +TEST_F(PassBuilderCTest, Basic) { + if (LLVMErrorRef E = + LLVMRunPassBuilder(PB, Module, true, true, "default")) { + char *Msg = LLVMGetErrorMessage(E); + LLVMConsumeError(E); + FAIL() << "Failed to run passes: " << Msg; + } +} + +TEST_F(PassBuilderCTest, InvalidPassIsError) { + LLVMErrorRef E1 = LLVMRunPassBuilder(PB, Module, true, true, ""); + LLVMErrorRef E2 = + LLVMRunPassBuilder(PB, Module, true, true, "does-not-exist-pass"); + ASSERT_TRUE(E1); + ASSERT_TRUE(E2); + LLVMConsumeError(E1); + LLVMConsumeError(E2); + LLVMDisposePassBuilder(PB); +}