diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f4474f7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,24 @@ +language: python + +python: + - "2.6" + - "2.7" + - "3.2" + - "3.3" + +branches: + only: + - master + +install: + - wget "http://repo.continuum.io/pkgs/free/linux-64/llvm-3.2-0.tar.bz2" + - tar -xjf llvm-3.2-0.tar.bz2 + - PATH+=":`pwd`/bin" + - export LD_LIBRARY_PATH="`pwd`/lib" + - export LLVM_CONFIG_PATH="`pwd`/bin/llvm-config" + - $LLVM_CONFIG_PATH --cflags # test llvm-config + - export LLVMPY_DYNLINK=1 + - python setup.py install -q + +script: cd ~; python -c "import sys;import llvm;sys.exit(0 if llvm.test() == 0 else 1)" + diff --git a/CHANGELOG b/CHANGELOG index 5af6169..45d6a5f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,40 @@ +2014-04-28 0.12.5: +--------------------- + * Fixes memory leaks (#92) + * Fixes tarball (#99) + +2014-03-20 0.12.4: +--------------------- + * Add dylib_import_library and friends + * Fix BasicBlock downcast + * Module hashing + * Fix test script + +2014-02-18 0.12.3: +--------------------- + * Fix deprecation message for py2.6 + * Fix llvm_cbuilder for using deprecated_alloca + * Merged PR #88 by cantora + * Merged PR #94 by cgohlke + +2014-02-04 0.12.2: +--------------------- + * enhance wrapper efficiency by moving some capsule code into C++ + * fix unclosed file handler in avx_support + * multiple-dimension insert_value, extract_value + * various minor fixes + +2013-11-11 0.12.1: +--------------------- + * various bug fixes + +2013-08-28 0.12.0: +--------------------- + * update to LLVM 3.3 and maintain compatibility with LLVM 3.2 + * add LLRT for minimal support for 64-bit divmod on 32-bit platform + * start to adopt MCJIT (not quite usable on win32) + * various bug fixes + 2013-03-05 0.11.1: -------------------- * fix test when cc is not available diff --git a/MANIFEST.in b/MANIFEST.in index 295794c..25a211d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ -include CHANGELOG LICENSE README setup.py MANIFEST.in +include CHANGELOG LICENSE README.rst setup.py MANIFEST.in versioneer.py recursive-include llvm * +recursive-include llvmpy * recursive-include www * recursive-include test * recursive-include tools * diff --git a/README.rst b/README.rst index b16249a..a1abf84 100644 --- a/README.rst +++ b/README.rst @@ -16,26 +16,48 @@ Other Python versions may work. Quickstart ---------- -1. Get 3.2 version of LLVM, build it. Make sure ``--enable-pic`` is - passed to LLVM's ``configure``. +1. Get and extract LLVM 3.2 source tarball from + `llvm.org `_. Then, ``cd`` into + the extracted directory. - For LLVM 3.2, make sure that environment variable ``REQUIRES_RTTI=1`` is - defined when running ``make``. Otherwise, you may see "undefined symbol: - _ZTIN4llvm24PassRegistrationListenerE". Please refer to - http://llvm.org/docs/Packaging.html#c-features for details. +2. Run ``./configure --enable-optimized --prefix=LLVM_INSTALL_PATH``. -2. Get llvm-py and install it:: + **Note**: Without the ``--enable-optimized`` flag, debug build will be + selected. Unless you are developing LLVM or llvmpy, it is recommended + that the flag is used to reduce build time and binary size. + + **Note**: Use prefix to select the installation path. It is recommended + to separate your custom build from the default system package. Please + replace ``LLVM_INSTALL_PATH`` with your own path. + +3. Run ``REQUIRES_RTTI=1 make install`` to build and install. + + **Note**: With LLVM 3.2, the default build configuration has C++ RTTI + disabled. However, llvmpy requires RTTI. + + **Note**: Use ``make -j2 install`` to enable concurrent build. + Replace ``2`` with the actual number of processor you have. + +4. Get llvm-py and install it:: $ git clone git@github.com:llvmpy/llvmpy.git $ cd llvmpy - $ python setup.py install + $ LLVM_CONFIG_PATH=LLVM_INSTALL_PATH/bin/llvm-config python setup.py install Run the tests:: $ python -c "import llvm; llvm.test()" -3. See documentation at 'http://www.llvmpy.org' and examples +5. See documentation at 'http://www.llvmpy.org' and examples under 'test'. + +Common Build Problems +--------------------- + +1. If llvmpy cannot be imported due to "undefined symbol: + _ZTIN4llvm24PassRegistrationListenerE", it is because RTTI is not enabled + when building LLVM. "_ZTIN4llvm24PassRegistrationListenerE" is the typeinfo + of PassRegistrationListener class. LICENSE ------- diff --git a/buildscripts/condarecipe/bld.bat b/buildscripts/condarecipe/bld.bat new file mode 100644 index 0000000..e9177c5 --- /dev/null +++ b/buildscripts/condarecipe/bld.bat @@ -0,0 +1,6 @@ +set LLVMPY_DYNLINK=0 +set INCLUDE=%LIBRARY_INC% +set LIBPATH=%LIBRARY_LIB% +set LIB=%LIBRARY_LIB% +%PYTHON% setup.py install +if errorlevel 1 exit 1 diff --git a/buildscripts/condarecipe/build.sh b/buildscripts/condarecipe/build.sh new file mode 100644 index 0000000..5c98fde --- /dev/null +++ b/buildscripts/condarecipe/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +if [[ (`uname` == Linux) && (`uname -m` != armv6l) ]] +then + export CC=gcc + #gcc44 + export CXX=g++ + #g++44 +fi + +export LLVMPY_DYNLINK=$DISTRO_BUILD + +$PYTHON setup.py install diff --git a/buildscripts/condarecipe/meta.yaml b/buildscripts/condarecipe/meta.yaml new file mode 100644 index 0000000..4612840 --- /dev/null +++ b/buildscripts/condarecipe/meta.yaml @@ -0,0 +1,28 @@ +package: + name: llvmpy + version: 99.9.9 + +source: + git_url: git@github.com:llvmpy/llvmpy.git +# git_tag: 0.12.0 + +requirements: + build: + - llvm + - python + #- chrpath [linux] + run: + - llvm [unix] + - python + +test: + imports: + - llvm + - llvmpy + - llvmpy._api + - llvmpy._capsule + - llpython + - llvm_array + - llvm_cbuilder + + diff --git a/buildscripts/condarecipe/run_test.py b/buildscripts/condarecipe/run_test.py new file mode 100644 index 0000000..682b8d4 --- /dev/null +++ b/buildscripts/condarecipe/run_test.py @@ -0,0 +1,22 @@ +import sys +import platform +import llvm + +from llvm.core import Module +from llvm.ee import EngineBuilder +from llvm.utils import check_intrinsics + +m = Module.new('fjoidajfa') +eb = EngineBuilder.new(m) +target = eb.select_target() + +print('target.triple=%r' % target.triple) +if sys.platform == 'darwin': + s = {'64bit': 'x86_64', '32bit': 'x86'}[platform.architecture()[0]] + assert target.triple.startswith(s + '-apple-darwin') + +assert llvm.test(verbosity=2, run_isolated=False) == 0 +#check_intrinsics.main() + +print('llvm.__version__: %s' % llvm.__version__) +#assert llvm.__version__ == '0.12.0' diff --git a/docs/gh-pages.py b/docs/gh-pages.py index dd30e28..3ee5d20 100755 --- a/docs/gh-pages.py +++ b/docs/gh-pages.py @@ -30,7 +30,7 @@ from subprocess import Popen, PIPE, CalledProcessError, check_call pages_dir = 'gh-pages' html_dir = '_build/html' pdf_dir = '_build/latex' -pages_repo = 'git@github.com:llvmpy/llvmpy-doc.git' +pages_repo = 'https://github.com/llvmpy/llvmpy-doc.git' #----------------------------------------------------------------------------- # Functions diff --git a/docs/source/doc/getting_started.rst b/docs/source/doc/getting_started.rst index f9b9c56..53c2982 100644 --- a/docs/source/doc/getting_started.rst +++ b/docs/source/doc/getting_started.rst @@ -38,7 +38,7 @@ supported, for a variety of reasons. Versions -------- -llvmpy 0.9 requires version 3.1 of LLVM. It may not work with +llvmpy 0.11.2 uses LLVM 3.2 (or at least 3.1). It may not work with previous versions. llvmpy has been built and tested with Python 2.7 and 3.2. It should work with @@ -65,22 +65,6 @@ It does not matter which compiler LLVM itself was built with (``g++``, ``llvm-g++`` or any other); llvmpy can be built with any compiler. It has been tried only with gcc/g++ though. - -LLVM and ``--enable-pic`` -------------------------- - -The result of an LLVM build is a set of static libraries and object -files. The llvmpy contains an extension package that is built into a -shared object (\_core.so) which links to these static libraries and -object files. It is therefore required that the LLVM libraries and -object files be built with the ``-fPIC`` option (generate position -independent code). Be sure to use the ``--enable-pic`` option while -configuring LLVM (default is no PIC), like this: - -.. code-block:: bash - - $ ~/llvm ./configure --enable-pic --enable-optimized - llvm-config ----------- @@ -98,13 +82,34 @@ is different from that of 'root', so even if ``llvm-config`` is in your Steps ----- -Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to -LLVM's 'configure'. +1. Get and extract LLVM 3.2 source tarball from + `llvm.org `_. Then, ``cd`` into + the extracted directory. -Get llvmpy and install it: +2. Run ``./configure --enable-optimized --prefix=LLVM_INSTALL_PATH``. + **Note**: Without the ``--enable-optimized`` flag, debug build will be + selected. Unless you are developing LLVM or llvmpy, it is recommended + that the flag is used to reduce build time and binary size. + + **Note**: Use prefix to select the installation path. It is recommended + to separate your custom build from the default system package. Please + replace ``LLVM_INSTALL_PATH`` with your own path. -.. code-block:: bash +3. Run ``REQUIRES_RTTI=1 make`` to build. - $ git clone git@github.com:numba/llvmpy.git - $ cd llvmpy $ python setup.py install + **Note**: With LLVM 3.2, the default build configuration has C++ RTTI + disabled. However, llvmpy requires RTTI. + +4. Get llvm-py and install it:: + + $ git clone git@github.com:llvmpy/llvmpy.git + $ cd llvmpy + $ LLVM_CONFIG_PATH=LLVM_INSTALL_PATH/bin/llvm-config python setup.py install + + Run the tests:: + + $ python -c "import llvm; llvm.test()" + +5. See documentation at 'http://www.llvmpy.org' and examples + under 'test'. diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst index 7e86ee4..dee1c31 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst @@ -121,8 +121,8 @@ to talk about how LLVM represents stack variables. In LLVM, all memory accesses are explicit with load/store instructions, and it is carefully designed not to have (or need) an "address-of" operator. Notice how the type of the @G/@H global variables is actually -"i32\ *" even though the variable is defined as "i32". What this means -is that @G defines* space* for an i32 in the global data area, but its +"i32\*" even though the variable is defined as "i32". What this means +is that @G defines *space* for an i32 in the global data area, but its *name* actually refers to the address for that space. Stack variables work the same way, except that instead of being declared with global variable definitions, they are declared with the `LLVM alloca @@ -133,11 +133,11 @@ instruction `_: define i32 @example() { entry: - %X = alloca i32 ; type of %X is i32 *. + %X = alloca i32 ; type of %X is i32* ... - %tmp = load i32* %X ; load the stack value %X from the stack. - %tmp2 = add i32 %tmp, 1 ; increment it store i32 %tmp2, - i32* %X ; store it back + %tmp = load i32* %X ; load the stack value %X from the stack + %tmp2 = add i32 %tmp, 1 ; increment it + store i32 %tmp2, i32* %X ; store it back ... diff --git a/docs/source/doc/llvm.core.Constant.rst b/docs/source/doc/llvm.core.Constant.rst index ae67fa4..3822046 100644 --- a/docs/source/doc/llvm.core.Constant.rst +++ b/docs/source/doc/llvm.core.Constant.rst @@ -26,334 +26,335 @@ some examples: tr = Type.float() - r1 = Constant.real(tr, "3.141592") # create from a string r2 = - Constant.real(tr, 1.61803399) # create from a Python float {% - endhighlight %} - - # llvm.core.Constant - - This will become a table of contents (this text will be scraped). - {:toc} - - Static factory methods - ---------------------- - - ``null(ty)`` - ~~~~~~~~~~~~ - - A null value (all zeros) of type ``ty`` - - ``all_ones(ty)`` - ~~~~~~~~~~~~~~~~ - - All 1's value of type ``ty`` - - ``undef(ty)`` - ~~~~~~~~~~~~~ - - An undefined value of type ``ty`` - - ``int(ty, value)`` - ~~~~~~~~~~~~~~~~~~ - - Integer of type ``ty``, with value ``value`` (a Python int or long) - - ``int_signextend(ty, value)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Integer of signed type ``ty`` (use for signed types) - - ``real(ty, value)`` - ~~~~~~~~~~~~~~~~~~~ - - Floating point value of type ``ty``, with value ``value`` (a Python - float) - - ``stringz(value)`` - ~~~~~~~~~~~~~~~~~~ - - A null-terminated string. ``value`` is a Python string - - ``string(value)`` - ~~~~~~~~~~~~~~~~~ - - As ``string(ty)``, but not null terminated - - ``array(ty, consts)`` - ~~~~~~~~~~~~~~~~~~~~~ - - Array of type ``ty``, initialized with ``consts`` (an iterable yielding - ``Constant`` objects of the appropriate type) - - ``struct(ty, consts)`` - ~~~~~~~~~~~~~~~~~~~~~~ - - Struct (unpacked) of type ``ty``, initialized with ``consts`` (an - iterable yielding ``Constant`` objects of the appropriate type) - - ``packed_struct(ty, consts)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - As ``struct(ty, consts)`` but packed - - ``vector(consts)`` - ~~~~~~~~~~~~~~~~~~ - - Vector, initialized with ``consts`` (an iterable yielding ``Constant`` - objects of the appropriate type) - - ``sizeof(ty)`` - ~~~~~~~~~~~~~~ - - Constant value representing the sizeof the type ``ty`` - - Methods - ------- - - The following operations on constants are supported. For more details on - any operation, consult the `Constant - Expressions `_ - section of the LLVM Language Reference. - - ``k.neg()`` - ~~~~~~~~~~~ - - negation, same as ``0 - k`` - - ``k.not_()`` - ~~~~~~~~~~~~ - - 1's complement of ``k``. Note trailing underscore. - - ``k.add(k2)`` - ~~~~~~~~~~~~~ - - ``k + k2``, where ``k`` and ``k2`` are integers. - - ``k.fadd(k2)`` - ~~~~~~~~~~~~~~ - - ``k + k2``, where ``k`` and ``k2`` are floating-point. - - ``k.sub(k2)`` - ~~~~~~~~~~~~~ - - ``k - k2``, where ``k`` and ``k2`` are integers. - - ``k.fsub(k2)`` - ~~~~~~~~~~~~~~ - - ``k - k2``, where ``k`` and ``k2`` are floating-point. - - ``k.mul(k2)`` - ~~~~~~~~~~~~~ - - ``k * k2``, where ``k`` and ``k2`` are integers. - - ``k.fmul(k2)`` - ~~~~~~~~~~~~~~ - - ``k * k2``, where ``k`` and ``k2`` are floating-point. - - ``k.udiv(k2)`` - ~~~~~~~~~~~~~~ - - Quotient of unsigned division of ``k`` with ``k2`` - - ``k.sdiv(k2)`` - ~~~~~~~~~~~~~~ - - Quotient of signed division of ``k`` with ``k2`` - - ``k.fdiv(k2)`` - ~~~~~~~~~~~~~~ - - Quotient of floating point division of ``k`` with ``k2`` - - ``k.urem(k2)`` - ~~~~~~~~~~~~~~ - - Reminder of unsigned division of ``k`` with ``k2`` - - ``k.srem(k2)`` - ~~~~~~~~~~~~~~ - - Reminder of signed division of ``k`` with ``k2`` - - ``k.frem(k2)`` - ~~~~~~~~~~~~~~ - - Reminder of floating point division of ``k`` with ``k2`` - - ``k.and_(k2)`` - ~~~~~~~~~~~~~~ - - Bitwise and of ``k`` and ``k2``. Note trailing underscore. - - ``k.or_(k2)`` - ~~~~~~~~~~~~~ - - Bitwise or of ``k`` and ``k2``. Note trailing underscore. - - ``k.xor(k2)`` - ~~~~~~~~~~~~~ - - Bitwise exclusive-or of ``k`` and ``k2``. - - ``k.icmp(icmp, k2)`` - ~~~~~~~~~~~~~~~~~~~~ - - Compare ``k`` with ``k2`` using the predicate ``icmp``. See - `here `_ for list of predicates for integer - operands. - - ``k.fcmp(fcmp, k2)`` - ~~~~~~~~~~~~~~~~~~~~ - - Compare ``k`` with ``k2`` using the predicate ``fcmp``. See - `here `_ for list of predicates for real - operands. - - ``k.shl(k2)`` - ~~~~~~~~~~~~~ - - Shift ``k`` left by ``k2`` bits. - - ``k.lshr(k2)`` - ~~~~~~~~~~~~~~ - - Shift ``k`` logically right by ``k2`` bits (new bits are 0s). - - ``k.ashr(k2)`` - ~~~~~~~~~~~~~~ - - Shift ``k`` arithmetically right by ``k2`` bits (new bits are same as - previous sign bit). - - ``k.gep(indices)`` - ~~~~~~~~~~~~~~~~~~ - - GEP, see `LLVM docs `_. - - ``k.trunc(ty)`` - ~~~~~~~~~~~~~~~ - - Truncate ``k`` to a type ``ty`` of lower bitwidth. - - ``k.sext(ty)`` - ~~~~~~~~~~~~~~ - - Sign extend ``k`` to a type ``ty`` of higher bitwidth, while extending - the sign bit. - - ``k.zext(ty)`` - ~~~~~~~~~~~~~~ - - Sign extend ``k`` to a type ``ty`` of higher bitwidth, all new bits are - 0s. - - ``k.fptrunc(ty)`` - ~~~~~~~~~~~~~~~~~ - - Truncate floating point constant ``k`` to floating point type ``ty`` of - lower size than k's. - - ``k.fpext(ty)`` - ~~~~~~~~~~~~~~~ - - Extend floating point constant ``k`` to floating point type ``ty`` of - higher size than k's. - - ``k.uitofp(ty)`` - ~~~~~~~~~~~~~~~~ - - Convert an unsigned integer constant ``k`` to floating point constant of - type ``ty``. - - ``k.sitofp(ty)`` - ~~~~~~~~~~~~~~~~ - - Convert a signed integer constant ``k`` to floating point constant of - type ``ty``. - - ``k.fptoui(ty)`` - ~~~~~~~~~~~~~~~~ - - Convert a floating point constant ``k`` to an unsigned integer constant - of type ``ty``. - - ``k.fptosi(ty)`` - ~~~~~~~~~~~~~~~~ - - Convert a floating point constant ``k`` to a signed integer constant of - type ``ty``. - - ``k.ptrtoint(ty)`` - ~~~~~~~~~~~~~~~~~~ - - Convert a pointer constant ``k`` to an integer constant of type ``ty``. - - ``k.inttoptr(ty)`` - ~~~~~~~~~~~~~~~~~~ - - Convert an integer constant ``k`` to a pointer constant of type ``ty``. - - ``k.bitcast(ty)`` - ~~~~~~~~~~~~~~~~~ - - Convert ``k`` to a (equal-width) constant of type ``ty``. - - ``k.select(cond,k2,k3)`` - ~~~~~~~~~~~~~~~~~~~~~~~~ - - Replace value with ``k2`` if the 1-bit integer constant ``cond`` is 1, - else with ``k3``. - - ``k.extract_element(idx)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Extract value at ``idx`` (integer constant) from a vector constant - ``k``. - - ``k.insert_element(k2,idx)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Insert value ``k2`` (scalar constant) at index ``idx`` (integer - constant) of vector constant ``k``. - - ``k.shuffle_vector(k2,mask)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Shuffle vector constant ``k`` based on vector constants ``k2`` and - ``mask``. - - -------------- - - # Other Constant Classes - The following subclasses of ``Constant`` do not provide additional - methods, **they serve only to provide richer type information.** - - Subclass \| LLVM C++ Class \| Remarks \| - ---------\|----------------\|---------\| ``ConstantExpr`` \| - ``llvmConstantExpr`` \| A constant expression \| - ``ConstantAggregateZero``\ \| ``llvmConstantAggregateZero``\ \| All-zero - constant \| ``ConstantInt``\ \| ``llvmConstantInt``\ \| An integer - constant \| ``ConstantFP``\ \| ``llvmConstantFP``\ \| A floating-point - constant \| ``ConstantArray``\ \| ``llvmConstantArray``\ \| An array - constant \| ``ConstantStruct``\ \| ``llvmConstantStruct``\ \| A - structure constant \| ``ConstantVector``\ \| ``llvmConstantVector``\ \| - A vector constant \| ``ConstantPointerNull``\ \| - ``llvmConstantPointerNull``\ \| All-zero pointer constant \| - ``UndefValue``\ \| ``llvmUndefValue``\ \| corresponds to ``undef`` of - LLVM IR \| - - These types are helpful in ``isinstance`` checks, like so: - - {% highlight python %} ti = Type.int(32) k1 = Constant.int(ti, 42) # - int32_t k1 = 42; k2 = Constant.array(ti, [k1, k1]) # int32_t k2[] = { - k1, k1 }; - - assert isinstance(k1, ConstantInt) assert isinstance(k2, ConstantArray) - + r1 = Constant.real(tr, "3.141592") # create from a string + r2 = Constant.real(tr, 1.61803399) # create from a Python float + + +# llvm.core.Constant +- This will become a table of contents (this text will be scraped). +{:toc} + + +Static factory methods +---------------------- + +``null(ty)`` +~~~~~~~~~~~~ + +A null value (all zeros) of type ``ty`` + +``all_ones(ty)`` +~~~~~~~~~~~~~~~~ + +All 1's value of type ``ty`` + +``undef(ty)`` +~~~~~~~~~~~~~ + +An undefined value of type ``ty`` + +``int(ty, value)`` +~~~~~~~~~~~~~~~~~~ + +Integer of type ``ty``, with value ``value`` (a Python int or long) + +``int_signextend(ty, value)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Integer of signed type ``ty`` (use for signed types) + +``real(ty, value)`` +~~~~~~~~~~~~~~~~~~~ + +Floating point value of type ``ty``, with value ``value`` (a Python +float) + +``stringz(value)`` +~~~~~~~~~~~~~~~~~~ + +A null-terminated string. ``value`` is a Python string + +``string(value)`` +~~~~~~~~~~~~~~~~~ + +As ``string(ty)``, but not null terminated + +``array(ty, consts)`` +~~~~~~~~~~~~~~~~~~~~~ + +Array of type ``ty``, initialized with ``consts`` (an iterable yielding +``Constant`` objects of the appropriate type) + +``struct(ty, consts)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Struct (unpacked) of type ``ty``, initialized with ``consts`` (an +iterable yielding ``Constant`` objects of the appropriate type) + +``packed_struct(ty, consts)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As ``struct(ty, consts)`` but packed + +``vector(consts)`` +~~~~~~~~~~~~~~~~~~ + +Vector, initialized with ``consts`` (an iterable yielding ``Constant`` +objects of the appropriate type) + +``sizeof(ty)`` +~~~~~~~~~~~~~~ + +Constant value representing the sizeof the type ``ty`` + +Methods +------- + +The following operations on constants are supported. For more details on +any operation, consult the `Constant +Expressions `_ +section of the LLVM Language Reference. + +``k.neg()`` +~~~~~~~~~~~ + +negation, same as ``0 - k`` + +``k.not_()`` +~~~~~~~~~~~~ + +1's complement of ``k``. Note trailing underscore. + +``k.add(k2)`` +~~~~~~~~~~~~~ + +``k + k2``, where ``k`` and ``k2`` are integers. + +``k.fadd(k2)`` +~~~~~~~~~~~~~~ + +``k + k2``, where ``k`` and ``k2`` are floating-point. + +``k.sub(k2)`` +~~~~~~~~~~~~~ + +``k - k2``, where ``k`` and ``k2`` are integers. + +``k.fsub(k2)`` +~~~~~~~~~~~~~~ + +``k - k2``, where ``k`` and ``k2`` are floating-point. + +``k.mul(k2)`` +~~~~~~~~~~~~~ + +``k * k2``, where ``k`` and ``k2`` are integers. + +``k.fmul(k2)`` +~~~~~~~~~~~~~~ + +``k * k2``, where ``k`` and ``k2`` are floating-point. + +``k.udiv(k2)`` +~~~~~~~~~~~~~~ + +Quotient of unsigned division of ``k`` with ``k2`` + +``k.sdiv(k2)`` +~~~~~~~~~~~~~~ + +Quotient of signed division of ``k`` with ``k2`` + +``k.fdiv(k2)`` +~~~~~~~~~~~~~~ + +Quotient of floating point division of ``k`` with ``k2`` + +``k.urem(k2)`` +~~~~~~~~~~~~~~ + +Reminder of unsigned division of ``k`` with ``k2`` + +``k.srem(k2)`` +~~~~~~~~~~~~~~ + +Reminder of signed division of ``k`` with ``k2`` + +``k.frem(k2)`` +~~~~~~~~~~~~~~ + +Reminder of floating point division of ``k`` with ``k2`` + +``k.and_(k2)`` +~~~~~~~~~~~~~~ + +Bitwise and of ``k`` and ``k2``. Note trailing underscore. + +``k.or_(k2)`` +~~~~~~~~~~~~~ + +Bitwise or of ``k`` and ``k2``. Note trailing underscore. + +``k.xor(k2)`` +~~~~~~~~~~~~~ + +Bitwise exclusive-or of ``k`` and ``k2``. + +``k.icmp(icmp, k2)`` +~~~~~~~~~~~~~~~~~~~~ + +Compare ``k`` with ``k2`` using the predicate ``icmp``. See +`here `_ for list of predicates for integer +operands. + +``k.fcmp(fcmp, k2)`` +~~~~~~~~~~~~~~~~~~~~ + +Compare ``k`` with ``k2`` using the predicate ``fcmp``. See +`here `_ for list of predicates for real +operands. + +``k.shl(k2)`` +~~~~~~~~~~~~~ + +Shift ``k`` left by ``k2`` bits. + +``k.lshr(k2)`` +~~~~~~~~~~~~~~ + +Shift ``k`` logically right by ``k2`` bits (new bits are 0s). + +``k.ashr(k2)`` +~~~~~~~~~~~~~~ + +Shift ``k`` arithmetically right by ``k2`` bits (new bits are same as +previous sign bit). + +``k.gep(indices)`` +~~~~~~~~~~~~~~~~~~ + +GEP, see `LLVM docs `_. + +``k.trunc(ty)`` +~~~~~~~~~~~~~~~ + +Truncate ``k`` to a type ``ty`` of lower bitwidth. + +``k.sext(ty)`` +~~~~~~~~~~~~~~ + +Sign extend ``k`` to a type ``ty`` of higher bitwidth, while extending +the sign bit. + +``k.zext(ty)`` +~~~~~~~~~~~~~~ + +Sign extend ``k`` to a type ``ty`` of higher bitwidth, all new bits are +0s. + +``k.fptrunc(ty)`` +~~~~~~~~~~~~~~~~~ + +Truncate floating point constant ``k`` to floating point type ``ty`` of +lower size than k's. + +``k.fpext(ty)`` +~~~~~~~~~~~~~~~ + +Extend floating point constant ``k`` to floating point type ``ty`` of +higher size than k's. + +``k.uitofp(ty)`` +~~~~~~~~~~~~~~~~ + +Convert an unsigned integer constant ``k`` to floating point constant of +type ``ty``. + +``k.sitofp(ty)`` +~~~~~~~~~~~~~~~~ + +Convert a signed integer constant ``k`` to floating point constant of +type ``ty``. + +``k.fptoui(ty)`` +~~~~~~~~~~~~~~~~ + +Convert a floating point constant ``k`` to an unsigned integer constant +of type ``ty``. + +``k.fptosi(ty)`` +~~~~~~~~~~~~~~~~ + +Convert a floating point constant ``k`` to a signed integer constant of +type ``ty``. + +``k.ptrtoint(ty)`` +~~~~~~~~~~~~~~~~~~ + +Convert a pointer constant ``k`` to an integer constant of type ``ty``. + +``k.inttoptr(ty)`` +~~~~~~~~~~~~~~~~~~ + +Convert an integer constant ``k`` to a pointer constant of type ``ty``. + +``k.bitcast(ty)`` +~~~~~~~~~~~~~~~~~ + +Convert ``k`` to a (equal-width) constant of type ``ty``. + +``k.select(cond,k2,k3)`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Replace value with ``k2`` if the 1-bit integer constant ``cond`` is 1, +else with ``k3``. + +``k.extract_element(idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Extract value at ``idx`` (integer constant) from a vector constant +``k``. + +``k.insert_element(k2,idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert value ``k2`` (scalar constant) at index ``idx`` (integer +constant) of vector constant ``k``. + +``k.shuffle_vector(k2,mask)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Shuffle vector constant ``k`` based on vector constants ``k2`` and +``mask``. + +-------------- + +# Other Constant Classes +The following subclasses of ``Constant`` do not provide additional +methods, **they serve only to provide richer type information.** + +Subclass \| LLVM C++ Class \| Remarks \| +---------\|----------------\|---------\| ``ConstantExpr`` \| +``llvmConstantExpr`` \| A constant expression \| +``ConstantAggregateZero``\ \| ``llvmConstantAggregateZero``\ \| All-zero +constant \| ``ConstantInt``\ \| ``llvmConstantInt``\ \| An integer +constant \| ``ConstantFP``\ \| ``llvmConstantFP``\ \| A floating-point +constant \| ``ConstantArray``\ \| ``llvmConstantArray``\ \| An array +constant \| ``ConstantStruct``\ \| ``llvmConstantStruct``\ \| A +structure constant \| ``ConstantVector``\ \| ``llvmConstantVector``\ \| +A vector constant \| ``ConstantPointerNull``\ \| +``llvmConstantPointerNull``\ \| All-zero pointer constant \| +``UndefValue``\ \| ``llvmUndefValue``\ \| corresponds to ``undef`` of +LLVM IR \| + +These types are helpful in ``isinstance`` checks, like so: + +{% highlight python %} ti = Type.int(32) k1 = Constant.int(ti, 42) # +int32_t k1 = 42; k2 = Constant.array(ti, [k1, k1]) # int32_t k2[] = { +k1, k1 }; + +assert isinstance(k1, ConstantInt) assert isinstance(k2, ConstantArray) + Automatically Generated Documentation ------------------------------------- diff --git a/docs/source/index.rst b/docs/source/index.rst index 7798b77..fbf5c8b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,8 +3,8 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Documentation for llvmpy -======================== +llvmpy +====== Contents: @@ -22,7 +22,7 @@ Contents: Indices and tables -================== +------------------ * :ref:`genindex` * :ref:`modindex` diff --git a/example/vector_instr.py b/example/vector_instr.py new file mode 100644 index 0000000..e49d06a --- /dev/null +++ b/example/vector_instr.py @@ -0,0 +1,152 @@ +''' +This example shows: +1) how to use vector instructions +2) how to take advantage of LLVM loop vectorization to transform scalar + operations to vector operations +''' + +from __future__ import print_function +import llvm.core as lc +import llvm.ee as le +import llvm.passes as lp +from ctypes import CFUNCTYPE, POINTER, c_int, c_float + +def build_manual_vector(): + mod = lc.Module.new('manual.vector') + intty = lc.Type.int(32) + vecty = lc.Type.vector(lc.Type.float(), 4) + aryty = lc.Type.pointer(lc.Type.float()) + fnty = lc.Type.function(lc.Type.void(), [aryty, aryty, aryty, intty]) + fn = mod.add_function(fnty, name='vector_add') + bbentry = fn.append_basic_block('entry') + bbloopcond = fn.append_basic_block('loop.cond') + bbloopbody = fn.append_basic_block('loop.body') + bbexit = fn.append_basic_block('exit') + builder = lc.Builder.new(bbentry) + + # populate function body + in1, in2, out, size = fn.args + ZERO = lc.Constant.null(intty) + loopi_ptr = builder.alloca(intty) + builder.store(ZERO, loopi_ptr) + + builder.branch(bbloopcond) + builder.position_at_end(bbloopcond) + + loopi = builder.load(loopi_ptr) + loopcond = builder.icmp(lc.ICMP_ULT, loopi, size) + + builder.cbranch(loopcond, bbloopbody, bbexit) + builder.position_at_end(bbloopbody) + + vecaryty = lc.Type.pointer(vecty) + in1asvec = builder.bitcast(builder.gep(in1, [loopi]), vecaryty) + in2asvec = builder.bitcast(builder.gep(in2, [loopi]), vecaryty) + outasvec = builder.bitcast(builder.gep(out, [loopi]), vecaryty) + + vec1 = builder.load(in1asvec) + vec2 = builder.load(in2asvec) + + vecout = builder.fadd(vec1, vec2) + + builder.store(vecout, outasvec) + + next = builder.add(loopi, lc.Constant.int(intty, 4)) + builder.store(next, loopi_ptr) + + builder.branch(bbloopcond) + builder.position_at_end(bbexit) + + builder.ret_void() + + return mod, fn + + +def build_auto_vector(): + mod = lc.Module.new('auto.vector') + # Loop vectorize is sensitive to the size of the index size(!?) + intty = lc.Type.int(tuple.__itemsize__ * 8) + aryty = lc.Type.pointer(lc.Type.float()) + fnty = lc.Type.function(lc.Type.void(), [aryty, aryty, aryty, intty]) + fn = mod.add_function(fnty, name='vector_add') + bbentry = fn.append_basic_block('entry') + bbloopcond = fn.append_basic_block('loop.cond') + bbloopbody = fn.append_basic_block('loop.body') + bbexit = fn.append_basic_block('exit') + builder = lc.Builder.new(bbentry) + + # populate function body + in1, in2, out, size = fn.args + in1.add_attribute(lc.ATTR_NO_ALIAS) + in2.add_attribute(lc.ATTR_NO_ALIAS) + out.add_attribute(lc.ATTR_NO_ALIAS) + ZERO = lc.Constant.null(intty) + loopi_ptr = builder.alloca(intty) + builder.store(ZERO, loopi_ptr) + + builder.branch(bbloopcond) + builder.position_at_end(bbloopcond) + + loopi = builder.load(loopi_ptr) + loopcond = builder.icmp(lc.ICMP_ULT, loopi, size) + + builder.cbranch(loopcond, bbloopbody, bbexit) + builder.position_at_end(bbloopbody) + + in1elem = builder.load(builder.gep(in1, [loopi])) + in2elem = builder.load(builder.gep(in2, [loopi])) + + outelem = builder.fadd(in1elem, in2elem) + + builder.store(outelem, builder.gep(out, [loopi])) + + next = builder.add(loopi, lc.Constant.int(intty, 1)) + builder.store(next, loopi_ptr) + + builder.branch(bbloopcond) + builder.position_at_end(bbexit) + + builder.ret_void() + + return mod, fn + +def example(title, module_builder, opt): + print(title.center(80, '=')) + mod, fn = module_builder() + + eb = le.EngineBuilder.new(mod).opt(3) + if opt: + print('opt') + tm = eb.select_target() + pms = lp.build_pass_managers(mod=mod, tm=tm, opt=3, loop_vectorize=True, + fpm=False) + pms.pm.run(mod) + + print(mod) + print(mod.to_native_assembly()) + + engine = eb.create() + ptr = engine.get_pointer_to_function(fn) + + callable = CFUNCTYPE(None, POINTER(c_float), POINTER(c_float), + POINTER(c_float), c_int)(ptr) + + N = 20 + in1 = (c_float * N)(*range(N)) + in2 = (c_float * N)(*range(N)) + out = (c_float * N)() + + print('in1: ', list(in1)) + print('in1: ', list(in2)) + + callable(in1, in2, out, N) + + print('out', list(out)) + + +def main(): + example('manual vector function', build_manual_vector, False) + example('auto vector function', build_auto_vector, True) + +if __name__ == '__main__': + main() diff --git a/llpython/byte_control.py b/llpython/byte_control.py index 9df6d5c..8ca407e 100644 --- a/llpython/byte_control.py +++ b/llpython/byte_control.py @@ -1,12 +1,11 @@ -#! /usr/bin/env python # ______________________________________________________________________ - +from __future__ import absolute_import import opcode -import opcode_util +from . import opcode_util import pprint -from bytecode_visitor import BasicBlockVisitor, BenignBytecodeVisitorMixin -from control_flow import ControlFlowGraph +from .bytecode_visitor import BasicBlockVisitor, BenignBytecodeVisitorMixin +from .control_flow import ControlFlowGraph # ______________________________________________________________________ diff --git a/llpython/byte_flow.py b/llpython/byte_flow.py index 4a878b2..197c839 100644 --- a/llpython/byte_flow.py +++ b/llpython/byte_flow.py @@ -1,11 +1,10 @@ -#! /usr/bin/env python # ______________________________________________________________________ - +from __future__ import absolute_import import dis import opcode -from bytecode_visitor import BasicBlockVisitor -import opcode_util +from .bytecode_visitor import BasicBlockVisitor +from . import opcode_util # ______________________________________________________________________ diff --git a/llpython/byte_translator.py b/llpython/byte_translator.py index 3922099..a6e5864 100644 --- a/llpython/byte_translator.py +++ b/llpython/byte_translator.py @@ -1,22 +1,21 @@ -#! /usr/bin/env python # ______________________________________________________________________ '''Defines a bytecode based LLVM translator for llpython code. ''' # ______________________________________________________________________ # Module imports - +from __future__ import absolute_import import opcode import types import logging import llvm.core as lc -import opcode_util -import bytetype -from bytecode_visitor import BytecodeFlowVisitor -from byte_flow import BytecodeFlowBuilder -from byte_control import ControlFlowBuilder -from phi_injector import PhiInjector, synthetic_opname +from . import opcode_util +from . import bytetype +from .bytecode_visitor import BytecodeFlowVisitor +from .byte_flow import BytecodeFlowBuilder +from .byte_control import ControlFlowBuilder +from .phi_injector import PhiInjector, synthetic_opname # ______________________________________________________________________ # Module data diff --git a/llpython/bytecode_visitor.py b/llpython/bytecode_visitor.py index dcc3a0c..3fa3f48 100644 --- a/llpython/bytecode_visitor.py +++ b/llpython/bytecode_visitor.py @@ -1,10 +1,9 @@ -#! /usr/bin/env python # ______________________________________________________________________ - +from __future__ import absolute_import import itertools import opcode -from opcode_util import itercode +from .opcode_util import itercode # ______________________________________________________________________ diff --git a/llpython/bytetype.py b/llpython/bytetype.py index 211f3f8..484d09e 100644 --- a/llpython/bytetype.py +++ b/llpython/bytetype.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python # ______________________________________________________________________ import ctypes diff --git a/llpython/control_flow.py b/llpython/control_flow.py index 5ea030a..8026aba 100644 --- a/llpython/control_flow.py +++ b/llpython/control_flow.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python # ______________________________________________________________________ import pprint diff --git a/llpython/gen_bytecode_visitor.py b/llpython/gen_bytecode_visitor.py index 7f922e2..a60b345 100644 --- a/llpython/gen_bytecode_visitor.py +++ b/llpython/gen_bytecode_visitor.py @@ -1,7 +1,6 @@ -#! /usr/bin/env python # ______________________________________________________________________ - -import opcode_util +from __future__ import absolute_import +from . import opcode_util # ______________________________________________________________________ diff --git a/llpython/nobitey.py b/llpython/nobitey.py index 014216b..4236d29 100644 --- a/llpython/nobitey.py +++ b/llpython/nobitey.py @@ -1,6 +1,5 @@ -#! /usr/bin/env python # ______________________________________________________________________ - +from __future__ import absolute_import import sys import os.path import imp @@ -10,9 +9,8 @@ import types import llvm.core as lc import llvm.ee as le -import bytetype -import byte_translator -from pyaddfunc import pyaddfunc +from . import bytetype, byte_translator +from .pyaddfunc import pyaddfunc LLVM_TO_INT_PARSE_STR_MAP = { 8 : 'b', diff --git a/llpython/opcode_util.py b/llpython/opcode_util.py index efd0c5c..7a1972b 100644 --- a/llpython/opcode_util.py +++ b/llpython/opcode_util.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python # ______________________________________________________________________ import dis diff --git a/llpython/phi_injector.py b/llpython/phi_injector.py index 6cccb66..dfa1061 100644 --- a/llpython/phi_injector.py +++ b/llpython/phi_injector.py @@ -1,7 +1,6 @@ -#! /usr/bin/env python # ______________________________________________________________________ -from bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin +from .bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin # ______________________________________________________________________ diff --git a/llpython/pyaddfunc.py b/llpython/pyaddfunc.py index 8e09839..d6a2945 100644 --- a/llpython/pyaddfunc.py +++ b/llpython/pyaddfunc.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python # ______________________________________________________________________ import ctypes diff --git a/llpython/tests/llfuncs.py b/llpython/tests/llfuncs.py index 2a8614f..8b5b1f3 100644 --- a/llpython/tests/llfuncs.py +++ b/llpython/tests/llfuncs.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python # ______________________________________________________________________ def doslice (in_string, lower, upper): diff --git a/llpython/tests/llfunctys.py b/llpython/tests/llfunctys.py index b552cf4..8335044 100644 --- a/llpython/tests/llfunctys.py +++ b/llpython/tests/llfunctys.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python # ______________________________________________________________________ import llvm.core as lc diff --git a/llrtc/Makefile b/llrtc/Makefile new file mode 100644 index 0000000..b15eac5 --- /dev/null +++ b/llrtc/Makefile @@ -0,0 +1,22 @@ +all: + make -C lib + +ir: + make -C lib ir + +test: + make -C lib test + +clean-test: + make -C lib clean-test + +clean-temp: + make -C lib clean-temp + +clean: + make -C lib clean + +install: ir + cp llrt_*.ll ../llvm/llrt + make -C lib clean-temp + \ No newline at end of file diff --git a/llrtc/README.md b/llrtc/README.md new file mode 100644 index 0000000..539d9c3 --- /dev/null +++ b/llrtc/README.md @@ -0,0 +1,25 @@ +# LLRT: Low Level Runtime + +## Why? + +The same reason for LLVM compiler-rt. LLVM generates libgcc symbols, such as +__divdi3 for 64-bit division on 32-bit platform. They are not also available. +We need to ship compiler-rt but it is not Windows ready. +This subproject aims to provide a small portable subset of compiler-rt. +Start small and add only the things we really needed. +Performance is not crucial but should not be terrible. +Functionality and usefullness should be more important than performance. + +## Developer Instructions + +LLRT implements some functionalities in compiler-rt in ANSI C. +The C files are compiled using clang to produce LLVM IR which are shipped. +The IR files are committed in the repository. +So, remember to build the IR files commit them after modifying the C files. + +## Build Requirement + +- Make +- Clang +- Python + diff --git a/llrtc/lib/.gitignore b/llrtc/lib/.gitignore new file mode 100644 index 0000000..fbcf76a --- /dev/null +++ b/llrtc/lib/.gitignore @@ -0,0 +1,4 @@ +*.o +*.run +*.out +*.ll diff --git a/llrtc/lib/Makefile b/llrtc/lib/Makefile new file mode 100644 index 0000000..9dbfb27 --- /dev/null +++ b/llrtc/lib/Makefile @@ -0,0 +1,66 @@ +OUTPUT = llrt +SOURCES = udivmod64.c sdivmod64.c div64.c mod64.c +TESTS = test_udivmod64.c test_sdivmod64.c + +CLANG = clang +LLVM_LINK = llvm-link +CF = -Wall -ansi +CF_TEST = $(CF) -ftrapv +CF_BUILD = $(CF) -O0 -emit-llvm +OUTDIR = .. +STRIPPER = ../tools/striptriple.py + +all: ir + +ir: $(OUTDIR)/$(OUTPUT)_x86.ll $(OUTDIR)/$(OUTPUT)_x86_64.ll + +$(OUTDIR)/$(OUTPUT)_x86.ll: $(SOURCES:.c=_x86.bc) + $(LLVM_LINK) -S $+ -o $@ + python $(STRIPPER) $@ + +$(OUTDIR)/$(OUTPUT)_x86_64.ll: $(SOURCES:.c=_x86_64.bc) + $(LLVM_LINK) -S $+ -o $@ + python $(STRIPPER) $@ + +build-test: $(SOURCES:.c=.o) $(TESTS:.c=.run) + +lib$(OUTPUT).a: $(SOURCES:.c=.o) + $(CLANG) -static $+ -o $@ + +test: $(TESTS:.c=.run) + for src in $+; do \ + echo "testing $${src}"; \ + python $${src%.*}.py > $${src%.*}.out; \ + done; + +clean-test: + rm -f *.out + rm -f *.o + rm -f *.run + +clean-dist: clean-temp + rm -f *.ll + +clean-temp: + rm -f *.bc + rm -f *.o + rm -f *.out + +clean: clean-test clean-dist + +%.c: llrt.h + +%_x86.bc: %.c + $(CLANG) -m32 $(CF_BUILD) -c $< -o $@ + +%_x86_64.bc: %.c + $(CLANG) -m64 $(CF_BUILD) -c $< -o $@ + +%.o: %.c + $(CLANG) $(CF_TEST) -c $< + +%.run: %.c + $(CLANG) $(CF_TEST) -o $@ $+ + +test_udivmod64.run: udivmod64.o +test_sdivmod64.run: udivmod64.o sdivmod64.o diff --git a/llrtc/lib/div64.c b/llrtc/lib/div64.c new file mode 100644 index 0000000..8466965 --- /dev/null +++ b/llrtc/lib/div64.c @@ -0,0 +1,11 @@ +#include "llrt.h" + +uint64_t udiv64(uint64_t dividend, uint64_t divisor) +{ + return udivmod64(dividend, divisor, NULL); +} + +int64_t sdiv64(int64_t dividend, int64_t divisor) +{ + return sdivmod64(dividend, divisor, NULL); +} diff --git a/llrtc/lib/llrt.h b/llrtc/lib/llrt.h new file mode 100644 index 0000000..4e9e348 --- /dev/null +++ b/llrtc/lib/llrt.h @@ -0,0 +1,19 @@ +#ifndef LLRT_H_ +#define LLRT_H_ + +#include + +#define NULL 0 +#define BITS_PER_BYTE 8 + +uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); +int64_t sdivmod64(int64_t dividend, int64_t divisor, int64_t *remainder); + +uint64_t udiv64(uint64_t dividend, uint64_t divisor); +int64_t sdiv64(int64_t dividend, int64_t divisor); + +uint64_t umod64(uint64_t dividend, uint64_t divisor); +int64_t smod64(int64_t dividend, int64_t divisor); + +#endif /* LLRT_H_ */ + diff --git a/llrtc/lib/mod64.c b/llrtc/lib/mod64.c new file mode 100644 index 0000000..875f6b9 --- /dev/null +++ b/llrtc/lib/mod64.c @@ -0,0 +1,15 @@ +#include "llrt.h" + +uint64_t umod64(uint64_t dividend, uint64_t divisor) +{ + uint64_t rem; + udivmod64(dividend, divisor, &rem); + return rem; +} + +int64_t smod64(int64_t dividend, int64_t divisor) +{ + int64_t rem; + sdivmod64(dividend, divisor, &rem); + return rem; +} diff --git a/llrtc/lib/sdivmod64.c b/llrtc/lib/sdivmod64.c new file mode 100644 index 0000000..df294b3 --- /dev/null +++ b/llrtc/lib/sdivmod64.c @@ -0,0 +1,40 @@ +#include "llrt.h" +#include + +/* +Calls to udivmod64 internally. +Note: remainder uses sign of divisor. +*/ +int64_t sdivmod64(int64_t dividend, int64_t divisor, int64_t *remainder) +{ + int signbitidx = BITS_PER_BYTE * sizeof(dividend) - 1; + int signed_dividend = dividend < 0; + int signed_divisor = divisor < 0; + int signed_result = signed_divisor ^ signed_dividend; + + int64_t quotient; + uint64_t udvd, udvr, uquotient, uremainder; + + udvd = signed_dividend ? -dividend : dividend; + udvr = signed_divisor ? -divisor : divisor; + uquotient = udivmod64(udvd, udvr, &uremainder); + + if (signed_result){ + if (uremainder) { + quotient = -(int64_t)uquotient - 1; + } else { + quotient = -(int64_t)uquotient; + } + if (remainder) { + /* if signed, there could be unsigned overflow + causing undefined behavior */ + *remainder = (uint64_t)dividend - (uint64_t)quotient * (uint64_t)divisor; + } + } else { + quotient = (int64_t)uquotient; + if (remainder) { + *remainder = signed_divisor ? -uremainder : uremainder; + } + } + return quotient; +} diff --git a/llrtc/lib/test_sdivmod64.c b/llrtc/lib/test_sdivmod64.c new file mode 100644 index 0000000..1e804d6 --- /dev/null +++ b/llrtc/lib/test_sdivmod64.c @@ -0,0 +1,21 @@ +#include +#include +#include "llrt.h" + +int main(int argc, char * argv[]){ + int64_t n, d, q, r; + + if (argc != 3) { + printf("invalid argument: %s dividend divisor", argv[0]); + return 1; + } + sscanf(argv[1], "%lld", &n); + sscanf(argv[2], "%lld", &d); + + q = sdivmod64(n, d, &r); + + printf("%lld\n", q); + printf("%lld\n", r); + + return 0; +} diff --git a/llrtc/lib/test_sdivmod64.py b/llrtc/lib/test_sdivmod64.py new file mode 100644 index 0000000..4aa49a9 --- /dev/null +++ b/llrtc/lib/test_sdivmod64.py @@ -0,0 +1,56 @@ +import math +import os +import subprocess +udt = os.path.join('.', 'test_sdivmod64.run') + +def testcase(dividend, divisor): + print 'divmod64(%d, %d)' % (dividend, divisor) + + procargs = ('%s %s %s' % (udt, dividend, divisor)).split() + result = subprocess.check_output(procargs) + gotQ, gotR = map(int, result.splitlines()) + + expectQ = dividend // divisor + expectR = dividend % divisor + + print 'Q = %d, R = %d' % (gotQ, gotR) + + if expectQ != gotQ: + raise ValueError("invalid quotient: got=%d but expect=%d" % + (gotQ, expectQ)) + if expectR != gotR: + raise ValueError("invalid remainder: got=%d but expect=%d" % + (gotR, expectR)) + print 'OK' + +def testsequence(): + subjects = [ + (0, 1), + (0, 0xffffffff), + (1, 2), + (1, 983219), + (2, 2), + (3, 2), + (1024, 2), + (2048, 512), + (21321, 512), + (9329189, 1031), + (0xffffffff, 2), + (0xffffffff, 0xffff), + (0x1ffffffff, 2), + (0x1ffffffff, 0xffff), + (0xffff, 0xffffffff), + (0x0fffffffffffffff, 0xffff), + (0x7fffffffffffffff, 0x7fffffffffffffff), + (0x7fffffffffffffff, 0x7ffffffffffffff0), + (0x7fffffffffffffff, 87655678587161901), + ] + + for dvd, dvr in subjects: + testcase(dvd, dvr) + testcase(dvd, -dvr) + testcase(-dvd, dvr) + testcase(-dvd, -dvr) + +if __name__ == '__main__': + testsequence() diff --git a/llrtc/lib/test_udivmod64.c b/llrtc/lib/test_udivmod64.c new file mode 100644 index 0000000..70b44aa --- /dev/null +++ b/llrtc/lib/test_udivmod64.c @@ -0,0 +1,20 @@ +#include +#include +#include "llrt.h" + +int main(int argc, char * argv[]){ + uint64_t n, d, q, r; + if (argc != 3) { + printf("invalid argument: %s dividend divisor", argv[0]); + return 1; + } + sscanf(argv[1], "%llu", &n); + sscanf(argv[2], "%llu", &d); + + q = udivmod64(n, d, &r); + + printf("%llu\n", q); + printf("%llu\n", r); + + return 0; +} diff --git a/llrtc/lib/test_udivmod64.py b/llrtc/lib/test_udivmod64.py new file mode 100644 index 0000000..da07ccb --- /dev/null +++ b/llrtc/lib/test_udivmod64.py @@ -0,0 +1,53 @@ +import math +import os +import subprocess +udt = os.path.join('.', 'test_udivmod64.run') + +def testcase(dividend, divisor): + print 'divmod64(%d, %d)' % (dividend, divisor) + + procargs = ('%s %s %s' % (udt, dividend, divisor)).split() + result = subprocess.check_output(procargs) + gotQ, gotR = map(int, result.splitlines()) + + expectQ = dividend // divisor + expectR = dividend % divisor + + print 'Q = %d, R = %d' % (gotQ, gotR) + + if expectQ != gotQ: + raise ValueError("invalid quotient: got=%d but expect=%d" % + (gotQ, expectQ)) + if expectR != gotR: + raise ValueError("invalid remainder: got=%d but expect=%d" % + (gotR, expectR)) + print 'OK' + +def testsequence(): + subjects = [ + (0, 1), + (0, 0xffffffffffffffff), + (1, 2), + (1, 983219), + (2, 2), + (3, 2), + (1024, 2), + (2048, 512), + (21321, 512), + (9329189, 1031), + (0xffffffff, 2), + (0xffffffff, 0xffff), + (0x1ffffffff, 2), + (0x1ffffffff, 0xffff), + (0xffff, 0xffffffff), + (0xffffffffffffffff, 0xffff), + (0xffffffffffffffff, 0x7fffffffffffffff), + (0xffffffffffffffff, 0xfffffffffffffff0), + (0xffffffffffffffff, 87655678587161901), + ] + + for dvd, dvr in subjects: + testcase(dvd, dvr) + +if __name__ == '__main__': + testsequence() diff --git a/llrtc/lib/udivmod64.c b/llrtc/lib/udivmod64.c new file mode 100644 index 0000000..5936f98 --- /dev/null +++ b/llrtc/lib/udivmod64.c @@ -0,0 +1,84 @@ +/* +Implements unsigned divmod using for platform missing 64-bit division and/or +modulo functions. +*/ +#include "llrt.h" + +/* +count left zero for 64-bit words + +*/ +static +int clz64(uint64_t x) +{ + const int total_bits = sizeof(x) * BITS_PER_BYTE; + int zc = 0; + + while (zc < total_bits && ((x >> (total_bits - zc - 1)) & 1) == 0) { + ++zc; + } + return zc; +} + +typedef struct div_state_ +{ + uint64_t tmp, dvd; +} div_state; + +/* +Left shift div_state by 1 bit +*/ +static +void div_state_lshift(div_state *state) +{ + state->tmp = (state->tmp << 1) | (state->dvd >> 63); + state->dvd = state->dvd << 1; +} + +/* +Division of unsigned 64-bit word using 64-bit addition and subtration following +the shift-restore division algorithm. +For those interested in 32-bit implementation, +mapping of 64-bit addition and subtraction to 32-bit should be trivial. + +Reference: + - IBM. The PowerPC Compiler Writer's Guide + - LLVM compiler-rt + +Assumptions: + - all operands and results are positive + - unsigned wrapped around +*/ +uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder) +{ + div_state state = {0, dividend}; + uint64_t quotient = 0; + int i; + int skipahead; + + if (divisor == 0) { + return 1 / 0; /* intentionally div by zero */ + } + + /* + skipahead to reduce iteration + */ + skipahead = clz64(dividend); + + for (i = 0; i < skipahead; ++i) { + div_state_lshift(&state); + } + + /* + division loop + */ + for (i = skipahead; i < 64; ++i) { + div_state_lshift(&state); + if (state.tmp >= divisor) { + state.tmp = state.tmp - divisor; + quotient |= 1ull << (63 - i); + } + } + if (remainder) *remainder = state.tmp; + return quotient; +} diff --git a/llrtc/tools/striptriple.py b/llrtc/tools/striptriple.py new file mode 100644 index 0000000..a20ba34 --- /dev/null +++ b/llrtc/tools/striptriple.py @@ -0,0 +1,15 @@ +import sys +import re + +buf = [] +with open(sys.argv[1], 'r') as fin: + tripleline = re.compile('^target\s+triple\s+=\s+') + for line in fin.readlines(): + if not tripleline.match(line): + buf.append(line) + +with open(sys.argv[1], 'w') as fout: + for line in buf: + fout.write(line) + + diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 05fc94f..3f756ee 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -2,6 +2,7 @@ import re import sys from distutils.spawn import find_executable from os.path import abspath, dirname, isfile, join +from os import listdir from subprocess import Popen, PIPE @@ -39,55 +40,17 @@ def libs_options(): # NOTE: instead of actually looking at the components requested, # we just print out a bunch of libs for lib in """ -LLVMAnalysis -LLVMAsmParser -LLVMAsmPrinter -LLVMBitReader -LLVMBitWriter -LLVMCodeGen -LLVMCore -LLVMExecutionEngine -LLVMInstCombine -LLVMInstrumentation -LLVMInterpreter -LLVMipa -LLVMipo -LLVMJIT -LLVMLinker -LLVMMC -LLVMMCParser -LLVMObject -LLVMRuntimeDyld -LLVMScalarOpts -LLVMSelectionDAG -LLVMSupport -LLVMTarget -LLVMTransformUtils -LLVMVectorize -LLVMX86AsmParser -LLVMX86AsmPrinter -LLVMX86CodeGen -LLVMX86Desc -LLVMX86Disassembler -LLVMX86Info -LLVMX86Utils Advapi32 Shell32 """.split(): print('-l%s' % lib) - if isfile(join(find_llvm_prefix(), 'lib', 'LLVMPTXCodeGen.lib')): - print('-lLLVMPTXAsmPrinter') - print('-lLLVMPTXCodeGen') - print('-lLLVMPTXDesc') - print('-lLLVMPTXInfo') - - elif isfile(join(find_llvm_prefix(), 'lib', 'LLVMNVPTXCodeGen.lib')): - print('-lLLVMNVPTXAsmPrinter') - print('-lLLVMNVPTXCodeGen') - print('-lLLVMNVPTXDesc') - print('-lLLVMNVPTXInfo') - + bpath = join(find_llvm_prefix(), 'lib') + for filename in listdir(bpath): + filepath = join(bpath, filename) + if isfile(filepath) and filename.endswith('.lib') and filename.startswith('LLVM'): + name = filename.split('.', 1)[0] + print('-l%s' % name) def main(): try: @@ -98,12 +61,15 @@ def main(): if option == '--version': print(get_llvm_version()) + elif option == '--targets-built': + print('X86') # just do X86 + elif option == '--libs': libs_options() elif option == '--includedir': incdir = join(find_llvm_prefix(), 'include') - ensure_file(join(incdir, 'llvm' , 'BasicBlock.h')) + ensure_file(join(incdir, 'llvm' , 'Linker.h')) print(incdir) elif option == '--libdir': diff --git a/llvm/__init__.py b/llvm/__init__.py index e3e785f..9b24112 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -4,10 +4,13 @@ del get_versions from llvmpy import extra + version = extra.get_llvm_version() del extra class Wrapper(object): + __slots__ = '__ptr' + def __init__(self, ptr): assert ptr self.__ptr = ptr @@ -31,12 +34,14 @@ def _extract_ptrs(objs): class LLVMException(Exception): pass -def test(verbosity=1): +def test(verbosity=3, run_isolated=True): """test(verbosity=1) -> TextTestResult - Run self-test, and return unittest.runner.TextTestResult object. + Run self-test, and return the number of failures + errors """ - from llvm.test_llvmpy import run + from llvm.tests import run - return run(verbosity=verbosity) + result = run(verbosity=verbosity, run_isolated=run_isolated) + errct = len(result.failures) + len(result.errors) + return errct diff --git a/llvm/core.py b/llvm/core.py index bbe5d01..4db8135 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -41,150 +41,203 @@ import contextlib, weakref import llvm from llvm._intrinsic_ids import * - +from llvm.deprecated import deprecated from llvmpy import api #===----------------------------------------------------------------------=== # Enumerations #===----------------------------------------------------------------------=== +class Enum(int): + '''Overload integer to print the name of the enum. + ''' + def __repr__(self): + return '%s(%d)' % (type(self).__name__, self) + + @classmethod + def declare(cls): + declared = cls._declared_ = {} + scope = globals() + for name in filter(lambda s: s.startswith(cls.prefix), dir(cls)): + n = getattr(cls, name) + typ = type(name, (cls,), {}) + obj = typ(n) + declared[n] = obj + scope[name] = obj + + @classmethod + def get(cls, num): + return cls._declared_[num] # type id (llvm::Type::TypeID) -TYPE_VOID = api.llvm.Type.TypeID.VoidTyID -TYPE_HALF = api.llvm.Type.TypeID.HalfTyID -TYPE_FLOAT = api.llvm.Type.TypeID.FloatTyID -TYPE_DOUBLE = api.llvm.Type.TypeID.DoubleTyID -TYPE_X86_FP80 = api.llvm.Type.TypeID.X86_FP80TyID -TYPE_FP128 = api.llvm.Type.TypeID.FP128TyID -TYPE_PPC_FP128 = api.llvm.Type.TypeID.PPC_FP128TyID -TYPE_LABEL = api.llvm.Type.TypeID.LabelTyID -TYPE_INTEGER = api.llvm.Type.TypeID.IntegerTyID -TYPE_FUNCTION = api.llvm.Type.TypeID.FunctionTyID -TYPE_STRUCT = api.llvm.Type.TypeID.StructTyID -TYPE_ARRAY = api.llvm.Type.TypeID.ArrayTyID -TYPE_POINTER = api.llvm.Type.TypeID.PointerTyID -TYPE_VECTOR = api.llvm.Type.TypeID.VectorTyID -TYPE_METADATA = api.llvm.Type.TypeID.MetadataTyID -TYPE_X86_MMX = api.llvm.Type.TypeID.X86_MMXTyID +class TypeEnum(Enum): + prefix = 'TYPE_' + TypeID = api.llvm.Type.TypeID + + TYPE_VOID = TypeID.VoidTyID + TYPE_HALF = TypeID.HalfTyID + TYPE_FLOAT = TypeID.FloatTyID + TYPE_DOUBLE = TypeID.DoubleTyID + TYPE_X86_FP80 = TypeID.X86_FP80TyID + TYPE_FP128 = TypeID.FP128TyID + TYPE_PPC_FP128 = TypeID.PPC_FP128TyID + TYPE_LABEL = TypeID.LabelTyID + TYPE_INTEGER = TypeID.IntegerTyID + TYPE_FUNCTION = TypeID.FunctionTyID + TYPE_STRUCT = TypeID.StructTyID + TYPE_ARRAY = TypeID.ArrayTyID + TYPE_POINTER = TypeID.PointerTyID + TYPE_VECTOR = TypeID.VectorTyID + TYPE_METADATA = TypeID.MetadataTyID + TYPE_X86_MMX = TypeID.X86_MMXTyID + +TypeEnum.declare() # value IDs (llvm::Value::ValueTy enum) # According to the doxygen docs, it is not a good idea to use these enums. # There are more values than those declared. -VALUE_ARGUMENT = api.llvm.Value.ValueTy.ArgumentVal -VALUE_BASIC_BLOCK = api.llvm.Value.ValueTy.BasicBlockVal -VALUE_FUNCTION = api.llvm.Value.ValueTy.FunctionVal -VALUE_GLOBAL_ALIAS = api.llvm.Value.ValueTy.GlobalAliasVal -VALUE_GLOBAL_VARIABLE = api.llvm.Value.ValueTy.GlobalVariableVal -VALUE_UNDEF_VALUE = api.llvm.Value.ValueTy.UndefValueVal -VALUE_BLOCK_ADDRESS = api.llvm.Value.ValueTy.BlockAddressVal -VALUE_CONSTANT_EXPR = api.llvm.Value.ValueTy.ConstantExprVal -VALUE_CONSTANT_AGGREGATE_ZERO = api.llvm.Value.ValueTy.ConstantAggregateZeroVal -VALUE_CONSTANT_DATA_ARRAY = api.llvm.Value.ValueTy.ConstantDataArrayVal -VALUE_CONSTANT_DATA_VECTOR = api.llvm.Value.ValueTy.ConstantDataVectorVal -VALUE_CONSTANT_INT = api.llvm.Value.ValueTy.ConstantIntVal -VALUE_CONSTANT_FP = api.llvm.Value.ValueTy.ConstantFPVal -VALUE_CONSTANT_ARRAY = api.llvm.Value.ValueTy.ConstantArrayVal -VALUE_CONSTANT_STRUCT = api.llvm.Value.ValueTy.ConstantStructVal -VALUE_CONSTANT_VECTOR = api.llvm.Value.ValueTy.ConstantVectorVal -VALUE_CONSTANT_POINTER_NULL = api.llvm.Value.ValueTy.ConstantPointerNullVal -VALUE_MD_NODE = api.llvm.Value.ValueTy.MDNodeVal -VALUE_MD_STRING = api.llvm.Value.ValueTy.MDStringVal -VALUE_INLINE_ASM = api.llvm.Value.ValueTy.InlineAsmVal -VALUE_PSEUDO_SOURCE_VALUE = api.llvm.Value.ValueTy.PseudoSourceValueVal -VALUE_FIXED_STACK_PSEUDO_SOURCE_VALUE = api.llvm.Value.ValueTy.FixedStackPseudoSourceValueVal -VALUE_INSTRUCTION = api.llvm.Value.ValueTy.InstructionVal +class ValueEnum(Enum): + prefix = 'VALUE_' + ValueTy = api.llvm.Value.ValueTy + + VALUE_ARGUMENT = ValueTy.ArgumentVal + VALUE_BASIC_BLOCK = ValueTy.BasicBlockVal + VALUE_FUNCTION = ValueTy.FunctionVal + VALUE_GLOBAL_ALIAS = ValueTy.GlobalAliasVal + VALUE_GLOBAL_VARIABLE = ValueTy.GlobalVariableVal + VALUE_UNDEF_VALUE = ValueTy.UndefValueVal + VALUE_BLOCK_ADDRESS = ValueTy.BlockAddressVal + VALUE_CONSTANT_EXPR = ValueTy.ConstantExprVal + VALUE_CONSTANT_AGGREGATE_ZERO = ValueTy.ConstantAggregateZeroVal + VALUE_CONSTANT_DATA_ARRAY = ValueTy.ConstantDataArrayVal + VALUE_CONSTANT_DATA_VECTOR = ValueTy.ConstantDataVectorVal + VALUE_CONSTANT_INT = ValueTy.ConstantIntVal + VALUE_CONSTANT_FP = ValueTy.ConstantFPVal + VALUE_CONSTANT_ARRAY = ValueTy.ConstantArrayVal + VALUE_CONSTANT_STRUCT = ValueTy.ConstantStructVal + VALUE_CONSTANT_VECTOR = ValueTy.ConstantVectorVal + VALUE_CONSTANT_POINTER_NULL = ValueTy.ConstantPointerNullVal + VALUE_MD_NODE = ValueTy.MDNodeVal + VALUE_MD_STRING = ValueTy.MDStringVal + VALUE_INLINE_ASM = ValueTy.InlineAsmVal + VALUE_PSEUDO_SOURCE_VALUE = ValueTy.PseudoSourceValueVal + VALUE_FIXED_STACK_PSEUDO_SOURCE_VALUE = ValueTy.FixedStackPseudoSourceValueVal + VALUE_INSTRUCTION = ValueTy.InstructionVal + +ValueEnum.declare() # instruction opcodes (from include/llvm/Instruction.def) -OPCODE_RET = 1 -OPCODE_BR = 2 -OPCODE_SWITCH = 3 -OPCODE_INDIRECT_BR = 4 -OPCODE_INVOKE = 5 -OPCODE_RESUME = 6 -OPCODE_UNREACHABLE = 7 -OPCODE_ADD = 8 -OPCODE_FADD = 9 -OPCODE_SUB = 10 -OPCODE_FSUB = 11 -OPCODE_MUL = 12 -OPCODE_FMUL = 13 -OPCODE_UDIV = 14 -OPCODE_SDIV = 15 -OPCODE_FDIV = 16 -OPCODE_UREM = 17 -OPCODE_SREM = 18 -OPCODE_FREM = 19 -OPCODE_SHL = 20 -OPCODE_LSHR = 21 -OPCODE_ASHR = 22 -OPCODE_AND = 23 -OPCODE_OR = 24 -OPCODE_XOR = 25 -OPCODE_ALLOCA = 26 -OPCODE_LOAD = 27 -OPCODE_STORE = 28 -OPCODE_GETELEMENTPTR = 29 -OPCODE_FENCE = 30 -OPCODE_ATOMICCMPXCHG = 31 -OPCODE_ATOMICRMW = 32 -OPCODE_TRUNC = 33 -OPCODE_ZEXT = 34 -OPCODE_SEXT = 35 -OPCODE_FPTOUI = 36 -OPCODE_FPTOSI = 37 -OPCODE_UITOFP = 38 -OPCODE_SITOFP = 39 -OPCODE_FPTRUNC = 40 -OPCODE_FPEXT = 41 -OPCODE_PTRTOINT = 42 -OPCODE_INTTOPTR = 43 -OPCODE_BITCAST = 44 -OPCODE_ICMP = 45 -OPCODE_FCMP = 46 -OPCODE_PHI = 47 -OPCODE_CALL = 48 -OPCODE_SELECT = 49 -OPCODE_USEROP1 = 50 -OPCODE_USEROP2 = 51 -OPCODE_VAARG = 52 -OPCODE_EXTRACTELEMENT = 53 -OPCODE_INSERTELEMENT = 54 -OPCODE_SHUFFLEVECTOR = 55 -OPCODE_EXTRACTVALUE = 56 -OPCODE_INSERTVALUE = 57 -OPCODE_LANDINGPAD = 58 +class OpcodeEnum(Enum): + prefix = 'OPCODE_' + + OPCODE_RET = 1 + OPCODE_BR = 2 + OPCODE_SWITCH = 3 + OPCODE_INDIRECT_BR = 4 + OPCODE_INVOKE = 5 + OPCODE_RESUME = 6 + OPCODE_UNREACHABLE = 7 + OPCODE_ADD = 8 + OPCODE_FADD = 9 + OPCODE_SUB = 10 + OPCODE_FSUB = 11 + OPCODE_MUL = 12 + OPCODE_FMUL = 13 + OPCODE_UDIV = 14 + OPCODE_SDIV = 15 + OPCODE_FDIV = 16 + OPCODE_UREM = 17 + OPCODE_SREM = 18 + OPCODE_FREM = 19 + OPCODE_SHL = 20 + OPCODE_LSHR = 21 + OPCODE_ASHR = 22 + OPCODE_AND = 23 + OPCODE_OR = 24 + OPCODE_XOR = 25 + OPCODE_ALLOCA = 26 + OPCODE_LOAD = 27 + OPCODE_STORE = 28 + OPCODE_GETELEMENTPTR = 29 + OPCODE_FENCE = 30 + OPCODE_ATOMICCMPXCHG = 31 + OPCODE_ATOMICRMW = 32 + OPCODE_TRUNC = 33 + OPCODE_ZEXT = 34 + OPCODE_SEXT = 35 + OPCODE_FPTOUI = 36 + OPCODE_FPTOSI = 37 + OPCODE_UITOFP = 38 + OPCODE_SITOFP = 39 + OPCODE_FPTRUNC = 40 + OPCODE_FPEXT = 41 + OPCODE_PTRTOINT = 42 + OPCODE_INTTOPTR = 43 + OPCODE_BITCAST = 44 + OPCODE_ICMP = 45 + OPCODE_FCMP = 46 + OPCODE_PHI = 47 + OPCODE_CALL = 48 + OPCODE_SELECT = 49 + OPCODE_USEROP1 = 50 + OPCODE_USEROP2 = 51 + OPCODE_VAARG = 52 + OPCODE_EXTRACTELEMENT = 53 + OPCODE_INSERTELEMENT = 54 + OPCODE_SHUFFLEVECTOR = 55 + OPCODE_EXTRACTVALUE = 56 + OPCODE_INSERTVALUE = 57 + OPCODE_LANDINGPAD = 58 + +OpcodeEnum.declare() # calling conventions -CC_C = api.llvm.CallingConv.ID.C -CC_FASTCALL = api.llvm.CallingConv.ID.Fast -CC_COLDCALL = api.llvm.CallingConv.ID.Cold -CC_GHC = api.llvm.CallingConv.ID.GHC -CC_X86_STDCALL = api.llvm.CallingConv.ID.X86_StdCall -CC_X86_FASTCALL = api.llvm.CallingConv.ID.X86_FastCall -CC_ARM_APCS = api.llvm.CallingConv.ID.ARM_APCS -CC_ARM_AAPCS = api.llvm.CallingConv.ID.ARM_AAPCS -CC_ARM_AAPCS_VFP = api.llvm.CallingConv.ID.ARM_AAPCS_VFP -CC_MSP430_INTR = api.llvm.CallingConv.ID.MSP430_INTR -CC_X86_THISCALL = api.llvm.CallingConv.ID.X86_ThisCall -CC_PTX_KERNEL = api.llvm.CallingConv.ID.PTX_Kernel -CC_PTX_DEVICE = api.llvm.CallingConv.ID.PTX_Device -CC_MBLAZE_INTR = api.llvm.CallingConv.ID.MBLAZE_INTR -CC_MBLAZE_SVOL = api.llvm.CallingConv.ID.MBLAZE_SVOL +class CCEnum(Enum): + prefix = 'CC_' + + ID = api.llvm.CallingConv.ID + + CC_C = ID.C + CC_FASTCALL = ID.Fast + CC_COLDCALL = ID.Cold + CC_GHC = ID.GHC + CC_X86_STDCALL = ID.X86_StdCall + CC_X86_FASTCALL = ID.X86_FastCall + CC_ARM_APCS = ID.ARM_APCS + CC_ARM_AAPCS = ID.ARM_AAPCS + CC_ARM_AAPCS_VFP = ID.ARM_AAPCS_VFP + CC_MSP430_INTR = ID.MSP430_INTR + CC_X86_THISCALL = ID.X86_ThisCall + CC_PTX_KERNEL = ID.PTX_Kernel + CC_PTX_DEVICE = ID.PTX_Device + + if llvm.version <= (3, 3): + CC_MBLAZE_INTR = ID.MBLAZE_INTR + CC_MBLAZE_SVOL = ID.MBLAZE_SVOL + +CCEnum.declare() # int predicates -ICMP_EQ = api.llvm.CmpInst.Predicate.ICMP_EQ -ICMP_NE = api.llvm.CmpInst.Predicate.ICMP_NE -ICMP_UGT = api.llvm.CmpInst.Predicate.ICMP_UGT -ICMP_UGE = api.llvm.CmpInst.Predicate.ICMP_UGE -ICMP_ULT = api.llvm.CmpInst.Predicate.ICMP_ULT -ICMP_ULE = api.llvm.CmpInst.Predicate.ICMP_ULE -ICMP_SGT = api.llvm.CmpInst.Predicate.ICMP_SGT -ICMP_SGE = api.llvm.CmpInst.Predicate.ICMP_SGE -ICMP_SLT = api.llvm.CmpInst.Predicate.ICMP_SLT -ICMP_SLE = api.llvm.CmpInst.Predicate.ICMP_SLE +class ICMPEnum(Enum): + prefix = 'ICMP_' + Predicate = api.llvm.CmpInst.Predicate + + ICMP_EQ = Predicate.ICMP_EQ + ICMP_NE = Predicate.ICMP_NE + ICMP_UGT = Predicate.ICMP_UGT + ICMP_UGE = Predicate.ICMP_UGE + ICMP_ULT = Predicate.ICMP_ULT + ICMP_ULE = Predicate.ICMP_ULE + ICMP_SGT = Predicate.ICMP_SGT + ICMP_SGE = Predicate.ICMP_SGE + ICMP_SLT = Predicate.ICMP_SLT + ICMP_SLE = Predicate.ICMP_SLE + +ICMPEnum.declare() # same as ICMP_xx, for backward compatibility + IPRED_EQ = ICMP_EQ IPRED_NE = ICMP_NE IPRED_UGT = ICMP_UGT @@ -197,24 +250,33 @@ IPRED_SLT = ICMP_SLT IPRED_SLE = ICMP_SLE # real predicates -FCMP_FALSE = api.llvm.CmpInst.Predicate.FCMP_FALSE -FCMP_OEQ = api.llvm.CmpInst.Predicate.FCMP_OEQ -FCMP_OGT = api.llvm.CmpInst.Predicate.FCMP_OGT -FCMP_OGE = api.llvm.CmpInst.Predicate.FCMP_OGE -FCMP_OLT = api.llvm.CmpInst.Predicate.FCMP_OLT -FCMP_OLE = api.llvm.CmpInst.Predicate.FCMP_OLE -FCMP_ONE = api.llvm.CmpInst.Predicate.FCMP_ONE -FCMP_ORD = api.llvm.CmpInst.Predicate.FCMP_ORD -FCMP_UNO = api.llvm.CmpInst.Predicate.FCMP_UNO -FCMP_UEQ = api.llvm.CmpInst.Predicate.FCMP_UEQ -FCMP_UGT = api.llvm.CmpInst.Predicate.FCMP_UGT -FCMP_UGE = api.llvm.CmpInst.Predicate.FCMP_UGE -FCMP_ULT = api.llvm.CmpInst.Predicate.FCMP_ULT -FCMP_ULE = api.llvm.CmpInst.Predicate.FCMP_ULE -FCMP_UNE = api.llvm.CmpInst.Predicate.FCMP_UNE -FCMP_TRUE = api.llvm.CmpInst.Predicate.FCMP_TRUE + +class FCMPEnum(Enum): + prefix = 'FCMP_' + + Predicate = api.llvm.CmpInst.Predicate + + FCMP_FALSE = Predicate.FCMP_FALSE + FCMP_OEQ = Predicate.FCMP_OEQ + FCMP_OGT = Predicate.FCMP_OGT + FCMP_OGE = Predicate.FCMP_OGE + FCMP_OLT = Predicate.FCMP_OLT + FCMP_OLE = Predicate.FCMP_OLE + FCMP_ONE = Predicate.FCMP_ONE + FCMP_ORD = Predicate.FCMP_ORD + FCMP_UNO = Predicate.FCMP_UNO + FCMP_UEQ = Predicate.FCMP_UEQ + FCMP_UGT = Predicate.FCMP_UGT + FCMP_UGE = Predicate.FCMP_UGE + FCMP_ULT = Predicate.FCMP_ULT + FCMP_ULE = Predicate.FCMP_ULE + FCMP_UNE = Predicate.FCMP_UNE + FCMP_TRUE = Predicate.FCMP_TRUE + +FCMPEnum.declare() # real predicates + RPRED_FALSE = FCMP_FALSE RPRED_OEQ = FCMP_OEQ RPRED_OGT = FCMP_OGT @@ -233,68 +295,75 @@ RPRED_UNE = FCMP_UNE RPRED_TRUE = FCMP_TRUE # linkages (see llvm::GlobalValue::LinkageTypes) -LINKAGE_EXTERNAL = \ - api.llvm.GlobalValue.LinkageTypes.ExternalLinkage -LINKAGE_AVAILABLE_EXTERNALLY = \ - api.llvm.GlobalValue.LinkageTypes.AvailableExternallyLinkage -LINKAGE_LINKONCE_ANY = \ - api.llvm.GlobalValue.LinkageTypes.LinkOnceAnyLinkage -LINKAGE_LINKONCE_ODR = \ - api.llvm.GlobalValue.LinkageTypes.LinkOnceODRLinkage -LINKAGE_WEAK_ANY = \ - api.llvm.GlobalValue.LinkageTypes.WeakAnyLinkage -LINKAGE_WEAK_ODR = \ - api.llvm.GlobalValue.LinkageTypes.WeakODRLinkage -LINKAGE_APPENDING = \ - api.llvm.GlobalValue.LinkageTypes.AppendingLinkage -LINKAGE_INTERNAL = \ - api.llvm.GlobalValue.LinkageTypes.InternalLinkage -LINKAGE_PRIVATE = \ - api.llvm.GlobalValue.LinkageTypes.PrivateLinkage -LINKAGE_DLLIMPORT = \ - api.llvm.GlobalValue.LinkageTypes.DLLImportLinkage -LINKAGE_DLLEXPORT = \ - api.llvm.GlobalValue.LinkageTypes.DLLExportLinkage -LINKAGE_EXTERNAL_WEAK = \ - api.llvm.GlobalValue.LinkageTypes.ExternalWeakLinkage -LINKAGE_COMMON = \ - api.llvm.GlobalValue.LinkageTypes.CommonLinkage -LINKAGE_LINKER_PRIVATE = \ - api.llvm.GlobalValue.LinkageTypes.LinkerPrivateLinkage -LINKAGE_LINKER_PRIVATE_WEAK = \ - api.llvm.GlobalValue.LinkageTypes.LinkerPrivateWeakLinkage +class LinkageEnum(Enum): + prefix = 'LINKAGE_' + LinkageTypes = api.llvm.GlobalValue.LinkageTypes + + LINKAGE_EXTERNAL = LinkageTypes.ExternalLinkage + LINKAGE_AVAILABLE_EXTERNALLY = LinkageTypes.AvailableExternallyLinkage + LINKAGE_LINKONCE_ANY = LinkageTypes.LinkOnceAnyLinkage + LINKAGE_LINKONCE_ODR = LinkageTypes.LinkOnceODRLinkage + LINKAGE_WEAK_ANY = LinkageTypes.WeakAnyLinkage + LINKAGE_WEAK_ODR = LinkageTypes.WeakODRLinkage + LINKAGE_APPENDING = LinkageTypes.AppendingLinkage + LINKAGE_INTERNAL = LinkageTypes.InternalLinkage + LINKAGE_PRIVATE = LinkageTypes.PrivateLinkage + LINKAGE_DLLIMPORT = LinkageTypes.DLLImportLinkage + LINKAGE_DLLEXPORT = LinkageTypes.DLLExportLinkage + LINKAGE_EXTERNAL_WEAK = LinkageTypes.ExternalWeakLinkage + LINKAGE_COMMON = LinkageTypes.CommonLinkage + LINKAGE_LINKER_PRIVATE = LinkageTypes.LinkerPrivateLinkage + LINKAGE_LINKER_PRIVATE_WEAK = LinkageTypes.LinkerPrivateWeakLinkage + +LinkageEnum.declare() # visibility (see llvm/GlobalValue.h) -VISIBILITY_DEFAULT = api.llvm.GlobalValue.VisibilityTypes.DefaultVisibility -VISIBILITY_HIDDEN = api.llvm.GlobalValue.VisibilityTypes.HiddenVisibility -VISIBILITY_PROTECTED = api.llvm.GlobalValue.VisibilityTypes.ProtectedVisibility +class VisibilityEnum(Enum): + prefix = 'VISIBILITY_' -# parameter attributes llvm::Attributes::AttrVal (see llvm/Attributes.h) -ATTR_NONE = api.llvm.Attributes.AttrVal.None_ -ATTR_ZEXT = api.llvm.Attributes.AttrVal.ZExt -ATTR_SEXT = api.llvm.Attributes.AttrVal.SExt -ATTR_NO_RETURN = api.llvm.Attributes.AttrVal.NoReturn -ATTR_IN_REG = api.llvm.Attributes.AttrVal.InReg -ATTR_STRUCT_RET = api.llvm.Attributes.AttrVal.StructRet -ATTR_NO_UNWIND = api.llvm.Attributes.AttrVal.NoUnwind -ATTR_NO_ALIAS = api.llvm.Attributes.AttrVal.NoAlias -ATTR_BY_VAL = api.llvm.Attributes.AttrVal.ByVal -ATTR_NEST = api.llvm.Attributes.AttrVal.Nest -ATTR_READ_NONE = api.llvm.Attributes.AttrVal.ReadNone -ATTR_READONLY = api.llvm.Attributes.AttrVal.ReadOnly -ATTR_NO_INLINE = api.llvm.Attributes.AttrVal.NoInline -ATTR_ALWAYS_INLINE = api.llvm.Attributes.AttrVal.AlwaysInline -ATTR_OPTIMIZE_FOR_SIZE = api.llvm.Attributes.AttrVal.OptimizeForSize -ATTR_STACK_PROTECT = api.llvm.Attributes.AttrVal.StackProtect -ATTR_STACK_PROTECT_REQ = api.llvm.Attributes.AttrVal.StackProtectReq -ATTR_ALIGNMENT = api.llvm.Attributes.AttrVal.Alignment -ATTR_NO_CAPTURE = api.llvm.Attributes.AttrVal.NoCapture -ATTR_NO_REDZONE = api.llvm.Attributes.AttrVal.NoRedZone -ATTR_NO_IMPLICIT_FLOAT = api.llvm.Attributes.AttrVal.NoImplicitFloat -ATTR_NAKED = api.llvm.Attributes.AttrVal.Naked -ATTR_INLINE_HINT = api.llvm.Attributes.AttrVal.InlineHint -ATTR_STACK_ALIGNMENT = api.llvm.Attributes.AttrVal.StackAlignment + VISIBILITY_DEFAULT = api.llvm.GlobalValue.VisibilityTypes.DefaultVisibility + VISIBILITY_HIDDEN = api.llvm.GlobalValue.VisibilityTypes.HiddenVisibility + VISIBILITY_PROTECTED = api.llvm.GlobalValue.VisibilityTypes.ProtectedVisibility +VisibilityEnum.declare() + +# parameter attributes +# LLVM 3.2 llvm::Attributes::AttrVal (see llvm/Attributes.h) +# LLVM 3.3 llvm::Attribute::AttrKind (see llvm/Attributes.h) +class AttrEnum(Enum): + prefix = 'ATTR_' + + if llvm.version >= (3, 3): + AttrVal = api.llvm.Attribute.AttrKind + else: + AttrVal = api.llvm.Attributes.AttrVal + + ATTR_NONE = AttrVal.None_ + ATTR_ZEXT = AttrVal.ZExt + ATTR_SEXT = AttrVal.SExt + ATTR_NO_RETURN = AttrVal.NoReturn + ATTR_IN_REG = AttrVal.InReg + ATTR_STRUCT_RET = AttrVal.StructRet + ATTR_NO_UNWIND = AttrVal.NoUnwind + ATTR_NO_ALIAS = AttrVal.NoAlias + ATTR_BY_VAL = AttrVal.ByVal + ATTR_NEST = AttrVal.Nest + ATTR_READ_NONE = AttrVal.ReadNone + ATTR_READONLY = AttrVal.ReadOnly + ATTR_NO_INLINE = AttrVal.NoInline + ATTR_ALWAYS_INLINE = AttrVal.AlwaysInline + ATTR_OPTIMIZE_FOR_SIZE = AttrVal.OptimizeForSize + ATTR_STACK_PROTECT = AttrVal.StackProtect + ATTR_STACK_PROTECT_REQ = AttrVal.StackProtectReq + ATTR_ALIGNMENT = AttrVal.Alignment + ATTR_NO_CAPTURE = AttrVal.NoCapture + ATTR_NO_REDZONE = AttrVal.NoRedZone + ATTR_NO_IMPLICIT_FLOAT = AttrVal.NoImplicitFloat + ATTR_NAKED = AttrVal.Naked + ATTR_INLINE_HINT = AttrVal.InlineHint + ATTR_STACK_ALIGNMENT = AttrVal.StackAlignment + +AttrEnum.declare() class Module(llvm.Wrapper): """A Module instance stores all the information related to an LLVM module. @@ -310,6 +379,7 @@ class Module(llvm.Wrapper): module_obj = Module.new('my_module') """ + __slots__ = '__weakref__' __cache = weakref.WeakValueDictionary() def __new__(cls, ptr): @@ -382,12 +452,12 @@ class Module(llvm.Wrapper): """ return str(self._ptr) + def __hash__(self): + return id(self._ptr) + def __eq__(self, rhs): - assert isinstance(rhs, Module), type(rhs) if isinstance(rhs, Module): - return str(self) == str(rhs) - else: - return False + return self._ptr == rhs._ptr def __ne__(self, rhs): return not (self == rhs) @@ -443,7 +513,7 @@ class Module(llvm.Wrapper): mode, errmsg) if failed: - raise llvm.LLVMException(errmsg) + raise llvm.LLVMException(errmsg.getvalue()) def get_type_named(self, name): typ = self._ptr.getTypeByName(name) @@ -535,7 +605,7 @@ class Module(llvm.Wrapper): ret = False if fileobj is None: ret = True - fileobj = BytesIO + fileobj = BytesIO() api.llvm.WriteBitcodeToFile(self._ptr, fileobj) if ret: return fileobj.getvalue() @@ -619,6 +689,7 @@ class Type(llvm.Wrapper): Use one of the static methods to create an instance. Example: ty = Type.double() """ + __slots__ = '__name__' _type_ = api.llvm.Type def __init__(self, ptr): @@ -730,7 +801,7 @@ class Type(llvm.Wrapper): otherwise, creates a literal type.""" context = api.llvm.getGlobalContext() is_packed = True - ptr = api.llvm.StructType.create(context) + ptr = api.llvm.StructType.create(context, name) ptr.setBody(llvm._extract_ptrs(element_tys), is_packed) return StructType(ptr) @@ -800,6 +871,9 @@ class Type(llvm.Wrapper): def __str__(self): return str(self._ptr) + def __hash__(self): + return hash(self._ptr) + def __eq__(self, rhs): return self._ptr is rhs._ptr @@ -808,6 +882,7 @@ class Type(llvm.Wrapper): class IntegerType(Type): """Represents an integer type.""" + __slots__ = () _type_ = api.llvm.IntegerType @property @@ -817,6 +892,7 @@ class IntegerType(Type): class FunctionType(Type): """Represents a function type.""" + __slots__ = () _type_ = api.llvm.FunctionType @property @@ -846,6 +922,7 @@ class FunctionType(Type): class StructType(Type): """Represents a structure type.""" _type_ = api.llvm.StructType + __slots__ = () @property def element_count(self): @@ -879,7 +956,10 @@ class StructType(Type): self._ptr.setName(name) def _get_name(self): - return self._ptr.getName() + if self._ptr.isLiteral(): + return "" + else: + return self._ptr.getName() name = property(_get_name, _set_name) @@ -895,9 +975,13 @@ class StructType(Type): def is_opaque(self): return self._ptr.isOpaque() + def is_layout_identical(self, other): + return self._ptr.isLayoutIdentical(other._ptr) + class ArrayType(Type): """Represents an array type.""" _type_ = api.llvm.ArrayType + __slots__ = () @property def element(self): @@ -909,6 +993,7 @@ class ArrayType(Type): class PointerType(Type): _type_ = api.llvm.PointerType + __slots__ = () @property def pointee(self): @@ -920,6 +1005,7 @@ class PointerType(Type): class VectorType(Type): _type_ = api.llvm.VectorType + __slots__ = () @property def element(self): @@ -931,6 +1017,7 @@ class VectorType(Type): class Value(llvm.Wrapper): _type_ = api.llvm.Value + __slots__ = '__weakref__' def __init__(self, builder, ptr): assert builder is _ValueFactory @@ -961,6 +1048,9 @@ class Value(llvm.Wrapper): def __str__(self): return str(self._ptr) + def __hash__(self): + return hash(self._ptr) + def __eq__(self, rhs): if isinstance(rhs, Value): return str(self) == str(rhs) @@ -996,6 +1086,7 @@ class Value(llvm.Wrapper): class User(Value): _type_ = api.llvm.User + __slots__ = () @property def operand_count(self): @@ -1010,6 +1101,7 @@ class User(Value): class Constant(User): _type_ = api.llvm.Constant + __slots__ = () @staticmethod def null(ty): @@ -1195,6 +1287,7 @@ class Constant(User): class ConstantExpr(Constant): _type_ = api.llvm.ConstantExpr + __slots__ = () @property def opcode(self): @@ -1205,19 +1298,20 @@ class ConstantExpr(Constant): return self._ptr.getOpcodeName() class ConstantAggregateZero(Constant): - pass + __slots__ = () class ConstantDataArray(Constant): - pass + __slots__ = () class ConstantDataVector(Constant): - pass + __slots__ = () class ConstantInt(Constant): _type_ = api.llvm.ConstantInt + __slots__ = () @property def z_ext_value(self): @@ -1233,30 +1327,32 @@ class ConstantInt(Constant): class ConstantFP(Constant): - pass + __slots__ = () class ConstantArray(Constant): - pass + __slots__ = () class ConstantStruct(Constant): - pass + __slots__ = () class ConstantVector(Constant): - pass + __slots__ = () class ConstantPointerNull(Constant): - pass + __slots__ = () class UndefValue(Constant): - pass + __slots__ = () + class GlobalValue(Constant): _type_ = api.llvm.GlobalValue + __slots__ = () def _get_linkage(self): return self._ptr.getLinkage() @@ -1302,6 +1398,7 @@ class GlobalValue(Constant): class GlobalVariable(GlobalValue): _type_ = api.llvm.GlobalVariable + __slots__ = () @staticmethod def new(module, ty, name, addrspace=0): @@ -1362,28 +1459,60 @@ class GlobalVariable(GlobalValue): thread_local = property(_get_thread_local, _set_thread_local) class Argument(Value): + __slots__ = () _type_ = api.llvm.Argument + _valid_attrs = frozenset([ATTR_BY_VAL, ATTR_NEST, ATTR_NO_ALIAS, + ATTR_NO_CAPTURE, ATTR_STRUCT_RET]) - def add_attribute(self, attr): - context = api.llvm.getGlobalContext() - attrbldr = api.llvm.AttrBuilder.new() - attrbldr.addAttribute(attr) - attrs = api.llvm.Attributes.get(context, attrbldr) - self._ptr.addAttr(attrs) + if llvm.version >= (3, 3): + def add_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.AttributeSet.get(context, 0, attrbldr) + self._ptr.addAttr(attrs) - def remove_attribute(self, attr): - context = api.llvm.getGlobalContext() - attrbldr = api.llvm.AttrBuilder.new() - attrbldr.addAttribute(attr) - attrs = api.llvm.Attributes.get(context, attrbldr) - self._ptr.removeAttr(attrs) + if attr not in self: + raise ValueError("Attribute %r is not valid for arg %s" % + (attr, self)) - def _set_alignment(self, align): - context = api.llvm.getGlobalContext() - attrbldr = api.llvm.AttrBuilder.new() - attrbldr.addAlignmentAttr(align) - attrs = api.llvm.Attributes.get(context, attrbldr) - self._ptr.addAttr(attrs) + def remove_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.AttributeSet.get(context, 0, attrbldr) + self._ptr.removeAttr(attrs) + + def _set_alignment(self, align): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAlignmentAttr(align) + attrs = api.llvm.AttributeSet.get(context, 0, attrbldr) + self._ptr.addAttr(attrs) + else: + def add_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttr(attrs) + if attr not in self: + raise ValueError("Attribute %r is not valid for arg %s" % + (attr, self)) + + def remove_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.removeAttr(attrs) + + def _set_alignment(self, align): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAlignmentAttr(align) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttr(attrs) def _get_alignment(self): return self._ptr.getParamAlignment() @@ -1391,7 +1520,47 @@ class Argument(Value): alignment = property(_get_alignment, _set_alignment) + @property + def attributes(self): + '''Returns a set of defined attributes. + ''' + return set(attr for attr in self._valid_attrs if attr in self) + + def __contains__(self, attr): + if attr == ATTR_BY_VAL: + return self.has_by_val() + elif attr == ATTR_NEST: + return self.has_nest() + elif attr == ATTR_NO_ALIAS: + return self.has_no_alias() + elif attr == ATTR_NO_CAPTURE: + return self.has_no_capture() + elif attr == ATTR_STRUCT_RET: + return self.has_struct_ret() + else: + raise ValueError('invalid attribute for argument') + + @property + def arg_no(self): + return self._ptr.getArgNo() + + def has_by_val(self): + return self._ptr.hasByValAttr() + + def has_nest(self): + return self._ptr.hasNestAttr() + + def has_no_alias(self): + return self._ptr.hasNoAliasAttr() + + def has_no_capture(self): + return self._ptr.hasNoCaptureAttr() + + def has_struct_ret(self): + return self._ptr.hasStructRetAttr() + class Function(GlobalValue): + __slots__ = () _type_ = api.llvm.Function @staticmethod @@ -1501,7 +1670,10 @@ class Function(GlobalValue): context = api.llvm.getGlobalContext() attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAttribute(attr) - attrs = api.llvm.Attributes.get(context, attrbldr) + if llvm.version >= (3, 3): + attrs = api.llvm.Attribute.get(context, attrbldr) + else: + attrs = api.llvm.Attributes.get(context, attrbldr) self._ptr.removeFnAttr(attrs) def viewCFGOnly(self): @@ -1527,6 +1699,7 @@ class Function(GlobalValue): #===----------------------------------------------------------------------=== class InlineAsm(Value): + __slots__ = () _type_ = api.llvm.InlineAsm @staticmethod @@ -1541,6 +1714,7 @@ class InlineAsm(Value): #===----------------------------------------------------------------------=== class MetaData(Value): + __slots__ = () _type_ = api.llvm.MDNode @staticmethod @@ -1597,6 +1771,7 @@ class MetaDataString(Value): class NamedMetaData(llvm.Wrapper): + __slots__ = () @staticmethod def get_or_insert(mod, name): @@ -1626,6 +1801,7 @@ class NamedMetaData(llvm.Wrapper): #===----------------------------------------------------------------------=== class Instruction(User): + __slots__ = () _type_ = api.llvm.Instruction @property @@ -1685,6 +1861,12 @@ class Instruction(User): def set_metadata(self, kind, metadata): self._ptr.setMetadata(kind, metadata._ptr) + def has_metadata(self): + return self._ptr.hasMetadata() + + def get_metadata(self, kind): + return self._ptr.getMetadata(kind) + @property def opcode(self): return self._ptr.getOpcode() @@ -1696,8 +1878,12 @@ class Instruction(User): def erase_from_parent(self): return self._ptr.eraseFromParent() + def replace_all_uses_with(self, inst): + self._ptr.replaceAllUsesWith(inst) + class CallOrInvokeInstruction(Instruction): + __slots__ = () _type_ = api.llvm.CallInst, api.llvm.InvokeInst def _get_cc(self): @@ -1712,21 +1898,33 @@ class CallOrInvokeInstruction(Instruction): context = api.llvm.getGlobalContext() attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAttribute(attr) - attrs = api.llvm.Attributes.get(context, attrbldr) + if llvm.version >= (3, 3): + attrs = api.llvm.Attribute.get(context, attrbldr) + else: + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttribute(idx, attrs) def remove_parameter_attribute(self, idx, attr): context = api.llvm.getGlobalContext() attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAttribute(attr) - attrs = api.llvm.Attributes.get(context, attrbldr) + if llvm.version >= (3, 3): + attrs = api.llvm.Attribute.get(context, attrbldr) + else: + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.removeAttribute(idx, attrs) def set_parameter_alignment(self, idx, align): context = api.llvm.getGlobalContext() attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAlignmentAttr(align) - attrs = api.llvm.Attributes.get(context, attrbldr) + if llvm.version >= (3, 3): + attrs = api.llvm.Attribute.get(context, attrbldr) + else: + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttribute(idx, attrs) def _get_called_function(self): @@ -1741,6 +1939,7 @@ class CallOrInvokeInstruction(Instruction): class PHINode(Instruction): + __slots__ = () _type_ = api.llvm.PHINode @property @@ -1758,21 +1957,60 @@ class PHINode(Instruction): class SwitchInstruction(Instruction): + __slots__ = () + _type_ = api.llvm.SwitchInst def add_case(self, const, bblk): self._ptr.addCase(const._ptr, bblk._ptr) class CompareInstruction(Instruction): + __slots__ = () + _type_ = api.llvm.CmpInst @property def predicate(self): - return self._ptr.getPredicate() + n = self._ptr.getPredicate() + try: + return ICMPEnum.get(n) + except KeyError: + return FCMPEnum.get(n) + + +class AllocaInstruction(Instruction): + __slots__ = () + _type_ = api.llvm.AllocaInst + + @property + def alignment(self): + return self._ptr.getAlignment() + + @alignment.setter + def alignment(self, n): + self._ptr.setAlignment(n) + + @property + def array_size(self): + return self._ptr.getArraySize() + + @array_size.setter + def array_size(self, value): + return self._ptr.setArraySize(value._ptr)._ptr + + @property + def is_array(self): + return self._ptr.isArrayAllocation() + + @property + def is_static(self): + return self._ptr.isStaticAlloca() + #===----------------------------------------------------------------------=== # Basic block #===----------------------------------------------------------------------=== class BasicBlock(Value): + __slots__ = () _type_ = api.llvm.BasicBlock def insert_before(self, name): @@ -1799,6 +2037,7 @@ class BasicBlock(Value): class _ValueFactory(object): + __slots__ = () cache = weakref.WeakValueDictionary() # value ID -> class map @@ -1827,7 +2066,8 @@ class _ValueFactory(object): VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction, VALUE_INSTRUCTION + OPCODE_SWITCH : SwitchInstruction, VALUE_INSTRUCTION + OPCODE_ICMP : CompareInstruction, - VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction + VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction, + VALUE_INSTRUCTION + OPCODE_ALLOCA : AllocaInstruction, } @classmethod @@ -1874,6 +2114,7 @@ _atomic_orderings = { } class Builder(llvm.Wrapper): + __slots__ = () @staticmethod def new(basic_block): @@ -1964,29 +2205,34 @@ class Builder(llvm.Wrapper): # arithmethic, bitwise and logical - def add(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name)) + def add(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def fadd(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFAdd(lhs._ptr, rhs._ptr, name)) - def sub(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateSub(lhs._ptr, rhs._ptr, name)) + def sub(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateSub(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def fsub(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFSub(lhs._ptr, rhs._ptr, name)) - def mul(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateMul(lhs._ptr, rhs._ptr, name)) + def mul(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateMul(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def fmul(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) - def udiv(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateUDiv(lhs._ptr, rhs._ptr, name)) + def udiv(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateUDiv(lhs._ptr, rhs._ptr, name, + exact)) - def sdiv(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateSDiv(lhs._ptr, rhs._ptr, name)) + def sdiv(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateSDiv(lhs._ptr, rhs._ptr, name, + exact)) def fdiv(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFDiv(lhs._ptr, rhs._ptr, name)) @@ -2000,14 +2246,17 @@ class Builder(llvm.Wrapper): def frem(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFRem(lhs._ptr, rhs._ptr, name)) - def shl(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name)) + def shl(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name, + nuw, nsw)) - def lshr(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name)) + def lshr(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name, + exact)) - def ashr(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateAShr(lhs._ptr, rhs._ptr, name)) + def ashr(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateAShr(lhs._ptr, rhs._ptr, name, + exact)) def and_(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateAnd(lhs._ptr, rhs._ptr, name)) @@ -2018,8 +2267,8 @@ class Builder(llvm.Wrapper): def xor(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateXor(lhs._ptr, rhs._ptr, name)) - def neg(self, val, name=""): - return _make_value(self._ptr.CreateNeg(val._ptr, name)) + def neg(self, val, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateNeg(val._ptr, name, nuw, nsw)) def not_(self, val, name=""): return _make_value(self._ptr.CreateNot(val._ptr, name)) @@ -2027,7 +2276,6 @@ class Builder(llvm.Wrapper): # memory def malloc(self, ty, name=""): - context = api.llvm.getGlobalContext() allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) ity = allocsz.getType() malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, @@ -2041,7 +2289,6 @@ class Builder(llvm.Wrapper): return _make_value(inst) def malloc_array(self, ty, size, name=""): - context = api.llvm.getGlobalContext() allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) ity = allocsz.getType() malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, @@ -2054,12 +2301,13 @@ class Builder(llvm.Wrapper): inst = self._ptr.Insert(malloc, name) return _make_value(inst) - def alloca(self, ty, name=""): - intty = Type.int() - return _make_value(self._ptr.CreateAlloca(ty._ptr, None, name)) + def alloca(self, ty, size=None, name=""): + sizeptr = size._ptr if size else None + return _make_value(self._ptr.CreateAlloca(ty._ptr, sizeptr, name)) + @deprecated def alloca_array(self, ty, size, name=""): - return _make_value(self._ptr.CreateAlloca(ty._ptr, size._ptr, name)) + return self.alloca(ty, size, name=name) def free(self, ptr): free = api.llvm.CallInst.CreateFree(ptr._ptr, self.basic_block._ptr) @@ -2146,15 +2394,20 @@ class Builder(llvm.Wrapper): # misc def extract_value(self, retval, idx, name=""): - return _make_value(self._ptr.CreateExtractValue(retval._ptr, [idx], name)) + if not isinstance(idx, (tuple, list)): + idx = [idx] + return _make_value(self._ptr.CreateExtractValue(retval._ptr, idx, + name)) # obsolete synonym for extract_value getresult = extract_value def insert_value(self, retval, rhs, idx, name=""): + if not isinstance(idx, (tuple, list)): + idx = [idx] return _make_value(self._ptr.CreateInsertValue(retval._ptr, rhs._ptr, - [idx], + idx, name)) def phi(self, ty, name=""): @@ -2294,29 +2547,8 @@ if api.llvm.InitializeNativeTargetAsmPrinter(): # should this be an optional feature? # should user trigger the initialization? raise llvm.LLVMException("No native asm printer!?") - -#===----------------------------------------------------------------------=== -# Initialization -#===----------------------------------------------------------------------=== - -HAS_PTX = HAS_NVPTX = False - -if True: # use PTX? - try: - api.LLVMInitializePTXTarget() - api.LLVMInitializePTXTargetInfo() - api.LLVMInitializePTXTargetMC() - api.LLVMInitializePTXAsmPrinter() - HAS_PTX = True - except AttributeError: - try: - api.LLVMInitializeNVPTXTarget() - api.LLVMInitializeNVPTXTargetInfo() - api.LLVMInitializeNVPTXTargetMC() - api.LLVMInitializeNVPTXAsmPrinter() - HAS_NVPTX = True - except AttributeError: - pass - - - +if api.llvm.InitializeNativeTargetAsmParser(): + # required by MCJIT? + # should this be an optional feature? + # should user trigger the initialization? + raise llvm.LLVMException("No native asm parser!?") diff --git a/llvm/deprecated.py b/llvm/deprecated.py new file mode 100644 index 0000000..6db5fe7 --- /dev/null +++ b/llvm/deprecated.py @@ -0,0 +1,25 @@ +""" +Shameless borrowed from Smart_deprecation_warnings +https://wiki.python.org/moin/PythonDecoratorLibrary +""" + +import warnings +import functools + + +def deprecated(func): + """This is a decorator which can be used to mark functions + as deprecated. It will result in a warning being emitted + when the function is used.""" + + @functools.wraps(func) + def new_func(*args, **kwargs): + warnings.warn_explicit( + "Call to deprecated function %s." % (func.__name__,), + category=DeprecationWarning, + filename=func.func_code.co_filename, + lineno=func.func_code.co_firstlineno + 1 + ) + return func(*args, **kwargs) + + return new_func diff --git a/llvm/ee.py b/llvm/ee.py index 9531427..f615b61 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -30,33 +30,23 @@ "Execution Engine and related classes." -from io import BytesIO -import contextlib +import sys import llvm from llvm import core from llvm.passes import TargetData, TargetTransformInfo from llvmpy import api, extra + #===----------------------------------------------------------------------=== -# Enumerations +# import items which were moved to target module #===----------------------------------------------------------------------=== +from llvm.target import (initialize_all, initialize_target, + print_registered_targets, get_host_cpu_name, get_default_triple, + TargetMachine, + BO_BIG_ENDIAN, BO_LITTLE_ENDIAN, + CM_DEFAULT, CM_JITDEFAULT, CM_SMALL, CM_KERNEL, CM_MEDIUM, CM_LARGE, + RELOC_DEFAULT, RELOC_STATIC, RELOC_PIC, RELOC_DYNAMIC_NO_PIC) -BO_BIG_ENDIAN = 0 -BO_LITTLE_ENDIAN = 1 - -# CodeModel -CM_DEFAULT = api.llvm.CodeModel.Model.Default -CM_JITDEFAULT = api.llvm.CodeModel.Model.JITDefault -CM_SMALL = api.llvm.CodeModel.Model.Small -CM_KERNEL = api.llvm.CodeModel.Model.Kernel -CM_MEDIUM = api.llvm.CodeModel.Model.Medium -CM_LARGE = api.llvm.CodeModel.Model.Large - -# Reloc -RELOC_DEFAULT = api.llvm.Reloc.Model.Default -RELOC_STATIC = api.llvm.Reloc.Model.Static -RELOC_PIC = api.llvm.Reloc.Model.PIC_ -RELOC_DYNAMIC_NO_PIC = api.llvm.Reloc.Model.DynamicNoPIC #===----------------------------------------------------------------------=== # Generic value @@ -132,7 +122,7 @@ class EngineBuilder(llvm.Wrapper): level valid [0, 1, 2, 3] -- [None, Less, Default, Aggressive] ''' assert 0 <= level <= 3 - self._ptr.setOptLevel = level + self._ptr.setOptLevel(level) return self def mattrs(self, string): @@ -150,9 +140,17 @@ class EngineBuilder(llvm.Wrapper): ''' if tm is not None: engine = self._ptr.create(tm._ptr) + elif (sys.platform.startswith('win32') and + getattr(self, '_use_mcjit', False)): + # force ELF generation on MCJIT on win32 + triple = get_default_triple() + tm = TargetMachine.new('%s-elf' % triple) + engine = self._ptr.create(tm._ptr) else: engine = self._ptr.create() - return ExecutionEngine(engine) + ee = ExecutionEngine(engine) + ee.finalize_object() # no effect for legacy JIT + return ee def select_target(self, *args): '''get the corresponding target machine @@ -167,6 +165,12 @@ class EngineBuilder(llvm.Wrapper): ptr = self._ptr.selectTarget() return TargetMachine(ptr) + def mcjit(self, enable): + '''Enable/disable MCJIT + ''' + self._ptr.setUseMCJIT(enable) + self._use_mcjit = True + return self #===----------------------------------------------------------------------=== # Execution engine @@ -188,6 +192,9 @@ class ExecutionEngine(llvm.Wrapper): ptr = self._ptr.runFunction(fn._ptr, list(map(lambda x: x._ptr, args))) return GenericValue(ptr) + def get_pointer_to_named_function(self, name, abort=True): + return self._ptr.getPointerToNamedFunction(name, abort) + def get_pointer_to_function(self, fn): return self._ptr.getPointerToFunction(fn._ptr) @@ -213,133 +220,45 @@ class ExecutionEngine(llvm.Wrapper): def remove_module(self, module): return self._ptr.removeModule(module._ptr) + def finalize_object(self): + return self._ptr.finalizeObject() + @property def target_data(self): ptr = self._ptr.getDataLayout() return TargetData(ptr) + #===----------------------------------------------------------------------=== -# Target machine +# Dynamic Library #===----------------------------------------------------------------------=== -def print_registered_targets(): - ''' - Note: print directly to stdout - ''' - api.llvm.TargetRegistry.printRegisteredTargetsForVersion() +def dylib_add_symbol(name, ptr): + api.llvm.sys.DynamicLibrary.AddSymbol(name, ptr) -def get_host_cpu_name(): - '''return the string name of the host CPU - ''' - return api.llvm.sys.getHostCPUName() +def dylib_address_of_symbol(name): + return api.llvm.sys.DynamicLibrary.SearchForAddressOfSymbol(name) -def get_default_triple(): - '''return the target triple of the host in str-rep - ''' - return api.llvm.sys.getDefaultTargetTriple() +def dylib_import_library(filename): + """Permanently import a dynamic library. + + Returns a DynamicLibrary object + + Raises RuntimeError + """ + return DynamicLibrary(filename) -class TargetMachine(llvm.Wrapper): - - @staticmethod - def new(triple='', cpu='', features='', opt=2, cm=CM_DEFAULT, - reloc=RELOC_DEFAULT): - if not triple: - triple = get_default_triple() - if not cpu: - cpu = get_host_cpu_name() - with contextlib.closing(BytesIO()) as error: - target = api.llvm.TargetRegistry.lookupTarget(triple, error) - if not target: - raise llvm.LLVMException(error) - if not target.hasTargetMachine(): - raise llvm.LLVMException(target, "No target machine.") - target_options = api.llvm.TargetOptions.new() - tm = target.createTargetMachine(triple, cpu, features, - target_options, - reloc, cm, opt) - if not tm: - raise llvm.LLVMException("Cannot create target machine") - return TargetMachine(tm) - - @staticmethod - def lookup(arch, cpu='', features='', opt=2, cm=CM_DEFAULT, - reloc=RELOC_DEFAULT): - '''create a targetmachine given an architecture name - - For a list of architectures, - use: `llc -help` - - For a list of available CPUs, - use: `llvm-as < /dev/null | llc -march=xyz -mcpu=help` - - For a list of available attributes (features), - use: `llvm-as < /dev/null | llc -march=xyz -mattr=help` - ''' - triple = api.llvm.Triple.new() - with contextlib.closing(BytesIO()) as error: - target = api.llvm.TargetRegistry.lookupTarget(arch, triple, error) - if not target: - raise llvm.LLVMException(error) - if not target.hasTargetMachine(): - raise llvm.LLVMException(target, "No target machine.") - target_options = api.llvm.TargetOptions.new() - tm = target.createTargetMachine(str(triple), cpu, features, - target_options, - reloc, cm, opt) - if not tm: - raise llvm.LLVMException("Cannot create target machine") - return TargetMachine(tm) - - def _emit_file(self, module, cgft): - pm = api.llvm.PassManager.new() - os = extra.make_raw_ostream_for_printing() - pm.add(api.llvm.DataLayout.new(str(self.target_data))) - failed = self._ptr.addPassesToEmitFile(pm, os, cgft) - pm.run(module) - - - CGFT = api.llvm.TargetMachine.CodeGenFileType - if cgft == CGFT.CGFT_ObjectFile: - return os.bytes() - else: - return os.str() - - def emit_assembly(self, module): - '''returns byte string of the module as assembly code of the target machine - ''' - CGFT = api.llvm.TargetMachine.CodeGenFileType - return self._emit_file(module._ptr, CGFT.CGFT_AssemblyFile) - - def emit_object(self, module): - '''returns byte string of the module as native code of the target machine - ''' - CGFT = api.llvm.TargetMachine.CodeGenFileType - return self._emit_file(module._ptr, CGFT.CGFT_ObjectFile) - - @property - def target_data(self): - '''get target data of this machine - ''' - return TargetData(self._ptr.getDataLayout()) - - @property - def target_name(self): - return self._ptr.getTarget().getName() - - @property - def target_short_description(self): - return self._ptr.getTarget().getShortDescription() - - @property - def triple(self): - return self._ptr.getTargetTriple() - - @property - def cpu(self): - return self._ptr.getTargetCPU() - - @property - def feature_string(self): - return self._ptr.getTargetFeatureString() +class DynamicLibrary(object): + def __init__(self, filename): + """ + Raises RuntimeError + """ + self._ptr = api.llvm.sys.DynamicLibrary.getPermanentLibrary( + filename) + def get_address_of_symbol(self, symbol): + """ + Get the address of `symbol` (str) as integer + """ + return self._ptr.getAddressOfSymbol(symbol) diff --git a/llvm/llrt.py b/llvm/llrt.py new file mode 100644 index 0000000..c704a66 --- /dev/null +++ b/llvm/llrt.py @@ -0,0 +1,79 @@ +import os +import llvm.core as lc +import llvm.passes as lp +import llvm.ee as le + +def replace_divmod64(lfunc): + '''Replaces all 64-bit integer division (sdiv, udiv) and modulo (srem, urem) + ''' + int64 = lc.Type.int(64) + int64ptr = lc.Type.pointer(lc.Type.int(64)) + + functy = lc.Type.function(int64, [int64, int64]) + udiv64 = lfunc.module.get_or_insert_function(functy, '__llrt_udiv64') + sdiv64 = lfunc.module.get_or_insert_function(functy, '__llrt_sdiv64') + umod64 = lfunc.module.get_or_insert_function(functy, '__llrt_umod64') + smod64 = lfunc.module.get_or_insert_function(functy, '__llrt_smod64') + + builder = lc.Builder.new(lfunc.entry_basic_block) + for bb in lfunc.basic_blocks: + for inst in bb.instructions: + if inst.opcode_name == 'sdiv' and inst.type == int64: + _replace_with(builder, inst, sdiv64) + elif inst.opcode_name == 'udiv' and inst.type == int64: + _replace_with(builder, inst, udiv64) + elif inst.opcode_name == 'srem' and inst.type == int64: + _replace_with(builder, inst, smod64) + elif inst.opcode_name == 'urem' and inst.type == int64: + _replace_with(builder, inst, umod64) + +def _replace_with(builder, inst, func): + '''Replace instruction with a call to the function with the same operands + as arguments. + ''' + builder.position_before(inst) + replacement = builder.call(func, inst.operands) + inst.replace_all_uses_with(replacement._ptr) + inst.erase_from_parent() + +def load(arch): + '''Load the LLRT module corresponding to the given architecture + Creates a new module and optimizes it using the information from + the host machine. + ''' + if arch != 'x86_64': + arch = 'x86' + path = os.path.join(os.path.dirname(__file__), 'llrt', 'llrt_%s.ll' % arch) + with open(path) as fin: + lib = lc.Module.from_assembly(fin) + + # run passes to optimize + tm = le.TargetMachine.new() + pms = lp.build_pass_managers(tm, opt=3, fpm=False) + pms.pm.run(lib) + return lib + +class LLRT(object): + def __init__(self): + arch = le.get_default_triple().split('-', 1)[0] + self.module = load(arch) + self.engine = le.EngineBuilder.new(self.module).opt(3).create() + self.installed_symbols = set() + + def install_symbols(self): + '''Bind all the external symbols to the global symbol map. + Any future reference to these symbols will be automatically resolved + by LLVM. + ''' + for lfunc in self.module.functions: + if lfunc.linkage == lc.LINKAGE_EXTERNAL: + mangled = '__llrt_' + lfunc.name + self.installed_symbols.add(mangled) + ptr = self.engine.get_pointer_to_function(lfunc) + le.dylib_add_symbol(mangled, ptr) + + def uninstall_symbols(self): + for sym in self.installed_symbols: + le.dylib_add_symbol(sym, 0) + + diff --git a/llvm/llrt/llrt_x86.ll b/llvm/llrt/llrt_x86.ll new file mode 100644 index 0000000..5096214 --- /dev/null +++ b/llvm/llrt/llrt_x86.ll @@ -0,0 +1,371 @@ +; ModuleID = 'udivmod64_x86.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32-S128" + +%struct.div_state_ = type { i64, i64 } + +define i64 @udivmod64(i64 %dividend, i64 %divisor, i64* %remainder) nounwind ssp { + %1 = alloca i64, align 4 + %2 = alloca i64, align 8 + %3 = alloca i64, align 8 + %4 = alloca i64*, align 4 + %state = alloca %struct.div_state_, align 4 + %quotient = alloca i64, align 8 + %i = alloca i32, align 4 + %skipahead = alloca i32, align 4 + store i64 %dividend, i64* %2, align 8 + store i64 %divisor, i64* %3, align 8 + store i64* %remainder, i64** %4, align 4 + %5 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0 + store i64 0, i64* %5, align 4 + %6 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 1 + %7 = load i64* %2, align 8 + store i64 %7, i64* %6, align 4 + store i64 0, i64* %quotient, align 8 + %8 = load i64* %3, align 8 + %9 = icmp eq i64 %8, 0 + br i1 %9, label %10, label %11 + +;