Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LLVM-pass plugin support to LDC. Commandline flag: -plugin=.... #2554

Merged
merged 10 commits into from
Feb 13, 2018
19 changes: 19 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ set(DRV_SRC
driver/linker-gcc.cpp
driver/linker-msvc.cpp
driver/main.cpp
driver/plugins.cpp
${CMAKE_BINARY_DIR}/driver/ldc-version.cpp
)
set(DRV_HDR
Expand All @@ -337,6 +338,7 @@ set(DRV_HDR
driver/ldc-version.h
driver/archiver.h
driver/linker.h
driver/plugins.h
driver/targetmachine.h
driver/toobj.h
driver/tool.h
Expand Down Expand Up @@ -559,6 +561,23 @@ if(LDC_WITH_LLD)
endif()
endif()

# Plugin support
if(APPLE)
# There doesn't seem to be a downside to enabling plugins on macOS
set(LDC_ENABLE_PLUGINS_DEFAULT ON)
else()
set(LDC_ENABLE_PLUGINS_DEFAULT OFF)
endif()
set(LDC_ENABLE_PLUGINS ${LDC_ENABLE_PLUGINS_DEFAULT} CACHE BOOL "Build LDC with plugin support (increases binary size)")
if(LDC_ENABLE_PLUGINS)
message(STATUS "Building LDC with plugin support")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a default of 'off' means that few people will try it, perhaps you should add a status "Building LDC without plugin support"?

add_definitions(-DLDC_ENABLE_PLUGINS)
# For plugin support, we need to link with --export-dynamic on Unix.
if(UNIX AND NOT APPLE)
set(LDC_LINKERFLAG_LIST "${LDC_LINKERFLAG_LIST};-Wl,--export-dynamic")
endif()
endif()

set(LDC_LINK_MANUALLY OFF)
if(UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")))
# On Unix-like systems, DMD and LDC will use the C compiler for linking, but
Expand Down
3 changes: 3 additions & 0 deletions driver/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "driver/exe_path.h"
#include "driver/ldc-version.h"
#include "driver/linker.h"
#include "driver/plugins.h"
#include "driver/targetmachine.h"
#include "gen/cl_helpers.h"
#include "gen/irstate.h"
Expand Down Expand Up @@ -1063,6 +1064,8 @@ int cppmain(int argc, char **argv) {
opts::initializeInstrumentationOptionsFromCmdline(
*global.params.targetTriple);

loadAllPlugins();

Strings libmodules;
return mars_mainBody(files, libmodules);
}
Expand Down
48 changes: 48 additions & 0 deletions driver/plugins.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//===-- driver/plugins.cpp -------------------------------------*- C++ -*-===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
//
// Implements functionality related to plugins (`-plugin=...`).
//
//===----------------------------------------------------------------------===//

#include "driver/plugins.h"

#if LDC_ENABLE_PLUGINS

#include "errors.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DynamicLibrary.h"

namespace {
namespace cl = llvm::cl;

cl::list<std::string>
pluginFiles("plugin", cl::CommaSeparated, cl::desc("Plugins to load."),
cl::value_desc("<dynamic_library.so, lib2.so>"));

} // anonymous namespace

/// Loads all plugins. The static constructor of each plugin should take care of
/// the plugins registering themself with the rest of LDC/LLVM.
void loadAllPlugins() {
for (auto &filename : pluginFiles) {
std::string errorString;
if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(filename.c_str(),
&errorString)) {
error(Loc(), "Error loading plugin '%s': %s", filename.c_str(),
errorString.c_str());
}
}
}

#else // #if LDC_ENABLE_PLUGINS

void loadAllPlugins() {}

#endif // LDC_ENABLE_PLUGINS
15 changes: 15 additions & 0 deletions driver/plugins.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//===-- driver/plugins.h ---------------------------------------*- C++ -*-===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//

#ifndef LDC_DRIVER_PLUGINS_H
#define LDC_DRIVER_PLUGINS_H

void loadAllPlugins();

#endif // LDC_DRIVER_PLUGINS_H
1 change: 1 addition & 0 deletions tests/lit.site.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ config.llvm_targetsstr = "@LLVM_TARGETS_TO_BUILD@"
config.default_target_bits = @DEFAULT_TARGET_BITS@
config.with_PGO = True
config.dynamic_compile = @LDC_DYNAMIC_COMPILE@
config.plugins_supported = "@LDC_ENABLE_PLUGINS@" == "ON"

config.name = 'LDC'

Expand Down
28 changes: 28 additions & 0 deletions tests/plugins/addFuncEntryCall/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

# ROOT_DIR = directory where Makefile sits
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
ROOT_DIR := $(dir $(MAKEFILE_PATH))

LLVM_CONFIG ?= llvm-config

CXXFLAGS ?= -O3
CXXFLAGS += $(shell $(LLVM_CONFIG) --cxxflags) -fno-rtti -fpic
# Remove all warning flags (they may or may not be supported by the compiler)
CXXFLAGS := $(filter-out -W%,$(CXXFLAGS))
CXXFLAGS := $(filter-out -fcolor-diagnostics,$(CXXFLAGS))

ifeq "$(shell uname)" "Darwin"
CXXFLAGS += -Wl,-flat_namespace -Wl,-undefined,suppress
endif

PASSLIB = addFuncEntryCallPass

all: $(PASSLIB)

$(PASSLIB): $(ROOT_DIR)$(PASSLIB).cpp
$(CXX) $(CXXFLAGS) -shared $< -o $@.so

.NOTPARALLEL: clean

clean:
rm -f $(PASSLIB).so
60 changes: 60 additions & 0 deletions tests/plugins/addFuncEntryCall/addFuncEntryCallPass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//===-- addFuncEntryCallPass.cpp - Optimize druntime calls ----------------===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the University of Illinois Open Source
// License. See the LICENSE file for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

using namespace llvm;

namespace {

class FuncEntryCallPass : public FunctionPass {

Constant *funcToCallUponEntry = nullptr;

public:
static char ID;
FuncEntryCallPass() : FunctionPass(ID) {}

bool doInitialization(Module &M) override;
bool runOnFunction(Function &F) override;
};
}

char FuncEntryCallPass::ID = 0;

bool FuncEntryCallPass::doInitialization(Module &M) {
// Add fwd declaration of the `void __test_funcentrycall(void)` function.
auto functionType = FunctionType::get(Type::getVoidTy(M.getContext()), false);
funcToCallUponEntry =
M.getOrInsertFunction("__test_funcentrycall", functionType);
return true;
}

bool FuncEntryCallPass::runOnFunction(Function &F) {
// Add call to `__test_funcentrycall(void)` at the start of _every_ function
// (this includes e.g. `ldc.register_dso`!)
llvm::BasicBlock &block = F.getEntryBlock();
IRBuilder<> builder(&block, block.begin());
builder.CreateCall(funcToCallUponEntry);
return true;
}

static void addFuncEntryCallPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new FuncEntryCallPass());
}
// Registration of the plugin's pass is done by the plugin's static constructor.
static RegisterStandardPasses
RegisterFuncEntryCallPass0(PassManagerBuilder::EP_EnabledOnOptLevel0,
addFuncEntryCallPass);
14 changes: 14 additions & 0 deletions tests/plugins/addFuncEntryCall/testPlugin.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// REQUIRES: Plugins

// RUN: make -f %S/Makefile
// RUN: %ldc -c -output-ll -plugin=./addFuncEntryCallPass.so -of=%t.ll %s
// RUN: FileCheck %s < %t.ll

// CHECK: define {{.*}}testfunction
int testfunction(int i)
{
// CHECK-NEXT: call {{.*}}__test_funcentrycall
return i * 2;
}

// CHECK-DAG: declare {{.*}}__test_funcentrycall
7 changes: 7 additions & 0 deletions tests/plugins/lit.local.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import os
import platform
import re

if (config.plugins_supported):
config.available_features.add('Plugins')
config.environment['LLVM_CONFIG'] = os.path.join(config.llvm_tools_dir, 'llvm-config')