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

Allow linking custom LLVM optimization passes #429

Open
wants to merge 93 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
2ff1221
Basic implementation
Dec 3, 2018
1d63213
Make the test more robust
Dec 3, 2018
1c97e27
Reorganize passes
Dec 4, 2018
591fa04
Add pass listing
Dec 4, 2018
83877a3
Add docs and minor api changes
Dec 4, 2018
e1f8ec6
Remove extra new line
Dec 4, 2018
421602e
Remov unnecessary changes from transforms.cpp
Dec 4, 2018
0894899
Add new line at the end of the file
Dec 4, 2018
72201d2
Fix test
Dec 4, 2018
f099f08
Lower required cmake version
Dec 4, 2018
a4888d7
Don't use nonlocal
Dec 4, 2018
cdec2d6
Avoid named arguments for python2's sake
Dec 4, 2018
cfc49ed
Correct extensions for different platforms
Dec 4, 2018
3fb8e9e
cd using an absolute path
Dec 4, 2018
460f6b3
Check correctly raised exception and adjust docs
Dec 4, 2018
a88b8b8
More adjustments for windows
Dec 4, 2018
70f6cd3
Prevent double loading of shared libraries
Dec 4, 2018
f5876b7
Remove unnecessary no-rtti option
Dec 4, 2018
38027a0
Rework loading demo pass
Dec 4, 2018
b252fee
Use add definitions
Dec 4, 2018
4e01749
Use the correct form for add definitions
Dec 4, 2018
5bc48ad
Add windows specific definitions
Dec 4, 2018
1a73def
Modify linking
Dec 4, 2018
91c72a4
Remov clutter
Dec 4, 2018
6acbfa4
Check correct arg name
Dec 4, 2018
53f4e0b
Restructure pass plugin loading
Dec 5, 2018
9435f0d
Remove non-existing folder from cmake
Dec 5, 2018
c79f49d
Don't use exclude-libs on osx
Dec 5, 2018
61971b3
Use system clang on osx
Dec 6, 2018
b1a14a8
Check cmake syntax
Dec 6, 2018
23f82be
Also set C compiler
Dec 6, 2018
9109a96
Set the compiler in travis build script
Dec 6, 2018
cf7a57a
Put compiler override in build.py
Dec 6, 2018
6097a18
Merge newest master
Dec 7, 2018
2920493
Force using minicondas cmake
Dec 6, 2018
924b5ae
Try to overwrite the reference to system linker
Dec 6, 2018
2bc47e4
Try removing changed path on osx
Dec 6, 2018
01dc090
Fix typo
Dec 6, 2018
734252c
Fix typo
Dec 6, 2018
6e6436b
Fix typo
Dec 6, 2018
07aa4a1
Add debug print
Dec 6, 2018
9dbd26a
Boostrap -> bootstrap
Dec 6, 2018
3b10ace
Try os x deloyment target setting
Dec 6, 2018
84de47c
Debug print of osx deployment target
Dec 6, 2018
908a273
Debug print of osx deployment target
Dec 6, 2018
6edcc02
Explicitly set osx depl target
Dec 6, 2018
a2a251b
Set osx depl target earlier
Dec 6, 2018
84b4932
One more varaible
Dec 6, 2018
87f5de5
Debug print sysroot
Dec 6, 2018
39d8991
Try overriding cc and cxx again
Dec 6, 2018
27c67b6
Explicitly set conda_build_support
Dec 6, 2018
3d6da95
Set sysroot in cmakelists
Dec 7, 2018
5889d97
Typo
Dec 7, 2018
b3a1274
Use osx specific sysroot variable
Dec 7, 2018
99efbc7
Try different sysroot
Dec 7, 2018
600c9b4
Set the correct sysroot
Dec 7, 2018
1069da2
Add debugging messages
Dec 7, 2018
a204bac
Explicit sysroot
Dec 7, 2018
8b1410b
Change env var in python
Dec 7, 2018
5e7d71d
Override compiler settings
Dec 7, 2018
bc8651c
Override cmake command
Dec 7, 2018
9c62c80
Switch to llvm 7
Dec 7, 2018
0807fbf
More debug info to cmake
Dec 7, 2018
cd417db
Manually insert cmake path
Dec 7, 2018
f60ba36
Argument order
Dec 7, 2018
d9c3a7f
Argument order
Dec 7, 2018
2a237f4
List the content of cmake lib
Dec 7, 2018
f85ad8e
Explicitly set llvm install prefix
Dec 7, 2018
ed0a3c4
Call travisci cmake for config
Dec 7, 2018
53df57f
Set cmake module path
Dec 10, 2018
9ed850c
Change home path
Dec 10, 2018
6d6da09
Change home path
Dec 10, 2018
dde89b9
Do something drastic
Dec 10, 2018
2ea83bf
Do something drastic
Dec 10, 2018
3a57e48
something even more drastic
Dec 10, 2018
c879b3b
Manually set llvm flags
Dec 10, 2018
6720cec
Link to passes explicitly
Dec 10, 2018
9ebbc2c
BUild dylib
Dec 10, 2018
f1a449a
Don't link passes explicitly
Dec 10, 2018
9ec52cc
Use platform independent path
Dec 10, 2018
e1f2cd4
Build a module on osx
Dec 10, 2018
c9f94ed
Add dynamic lookup
Dec 10, 2018
37aae81
Revert part of last change
Dec 10, 2018
f1cb4f6
Adjust build script
Dec 10, 2018
792ac93
Fix utils
Dec 10, 2018
1265e97
Fix utils
Dec 10, 2018
4142064
Adjust to link on windows
Dec 10, 2018
254afe9
Adjust build dir on windows
Dec 11, 2018
409764b
Rework plugin dir loading
Dec 11, 2018
38b3d2f
Add api export
Dec 11, 2018
7b6a015
Use load library
Dec 11, 2018
d40b9f6
Check for mscver
Dec 11, 2018
19f17f0
Fix doc reference
Dec 11, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions buildscripts/incremental/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

source activate $CONDA_ENV

if [ -n "$MACOSX_DEPLOYMENT_TARGET" ]; then
# OSX needs 10.7 or above with libc++ enabled
export MACOSX_DEPLOYMENT_TARGET=10.9
fi

if [[ ${MACOSX_DEPLOYMENT_TARGET} == 10.9 ]]; then
DARWIN_TARGET=x86_64-apple-darwin13.4.0
fi

# need to build with Anaconda compilers on osx, but they conflict with llvmdev... bootstap
if [[ $(uname) == Darwin ]]; then
# export LLVM_CONFIG explicitly as the one installed from llvmdev
Expand All @@ -21,14 +30,6 @@ if [[ $(uname) == Darwin ]]; then
${LLVM_CONFIG} --version
fi

if [ -n "$MACOSX_DEPLOYMENT_TARGET" ]; then
# OSX needs 10.7 or above with libc++ enabled
export MACOSX_DEPLOYMENT_TARGET=10.9
fi

if [[ ${MACOSX_DEPLOYMENT_TARGET} == 10.9 ]]; then
DARWIN_TARGET=x86_64-apple-darwin13.4.0
fi


# Make sure any error below is reported as such
Expand Down
5 changes: 5 additions & 0 deletions buildscripts/incremental/setup_conda_environment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ set -v

# Install llvmdev (separate channel, for now)
$CONDA_INSTALL -c numba llvmdev="7.0*"
$CONDA_INSTALL cmake

# Install the compiler toolchain, for osx, bootstrapping needed
# which happens in build.sh
Expand All @@ -50,3 +51,7 @@ fi

# Install dependencies for code coverage (codecov.io)
if [ "$RUN_COVERAGE" == "yes" ]; then $PIP_INSTALL codecov coveralls; fi

if [[ $(uname) == Darwin ]]; then
rm -rf /Users/travis/build/numba/llvmlite/bootstrap/lib/cmake/llvm/
fi
22 changes: 22 additions & 0 deletions docs/source/user-guide/binding/optimization-passes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ create and configure a :class:`PassManagerBuilder`.
methods or :meth:`PassManagerBuilder.populate` to add
optimization passes.

* .. method:: add_pass_by_arg(arg)

Add a pass defined by the supplied ``arg``. See also :meth:`PassRegistry.list_registered_passes`.
Raises ``ValueError`` if no such pass is found.

* .. function:: add_constant_merge_pass()

See `constmerge pass documentation <http://llvm.org/docs/Passes.html#constmerge-merge-duplicate-global-constants>`_.
Expand Down Expand Up @@ -174,3 +179,20 @@ create and configure a :class:`PassManagerBuilder`.

Returns ``True`` if the optimizations made any
modification to the module. Otherwise returns ``False``.

.. function:: load_pass_plugin(path)

Load a shared library defined by ``path`` which contains a custom
LLVM optimization path. See also `'Writing an LLVM Pass' <http://llvm.org/docs/WritingAnLLVMPass.html>`_.

.. class:: PassRegistry()

This class represents global pass registry for the optimization passes

* .. method:: list_registered_passes()

Returns the list of registered passes as a named tuple (arg, name).
``arg`` is the unique identifier used to add passes with :meth:`PassManager.add_pass_by_arg`,
``name`` is the human-readable name of the pass.
See also :func:`load_pass_plugin`.

6 changes: 6 additions & 0 deletions ffi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ add_definitions(${LLVM_DEFINITIONS})
# Look for SVML
set(CMAKE_REQUIRED_INCLUDES ${LLVM_INCLUDE_DIRS})


if (NOT WIN32)
add_compile_options("-fno-rtti")
endif()

CHECK_INCLUDE_FILES("llvm/IR/SVML.inc" HAVE_SVML)
if(HAVE_SVML)
message(STATUS "SVML found")
Expand All @@ -43,3 +48,4 @@ llvm_map_components_to_libnames(llvm_libs all)

# Link against LLVM libraries
target_link_libraries(llvmlite ${llvm_libs})
add_subdirectory(passes)
4 changes: 2 additions & 2 deletions ffi/Makefile.linux
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Using g++ is recommended for linking
CXX ?= g++

# -flto and --exclude-libs allow us to remove those parts of LLVM we don't use
# -flto allows us to remove those parts of LLVM we don't use
CXX_FLTO_FLAGS ?= -flto
LD_FLTO_FLAGS ?= -flto -Wl,--exclude-libs=ALL
LD_FLTO_FLAGS ?= -flto

CXXFLAGS = $(LLVM_CXXFLAGS) $(CXX_FLTO_FLAGS)
LDFLAGS := $(LDFLAGS) $(LLVM_LDFLAGS) $(LD_FLTO_FLAGS)
Expand Down
69 changes: 65 additions & 4 deletions ffi/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,30 @@
import shutil
import sys
import tempfile
from contextlib import contextmanager


if os.name == 'posix':
hello_pass_library = 'libLLVMPYHello.so'
else:
assert os.name == 'nt'
hello_pass_library = 'LLVMPYHello.dll'

here_dir = os.path.abspath(os.path.dirname(__file__))
build_dir = os.path.join(here_dir, 'build')
target_dir = os.path.join(os.path.dirname(here_dir), 'llvmlite', 'binding')

is_64bit = sys.maxsize >= 2**32


@contextmanager
def cwd(path):
old_wd = os.getcwd()
os.chdir(path)
yield
os.chdir(old_wd)


def try_cmake(cmake_dir, build_dir, generator):
old_dir = os.getcwd()
try:
Expand Down Expand Up @@ -60,6 +75,7 @@ def find_win32_generator():

# Drop generators that are too old
vspat = re.compile('Visual Studio (\d+)')

def drop_old_vs(g):
m = vspat.match(g)
if m is None:
Expand All @@ -81,7 +97,8 @@ def drop_old_vs(g):
return generator
finally:
shutil.rmtree(build_dir)
raise RuntimeError("No compatible cmake generator installed on this machine")
raise RuntimeError(
"No compatible cmake generator installed on this machine")


def main_win32():
Expand Down Expand Up @@ -115,19 +132,26 @@ def main_posix(kind, library_ext):
"set LLVM_CONFIG to the right executable path.\n"
"Read the documentation at http://llvmlite.pydata.org/ for more "
"information about building llvmlite.\n"
)
)
raise RuntimeError(msg)

# Get LLVM information for building
libs = run_llvm_config(llvm_config, "--system-libs --libs all".split())
# Normalize whitespace (trim newlines)
os.environ['LLVM_LIBS'] = ' '.join(libs.split())

cxxflags = run_llvm_config(llvm_config, ["--cxxflags"])
# on OSX cxxflags has null bytes at the end of the string, remove them
cxxflags = cxxflags.replace('\0', '')
cxxflags = cxxflags.split() + ['-fno-rtti', '-g']

if os.name == "posix" and sys.platform != "darwin":
# exclude unused symbols from all LLVM libraries except for passes, since
# we'll need for dynamically loaded pass libraries
excluded = ['-Wl,--exclude-libs,lib{}.a'.format(lname.strip())
for lname in libs.split('-l')
if lname and 'LLVMCore' not in lname
and 'LLVMSupport' not in lname]
# cxxflags.append(' '.join(excluded))
# look for SVML
include_dir = run_llvm_config(llvm_config, ['--includedir']).strip()
svml_indicator = os.path.join(include_dir, 'llvm', 'IR', 'SVML.inc')
Expand All @@ -150,17 +174,54 @@ def main_posix(kind, library_ext):
shutil.copy('libllvmlite' + library_ext, target_dir)


def build_passes():
if sys.platform == 'win32':
# just copy the result, hello pass will be built by cmake
shutil.copy(os.path.join(build_dir, "passes", "hello", "Release", hello_pass_library),
target_dir)
else:
with cwd(os.path.join(os.path.dirname(__file__), "passes")):
if os.name == 'posix' and sys.platform == 'darwin':
os.environ['CONDA_BUILD_SYSROOT'] = \
'/Applications/Xcode-9.4.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk'
os.environ['CC'] = 'clang'
os.environ['CXX'] = 'clang++'
cmake_exec = os.path.expandvars(
"$HOME/miniconda3/envs/travisci/bin/cmake")
shutil.rmtree(
"/Users/travis/build/numba/llvmlite/bootstrap/lib/cmake/llvm/")
else:
cmake_exec = 'cmake'

if not os.path.exists("build"):
os.makedirs("build")
assert os.path.isdir("build"), "passes/build must be a directory"
with cwd("build"):
if os.name == "posix":
subprocess.check_call([cmake_exec, '..'])
else:
generator = find_win32_generator()
try_cmake('..', '.', generator)

print("Calling " + cmake_exec)
subprocess.check_call(
[cmake_exec, '--build', '.', '--config', 'Release'])
shutil.copy(os.path.join(
"hello", hello_pass_library), target_dir)


def main():
if sys.platform == 'win32':
main_win32()
elif sys.platform.startswith('linux'):
main_posix('linux', '.so')
elif sys.platform.startswith(('freebsd','openbsd')):
elif sys.platform.startswith(('freebsd', 'openbsd')):
main_posix('freebsd', '.so')
elif sys.platform == 'darwin':
main_posix('osx', '.dylib')
else:
raise RuntimeError("unsupported platform: %r" % (sys.platform,))
build_passes()


if __name__ == "__main__":
Expand Down
40 changes: 40 additions & 0 deletions ffi/passes/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.2)

if (APPLE)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
set(MACOSX_DEPLOYMENT_TARGET "10.9")
set(CMAKE_OSX_SYSROOT "/Applications/Xcode-9.4.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk")
LIST(APPEND CMAKE_MODULE_PATH "/Users/travis/miniconda3/envs/travisci/lib/cmake")
SET(CMAKE_INSTALL_PREFIX "/Users/travis/miniconda3/envs/travisci")
SET(LLVM_INSTALL_PREFIX "/Users/travis/miniconda3/envs/travisci")
endif()

project(llvmpy-passes)

find_package(LLVM REQUIRED CONFIG)

execute_process(
COMMAND llvm-config --cxxflags ${LLVM_FIND_COMPONENTS}
RESULT_VARIABLE result_code
OUTPUT_VARIABLE LLVM_CXXFLAGS
OUTPUT_STRIP_TRAILING_WHITESPACE
)

set(CMAKE_CXX_FLAGS ${LLVM_CXXFLAGS})

add_definitions(${LLVM_DEFINITIONS})

if (WIN23)
add_definitions("/D LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING")
else()
add_definitions("-DLLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING")
endif()

if (NOT WIN32)
add_compile_options("-fno-rtti")
endif()

include_directories(${LLVM_INCLUDE_DIRS})

add_subdirectory(hello)

10 changes: 10 additions & 0 deletions ffi/passes/hello/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_library(LLVMPYHello MODULE Hello.cpp)

llvm_map_components_to_libnames(llvm_libs demangle)
if (APPLE)
target_link_libraries(LLVMPYHello PRIVATE ${llvm_libs} "-undefined dynamic_lookup")
elseif(WIN32)
target_link_libraries(LLVMPYHello PRIVATE ${llvm_libs} llvmlite)
else()
target_link_libraries(LLVMPYHello PRIVATE ${llvm_libs})
endif()
49 changes: 49 additions & 0 deletions ffi/passes/hello/Hello.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Demangle/Demangle.h"
#include <memory>

using namespace llvm;

namespace {
/*
Sample Hello World function pass. Named pyhello to avoid conflict
with LLVM's built-in example pass
*/
struct PyHello : public FunctionPass {
static char ID;
static const std::string name;
static const std::string arg;
PyHello() : FunctionPass(ID) { }
bool runOnFunction(Function& F) override {
errs() << "Hello: ";
errs().write_escaped(F.getName()) << "\n";
return false;
}
};

char PyHello::ID = 0;
const std::string PyHello::name = "Hello World Pass";
const std::string PyHello::arg = "pyhello";
} // end anonymous

extern "C" {
#if defined(_MSC_VER)
#define API_EXPORT(RTYPE) __declspec(dllexport) RTYPE
#else
#define API_EXPORT(RTYPE) RTYPE
#endif

API_EXPORT(void) LLVMPY_RegisterPass(LLVMPassRegistryRef PR) {
auto registry = unwrap(PR);
// check if there is already a pyhello pass
auto passInfo = registry->getPassInfo(PyHello::arg);
if (passInfo == nullptr) {
passInfo = new PassInfo(PyHello::name, PyHello::arg, &PyHello::ID,
PassInfo::NormalCtor_t(callDefaultCtor<PyHello>), false,
false);
registry->registerPass(*passInfo, true);
}
}
} // end extern "C"
Loading