diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3a05aa8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +llvm/_version.py export-subst diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6d6296f --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*~ +build +_build +*.pyc +*.so +/llvm/_intrinsic_ids.py +llvm_ +newbinding/api/* \ No newline at end of file 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 396ce0e..45d6a5f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,14 +1,88 @@ +2014-04-28 0.12.5: +--------------------- + * Fixes memory leaks (#92) + * Fixes tarball (#99) -0.7, in progress: +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 + * fix Python 3 division (Hernan Grecco) (Issue #59) + * add relocation enums and add reloc argument for TargetMachine + + +2013-03-01 0.11.0: +-------------------- + * fix Python 3 support on Windows + * New llvm binding + + +2013-02-01 0.10.2: +-------------------- + * change default to link dynamically to LLVM use: + $ export LLVMPY_DYNLINK=0 # link statically + $ export LLVMPY_DYNLINK=1 # link dynamically + $ unset LLVMPY_DYNLINK # tries to link dynamically if LLVM shared + # objects are found and statically otherwise + * fix llpython for Python 2.6 support + + +2013-01-25 0.10.1: +-------------------- + * fix support for Python 2.6 + + +2013-01-18 0.10.0: +-------------------- + * Add LLVM 3.2 support. + * New TargetData class. + * Fixed windows issue (Issue #42). + * Add ExecutionEngine.add_global_mapping and .get_pointer_to_global. + * Improved TargetMachine class and added code-model constants (CM_*). + * Added llvm.passes.build_pass_managers as a simpler way to build PassManagers. + + +in progress, 0.7: +----------------- * Add llvm.core.Argument.alignment property. * Migrate to LLVM 2.8. * Fix ffi link issue on darwin (Albert Mietus) (Issue #29). * LLVM tutorial ported (Max Shawabkeh) (Issue #33). -0.6, 31-Aug-2010: - +2010-08-31 0.6: +----------------- * Add and remove function attributes (Krzysztof Goj) (Issue #21). * Wrap fadd,fsub,fmul (Aaron S Lav) (Issue #31). * Migrate to LLVM 2.7. @@ -27,16 +101,16 @@ * Migrate to LLVM 2.5. -0.5, 22-Nov-2008: - +2008-11-22 0.5: +----------------- * Added vicmp, vfcmp instructions and constant expressions. * Builds on FreeBSD. * Updated documentation. * Migrate to LLVM 2.4. -0.4, 21-Nov-2008: - +2008-11-21 0.4: +----------------- * Code cleanup, added license headers. * Added llvm.core.load_library_permanently() (Issue #12). * Fix comparison using != (Issue #11). @@ -45,8 +119,8 @@ * Added viewCFG methods to Function (Paulo Silva). -0.3, 8-Sep-2008: - +2008-09-08 0.3: +----------------- * Passes added. * Assembly support: create modules from .ll files. * Various bug fixes. @@ -58,13 +132,13 @@ * Updated documentation. -0.2.1, 18-Jun-2008: - +2008-06-28 0.2.1: +------------------- * Build cleanly with LLVM 2.3 and 2.3svn. -0.2, 15-Jun-2008: - +2008-06-15 0.2: +----------------- * Independent package, need not be unpacked into llvm/bindings. * Fixed ownership issues with Module/ModuleProvider. * Modules, values and types can be stringified, to get their LLVM @@ -79,7 +153,6 @@ * Lots of cleanup. -0.1, 10-May-2008: - - * Initial release. - +2008-05-10 0.1: +----------------- + * Initial release diff --git a/LICENSE b/LICENSE index 579d556..8117ae1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ Copyright (c) 2008-10, Mahadevan R All rights reserved. +Copyright (c) 2012, Continuum Analytics, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/MANIFEST.in b/MANIFEST.in index ec22b21..25a211d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +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.md b/README.md deleted file mode 100644 index 74194eb..0000000 --- a/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# llvm-py: Python Bindings for LLVM # -llvm-py provides Python bindings for LLVM. - -## Home page ## -https://github.com/AndrewBC/llvm-py - -## Versions ## -This package has only been tested with LLVM 2.9, and Python 2.7, (not Python 3.x). - -## Quickstart ## -1. Get 2.9 version of LLVM, build it. Make sure '--enable-pic' is passed to LLVM's 'configure'. -2. Get llvm-py and install it: - -``` -$ git clone git@github.com:AndrewBC/llvm-py.git -$ cd llvm-py -$ python setup.py install -``` - -3. See documentation at 'www/web/index.html' and examples under 'test'. - -## LICENSE ## -llvm-py is distributed under the new BSD license, which is similar to the LLVM license itself. -See the file called LICENSE for the full license text. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..a1abf84 --- /dev/null +++ b/README.rst @@ -0,0 +1,67 @@ +================================ +llvmpy: Python bindings for LLVM +================================ + +Home page +--------- + +http://www.llvmpy.org + +Versions +-------- + +This package has been tested with LLVM 3.2, Python 2.6, 2.7 and 3.3. +Other Python versions may work. + +Quickstart +---------- + +1. Get and extract LLVM 3.2 source tarball from + `llvm.org `_. Then, ``cd`` into + the extracted directory. + +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. + +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 + $ 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'. + +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 +------- + +llvmpy is distributed under the new BSD license, which is similar to the LLVM +license itself. +See the file called LICENSE for the full license text. diff --git a/README_LLVM_CBUILDER.md b/README_LLVM_CBUILDER.md new file mode 100644 index 0000000..da180c4 --- /dev/null +++ b/README_LLVM_CBUILDER.md @@ -0,0 +1,144 @@ +LLVM CBuilder +============= + +A few short examples: +(TODO: add more later) + +```python +from llvm.core import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +``` + +```python +class Square(CDefinition): + _name_ = 'square' + _retty_ = C.double + _argtys_ = [ ('x', C.double) ] + + def body(self, x): + y = x * x + self.ret(y) +``` + +```python +m = Module.new('my_module') +llvm_square = Square()(m) +print(m) +``` + +``` +; ModuleID = 'my_module' + +define double @square(double %x) { +decl: + %0 = fmul double %x, %x + ret double %0 +} +``` + + +```python +class IsPrime(CDefinition): + _name_ = 'isprime' + _retty_ = C.int + _argtys_ = [('x', C.int)] + + def body(self, x): + false = zero = self.constant(C.int, 0) + true = one = self.constant(C.int, 1) + + two = self.constant(C.int, 2) + + with self.ifelse( x <= two ) as ifelse: + with ifelse.then(): + self.ret(true) + + with self.ifelse( (x % two) == zero ) as ifelse: + with ifelse.then(): + self.ret(false) + + idx = self.var(C.int, 3, name='idx') + + with self.loop() as loop: + with loop.condition() as setcond: + setcond( idx < x ) + + with loop.body(): + with self.ifelse( (x % idx ) == zero ) as ifelse: + with ifelse.then(): + self.ret(false) + idx += two + + self.ret(true) +``` + + + +``` +define i32 @isprime(i32 %x) { +decl: + %0 = icmp sle i32 %x, 2 + br i1 %0, label %if.then, label %if.end + +if.then: ; preds = %loop.body, %loop.cond, %if.end, %decl + %merge = phi i32 [ 1, %decl ], [ 0, %if.end ], [ 1, %loop.cond ], [ 0, %loop.body ] + ret i32 %merge + +if.end: ; preds = %decl + %1 = srem i32 %x, 2 + %2 = icmp eq i32 %1, 0 + br i1 %2, label %if.then, label %if.end4 + +if.end4: ; preds = %if.end + br label %loop.cond + +loop.cond: ; preds = %if.end7, %if.end4 + %idx.0 = phi i32 [ 3, %if.end4 ], [ %6, %if.end7 ] + %3 = icmp slt i32 %idx.0, %x + br i1 %3, label %loop.body, label %if.then + +loop.body: ; preds = %loop.cond + %4 = srem i32 %x, %idx.0 + %5 = icmp eq i32 %4, 0 + br i1 %5, label %if.then, label %if.end7 + +if.end7: ; preds = %loop.body + %6 = add i32 %idx.0, 2 + br label %loop.cond +} + +; ModuleID = 'my_module' + +define i32 @isprime(i32 %x) { +decl: + %0 = icmp sle i32 %x, 2 + br i1 %0, label %if.then, label %if.end + +if.then: ; preds = %loop.body, %loop.cond, %if.end, %decl + %merge = phi i32 [ 1, %decl ], [ 0, %if.end ], [ 1, %loop.cond ], [ 0, %loop.body ] + ret i32 %merge + +if.end: ; preds = %decl + %1 = srem i32 %x, 2 + %2 = icmp eq i32 %1, 0 + br i1 %2, label %if.then, label %if.end4 + +if.end4: ; preds = %if.end + br label %loop.cond + +loop.cond: ; preds = %if.end7, %if.end4 + %idx.0 = phi i32 [ 3, %if.end4 ], [ %6, %if.end7 ] + %3 = icmp slt i32 %idx.0, %x + br i1 %3, label %loop.body, label %if.then + +loop.body: ; preds = %loop.cond + %4 = srem i32 %x, %idx.0 + %5 = icmp eq i32 %4, 0 + br i1 %5, label %if.then, label %if.end7 + +if.end7: ; preds = %loop.body + %6 = add i32 %idx.0, 2 + br label %loop.cond +} +``` 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/Makefile b/docs/Makefile new file mode 100644 index 0000000..8e563cc --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,157 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build +SRCDIR = source + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRCDIR) +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/llvmpy.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/llvmpy.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/llvmpy" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/llvmpy" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +gh-pages: clean html + python gh-pages.py diff --git a/docs/gh-pages.py b/docs/gh-pages.py new file mode 100755 index 0000000..3ee5d20 --- /dev/null +++ b/docs/gh-pages.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +"""Script to commit the doc build outputs into the github-pages repo. + +Use: + + gh-pages.py [tag] + +If no tag is given, the current output of 'git describe' is used. If given, +that is how the resulting directory will be named. + +In practice, you should use either actual clean tags from a current build or +something like 'current' as a stable URL for the most current version of the """ + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- +import os +import re +import shutil +import sys +from os import chdir as cd +from os.path import join as pjoin + +from subprocess import Popen, PIPE, CalledProcessError, check_call + +#----------------------------------------------------------------------------- +# Globals +#----------------------------------------------------------------------------- + +pages_dir = 'gh-pages' +html_dir = '_build/html' +pdf_dir = '_build/latex' +pages_repo = 'https://github.com/llvmpy/llvmpy-doc.git' + +#----------------------------------------------------------------------------- +# Functions +#----------------------------------------------------------------------------- +def sh(cmd): + """Execute command in a subshell, return status code.""" + return check_call(cmd, shell=True) + + +def sh2(cmd): + """Execute command in a subshell, return stdout. + + Stderr is unbuffered from the subshell.x""" + p = Popen(cmd, stdout=PIPE, shell=True) + out = p.communicate()[0] + retcode = p.returncode + if retcode: + raise CalledProcessError(retcode, cmd) + else: + return out.rstrip() + + +def sh3(cmd): + """Execute command in a subshell, return stdout, stderr + + If anything appears in stderr, print it out to sys.stderr""" + p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True) + out, err = p.communicate() + retcode = p.returncode + if retcode: + raise CalledProcessError(retcode, cmd) + else: + return out.rstrip(), err.rstrip() + + +def init_repo(path): + """clone the gh-pages repo if we haven't already.""" + sh("git clone %s %s"%(pages_repo, path)) + here = os.getcwdu() + cd(path) + sh('git checkout gh-pages') + cd(here) + +#----------------------------------------------------------------------------- +# Script starts +#----------------------------------------------------------------------------- +if __name__ == '__main__': + # The tag can be given as a positional argument + try: + tag = sys.argv[1] + except IndexError: + try: + tag = sh2('git describe --exact-match') + except CalledProcessError: + tag = "dev" # Fallback + + startdir = os.getcwdu() + if not os.path.exists(pages_dir): + # init the repo + init_repo(pages_dir) + else: + # ensure up-to-date before operating + cd(pages_dir) + sh('git checkout gh-pages') + sh('git pull') + cd(startdir) + + dest = pjoin(pages_dir, tag) + + # don't `make html` here, because gh-pages already depends on html in Makefile + # sh('make html') + if tag != 'dev': + # only build pdf for non-dev targets + #sh2('make pdf') + pass + + # This is pretty unforgiving: we unconditionally nuke the destination + # directory, and then copy the html tree in there + shutil.rmtree(dest, ignore_errors=True) + shutil.copytree(html_dir, dest) + if tag != 'dev': + #shutil.copy(pjoin(pdf_dir, 'ipython.pdf'), pjoin(dest, 'ipython.pdf')) + pass + + try: + cd(pages_dir) + status = sh2('git status | head -1') + branch = re.match('\# On branch (.*)$', status).group(1) + if branch != 'gh-pages': + e = 'On %r, git branch is %r, MUST be "gh-pages"' % (pages_dir, + branch) + raise RuntimeError(e) + + sh('git add -A %s' % tag) + sh('git commit -m"Updated doc release: %s"' % tag) + print + print 'Most recent 3 commits:' + sys.stdout.flush() + sh('git --no-pager log --oneline HEAD~3..') + finally: + cd(startdir) + + print + print 'Now verify the build in: %r' % dest + print "If everything looks good, 'git push'" diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..701ef80 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,259 @@ +# -*- coding: utf-8 -*- +# +# llvmpy documentation build configuration file, created by +# sphinx-quickstart on Wed Aug 8 17:33:58 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os, glob + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('../..')) + +# Support sphinx.ext.autodoc to extract docstrings from modules without installing +# complete package. +# The python modules depend on _core, so we must build entire package first though. +built_lib = glob.glob('../../build/lib.*-%d.%d/' % sys.version_info[:2]) +if not built_lib: + sys.stderr.write("WARNING: To build complete documentation you must build " + "package first\n") +else: + # lib dir has platform suffix + sys.path.insert(0, os.path.abspath(built_lib[0])) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.mathjax', 'sphinx.ext.autodoc'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'llvmpy' +copyright = u'2013, Mahadevan R (2008-2010), Continuum Analytics (2012-2013)' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +try: + import llvm + version_strs = llvm.__version__.split('.') + # The short X.Y version. + version = '.'.join(version_strs[:2]) + # The full version, including alpha/beta/rc tags. + release = '%s.%s' % (version, '-'.join(version_strs[2].split('-')[:2])) +except ImportError: + version = 'unknown-version' + release = 'unknown-release' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'llvmpydoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'llvmpy.tex', u'llvmpy Documentation', + u'Mahadevan R (2008-2010), Continuum Analytics (2012)', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'llvmpy', u'llvmpy Documentation', + [u'Mahadevan R (2008-2010), Continuum Analytics (2012)'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'llvmpy', u'llvmpy Documentation', + u'Mahadevan R (2008-2010), Continuum Analytics (2012)', 'llvmpy', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' diff --git a/docs/source/doc/comparision.rst b/docs/source/doc/comparision.rst new file mode 100644 index 0000000..2f1b87b --- /dev/null +++ b/docs/source/doc/comparision.rst @@ -0,0 +1,147 @@ ++--------------------------------+ +| layout: page | ++--------------------------------+ +| title: Comparison Operations | ++--------------------------------+ + +Integer Comparision # {#icmp} +============================= + +Predicates for use with ``icmp`` instruction are listed below. All of +these are integer constants defined in the ``llvm.core`` module. + +``ICMP_EQ`` +----------- + +Equality + +``ICMP_NE`` +----------- + +Inequality + +``ICMP_UGT`` +------------ + +Unsigned greater than + +``ICMP_UGE`` +------------ + +Unsigned greater than or equal + +``ICMP_ULT`` +------------ + +Unsigned less than + +``ICMP_ULE`` +------------ + +Unsigned less than or equal + +``ICMP_SGT`` +------------ + +Signed greater than + +``ICMP_SGE`` +------------ + +Signed greater than or equal + +``ICMP_SLT`` +------------ + +Signed less than + +``ICMP_SLE`` +------------ + +Signed less than or equal + +Float Comparision # {#fcmp} +=========================== + +Predicates for use with ``fcmp`` instruction are listed below. All of +these are integer constants defined in the ``llvm.core`` module. + +``FCMP_FALSE`` +-------------- + +Always false + +``FCMP_OEQ`` +------------ + +True if ordered and equal + +``FCMP_OGT`` +------------ + +True if ordered and greater than + +``FCMP_OGE`` +------------ + +True if ordered and greater than or equal + +``FCMP_OLT`` +------------ + +True if ordered and less than + +``FCMP_OLE`` +------------ + +True if ordered and less than or equal + +``FCMP_ONE`` +------------ + +True if ordered and operands are unequal + +``FCMP_ORD`` +------------ + +True if ordered (no NaNs) + +``FCMP_UNO`` +------------ + +True if unordered: ``isnan(X) | isnan(Y)`` + +``FCMP_UEQ`` +------------ + +True if unordered or equal + +``FCMP_UGT`` +------------ + +True if unordered or greater than + +``FCMP_UGE`` +------------ + +True if unordered, greater than or equal + +``FCMP_ULT`` +------------ + +True if unordered, or less than + +``FCMP_ULE`` +------------ + +True if unordered, less than or equal + +``FCMP_UNE`` +------------ + +True if unordered or not equal + +``FCMP_TRUE`` +------------- + +Always true diff --git a/docs/source/doc/core.rst b/docs/source/doc/core.rst new file mode 100644 index 0000000..a3b94b6 --- /dev/null +++ b/docs/source/doc/core.rst @@ -0,0 +1,9 @@ +******************************** +llvm.core +******************************** + +.. toctree:: + :titlesonly: + :glob: + + llvm.core.* \ No newline at end of file diff --git a/docs/source/doc/examples.rst b/docs/source/doc/examples.rst new file mode 100644 index 0000000..9e01700 --- /dev/null +++ b/docs/source/doc/examples.rst @@ -0,0 +1,12 @@ +******************************** +Examples and LLVM Tutorials +******************************** + +.. toctree:: + :maxdepth: 1 + + firstexample.rst + examples/index.rst + kaleidoscope/index.rst + + diff --git a/docs/source/doc/examples/JITTutorial1.rst b/docs/source/doc/examples/JITTutorial1.rst new file mode 100644 index 0000000..09f3c33 --- /dev/null +++ b/docs/source/doc/examples/JITTutorial1.rst @@ -0,0 +1,36 @@ +A First Function +================== + +.. code-block:: python + + #!/usr/bin/env python + + from llvm.core import * + + #create a module + module = Module.new("tut1") + + #create a function type taking 3 32-bit integers, return a 32-bit integer + ty_int = Type.int(32) + func_type = Type.function(ty_int, (ty_int,)*3) + + #create a function of that type + mul_add = Function.new (module, func_type, "mul_add") + mul_add.calling_convention = CC_C + x = mul_add.args[0]; x.name = "x" + y = mul_add.args[1]; y.name = "y" + z = mul_add.args[2]; z.name = "z" + + #implement the function + + #new block + blk = mul_add.append_basic_block("entry") + + #IR builder + bldr = Builder.new(blk) + tmp_1 = bldr.mul(x, y, "tmp_1") + tmp_2 = bldr.add(tmp_1, z, "tmp_2") + + bldr.ret(tmp_2) + + print module diff --git a/docs/source/doc/examples/JITTutorial2.rst b/docs/source/doc/examples/JITTutorial2.rst new file mode 100644 index 0000000..6e76150 --- /dev/null +++ b/docs/source/doc/examples/JITTutorial2.rst @@ -0,0 +1,55 @@ +A More Complicated Function +=========================== + +.. code-block:: python + + #!/usr/bin/env python + + from llvm.core import * + + #create a module + module = Module.new("tut2") + + #create a function type taking 2 integers, return a 32-bit integer + ty_int = Type.int(32) + func_type = Type.function(ty_int, (ty_int, ty_int)) + + #create a function of that type + gcd = Function.new(module, func_type, "gcd") + + #name function args + x = gcd.args[0]; x.name = "x" + y = gcd.args[1]; y.name = "y" + + #implement the function + + #blocks... + entry = gcd.append_basic_block("entry") + ret = gcd.append_basic_block("return") + cond_false = gcd.append_basic_block("cond_false") + cond_true = gcd.append_basic_block("cond_true") + cond_false_2 = gcd.append_basic_block("cond_false_2") + + #create a llvm::IRBuilder + bldr = Builder.new(entry) + x_eq_y = bldr.icmp(IPRED_EQ, x, y, "tmp") + bldr.cbranch(x_eq_y, ret, cond_false) + + bldr.position_at_end (ret) + bldr.ret(x) + + bldr.position_at_end(cond_false) + x_lt_y = bldr.icmp(IPRED_ULT, x, y, "tmp") + bldr.cbranch(x_lt_y, cond_true, cond_false_2) + + bldr.position_at_end(cond_true) + y_sub_x = bldr.sub(y, x, "tmp") + recur_1 = bldr.call(gcd, (x, y_sub_x,), "tmp") + bldr.ret(recur_1) + + bldr.position_at_end(cond_false_2) + x_sub_y = bldr.sub(x, y, "x_sub_y") + recur_2 = bldr.call(gcd, (x_sub_y, y,), "tmp") + bldr.ret(recur_2) + + print module diff --git a/docs/source/doc/examples/index.rst b/docs/source/doc/examples/index.rst new file mode 100644 index 0000000..0cd3532 --- /dev/null +++ b/docs/source/doc/examples/index.rst @@ -0,0 +1,10 @@ +LLVM Tutorials +============== + +The following JIT tutorials were contributed by Sebastien Binet. + +.. toctree:: + :titlesonly: + + JITTutorial1.rst + JITTutorial2.rst diff --git a/docs/source/doc/firstexample.rst b/docs/source/doc/firstexample.rst new file mode 100644 index 0000000..0f6a4d0 --- /dev/null +++ b/docs/source/doc/firstexample.rst @@ -0,0 +1,125 @@ +Examples +======== + +A Simple Function +----------------- + +Let's create a (LLVM) module containing a single function, corresponding +to the ``C`` function: + +.. code-block:: c + + int sum(int a, int b) + { + return a + b; + } + +Here's how it looks in llvmpy: + +.. code-block:: python + + #!/usr/bin/env python + + # Import the llvmpy modules. + from llvm import * + from llvm.core import * + + # Create an (empty) module. + my_module = Module.new('my_module') + + # All the types involved here are "int"s. This type is represented + # by an object of the llvm.core.Type class: + ty_int = Type.int() # by default 32 bits + + # We need to represent the class of functions that accept two integers + # and return an integer. This is represented by an object of the + # function type (llvm.core.FunctionType): + ty_func = Type.function(ty_int, [ty_int, ty_int]) + + # Now we need a function named 'sum' of this type. Functions are not + # free-standing (in llvmpy); it needs to be contained in a module. + + f_sum = my_module.add_function(ty_func, "sum") + + # Let's name the function arguments as 'a' and 'b'. + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" + + # Our function needs a "basic block" -- a set of instructions that + # end with a terminator (like return, branch etc.). By convention + # the first block is called "entry". + bb = f_sum.append_basic_block("entry") + + # Let's add instructions into the block. For this, we need an + # instruction builder: + builder = Builder.new(bb) + + # OK, now for the instructions themselves. We'll create an add + # instruction that returns the sum as a value, which we'll use + # a ret instruction to return. + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + builder.ret(tmp) + + # We've completed the definition now! Let's see the LLVM assembly + # language representation of what we've created: + + print my_module + +Here is the output: + +.. code-block:: llvm + + ; ModuleID = 'my_module' + + define i32 @sum(i32 %a, i32 %b) { + entry: + %tmp = add i32 %a, %b ; [#uses=1] + ret i32 %tmp + } + +Adding JIT Compilation +---------------------- + +Let's compile this function in-memory and run it. + +.. code-block:: python + + #!/usr/bin/env python + + # Import the llvmpy modules. + + from llvm import * + from llvm.core import * + from llvm.ee import * # new import: ee = Execution Engine + + #Create a module, as in the previous example. + my_module = Module.new('my_module') + ty_int = Type.int() # by default 32 bits + ty_func = Type.function(ty_int, [ty_int, ty_int]) + f_sum = my_module.add_function(ty_func, "sum") + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" + bb = f_sum.append_basic_block("entry") + builder = Builder.new(bb) + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + builder.ret(tmp) + + # Create an execution engine object. This will create a JIT compiler + # on platforms that support it, or an interpreter otherwise. + ee = ExecutionEngine.new(my_module) + + # The arguments needs to be passed as "GenericValue" objects. + arg1 = GenericValue.int(ty_int, 100) + arg2 = GenericValue.int(ty_int, 42) + + # Now let's compile and run! + retval = ee.run_function(f_sum, [arg1, arg2]) + + # The return value is also GenericValue. Let's print it. + print "returned", retval.as_int() + +And here's the output: + +:: + + returned 142 diff --git a/docs/source/doc/functions.rst b/docs/source/doc/functions.rst new file mode 100644 index 0000000..8922dd0 --- /dev/null +++ b/docs/source/doc/functions.rst @@ -0,0 +1,149 @@ ++--------------------+ +| layout: page | ++--------------------+ +| title: Functions | ++--------------------+ + +Functions are represented by +`llvm.core.Function `_ objects. They are +contained within modules, and can be created either with the method +``module_obj.add_function`` or the static constructor ``Function.new``. +References to functions already present in a module can be retrieved via +``module.get_function_named`` or by the static constructor method +``Function.get``. All functions in a module can be enumerated by +iterating over ``module_obj.functions``. + + +.. code-block:: python + + # create a type, representing functions that take + an integer and return # a floating point value. ft = Type.function( + Type.float(), [ Type.int() ] ) + + # create a function of this type + f1 = module_obj.add_function(ft, "func1") + + # or equivalently, like this: + f2 = Function.new(module_obj, ft, "func2") + + # get a reference to an existing function + f3 = module_obj.get_function_named("func3") + + # or like this: + f4 = Function.get(module_obj, "func4") + + # list all function names in a module + for f in module_obj.functions: print f.name + + + +Intrinsic +========= + +References to intrinsic functions can be got via the static constructor +``intrinsic``. This returns a ``Function`` object, calling which is +equivalent to invoking the intrinsic. The ``intrinsic`` method has to be +called with a module object, an intrinsic ID (which is a numeric +constant) and a list of the types of arguments (which LLVM uses to +resolve overloaded intrinsic functions). + + +.. code-block:: python + + # get a reference to the llvm.bswap intrinsic + bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) + + # call it + builder.call(bswap, [value]) + + + +Here, the constant ``INTR_BSWAP``, available from ``llvm.core``, +represents the LLVM intrinsic +`llvm.bswap `_. The +``[Type.int()]`` selects the version of ``llvm.bswap`` that has a single +32-bit integer argument. The list of intrinsic IDs defined as integer +constants in ``llvm.core``. These are: + +{% include intrinsics.csv %} + +There are also target-specific intrinsics (which correspond to that +target's CPU instructions) available, but are omitted here for brevity. +Full list can be seen from +[*intrinsic\_ids.py](https://github.com/numba/llvmpy/blob/master/llvm/*\ intrinsic\_ids.py). +See the `LLVM Language +Reference `_ for more information +on the intrinsics, and the +`test `_ +directory in the source distribution for more examples. The intrinsic ID +can be retrieved from a function object with the read-only property +``intrinsic_id``. + + **Auto-generation of Intrinsic IDs** + + A script (tool/intrgen.py in source tree) generates the intrinsic + IDs automatically. This is necessary when compiling llvmpy with a + different version of LLVM. + +Calling Convention # {#callconv} +================================ + +The function's calling convention can be set using the +``calling_convention`` property. The following (integer) constants +defined in ``llvm.core`` can be used as values: + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| ``CC_C`` \| ``ccc`` \| +``CC_FASTCALL`` \| ``fastcc`` \| ``CC_COLDCALL`` \| ``coldcc`` \| +``CC_X86_STDCALL`` \| ``x86_stdcallcc`` \| ``CC_X86_FASTCALL`` \| +``x86_fastcallcc`` \| + +See the `LLVM docs `_ +for more information on each. Backend-specific numbered conventions can +be directly passed as integers. + +An arbitrary string identifying which garbage collector to use can be +set or got with the property ``collector``. + +The value objects corresponding to the arguments of a function can be +got using the read-only property ``args``. These can be iterated over, +and also be indexed via integers. An example: + + +.. code-block:: python + + # list all argument names and types for arg in + fn.args: print arg.name, "of type", arg.type + + # change the name of the first argument + fn.args[0].name = "objptr" + + + +Basic blocks (see later) are contained within functions. When newly +created, a function has no basic blocks. They have to be added +explicitly, using the ``append_basic_block`` method, which adds a new, +empty basic block as the last one in the function. The first basic block +of the function can be retrieved using the ``get_entry_basic_block`` +method. The existing basic blocks can be enumerated by iterating over +using the read-only property ``basic_blocks``. The number of basic +blocks can be got via ``basic_block_count`` method. Note that +``get_entry_basic_block`` is slightly faster than ``basic_blocks[0]`` +and so is ``basic_block_count``, over ``len(f.basic_blocks)``. + + +.. code-block:: python + + # add a basic block b1 = + fn.append_basic_block("entry") + + # get the first one + b2 = fn.get_entry_basic_block() b2 = fn.basic_mdblocks[0] # slower + than previous method + + # print names of all basic blocks + for b in fn.basic_blocks: print b.name + + # get number of basic blocks + n = fn.basic_block_count n = len(fn.basic_blocks) # slower than + previous method diff --git a/docs/source/doc/getting_started.rst b/docs/source/doc/getting_started.rst new file mode 100644 index 0000000..53c2982 --- /dev/null +++ b/docs/source/doc/getting_started.rst @@ -0,0 +1,115 @@ + +Introduction +============ + +`LLVM `_ (Low-Level Virtual Machine) provides +enough infrastructure to use it as the backend for your compiled, or +JIT-compiled language. It provides extensive optimization support, and +static and dynamic (JIT) backends for many platforms. See the website at +http://www.llvm.org/ to discover more. + +Python bindings for LLVM provides a gentler learning curve for working +with the LLVM APIs. It should also be easier to create working +prototypes and experimental languages using this medium. + +Together with `clang `_ or +`llvm-gcc `_ +it also a provides a means to quickly instrument C and C++ sources. For e.g., +llvm-gcc can be used to generate the LLVM assembly for a given C source file, +which can then be loaded and manipulated (adding profiling code to every function, +say) using a llvmpy based Python script. + +License +------- + +Both LLVM and llvmpy are distributed under (different) permissive open +source licenses. llvmpy uses the `new BSD +license `_. More +information is available +`here `_. + +Platforms +--------- + +llvmpy has been built/tested/reported to work on various GNU/Linux +flavours, BSD, Mac OS X; on i386 and amd64 architectures. Windows is not +supported, for a variety of reasons. + +Versions +-------- + +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 +earlier versions. + + +Installation +============ + +The Git repo of llvmpy is at https://github.com/llvmpy/llvmpy.git. +You'll need to build and install it before it can be used. At least the +following will be required for this: + +- C and C++ compilers (gcc/g++) +- Python itself +- Python development files (headers and libraries) +- LLVM, either installed or built + +On debian-based systems, the first three can be installed with the +command ``sudo apt-get install gcc g++ python python-dev``. Ensure that +your distro's repository has the appropriate version of LLVM! + +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-config +----------- + +In order to build llvmpy, it's build script needs to know from where it +can invoke the llvm helper program, ``llvm-config``. If you've installed +LLVM, then this will be available in your ``PATH``, and nothing further +needs to be done. If you've built LLVM yourself, or for any reason +``llvm-config`` is not in your ``PATH``, you'll need to pass the full +path of ``llvm-config`` to the build script. + +You'll need to be 'root' to install llvmpy. Remember that your ``PATH`` +is different from that of 'root', so even if ``llvm-config`` is in your +``PATH``, it may not be available when you do ``sudo``. + +Steps +----- + +1. Get and extract LLVM 3.2 source tarball from + `llvm.org `_. Then, ``cd`` into + the extracted directory. + +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. + +3. Run ``REQUIRES_RTTI=1 make`` to build. + + **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/PythonLangImpl1.rst b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst new file mode 100644 index 0000000..ae4b80d --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst @@ -0,0 +1,312 @@ +************************************************* +Chapter 1: Tutorial Introduction and the Lexer +************************************************* + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction +============ + +Welcome to the "Implementing a language with LLVM" tutorial. This +tutorial runs through the implementation of a simple language, showing +how fun and easy it can be. This tutorial will get you up and started as +well as help to build a framework you can extend to other languages. The +code in this tutorial can also be used as a playground to hack on other +LLVM specific things. + +It is useful to point out ahead of time that this tutorial is really +about teaching compiler techniques and LLVM specifically, *not* about +teaching modern and sane software engineering principles. In practice, +this means that we'll take a number of shortcuts to simplify the +exposition. If you dig in and use the code as a basis for future +projects, fixing its deficiencies shouldn't be hard. + +We've tried to put this tutorial together in a way that makes chapters +easy to skip over if you are already familiar with or are uninterested +in the various pieces. The structure of the tutorial is: + +- :ref:`Chapter 1 `: **Introduction to the Kaleidoscope + language, and the definition of its Lexer** -- This shows where we + are going and the basic functionality that we want it to do. In order + to make this tutorial maximally understandable and hackable, we + choose to implement everything in Python instead of using lexer and + parser generators. LLVM obviously works just fine with such tools, + feel free to use one if you prefer. + +- `Chapter 2 `_: **Implementing a Parser and + AST** -- With the lexer in place, we can talk about parsing + techniques and basic AST construction. This tutorial describes + recursive descent parsing and operator precedence parsing. Nothing in + Chapters 1 or 2 is LLVM-specific, the code doesn't even import the + LLVM modules at this point. :) + +- `Chapter 3 `_: **Code generation to LLVM IR** + -- With the AST ready, we can show off how easy generation of LLVM IR + really is. + +- `Chapter 4 `_: **Adding JIT and Optimizer + support** -- Because a lot of people are interested in using LLVM as + a JIT, we'll dive right into it and show you the 3 lines it takes to + add JIT support. LLVM is also useful in many other ways, but this is + one simple and "sexy" way to shows off its power. :) + +- `Chapter 5 `_: **Extending the Language: + Control Flow** -- With the language up and running, we show how to + extend it with control flow operations (if/then/else and a 'for' + loop). This gives us a chance to talk about simple SSA construction + and control flow. + +- `Chapter 6 `_: **Extending the Language: + User-defined Operators** -- This is a silly but fun chapter that + talks about extending the language to let the user program define + their own arbitrary unary and binary operators (with assignable + precedence!). This lets us build a significant piece of the + "language" as library routines. + +- `Chapter 7 `_: **Extending the Language: + Mutable Variables** -- This chapter talks about adding user-defined + local variables along with an assignment operator. The interesting + part about this is how easy and trivial it is to construct SSA form + in LLVM: no, LLVM does *not* require your front-end to construct SSA + form! + +- `Chapter 8 `_: **Conclusion and other useful + LLVM tidbits** -- This chapter wraps up the series by talking about + potential ways to extend the language, but also includes a bunch of + pointers to info about "special topics" like adding garbage + collection support, exceptions, debugging, support for "spaghetti + stacks", and a bunch of other tips and tricks. + +By the end of the tutorial, we'll have written a bit less than 540 lines +of non-comment, non-blank, lines of code. With this small amount of +code, we'll have built up a very reasonable compiler for a non-trivial +language including a hand-written lexer, parser, AST, as well as code +generation support with a JIT compiler. While other systems may have +interesting "hello world" tutorials, I think the breadth of this +tutorial is a great testament to the strengths of LLVM and why you +should consider it if you're interested in language or compiler design. + +A note about this tutorial: we expect you to extend the language and +play with it on your own. Take the code and go crazy hacking away at it, +compilers don't need to be scary creatures - it can be a lot of fun to +play with languages! + +-------------- + +.. _language: + +The Basic Language +================================ + +This tutorial will be illustrated with a toy language that we'll call +"`Kaleidoscope `_\ " (derived +from "meaning beautiful, form, and view"). Kaleidoscope is a procedural +language that allows you to define functions, use conditionals, math, +etc. Over the course of the tutorial, we'll extend Kaleidoscope to +support the if/then/else construct, a for loop, user defined operators, +JIT compilation with a simple command line interface, etc. + +Because we want to keep things simple, the only datatype in Kaleidoscope +is a 64-bit floating point type. As such, all values are implicitly +double precision and the language doesn't require type declarations. +This gives the language a very nice and simple syntax. For example, the +following simple example computes `Fibonacci +numbers `_: + + +.. code-block:: text + + # Compute the x'th fibonacci number. + def fib(x) + if x < 3 + return 1 + else + return fib(x-1)+fib(x-2) + + # This expression will compute the 40th number. + fib(40) + + + +We also allow Kaleidoscope to call into standard library functions (the +LLVM JIT makes this completely trivial). This means that you can use the +'extern' keyword to define a function before you use it (this is also +useful for mutually recursive functions). For example: + + +.. code-block:: python + + extern sin(arg); + extern cos(arg); + extern atan2(arg1 arg2); + + atan2(sin(0.4), cos(42)) + + + +A more interesting example is included in Chapter 6 where we write a +little Kaleidoscope application that +`displays `_ a Mandelbrot Set at various +levels of magnification. + +Lets dive into the implementation of this language! + +-------------- + +The Lexer +==================== + +When it comes to implementing a language, the first thing needed is the +ability to process a text file and recognize what it says. The +traditional way to do this is to use a +`lexer `_ (aka +'scanner') to break the input up into "tokens". Each token returned by +the lexer includes a token type and potentially some metadata (e.g. the +numeric value of a number). First, we define the possibilities: + + +.. code-block:: python + + # The lexer yields one of these types for each token. + class EOFToken(object): pass + + class DefToken(object): pass + + class ExternToken(object): pass + + class IdentifierToken(object): + def __init__(self, name): + self.name = name + + class NumberToken(object): + def __init__(self, value): + self.value = value + + class CharacterToken(object): + def __init__(self, char): + self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): + return not self == other + + +Each token yielded by our lexer will be of one of the above types. For +simple tokens that are always the same, like the "def" keyword, the +lexer will yield ``DefToken()``. Identifiers, numbers and characters, +on the other hand, have extra data, so when the lexer encounteres the +number 123.45, it will emit it as ``NumberToken(123.45)``. An identifier +``foo`` will be emitted as ``IdentifierToken('foo')``. And finally, an +unknown character like '+' will be returned as ``CharacterToken('+')``. +You may notice that we overload the equality and inequality operators +for the characters; this will later simplify character comparisons in +the parser code. + +The actual implementation of the lexer is a single function called +``Tokenize``, which takes a string and +`yields `_ +tokens. For simplicity, we will use `regular +expressions `_ to parse out the +tokens. This is terribly inefficient, but perfectly sufficient for our +needs. + +First, we define the regular expressions for our tokens. Numbers and +strings of digits, optionally followed by a period and another string of +digits. Identifiers (and keywords) are alphanumeric string starting with +a letter and comments are anything between a hash (``#``) and the end of +the line. + + +.. code-block:: python + + import re + + ... + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') + REGEX_COMMENT = re.compile('#.*') + + +Next, let's start defining the ``Tokenize`` function itself. The first +thing we need to do is set up a loop that scans the string, while +ignoring whitespace between tokens: + + +.. code-block:: python + + def Tokenize(string): + while string: # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + + + + +Next we want to find out what the next token is. For this we run the +regexes we defined above on the remainder of the string. To simplify the +rest of the code, we run all three regexes each time. As mentioned +above, inefficiencies are ignored for the purpose of this tutorial: + + +.. code-block:: python + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + +Now we check if any of the regexes matched. For comments, we simply +ignore the captured match: + + +.. code-block:: python + + # Check if any of the regexes matched and yield + # the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + + # For numbers, we yield the captured match, converted to a float and + # tagged with the appropriate token type: + + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + + # The identifier case is a little more complex. We have to check for + # keywords to decide whether we have captured an identifier or a keyword: + + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + + + # Finally, if we haven't recognized a comment, a number of an identifier, + # we yield the current character as an "unknown character" token. This is + # used, for example, for operators like ``+`` or ``*``: + + else: # Yield the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + + # Once we're done with the loop, we return a final end-of-file token: + + + yield EOFToken() + diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst new file mode 100644 index 0000000..a375512 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst @@ -0,0 +1,1079 @@ +*************************************************** +Chapter 2: Implementing a Parser and AST +*************************************************** + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction +======================= + +Welcome to Chapter 2 of the `Implementing a language with +LLVM `_ tutorial. This +chapter shows you how to use the lexer, built in `Chapter +1 `_, to build a full +`parser `_ for our Kaleidoscope +language. Once we have a parser, we'll define and build an `Abstract +Syntax Tree `_ (AST). + +The parser we will build uses a combination of `Recursive Descent +Parsing `_ and +`Operator-Precedence +Parsing `_ to +parse the Kaleidoscope language (the latter for binary expressions and +the former for everything else). Before we get to parsing though, lets +talk about the output of the parser: the Abstract Syntax Tree. + +-------------- + +The Abstract Syntax Tree (AST) +======================================= + +The AST for a program captures its behavior in such a way that it is +easy for later stages of the compiler (e.g. code generation) to +interpret. We basically want one object for each construct in the +language, and the AST should closely model the language. In +Kaleidoscope, we have expressions, a prototype, and a function object. +We'll start with expressions first: + + +.. code-block:: python + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + def __init__(self, value): + self.value = value + + + + + +The code above shows the definition of the base ExpressionNode class and +one subclass which we use for numeric literals. The important thing to +note about this code is that the NumberExpressionNode class captures the +numeric value of the literal as an instance variable. This allows later +phases of the compiler to know what the stored numeric value is. + +Right now we only create the AST, so there are no useful methods on +them. It would be very easy to add a virtual method to pretty print the +code, for example. Here are the other expression AST node definitions +that we'll use in the basic form of the Kaleidoscope language: + + +.. code-block:: python + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + def __init__(self, name): + self.name = name + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + def __init__(self, callee, args): + self.callee = callee + self.args = args + + + +This is all (intentionally) rather straight-forward: variables capture +the variable name, binary operators capture their opcode (e.g. '+'), and +calls capture a function name as well as a list of any argument +expressions. One thing that is nice about our AST is that it captures +the language features without talking about the syntax of the language. +Note that there is no discussion about precedence of binary operators, +lexical structure, etc. + +For our basic language, these are all of the expression nodes we'll +define. Because it doesn't have conditional control flow, it isn't +Turing-complete; we'll fix that in a later installment. The two things +we need next are a way to talk about the interface to a function, and a +way to talk about functions themselves: + + +.. code-block:: python + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + def __init__(self, name, args): + self.name = name + self.args = args + + # This class represents a function definition itself. + class FunctionNode(object): + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + + +In Kaleidoscope, functions are typed with just a count of their +arguments. Since all values are double precision floating point, the +type of each argument doesn't need to be stored anywhere. In a more +aggressive and realistic language, the ``ExpressionNode`` class would +probably have a type field. + +With this scaffolding, we can now talk about parsing expressions and +function bodies in Kaleidoscope. + +-------------- + +Parser Basics +=============================== + +Now that we have an AST to build, we need to define the parser code to +build it. The idea here is that we want to parse something like +``x + y`` (which is returned as three tokens by the lexer) into an AST +that could be generated with calls like this: + + +.. code-block:: python + + x = VariableExpressionNode('x') + y = VariableExpressionNode('y') + result = BinaryOperatorExpressionNode('+', x, y) + + + +In order to do this, we'll start by defining a lightweight ``Parser`` +class with some basic helper routines: + + +.. code-block:: python + + class Parser(object): + + def __init__ (self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + + +This implements a simple token buffer around the lexer. This allows us +to look one token ahead at what the lexer is returning. Every function +in our parser will assume that ``self.current`` is the current token +that needs to be parsed. Note that the first token is read as soon as +the parser is instantiated. Let us ignore the ``binop_precedence`` +parameter for now. It will be explained when we start parsing binary +operators. + +With these basic helper functions, we can implement the first piece of +our grammar: numeric literals. + +-------------- + +Basic Expression Parsing +============================================= + +We start with numeric literals, because they are the simplest to +process. For each production in our grammar, we'll define a function +which parses that production. For numeric literals, we have: + + +.. code-block:: python + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + + +This method is very simple: it expects to be called when the current +token is a ``NumberToken``. It takes the current number value, creates a +``NumberExpressionNode``, advances to the next token, and finally +returns. + +There are some interesting aspects to this. The most important one is +that this routine eats all of the tokens that correspond to the +production and returns the lexer buffer with the next token (which is +not part of the grammar production) ready to go. This is a fairly +standard way to go for recursive descent parsers. For a better example, +the parenthesis operator is defined like this: + + +.. code-block:: python + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + + + + +This function illustrates an interesting aspect of the parser. The +function uses recursion by calling ``ParseExpression`` (we will soon see +that ``ParseExpression`` can call ``ParseParenExpr``). This is powerful +because it allows us to handle recursive grammars, and keeps each +production very simple. Note that parentheses do not cause construction +of AST nodes themselves. While we could do it this way, the most +important role of parentheses are to guide the parser and provide +grouping. Once the parser constructs the AST, parentheses are not +needed. + +The next simple production is for handling variable references and +function calls: + + +.. code-block:: python + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name); + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + + + + +This routine follows the same style as the other routines. It expects to +be called if the current token is an ``IdentifierToken``. It also has +recursion and error handling. One interesting aspect of this is that it +uses *look-ahead* to determine if the current identifier is a stand +alone variable reference or if it is a function call expression. It +handles this by checking to see if the token after the identifier is a +'(' token, constructing either a ``VariableExpressionNode`` or +``CallExpressionNode`` as appropriate. + +Now that we have all of our simple expression-parsing logic in place, we +can define a helper function to wrap it together into one entry point. +We call this class of expressions "primary" expressions, for reasons +that will become more clear `later in the +tutorial `_. In order to parse an arbitrary +primary expression, we need to determine what sort of expression it is: + + +.. code-block:: python + + # primary ::= identifierexpr | numberexpr | parenexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr(); + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + + + +Now that you see the definition of this function, it is more obvious why +we can assume the state of ``Parser.current`` in the various functions. +This uses look-ahead to determine which sort of expression is being +inspected, and then parses it with a function call. + +Now that basic expressions are handled, we need to handle binary +expressions. They are a bit more complex. + +-------------- + +Binary Expression Parsing +=========================================== + +Binary expressions are significantly harder to parse because they are +often ambiguous. For example, when given the string ``x+y*z``, the +parser can choose to parse it as either ``(x+y)*z`` or ``x+(y*z)``. With +common definitions from mathematics, we expect the later parse, because +``*`` (multiplication) has higher *precedence* than ``+`` (addition). + +There are many ways to handle this, but an elegant and efficient way is +to use `Operator-Precedence +Parsing `_. +This parsing technique uses the precedence of binary operators to guide +recursion. To start with, we need a table of precedences. Remember the +``binop_precedence`` parameter we passed to the ``Parser`` constructor? +Now is the time to use it: + + +.. code-block:: python + + def main(): + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main ``interpreter loop``. + while True: + + ... + + parser = Parser(Tokenize(raw), operator_precedence) + + + + + +For the basic form of Kaleidoscope, we will only support 4 binary +operators (this can obviously be extended by you, our brave and intrepid +reader). Having a dictionary makes it easy to add new operators and +makes it clear that the algorithm doesn't depend on the specific +operators involved, but it would be easy enough to eliminate the map and +hardcode the comparisons. + +We also define a helper function to get the precedence of the current +token, or -1 if the token is not a binary operator: + + +.. code-block:: python + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 + + + +With the helper above defined, we can now start parsing binary +expressions. The basic idea of operator precedence parsing is to break +down an expression with potentially ambiguous binary operators into +pieces. Consider, for example, the expression ``a+b+(c+d)*e*f+g``. +Operator precedence parsing considers this as a stream of primary +expressions separated by binary operators. As such, it will first parse +the leading primary expression ``a``, then it will see the pairs +``[+, b] [+, (c+d)] [*, e] [*, f] and [+, g]``. Note that because +parentheses are primary expressions, the binary expression parser +doesn't need to worry about nested subexpressions like (c+d) at all. + +To start, an expression is a primary expression potentially followed by +a sequence of ``[binop,primaryexpr]`` pairs: + + +.. code-block:: python + + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) + + + +``ParseBinOpRHS`` is the function that parses the sequence of pairs for +us. It takes a precedence and a pointer to an expression for the part +that has been parsed so far. Note that ``x`` is a perfectly valid +expression: As such, ``binoprhs`` is allowed to be empty, in which case +it returns the expression that is passed into it. In our example above, +the code passes the expression for ``a`` into ``ParseBinOpRHS`` and the +current token is ``+``. + +The precedence value passed into ``ParseBinOpRHS`` indicates the * +minimal operator precedence * that the function is allowed to eat. For +example, if the current pair stream is ``[+, x]`` and ``ParseBinOpRHS`` +is passed in a precedence of 40, it will not consume any tokens (because +the precedence of '+' is only 20). With this in mind, ``ParseBinOpRHS`` +starts with: + + +.. code-block:: python + + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + + + + +This code gets the precedence of the current token and checks to see if +if is too low. Because we defined invalid tokens to have a precedence of +-1, this check implicitly knows that the pair-stream ends when the token +stream runs out of binary operators. If this check succeeds, we know +that the token is a binary operator and that it will be included in this +expression: + + +.. code-block:: python + + binary_operator = self.current.char + self.Next() # eat the operator. + + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + + + + +As such, this code eats (and remembers) the binary operator and then +parses the primary expression that follows. This builds up the whole +pair, the first of which is ``[+, b]`` for the running example. + +Now that we parsed the left-hand side of an expression and one pair of +the RHS sequence, we have to decide which way the expression associates. +In particular, we could have ``(a+b) binop unparsed`` or +``a + (b binop unparsed)``. To determine this, we look ahead at +``binop`` to determine its precedence and compare it to BinOp's +precedence (which is '+' in this case): + + +.. code-block:: python + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + ... + + + +If the precedence of the binop to the right of ``RHS`` is lower or equal +to the precedence of our current operator, then we know that the +parentheses associate as ``(a+b) binop ...``. In our example, the +current operator is ``+`` and the next operator is ``+``, we know that +they have the same precedence. In this case we'll create the AST node +for ``a+b``, and then continue parsing: + + +.. code-block:: python + + if precedence < next_precedence: + ... if body omitted ... + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right); + + + + + +In our example above, this will turn ``a+b+`` into ``(a+b)`` and execute +the next iteration of the loop, with ``+`` as the current token. The +code above will eat, remember, and parse ``(c+d)`` as the primary +expression, which makes the current pair equal to ``[+, (c+d)]``. It +will then evaluate the 'if' conditional above with ``*`` as the binop to +the right of the primary. In this case, the precedence of ``*`` is +higher than the precedence of ``+`` so the if condition will be entered. + +The critical question left here is +``how can the if condition parse the right hand side in full``? In +particular, to build the AST correctly for our example, it needs to get +all of ``( c + d ) * e * f`` as the RHS expression variable. The code to +do this is surprisingly simple (code from the above two blocks +duplicated for context): + + +.. code-block:: python + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + + + + +At this point, we know that the binary operator to the RHS of our +primary has higher precedence than the binop we are currently parsing. +As such, we know that any sequence of pairs whose operators are all +higher precedence than ``+`` should be parsed together and returned as +``RHS``. To do this, we recursively invoke the ``ParseBinOpRHS`` +function specifying ``precedence + 1`` as the minimum precedence +required for it to continue. In our example above, this will cause it to +return the AST node for ``(c+d)*e*f`` as RHS, which is then set as the +RHS of the '+' expression. + +Finally, on the next iteration of the while loop, the ``+g`` piece is +parsed and added to the AST. With this little bit of code (11 +non-trivial lines), we correctly handle fully general binary expression +parsing in a very elegant way. This was a whirlwind tour of this code, +and it is somewhat subtle. I recommend running through it with a few +tough examples to see how it works. + +This wraps up handling of expressions. At this point, we can point the +parser at an arbitrary token stream and build an expression from it, +stopping at the first token that is not part of the expression. Next up +we need to handle function definitions, etc. + +-------------- + +Parsing the Rest +=============================== + +The next thing missing is handling of function prototypes. In +Kaleidoscope, these are used both for 'extern' function declarations as +well as function body definitions. The code to do this is +straight-forward and not very interesting (once you've survived +expressions): + + +.. code-block:: python + + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + + + + +Given this, a function definition is very simple, just a prototype plus +an expression to implement the body: + + +.. code-block:: python + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + + +In addition, we support 'extern' to declare functions like 'sin' and +'cos' as well as to support forward declaration of user functions. These +'extern's are just prototypes with no body: + + +.. code-block:: python + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + + +Finally, we'll also let the user type in arbitrary top-level expressions +and evaluate them on the fly. We will handle this by defining anonymous +nullary (zero argument) functions for them: + + +.. code-block:: python + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + + +Now that we have all the pieces, let's build a little driver that will +let us actually *execute* this code we've built! + +-------------- + +The Driver +====================== + +The driver for this simply invokes all of the parsing pieces with a +top-level dispatch loop. There isn't much interesting here, so I'll just +include the top-level loop. See :ref:`below ` for full code. + + +.. code-block:: python + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + return + + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + + + + +Here we create a new ``Parser`` for each line read, and try to parse out +all the expressions, declarations and definitions in the line. We also +allow the user to quit using Ctrl+C. + +-------------- + +Conclusions +============================ + +With just under 330 lines of commented code (200 lines of non-comment, +non-blank code), we fully defined our minimal language, including a +lexer, parser, and AST builder. With this done, the executable will +validate Kaleidoscope code and tell us if it is grammatically invalid. +For example, here is a sample interaction: + + +.. code-block:: bash + + $ python kaleidoscope.py + ready> def foo(x y) x+foo(y, 4.0) + Parsed a function definition. + ready> def foo(x y) x+y y + Parsed a function definition. + Parsed a top-level expression. + ready> def foo(x y) x+y ) + Parsed a function definition. + Error: Unknown token when expecting an expression. + ready> extern sin(a); + Parsed an extern. + ready> ^C + $ + + + +There is a lot of room for extension here. You can define new AST nodes, +extend the language in many ways, etc. In the `next +installment `_, we will describe how to generate +LLVM Intermediate Representation (IR) from the AST. + +-------------- + +.. _code: + +Full Code Listing +=========================== + +Here is the complete code listing for this and the previous chapter. +Note that it is fully self-contained: you don't need LLVM or any +external libraries at all for this. + + +.. code-block:: python + + #!/usr/bin/env python + + import re + +Lexer +----- + +.. code-block:: python + + # The lexer yields one of these types for each token. + class EOFToken(object): + pass + + class DefToken(object): + pass + + class ExternToken(object): + pass + + class IdentifierToken(object): + def __init__(self, name): + self.name = name + + class NumberToken(object): + def __init__(self, value): + self.value = value + + class CharacterToken(object): + def __init__(self, char): + self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): + return not self == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') + REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +.. code-block:: python + + # Base class for all expression nodes. + class ExpressionNode(object): + pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + def __init__(self, value): + self.value = value + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + def __init__(self, name): + self.name = name + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + def __init__(self, callee, args): + self.callee = callee + self.args = args + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + def __init__(self, name, args): + self.name = name + self.args = args + + # This class represents a function definition itself. + class FunctionNode(object): + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + + +Parser +------ + +.. code-block:: python + + class Parser(object): + + def __init__(self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr | numberexpr | parenexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Parsed a function definition.') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Parsed an extern.') + + def HandleTopLevelExpression(self): + self.Handle(self.ParseTopLevelExpr, 'Parsed a top-level expression.') + + def Handle(self, function, message): + try: + function() + print message + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + + + +Main driver code. +----------------- + +.. code-block:: python + + def main(): + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + return + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + if __name__ == '__main__': + main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst new file mode 100644 index 0000000..15ec212 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst @@ -0,0 +1,1087 @@ +******************************************* +Chapter 3: Code generation to LLVM IR +******************************************* + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction +======================= + +Welcome to Chapter 3 of the `Implementing a language with +LLVM `_ tutorial. This +chapter shows you how to transform the `Abstract Syntax +Tree `_, built in Chapter 2, into LLVM IR. This +will teach you a little bit about how LLVM does things, as well as +demonstrate how easy it is to use. It's much more work to build a lexer +and parser than it is to generate LLVM IR code. :) + +**Please note**: the code in this chapter and later requires llvmpy 0.6 +and LLVM 2.7. Earlier versions will most likely not work with it. Also +note that you need to use a version of this tutorial that matches your +llvmpy release: If you are using an official llvmpy release, use the +version of the documentation on the `llvmpy examples +page `_ + +-------------- + +Code Generation Setup +================================= + +In order to generate LLVM IR, we want some simple setup to get started. +First we define code generation methods in each AST node class: + + +.. code-block:: python + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + ... + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + ... + + ... + + + + + +The ``CodeGen`` method says to emit IR for that AST node along with all +the things it depends on, and they all return an LLVM Value object. +"Value" is the class used to represent a "`Static Single Assignment +(SSA) `_ +register" or "SSA value" in LLVM. The most distinct aspect of SSA values +is that their value is computed as the related instruction executes, and +it does not get a new value until (and if) the instruction re-executes. +In other words, there is no way to "change" an SSA value. For more +information, please read up on `Static Single +Assignment `_ +- the concepts are really quite natural once you grok them. + +We will also need to define some global variables which we will be used +during code generation: + + +.. code-block:: python + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + + + + +``g_llvm_module`` is the LLVM construct that contains all of the +functions and global variables in a chunk of code. In many ways, it is +the top-level structure that the LLVM IR uses to contain code. + +``g_llvm_builder`` is a helper object that makes it easy to generate +LLVM instructions. Instances of the +`llvm.core.Builder `_ class keep track of the +current place to insert instructions and have methods to create new +instructions. Note that we do not initialize this variable; instead, it +will be initialized whenever we start generating code for a function. + +Finally, ``g_named_values`` is a dictionary that keeps track of which +values are defined in the current scope and what their LLVM +representation is. In other words, it is a symbol table for the code. In +this form of Kaleidoscope, the only things that can be referenced are +function parameters. As such, function parameters will be in this map +when generating code for their function body. + +With these basics in place, we can start talking about how to generate +code for each expression. Note that this assumes that ``g_llvm_builder`` +has been set up to generate code *into* something. For now, we'll assume +that this has already been done, and we'll just use it to emit code. + +-------------- + +Expression Code Generation +===================================== + +Generating LLVM code for expression nodes is very straightforward: less +than 35 lines of commented code for all four of our expression nodes. +First we'll do numeric literals: + + +.. code-block:: python + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + + + + + +In llvmpy, floating point numeric constants are represented with the +``llvm.core.ConstantFP`` class. To create one, we can use the static +``real()`` method in the ``llvm.core.Constant`` class. This code +basically just creates and returns a ``ConstantFP``. Note that in the +LLVM IR constants are all uniqued together and shared. For this reason, +we create the constant through a factory method instead of instantiating +one directly. + + +.. code-block:: python + + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) + + + +References to variables are also quite simple using LLVM. In the simple +version of Kaleidoscope, we assume that the variable has already been +emitted somewhere and its value is available. In practice, the only +values that can be in the ``g_named_values`` dictionary are function +arguments. This code simply checks to see that the specified name is in +the map (if not, an unknown variable is being referenced) and returns +the value for it. In future chapters, we'll add support for `loop +induction variables `_ in the symbol table, +and for `local variables `_. + + +.. code-block:: python + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + + + + +Binary operators start to get more interesting. The basic idea here is +that we recursively emit code for the left-hand side of the expression, +then the right-hand side, then we compute the result of the binary +expression depending on which operator is being used. + +In the example above, the LLVM builder class is starting to show its +value. ``g_llvm_builder`` knows where to insert the newly created +instruction, all you have to do is specify what instruction to create +(e.g. with ``add``), which operands to use (``left`` and ``right`` here) +and optionally provide a name for the generated instruction. + +One nice thing about LLVM is that the name is just a hint. For instance, +if the code above emits multiple "addtmp" variables, LLVM will +automatically provide each one with an increasing, unique numeric +suffix. Local value names for instructions are purely optional, but it +makes it much easier to read the IR dumps. + +`LLVM instructions `_ are +constrained by strict rules: for example, the Left and Right operators +of an `add instruction `_ +must have the same type, and the result type of the add must match the +operand types. Because all values in Kaleidoscope are doubles, this +makes for very simple code for add, sub and mul. + +On the other hand, LLVM specifies that the `fcmp +instruction `_ always +returns an 'i1' value (a one bit integer). The problem with this is that +Kaleidoscope wants the value to be a 0.0 or 1.0 value. In order to get +these semantics, we combine the fcmp instruction with a `uitofp +instruction `_. This +instruction converts its input integer into a floating point value by +treating the input as an unsigned value. In contrast, if we used the +`sitofp instruction `_, +the Kaleidoscope ``<`` operator would return 0.0 and -1.0, depending on +the input value. + + +.. code-block:: python + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + + + + +Code generation for function calls is quite straightforward with LLVM. +The code above initially does a function name lookup in the LLVM +Module's symbol table. Recall that the LLVM Module is the container that +holds all of the functions we are JIT'ing. By giving each function the +same name as what the user specifies, we can use the LLVM symbol table +to resolve function names for us. + +Once we have the function to call, we codegen each argument that is to +be passed in, and create an LLVM `call +instruction `_. Note that +LLVM uses the native C calling conventions by default, allowing these +calls to also call into standard library functions like "sin" and "cos", +with no additional effort. + +This wraps up our handling of the four basic expressions that we have so +far in Kaleidoscope. Feel free to go in and add some more. For example, +by browsing the `LLVM language +reference `_ you'll find several +other interesting instructions that are really easy to plug into our +basic framework. + +-------------- + +Function Code Generation +=================================== + +Code generation for prototypes and functions must handle a number of +details, which make their code less beautiful than expression code +generation, but allows us to illustrate some important points. First, +let's talk about code generation for prototypes: they are used both for +function bodies and external function declarations. The code starts +with: + + +.. code-block:: python + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + + + + +The call to ``Type.function`` creates the ``FunctionType`` that should +be used for a given Prototype. Since all function arguments in +Kaleidoscope are of type double, the first line creates a list of "N" +LLVM double types. It then uses the ``Type.function`` method to create a +function type that takes "N" doubles as arguments, returns one double as +a result, and that is not vararg (the False parameter indicates this). +Note that Types in LLVM are uniqued just like Constants are, so you +don't instantiate them directly. + +The final line above actually creates the function that the prototype +will correspond to. This indicates the type and name to use, as well as +which module to insert into. Note that by default, the function will +have `external +linkage `_, which means +that the function may be defined outside the current module and/or that +it is callable by functions outside the module. The name passed in is +the name the user specified: since ``g_llvm_module`` is specified, this +name is registered in ``g_llvm_module``'s symbol table, which is used by +the function call code above. + + +.. code-block:: python + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + + +The Module symbol table works just like the Function symbol table when +it comes to name conflicts: if a new function is created with a name was +previously added to the symbol table, it will get implicitly renamed +when added to the Module. The code above exploits this fact to determine +if there was a previous definition of this function. + +In Kaleidoscope, we choose to allow redefinitions of functions in two +cases: first, we want to allow 'extern'ing a function more than once, as +long as the prototypes for the externs match (since all arguments have +the same type, we just have to check that the number of arguments +match). Second, we want to allow 'extern'ing a function and then +defining a body for it. This is useful when defining mutually recursive +functions. + +In order to implement this, the code above first checks to see if there +is a collision on the name of the function. If so, it deletes the +function we just created (by calling ``delete``) and then calling +``get_function_named`` to get the existing function with the specified +name. + + +.. code-block:: python + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + + + + +In order to verify the logic above, we first check to see if the +pre-existing function is a forward declaration. Since we don't allow +anything after a full definition of the function, the code rejects this +case. If the previous reference to a function was an 'extern', we simply +verify that the number of arguments for that definition and this one +match up. If not, we emit an error. + + +.. code-block:: python + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol + table. g_named_values[arg_name] = arg + + return function + + + + + +The last bit of code for prototypes loops over all of the arguments in +the function, setting the name of the LLVM Argument objects to match, +and registering the arguments in the ``g_named_values`` map for future +use by the ``VariableExpressionNode``. Note that we don't check for +conflicting argument names here (e.g. "extern foo(a b a)"). Doing so +would be very straight-forward with the mechanics we have already used +above. Once this is all set up, it returns the Function object to the +caller. + + +.. code-block:: python + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + + + + +Code generation for function definitions starts out simply enough: we +just clear out the ``g_named_values`` dictionary to make sure that there +isn't anything in it from the last function we compiled and codegen the +prototype. Code generation of the prototype ensures that there is an +LLVM Function object that is ready to go for us. + + +.. code-block:: python + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + + + + +Now we get to the point where ``g_llvm_builder`` is set up. The first +line creates a new `basic +block `_ (named "entry"), +which is inserted into the function. The second line declares that the +global ``g_llvm_builder`` object is to be changed. The last line creates +a new builder that is set up to insert new instructions into the basic +block we just created. Basic blocks in LLVM are an important part of +functions that define the `Control Flow +Graph `_. Since we +don't have any control flow, our functions will only contain one block +at this point. We'll fix this in `Chapter 5 `_ :). + +.. code-block:: python + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + + + +Once the insertion point is set up, we call the ``CodeGen`` method for +the root expression of the function. If no error happens, this emits +code to compute the expression into the entry block and returns the +value that was computed. Assuming no error, we then create an LLVM `ret +instruction `_, which +completes the function. Once the function is built, we call ``verify``, +which is provided by LLVM. This function does a variety of consistency +checks on the generated code, to determine if our compiler is doing +everything right. Using this is important: it can catch a lot of bugs. +Once the function is finished and validated, we return it. + + +.. code-block:: python + + except: + function.delete() + raise + + return function + + + + + +The only piece left here is handling of the error case. For simplicity, +we handle this by merely deleting the function we produced with the +``delete`` method. This allows the user to redefine a function that they +incorrectly typed in before: if we didn't delete it, it would live in +the symbol table, with a body, preventing future redefinition. + +This code does have a bug, though. Since the ``PrototypeNode::CodeGen`` +can return a previously defined forward declaration, our code can +actually delete a forward declaration. There are a number of ways to fix +this bug; see what you can come up with! Here is a testcase: + + +.. code-block:: python + + extern foo(a b) # ok, defines foo. + def foo(a b) c # error, 'c' is invalid. + def bar() foo(1, 2) # error, unknown function "foo" + + + +-------------- + +Driver Changes and Closing Thoughts +=============================================== + +For now, code generation to LLVM doesn't really get us much, except that +we can look at the pretty IR calls. The sample code inserts calls to +CodeGen into the ``Handle*`` functions, and then dumps out the LLVM IR. +This gives a nice way to look at the LLVM IR for simple functions. For +example: + + +.. code-block:: bash + + ready> 4+5 + Read a top-level expression: + define double @0() { + entry: + ret double 9.000000e+00 + } + + + +Note how the parser turns the top-level expression into anonymous +functions for us. This will be handy when we add JIT support in the next +chapter. Also note that the code is very literally transcribed, no +optimizations are being performed except simple constant folding done by +the Builder. We will add optimizations explicitly in the next chapter. + + +.. code-block:: bash + + ready> def foo(a b) a *a + 2* a *b + b* b + Read a function definition: + define double @foo(double %a, double %b) { + entry: + %multmp = fmul double %a, %a ; [#uses=1] + %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] + %multmp2 = fmul double %multmp1, %b ; [#uses=1] + %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] + %multmp3 = fmul double %b, %b ; [#uses=1] + %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] + ret double %addtmp4 + } + + + +This shows some simple arithmetic. Notice the striking similarity to the +LLVM builder calls that we use to create the instructions. + + +.. code-block:: bash + + ready> def bar(a) foo(a, 4.0) + bar(31337) + Read a function definition: + define double @bar(double %a) { + entry: + %calltmp = call double @foo(double %a, double 4.000000e+00) ; [#uses=1] + %calltmp1 = call double @bar(double 3.133700e+04) ; [#uses=1] + %addtmp = fadd double %calltmp, %calltmp1 ; [#uses=1] + ret double %addtmp + } + + + +This shows some function calls. Note that this function will take a long +time to execute if you call it. In the future we'll add conditional +control flow to actually make recursion useful :). + + +.. code-block:: bash + + ready> extern cos(x) + Read extern: + declare double @cos(double) + + ready> cos(1.234) + Read a top-level expression: + define double @1() { + entry: + %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] + ret double %calltmp + } + + + +This shows an extern for the libm "cos" function, and a call to it. + + +.. code-block:: bash + + ready> ^C + ; ModuleID = 'my cool jit' + + define double @0() { + entry: + ret double 9.000000e+00 + } + + define double @foo(double %a, double %b) { + entry: + %multmp = fmul double %a, %a ; [#uses=1] + %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] + %multmp2 = fmul double %multmp1, %b ; [#uses=1] + %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] + %multmp3 = fmul double %b, %b ; [#uses=1] + %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] + ret double %addtmp4 + } + + define double @bar(double %a) { + entry: + %calltmp = call double @foo(double %a, double 4.000000e+00) ; [#uses=1] + %calltmp1 = call double @bar(double 3.133700e+04) ; [#uses=1] + %addtmp = fadd double %calltmp, %calltmp1 ; [#uses=1] + ret double %addtmp + } + + declare double @cos(double) + + define double @1() { + entry: + %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] + ret double %calltmp + } + + + +When you quit the current demo, it dumps out the IR for the entire +module generated. Here you can see the big picture with all the +functions referencing each other. + +This wraps up the third chapter of the Kaleidoscope tutorial. Up next, +we'll describe how to `add JIT codegen and optimizer +support `_ to this so we can actually start +running code! + +-------------- + +Full Code Listing +=========================== + +Here is the complete code listing for our running example, enhanced with +the LLVM code generator. Because this uses the llvmpy libraries, you +need to `download <../download.html>`_ and +`install <../userguide.html#install>`_ them. + + +.. code-block:: python + + #!/usr/bin/env python + + import re + from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT + +Globals +------- + +.. code-block:: python + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + +Lexer +----- + +.. code-block:: python + + # The lexer yields one of these types for each token. + class EOFToken(object): + pass + + class DefToken(object): + pass + + class ExternToken(object): + pass + + class IdentifierToken(object): + def __init__(self, name): + self.name = name + + class NumberToken(object): + def __init__(self, value): + self.value = value + + class CharacterToken(object): + def __init__(self, char): + self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken)and self.char == other.char + def __ne__(self, other): + return not self == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') + REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +.. code-block:: python + + # Base class for all expression nodes. + class ExpressionNode(object): + pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + + def __init__(self, name, args): + self.name = name + self.args = args + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + except: + function.delete() + raise + + return function + +Parser +------ + +.. code-block:: python + + class Parser(object): + + def __init__(self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr | numberexpr | parenexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + self.Handle(self.ParseTopLevelExpr, 'Read a top-level expression:') + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +Main driver code. +----------------- + +.. code-block:: python + + def main(): + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. + print '\n', g_llvm_module + + if __name__ == '__main__': + main() \ No newline at end of file diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl4.rst b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst new file mode 100644 index 0000000..7ac3d97 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst @@ -0,0 +1,936 @@ +************************************************* +Chapter 4: Adding JIT and Optimizer Support +************************************************* + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction +======================= + +Welcome to Chapter 4 of the `Implementing a language with +LLVM `_ tutorial. Chapters +1-3 described the implementation of a simple language and added support +for generating LLVM IR. This chapter describes two new techniques: +adding optimizer support to your language, and adding JIT compiler +support. These additions will demonstrate how to get nice, efficient +code for the Kaleidoscope language. + +-------------- + +Trivial Constant Folding +============================================== + +Our demonstration for Chapter 3 is elegant and easy to extend. +Unfortunately, it does not produce wonderful code. The LLVM Builder, +however, does give us obvious optimizations when compiling simple code: + + +.. code-block:: bash + + ready> def test(x) 1+2+x + Read function definition: + define double @test(double %x) { + entry: + %addtmp = fadd double 3.000000e+00, %x + ret double %addtmp + } + + + +This code is not a literal transcription of the AST built by parsing the +input. That would be: + + +.. code-block:: bash + + ready> def test(x) 1+2+x + Read function definition: + define double @test(double %x) { + entry: + %addtmp = fadd double 2.000000e+00, 1.000000e+00 + %addtmp1 = fadd double %addtmp, %x + ret double %addtmp1 + } + + + +Constant folding, as seen above, in particular, is a very common and +very important optimization: so much so that many language implementors +implement constant folding support in their AST representation. + +With LLVM, you don't need this support in the AST. Since all calls to +build LLVM IR go through the LLVM IR builder, the builder itself checked +to see if there was a constant folding opportunity when you call it. If +so, it just does the constant fold and return the constant instead of +creating an instruction. + +Well, that was easy :). In practice, we recommend always using +``llvm.core.Builder`` when generating code like this. It has no +"syntactic overhead" for its use (you don't have to uglify your compiler +with constant checks everywhere) and it can dramatically reduce the +amount of LLVM IR that is generated in some cases (particular for +languages with a macro preprocessor or that use a lot of constants). + +On the other hand, the ``Builder`` is limited by the fact that it does +all of its analysis inline with the code as it is built. If you take a +slightly more complex example: + + +.. code-block:: bash + + ready> def test(x) (1+2+x)*(x+(1+2)) + Read a function definition: + define double @test(double %x) { + entry: + %addtmp = fadd double 3.000000e+00, %x ; [#uses=1] + %addtmp1 = fadd double %x, 3.000000e+00 ; [#uses=1] + %multmp = fmul double %addtmp, %addtmp1 ; [#uses=1] + ret double %multmp + } + + + +In this case, the LHS and RHS of the multiplication are the same value. +We'd really like to see this generate"``tmp = x+3; result = tmp*tmp;`` +instead of computing ``x+3`` twice. + +Unfortunately, no amount of local analysis will be able to detect and +correct this. This requires two transformations: reassociation of +expressions (to make the add's lexically identical) and Common +Subexpression Elimination (CSE) to delete the redundant add instruction. +Fortunately, LLVM provides a broad range of optimizations that you can +use, in the form of "passes". + +-------------- + +LLVM Optimization Passes +============================================= + +LLVM provides many optimization passes, which do many different sorts of +things and have different tradeoffs. Unlike other systems, LLVM doesn't +hold to the mistaken notion that one set of optimizations is right for +all languages and for all situations. LLVM allows a compiler implementor +to make complete decisions about what optimizations to use, in which +order, and in what situation. + +As a concrete example, LLVM supports both "whole module" passes, which +look across as large of body of code as they can (often a whole file, +but if run at link time, this can be a substantial portion of the whole +program). It also supports and includes "per-function" passes which just +operate on a single function at a time, without looking at other +functions. For more information on passes and how they are run, see the +`How to Write a Pass `_ +document and the `List of LLVM +Passes `_. + +For Kaleidoscope, we are currently generating functions on the fly, one +at a time, as the user types them in. We aren't shooting for the +ultimate optimization experience in this setting, but we also want to +catch the easy and quick stuff where possible. As such, we will choose +to run a few per-function optimizations as the user types the function +in. If we wanted to make a "static Kaleidoscope compiler", we would use +exactly the code we have now, except that we would defer running the +optimizer until the entire file has been parsed. + +In order to get per-function optimizations going, we need to set up a +`FunctionPassManager `_ +to hold and organize the LLVM optimizations that we want to run. Once we +have that, we can add a set of optimizations to run. The code looks like +this: + + +.. code-block:: python + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + ... + + def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + + +This code defines a ``FunctionPassManager``, ``g_llvm_pass_manager``. +Once it is set up, we use a series of "add" calls to add a bunch of LLVM +passes. The first pass is basically boilerplate, it adds a pass so that +later optimizations know how the data structures in the program are laid +out. (The "``g_llvm_executor``\ " variable is related to the JIT, which +we will get to in the next section.) In this case, we choose to add 4 +optimization passes. The passes we chose here are a pretty standard set +of "cleanup" optimizations that are useful for a wide variety of code. I +won't delve into what they do but, believe me, they are a good starting +place :). + +Once the pass manager is set up, we need to make use of it. We do this +by running it after our newly created function is constructed (in +``FunctionNode.CodeGen``), but before it is returned to the client: + + +.. code-block:: python + + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + + + + + +As you can see, this is pretty straightforward. The +``FunctionPassManager`` optimizes and updates the LLVM Function in +place, improving (hopefully) its body. With this in place, we can try +our test above again: + + +.. code-block:: bash + + ready> def test(x) (1+2+x)*(x+(1+2)) + Read a function definition: + define double @test(double %x) { + entry: + %addtmp = fadd double %x, 3.000000e+00 ; [#uses=2] + %multmp = fmul double %addtmp, %addtmp ; [#uses=1] + ret double %multmp + } + + + +As expected, we now get our nicely optimized code, saving a floating +point add instruction from every execution of this function. + +LLVM provides a wide variety of optimizations that can be used in +certain circumstances. Some `documentation about the various +passes `_ is available, but it +isn't very complete. Another good source of ideas can come from looking +at the passes that ``llvm-gcc`` or ``llvm-ld`` run to get started. The +``opt`` tool allows you to experiment with passes from the command line, +so you can see if they do anything. + +Now that we have reasonable code coming out of our front-end, lets talk +about executing it! + +-------------- + +Adding a JIT Compiler +============================== + +Code that is available in LLVM IR can have a wide variety of tools +applied to it. For example, you can run optimizations on it (as we did +above), you can dump it out in textual or binary forms, you can compile +the code to an assembly file (.s) for some target, or you can JIT +compile it. The nice thing about the LLVM IR representation is that it +is the "common currency" between many different parts of the compiler. + +In this section, we'll add JIT compiler support to our interpreter. The +basic idea that we want for Kaleidoscope is to have the user enter +function bodies as they do now, but immediately evaluate the top-level +expressions they type in. For example, if they type in "1 + 2", we +should evaluate and print out 3. If they define a function, they should +be able to call it from the command line. + +In order to do this, we first declare and initialize the JIT. This is +done by adding and initializing a global variable: + + +.. code-block:: python + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + + +This creates an abstract "Execution Engine" which can be either a JIT +compiler or the LLVM interpreter. LLVM will automatically pick a JIT +compiler for you if one is available for your platform, otherwise it +will fall back to the interpreter. + +Once the ``ExecutionEngine`` is created, the JIT is ready to be used. We +can use the ``run_function`` method of the execution engine to execute a +compiled function and get its return value. In our case, this means that +we can change the code that parses a top-level expression to look like +this: + + +.. code-block:: python + + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +Recall that we compile top-level expressions into a self-contained LLVM +function that takes no arguments and returns the computed double. + +With just these two changes, lets see how Kaleidoscope works now! + +.. code-block:: bash + + ready> 4+5 + Read a top level expression: + define double @0() { + entry: + ret double 9.000000e+00 + } + + Evaluated to: 9.0 + + + +Well this looks like it is basically working. The dump of the function +shows the "no argument function that always returns double" that we +synthesize for each top-level expression that is typed in. This +demonstrates very basic functionality, but can we do more? + + +.. code-block:: bash + + ready> def testfunc(x y) x + y*2 + Read a function definition: + define double @testfunc(double %x, double %y) { + entry: + %multmp = fmul double %y, 2.000000e+00 ; [#uses=1] + %addtmp = fadd double %multmp, %x ; [#uses=1] + ret double %addtmp + } + + ready> testfunc(4, 10) + Read a top level expression: + define double @0() { + entry: + %calltmp = call double @testfunc(double 4.000000e+00, double 1.000000e+01) ; [#uses=1] + ret double %calltmp + } + + *Evaluated to: 24.0* + + + +This illustrates that we can now call user code, but there is something +a bit subtle going on here. Note that we only invoke the JIT on the +anonymous functions that *call testfunc*, but we never invoked it on +*testfunc* itself. What actually happened here is that the JIT scanned +for all non-JIT'd functions transitively called from the anonymous +function and compiled all of them before returning from +``run_function()``. + +The JIT provides a number of other more advanced interfaces for things +like freeing allocated machine code, rejit'ing functions to update them, +etc. However, even with this simple code, we get some surprisingly +powerful capabilities - check this out (I removed the dump of the +anonymous functions, you should get the idea by now :) : + + +.. code-block:: bash + + ready> extern sin(x) + Read an extern: + declare double @sin(double) + + ready> extern cos(x) + Read an extern: + declare double @cos(double) + + ready> sin(1.0) + *Evaluated to: 0.841470984808* + + ready> def foo(x) sin(x) *sin(x) + cos(x)* cos(x) + Read a function definition: + define double @foo(double %x) { + entry: + %calltmp = call double @sin(double %x) ; [#uses=1] + %calltmp1 = call double @sin(double %x) ; [#uses=1] + %multmp = fmul double %calltmp, %calltmp1 ; [#uses=1] + %calltmp2 = call double @cos(double %x) ; [#uses=1] + %calltmp3 = call double @cos(double %x) ; [#uses=1] + %multmp4 = fmul double %calltmp2, %calltmp3 ; [#uses=1] + %addtmp = fadd double %multmp, %multmp4 ; [#uses=1] + ret double %addtmp + } + + ready> foo(4.0) + *Evaluated to: 1.000000* + + + +Whoa, how does the JIT know about sin and cos? The answer is +surprisingly simple: in this example, the JIT started execution of a +function and got to a function call. It realized that the function was +not yet JIT compiled and invoked the standard set of routines to resolve +the function. In this case, there is no body defined for the function, +so the JIT ended up calling ``dlsym("sin")`` on the Python process that +is hosting our Kaleidoscope prompt. Since ``sin`` is defined within the +JIT's address space, it simply patches up calls in the module to call +the libm version of ``sin`` directly. + +One interesting application of this is that we can now extend the +language by writing arbitrary C++ code to implement operations. For +example, we can create a C file with the following simple function: + + +.. code-block:: c + + #include + + double putchard(double x) { + putchar((char)x); return 0; + } + +We can then compile this into a shared library with GCC:: + + gcc -shared -fPIC -o putchard.so putchard.c + + +Now we can load this library into the Python process using +``llvm.core.load_library_permanently`` and access it from Kaleidoscope +to produce simple output to the console:: + + >>> import llvm.core + >>> llvm.core.load_library_permanently('/home/max/llvmpy-tutorial/putchard.so') + >>> import kaleidoscope + >>> kaleidoscope.main() + ready> extern putchard(x) + Read an extern: + declare double @putchard(double) + + ready> putchard(65) + putchard(66) + putchard(67) + putchard(10) + *ABC* + Evaluated to: 0.0 + + + +Similar code could be used to implement file I/O, console input, and +many other capabilities in Kaleidoscope. + +This completes the JIT and optimizer chapter of the Kaleidoscope +tutorial. At this point, we can compile a non-Turing-complete +programming language, optimize and JIT compile it in a user-driven way. +Next up we'll look into `extending the language with control flow +constructs `_, tackling some interesting LLVM IR +issues along the way. + +-------------- + +Full Code Listing +=========================== + +Here is the complete code listing for our running example, enhanced with +the LLVM JIT and optimizer: + + +.. code-block:: python + + #!/usr/bin/env python + + import re + from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT + from llvm.ee import ExecutionEngine, TargetData + from llvm.passes import FunctionPassManager + from llvm.passes import (PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) + +Globals +------- + +.. code-block:: python + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + +Lexer +----- + +.. code-block:: python + + # The lexer yields one of these types for each token. + class EOFToken(object): + pass + + class DefToken(object): + pass + + class ExternToken(object): + pass + + class IdentifierToken(object): + def __init__(self, name): + self.name = name + + class NumberToken(object): + def __init__(self, value): + self.value = value + + class CharacterToken(object): + def __init__(self, char): + self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): + return not self == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') + REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +.. code-block:: python + + # Base class for all expression nodes. + class ExpressionNode(object): + pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + + def __init__(self, name, args): + self.name = name + self.args = args + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + +Parser +------ + +.. code-block:: python + + class Parser(object): + + def __init__(self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr | numberexpr | parenexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +Main driver code. +----------------- + +.. code-block:: python + + def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. + print '', g_llvm_module + + if __name__ == '__main__': + main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl5.rst b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst new file mode 100644 index 0000000..33edba2 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst @@ -0,0 +1,1549 @@ +***************************************************** +Chapter 5: Extending the Language: Control Flow +***************************************************** + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction +======================= + +Welcome to Chapter 5 of the `Implementing a language with +LLVM `_ tutorial. Parts +1-4 described the implementation of the simple Kaleidoscope language and +included support for generating LLVM IR, followed by optimizations and a +JIT compiler. Unfortunately, as presented, Kaleidoscope is mostly +useless: it has no control flow other than call and return. This means +that you can't have conditional branches in the code, significantly +limiting its power. In this episode of "build that compiler", we'll +extend Kaleidoscope to have an if/then/else expression plus a simple +'for' loop. + +-------------- + +If/Then/Else +======================== + +Extending Kaleidoscope to support if/then/else is quite straightforward. +It basically requires adding lexer support for this "new" concept to the +lexer, parser, AST, and LLVM code emitter. This example is nice, because +it shows how easy it is to "grow" a language over time, incrementally +extending it as new ideas are discovered. + +Before we get going on "how" we add this extension, lets talk about +"what" we want. The basic idea is that we want to be able to write this +sort of thing: + + +.. code-block:: python + + def fib(x) + if x < 3 then + 1 + else + fib(x-1) + fib(x-2) + + + +In Kaleidoscope, every construct is an expression: there are no +statements. As such, the if/then/else expression needs to return a value +like any other. Since we're using a mostly functional form, we'll have +it evaluate its conditional, then return the 'then' or 'else' value +based on how the condition was resolved. This is very similar to the C +"?:" expression. + +The semantics of the if/then/else expression is that it evaluates the +condition to a boolean equality value: 0.0 is considered to be false and +everything else is considered to be true. If the condition is true, the +first subexpression is evaluated and returned, if the condition is +false, the second subexpression is evaluated and returned. Since +Kaleidoscope allows side-effects, this behavior is important to nail +down. + +Now that we know what we "want", let's break this down into its +constituent pieces. + +Lexer Extensions for If/Then/Else +----------------------------------------------- + +The lexer extensions are straightforward. First we add new token classes +for the relevant tokens: + + +.. code-block:: python + + class IfToken(object): + pass + class ThenToken(object): + pass + class ElseToken(object): + pass + + + +Once we have that, we recognize the new keywords in the lexer. This is +pretty simple stuff: + + +.. code-block:: python + + ... + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + else: + yield IdentifierToken(identifier) + + + +AST Extensions for If/Then/Else +------------------------------------------- + +To represent the new expression we add a new AST node for it: + + +.. code-block:: python + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def __init__(self, condition, then_branch, else_branch): + self.condition = condition + self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): + ... + + + +The AST node just has pointers to the various subexpressions. + +Parser Extensions for If/Then/Else +------------------------------------------------- + +Now that we have the relevant tokens coming from the lexer and we have +the AST node to build, our parsing logic is relatively straightforward. +First we define a new parsing function: + + +.. code-block:: python + + # ifexpr ::= 'if' expression 'then' expression 'else' expression + def ParseIfExpr(self): + self.Next() # eat the if. + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + + + + +Next we hook it up as a primary expression: + + +.. code-block:: python + + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr(); + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + + +LLVM IR for If/Then/Else +----------------------------------- + +Now that we have it parsing and building the AST, the final piece is +adding LLVM code generation support. This is the most interesting part +of the if/then/else example, because this is where it starts to +introduce new concepts. All of the code above has been thoroughly +described in previous chapters. + +To motivate the code we want to produce, lets take a look at a simple +example. Consider: + + +.. code-block:: python + + extern foo(); + extern bar(); + def baz(x) if x then foo() else bar(); + + + +If you disable optimizations, the code you'll (soon) get from +Kaleidoscope looks something like this: + + +.. code-block:: llvm + + declare double @foo() + + declare double @bar() + + define double @baz(double %x) { + entry: + %ifcond = fcmp one double %x, 0.000000e+00 + br i1 %ifcond, label %then, label %else + + then: ; preds = %entry + %calltmp = call double @foo() + br label %ifcont + + else: ; preds = %entry + %calltmp1 = call double @bar() + br label %ifcont + + ifcont: ; preds = %else, %then + %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ] + ret double %iftmp + } + + + +To visualize the control flow graph, you can use a nifty feature of the +LLVM `opt `_ tool. If you put this LLVM +IR into "t.ll" and run ``llvm-as < t.ll | opt -analyze -view-cfg``, a +`window will pop +up `_ and +you'll see this graph: + +Another way to get this is to call "``function.viewCFG()``\ " or +"``function.viewCFGOnly()``\ " (where F is a "``llvm.core.Function``\ ") +either by inserting actual calls into the code and recompiling or by +calling these in the debugger. LLVM has many nice features for +visualizing various graphs, but note that these are available only if +your LLVM was built with Graphviz support (accomplished by having +Graphviz and Ghostview installed when building LLVM). + +Getting back to the generated code, it is fairly simple: the entry block +evaluates the conditional expression ("x" in our case here) and compares +the result to 0.0 with the +`fcmp `_ one instruction +('one' is "Ordered and Not Equal"). Based on the result of this +expression, the code jumps to either the "then" or "else" blocks, which +contain the expressions for the true/false cases. + +Once the then/else blocks are finished executing, they both branch back +to the 'ifcont' block to execute the code that happens after the +if/then/else. In this case the only thing left to do is to return to the +caller of the function. The question then becomes: how does the code +know which expression to return? + +The answer to this question involves an important SSA operation: the +`Phi +operation `_. +If you're not familiar with SSA, `the wikipedia +article `_ +is a good introduction and there are various other introductions to it +available on your favorite search engine. The short version is that +"execution" of the Phi operation requires "remembering" which block +control came from. The Phi operation takes on the value corresponding to +the input control block. In this case, if control comes in from the +"then" block, it gets the value of "calltmp". If control comes from the +"else" block, it gets the value of "calltmp1". + +At this point, you are probably starting to think "Oh no! This means my +simple and elegant front-end will have to start generating SSA form in +order to use LLVM!". Fortunately, this is not the case, and we strongly +advise *not* implementing an SSA construction algorithm in your +front-end unless there is an amazingly good reason to do so. In +practice, there are two sorts of values that float around in code +written for your average imperative programming language that might need +Phi nodes: + + - 1. Code that involves user variables: ``x = 1; x = x + 1;`` + - 2. Values that are implicit in the structure of your AST, such as the + Phi node in this case. + +In `Chapter 7 `_ of this tutorial ("mutable +variables"), we'll talk about #1 in depth. For now, just believe me that +you don't need SSA construction to handle this case. For #2, you have +the choice of using the techniques that we will describe for #1, or you +can insert Phi nodes directly, if convenient. In this case, it is really +really easy to generate the Phi node, so we choose to do it directly. + +Okay, enough of the motivation and overview, lets generate code! + +Code Generation for If/Then/Else +------------------------------------------------ + +In order to generate code for this, we implement the ``Codegen`` method +for ``IfExpressionNode``: + + +.. code-block:: python + + def CodeGen(self): + condition = self.condition.CodeGen() + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + + + + +This code is straightforward and similar to what we saw before. We emit +the expression for the condition, then compare that value to zero to get +a truth value as a 1-bit (bool) value. + + +.. code-block:: python + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + + + + +This code creates the basic blocks that are related to the if/then/else +statement, and correspond directly to the blocks in the example above. +The first line gets the current Function object that is being built. It +gets this by asking the builder for the current BasicBlock, and asking +that block for its "parent" (the function it is currently embedded +into). + +Once it has that, it creates three block which are automatically +inserted into the end of the function. Once the blocks are created, we +can emit the conditional branch that chooses between them. Note that +creating new blocks does not implicitly affect the Builder, so it is +still inserting into the block that the condition went into. + + +.. code-block:: python + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + + + + +After the conditional branch is inserted, we move the builder to start +inserting into the "then" block. Strictly speaking, this call moves the +insertion point to be at the end of the specified block. However, since +the "then" block is empty, it also starts out by inserting at the +beginning of the block. :) + +Once the insertion point is set, we recursively codegen the "then" +expression from the AST. To finish off the "then" block, we create an +unconditional branch to the merge block. One interesting (and very +important) aspect of the LLVM IR is that it `requires all basic blocks +to be +"terminated" `_ +with a `control flow +instruction `_ such +as return or branch. This means that all control flow, *including +fallthroughs* must be made explicit in the LLVM IR. If you violate this +rule, the verifier will emit an error. + +The final line here is quite subtle, but is very important. The basic +issue is that when we create the Phi node in the merge block, we need to +set up the block/value pairs that indicate how the Phi will work. +Importantly, the Phi node expects to have an entry for each predecessor +of the block in the CFG. Why then, are we getting the current block when +we just set it to then\_block 5 lines above? The problem is that the +"Then" expression may actually itself change the block that the Builder +is emitting into if, for example, it contains a nested "if/then/else" +expression. Because calling Codegen recursively could arbitrarily change +the notion of the current block, we are required to get an up-to-date +value for code that will set up the Phi node. + + +.. code-block:: python + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + + + + +Code generation for the 'else' block is basically identical to codegen +for the 'then' block. The only significant difference is the first line, +which adds the 'else' block to the function. Recall previously that the +'else' block was created, but not added to the function. Now that the +'then' and 'else' blocks are emitted, we can finish up with the merge +code: + + +.. code-block:: python + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + + + + +The first line changes the insertion point so that newly created code +will go into the "merge" block. Once that is done, we need to create the +PHI node and set up the block/value pairs for the PHI. + +Finally, the CodeGen function returns the phi node as the value computed +by the if/then/else expression. In our example above, this returned +value will feed into the code for the top-level function, which will +create the return instruction. + +Overall, we now have the ability to execute conditional code in +Kaleidoscope. With this extension, Kaleidoscope is a fairly complete +language that can calculate a wide variety of numeric functions. Next up +we'll add another useful expression that is familiar from non-functional +languages... + +-------------- + +'for' Loop Expression +============================== + +Now that we know how to add basic control flow constructs to the +language, we have the tools to add more powerful things. Lets add +something more aggressive, a 'for' expression: + + +.. code-block:: python + + extern putchard(char) + def printstar(n) + for i = 1, i < n, 1.0 in + putchard(42) # ascii 42 = '*' + + # print 100 '*' characters + printstar(100) + + + + + +This expression defines a new variable (``i`` in this case) which +iterates from a starting value, while the condition (``i < n`` in this +case) is true, incrementing by an optional step value ("1.0" in this +case). If the step value is omitted, it defaults to 1.0. While the loop +is true, it executes its body expression. Because we don't have anything +better to return, we'll just define the loop as always returning 0.0. In +the future when we have mutable variables, it will get more useful. + +As before, lets talk about the changes that we need to Kaleidoscope to +support this. + +Lexer Extensions for the 'for' Loop +-------------------------------------------------- + +The lexer extensions are the same sort of thing as for if/then/else: + + +.. code-block:: python + + ... + + class ThenToken(object): + pass + class ElseToken(object): + pass + class ForToken(object): + pass + class InToken(object): + pass + + ... + + def Tokenize(string): + + ... + + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) + + + + + +AST Extensions for the 'for' Loop +---------------------------------------------- + +The AST node is just as simple. It basically boils down to capturing the +variable name and the constituent expressions in the node. + + +.. code-block:: python + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def __init__(self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable + self.start = start + self.end = end + self.step = step + self.body = body + + def CodeGen(self): + ... + + + +Parser Extensions for the 'for' Loop +---------------------------------------------------- + +The parser code is also fairly standard. The only interesting thing here +is handling of the optional step value. The parser code handles it by +checking to see if the second comma is present. If not, it sets the step +value to null in the AST node: + + +.. code-block:: python + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression + def ParseForExpr(self): + self.Next() # eat the for. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + + + + +LLVM IR for the 'for' Loop +-------------------------------------- + +Now we get to the good part: the LLVM IR we want to generate for this +thing. With the simple example above, we get this LLVM IR (note that +this dump is generated with optimizations disabled for clarity): + + +.. code-block:: llvm + + declare double @putchard(double) + + define double @printstar(double %n) { + entry: + ; initial value = 1.0 (inlined into phi) + br label %loop + + loop: ; preds = %loop, %entry + %i = phi double [ + 1.000000e+00, %entry ], [ %nextvar, %loop ] + ; body + %calltmp = call double @putchard(double 4.200000e+01) + ; increment + %nextvar = fadd double %i, 1.000000e+00 + + ; termination test + %cmptmp = fcmp ult double %i, %n + %booltmp = uitofp i1 %cmptmp to double + %loopcond = fcmp one double %booltmp, 0.000000e+00 + br i1 %loopcond, label %loop, label %afterloop + + afterloop: ; preds = %loop + ; loop always returns 0.0 + ret double 0.000000e+00 } + + + +This loop contains all the same constructs we saw before: a phi node, +several expressions, and some basic blocks. Lets see how this fits +together. + +Code Generation for the 'for' Loop +--------------------------------------------------- + +The first part of Codegen is very simple: we just output the start +expression for the loop value: + + +.. code-block:: python + + def CodeGen(self): + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + +With this out of the way, the next step is to set up the LLVM basic +block for the start of the loop body. In the case above, the whole loop +body is one block, but remember that the body code itself could consist +of multiple blocks (e.g. if it contains an if/then/else or a for/in +expression). + +.. code-block:: python + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + + + + +This code is similar to what we saw for if/then/else. Because we will +need it to create the Phi node, we remember the block that falls through +into the loop. Once we have that, we create the actual block that starts +the loop and create an unconditional branch for the fall-through between +the two blocks. + + +.. code-block:: python + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block); + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + + + + +Now that the "pre\_header\_block" for the loop is set up, we switch to +emitting code for the loop body. To begin with, we move the insertion +point and create the PHI node for the loop induction variable. Since we +already know the incoming value for the starting value, we add it to the +Phi node. Note that the Phi will eventually get a second value for the +backedge, but we can't set it up yet (because it doesn't exist!). + + +.. code-block:: python + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + + + + +Now the code starts to get more interesting. Our 'for' loop introduces a +new variable to the symbol table. This means that our symbol table can +now contain either function arguments or loop variables. To handle this, +before we codegen the body of the loop, we add the loop variable as the +current value for its name. Note that it is possible that there is a +variable of the same name in the outer scope. It would be easy to make +this an error (emit an error and return null if there is already an +entry for VarName) but we choose to allow shadowing of variables. In +order to handle this correctly, we remember the Value that we are +potentially shadowing in ``old_value`` (which will be None if there is +no shadowed variable). + +Once the loop variable is set into the symbol table, the code +recursively codegen's the body. This allows the body to use the loop +variable: any references to it will naturally find it in the symbol +table. + + +.. code-block:: python + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + + + + +Now that the body is emitted, we compute the next value of the iteration +variable by adding the step value, or 1.0 if it isn't present. +``next_value`` will be the value of the loop variable on the next +iteration of the loop. + + +.. code-block:: python + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + + +Finally, we evaluate the exit value of the loop, to determine whether +the loop should exit. This mirrors the condition evaluation for the +if/then/else statement. + + +.. code-block:: python + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + + + + +With the code for the body of the loop complete, we just need to finish +up the control flow for it. This code remembers the end block (for the +phi node), then creates the block for the loop exit ("afterloop"). Based +on the value of the exit condition, it creates a conditional branch that +chooses between executing the loop again and exiting the loop. Any +future code is emitted in the "afterloop" block, so it sets the +insertion position to it. + + +.. code-block:: python + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + + + + +The final code handles various cleanups: now that we have the +"next\_value", we can add the incoming value to the loop PHI node. After +that, we remove the loop variable from the symbol table, so that it +isn't in scope after the for loop. Finally, code generation of the for +loop always returns 0.0, so that is what we return from +``ForExpressionNode::CodeGen``. + +With this, we conclude the "adding control flow to Kaleidoscope" chapter +of the tutorial. In this chapter we added two control flow constructs, +and used them to motivate a couple of aspects of the LLVM IR that are +important for front-end implementors to know. In the next chapter of our +saga, we will get a bit crazier and add `user-defined +operators `_ to our poor innocent language. + +-------------- + +Full Code Listing +=========================== + +Here is the complete code listing for our running example, enhanced with +the if/then/else and for expressions: + + +.. code-block:: python + + #!/usr/bin/env python + + import re + from llvm.core import Module, Constant, Type, Function, Builder + from llvm.ee import ExecutionEngine, TargetData + from llvm.passes import FunctionPassManager + + from llvm.core import FCMP_ULT, FCMP_ONE + from llvm.passes import (PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) + +Globals +------- + +.. code-block:: python + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + +Lexer +----- + +.. code-block:: python + + # The lexer yields one of these types for each token. + class EOFToken(object): + pass + class DefToken(object): + pass + class ExternToken(object): + pass + class IfToken(object): + pass + class ThenToken(object): + pass + class ElseToken(object): + pass + class ForToken(object): + pass + class InToken(object): + pass + + class IdentifierToken(object): + def __init__(self, name): + self.name = name + + class NumberToken(object): + def __init__(self, value): + self.value = value + + class CharacterToken(object): + def __init__(self, char): + self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): + return not self == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') + REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +.. code-block:: python + + # Base class for all expression nodes. + class ExpressionNode(object): + pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def __init__(self, condition, then_branch, else_branch): + self.condition = condition + self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): + condition = self.condition.CodeGen() + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def __init__(self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable + self.start = start + self.end = end + self.step = step + self.body = body + + def CodeGen(self): + # Output this as: + # ... + # start = startexpr + # goto loop + # loop: + # variable = phi [start, loopheader], [nextvariable, loopend] + # ... + # bodyexpr + # ... + # loopend: + # step = stepexpr + # nextvariable = variable + step # endcond = endexpr # br endcond, loop, endloop + # outloop: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + + def __init__(self, name, args): + self.name = name + self.args = args + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + +Parser +------ + +.. code-block:: python + + class Parser(object): + + def __init__(self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression + def ParseIfExpr(self): + self.Next() # eat the if. + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' + expression + def ParseForExpr(self): + self.Next() # eat the for. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # primary ::= identifierexpr | numberexpr | parenexpr | ifexpr | forexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif isinstance(self.current, ForToken): + return self.ParseForExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +Main driver code. +----------------- + +.. code-block:: python + + def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if __name__ == '__main__': + main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl6.rst b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst new file mode 100644 index 0000000..8ff31d4 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst @@ -0,0 +1,1557 @@ +********************************************************************** +Chapter 6: Extending the Language: User-defined Operators +********************************************************************** + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction +======================= + +Welcome to Chapter 6 of the `Implementing a language with +LLVM `_ tutorial. At this +point in our tutorial, we now have a fully functional language that is +fairly minimal, but also useful. There is still one big problem with it, +however. Our language doesn't have many useful operators (like division, +logical negation, or even any comparisons besides less-than). + +This chapter of the tutorial takes a wild digression into adding +user-defined operators to the simple and beautiful Kaleidoscope +language. This digression now gives us a simple and ugly language in +some ways, but also a powerful one at the same time. One of the great +things about creating your own language is that you get to decide what +is good or bad. In this tutorial we'll assume that it is okay to use +this as a way to show some interesting parsing techniques. + +At the end of this tutorial, we'll run through an example Kaleidoscope +application that :ref:`renders the Mandelbrot set `. This gives an +example of what you can build with Kaleidoscope and its feature set. + +User-defined Operators: the Idea +========================================== + +The "operator overloading" that we will add to Kaleidoscope is more +general than languages like C++. In C++, you are only allowed to +redefine existing operators: you can't programatically change the +grammar, introduce new operators, change precedence levels, etc. In this +chapter, we will add this capability to Kaleidoscope, which will let the +user round out the set of operators that are supported. + +The point of going into user-defined operators in a tutorial like this +is to show the power and flexibility of using a hand-written parser. +Thus far, the parser we have been implementing uses recursive descent +for most parts of the grammar and operator precedence parsing for the +expressions. See `Chapter 2 `_ for details. +Without using operator precedence parsing, it would be very difficult to +allow the programmer to introduce new operators into the grammar: the +grammar is dynamically extensible as the JIT runs. + +The two specific features we'll add are programmable unary operators +(right now, Kaleidoscope has no unary operators at all) as well as +binary operators. An example of this is: + + +.. code-block:: python + + # Logical unary not. + def unary!(v) + if v then + 0 + else + 1 + + # Define > with the same precedence as <. + def binary> 10 (LHS RHS) + RHS < LHS + + # Binary "logical or", (note that it does not "short circuit"). + def binary| 5 (LHS RHS) + if LHS then + 1 + else if RHS then + 1 + else + 0 + + # Define = with slightly lower precedence than relationals. + def binary= 9 (LHS RHS) + !(LHS < RHS | LHS > RHS) + + + +Many languages aspire to being able to implement their standard runtime +library in the language itself. In Kaleidoscope, we can implement +significant parts of the language in the library! + +We will break down implementation of these features into two parts: +implementing support for user-defined binary operators and adding unary +operators. + +-------------- + +User-defined Binary Operators +========================================= + +Adding support for user-defined binary operators is pretty simple with +our current framework. We'll first add support for the unary/binary +keywords: + + +.. code-block:: python + + class InToken(object): + pass + class BinaryToken(object): + pass + class UnaryToken(object): + pass + + ... + + def Tokenize(string): + ... + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + else: + yield IdentifierToken(identifier) + +This just adds lexer support for the unary and binary keywords, like we +did in `previous chapters `_. One nice +thing about our current AST, is that we represent binary operators with +full generalisation by using their ASCII code as the opcode. For our +extended operators, we'll use this same representation, so we don't need +any new AST or parser support. + +On the other hand, we have to be able to represent the definitions of +these new operators, in the "def binary| 5" part of the function +definition. In our grammar so far, the "name" for the function +definition is parsed as the "prototype" production and into the +``PrototypeNode``. To represent our new user-defined operators as +prototypes, we have to extend the ``PrototypeNode`` like this: + +.. code-block:: python + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes), as well as if it is an operator. + class PrototypeNode(object): + + def __init__(self, name, args, is_operator=False, precedence=0): + self.name = name + self.args = args + self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): + return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): + assert self.is_operator + return self.name[-1] + + def CodeGen(self): + ... + + + +Basically, in addition to knowing a name for the prototype, we now keep +track of whether it was an operator, and if it was, what precedence +level the operator is at. The precedence is only used for binary +operators (as you'll see below, it just doesn't apply for unary +operators). Now that we have a way to represent the prototype for a +user-defined operator, we need to parse it: + + +.. code-block:: python + + # prototype + # ::= id '(' id* ')' + # ::= binary LETTER number? (id, id) + # ::= unary LETTER (id) + def ParsePrototype(self): + precedence = None + if isinstance(self.current, IdentifierToken): + kind = 'normal' + function_name = self.current.name + self.Next() # eat function name. + elif isinstance(self.current, BinaryToken): + kind = 'binary' + self.Next() # eat 'binary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "binary".') + function_name = 'binary' + self.current.char + self.Next() # eat the operator. + if isinstance(self.current, NumberToken): + if not 1 <= self.current.value <= 100: + raise RuntimeError('Invalid precedence: must be in range [1, 100].') + precedence = self.current.value + self.Next() # eat the precedence. + else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + + + + +This is all fairly straightforward parsing code, and we have already +seen a lot of similar code in the past. One interesting part about the +code above is the couple lines that set up ``function_name`` for +operators. This builds names like "binary@" for a newly defined "@" +operator. This then takes advantage of the fact that symbol names in the +LLVM symbol table are allowed to have any character in them. + +The next interesting thing to add, is codegen support for these binary +operators. Given our current structure, this is a simple addition of a +default case for our existing binary operator node: + + +.. code-block:: python + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + + + + + +As you can see above, the new code is actually really simple. It just +does a lookup for the appropriate operator in the symbol table and +generates a function call to it. Since user-defined operators are just +built as normal functions (because the "prototype" boils down to a +function with the right name) everything falls into place. + +The final piece of code we are missing, is a bit of top-level magic. We +will need to make the dinary precedence map global and modify it +whenever we define a new binary operator: + + +.. code-block:: python + + # The binary operator precedence chart. + g_binop_precedence = {} + ... + class FunctionNode(object): + ... + def CodeGen(self): + ... + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + ... + # Finish off the function. + try: + ... + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + + ... + def main(): + ... + g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 + g_binop_precedence['*'] = 40 + ... + + + +Basically, before CodeGening a function, if it is a user-defined +operator, we register it in the precedence table. This allows the binary +operator parsing logic we already have in place to handle it. Since we +are working on a fully-general operator precedence parser, this is all +we need to do to "extend the grammar". + +Now we have useful user-defined binary operators. This builds a lot on +the previous framework we built for other operators. Adding unary +operators is a bit more challenging, because we don't have any framework +for it yet - let's see what it takes. + +User-defined Unary Operators +======================================= + +Since we don't currently support unary operators in the Kaleidoscope +language, we'll need to add everything to support them. Above, we added +simple support for the 'unary' keyword to the lexer. In addition to +that, we need an AST node: + + +.. code-block:: python + + # Expression class for a unary operator. + class UnaryExpressionNode(ExpressionNode): + + def __init__(self, operator, operand): + self.operator = operator + self.operand = operand + + def CodeGen(self): + ... + + + +This AST node is very simple and obvious by now. It directly mirrors the +binary operator AST node, except that it only has one child. With this, +we need to add the parsing logic. Parsing a unary operator is pretty +simple: we'll add a new function to do it: + + +.. code-block:: python + + # unary ::= primary | unary_operator unary + def ParseUnary(self): + # If the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or + self.current in [CharacterToken('('), CharacterToken(',')]): + return self.ParsePrimary() + + # If this is a unary operator, read it. + operator = self.current.chara + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + + + + +The grammar we add is pretty straightforward here. If we see a unary +operator when parsing a primary operator, we eat the operator as a +prefix and parse the remaining piece as another unary operator. This +allows us to handle multiple unary operators (e.g. ``!!x``). Note that +unary operators can't have ambiguous parses like binary operators can, +so there is no need for precedence information. + +The problem with this function, is that we need to call ParseUnary from +somewhere. To do this, we change previous callers of ParsePrimary to +call ParseUnary instead: + + +.. code-block:: python + + # binoprhs ::= (binary_operator unary)* + def ParseBinOpRHS(self, left, left_precedence): + ... + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + ... + + # expression ::= unary binoprhs + def ParseExpression(self): + left = self.ParseUnary() + return self.ParseBinOpRHS(left, 0) + + + +With these two simple changes, we are now able to parse unary operators +and build the AST for them. Next up, we need to add parser support for +prototypes, to parse the unary operator prototype. We extend the binary +operator code above with: + + +.. code-block:: python + + # prototype + # ::= id '(' id* ')' + # ::= binary LETTER number? (id, id) + # ::= unary LETTER (id) + def ParsePrototype(self): + precedence = None + if isinstance(self.current, IdentifierToken): + ... + elif isinstance(self.current, UnaryToken): + kind = 'unary' + self.Next() # eat 'unary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "unary".') + function_name = 'unary' + self.current.char + self.Next() #eat the operator. + elif isinstance(self.current, BinaryToken): + ... + else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') + ... + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + + + + +As with binary operators, we name unary operators with a name that +includes the operator character. This assists us at code generation +time. Speaking of, the final piece we need to add is codegen support for +unary operators. It looks like this: + + +.. code-block:: python + + class UnaryExpressionNode(ExpressionNode): + ... + def CodeGen(self): + operand = self.operand.CodeGen() + function = g_llvm_module.get_function_named('unary' + self.operator) + return g_llvm_builder.call(function, [operand], 'unop') + + + +This code is similar to, but simpler than, the code for binary +operators. It is simpler primarily because it doesn't need to handle any +predefined operators. + +-------------- + +Kicking the Tires +============================== + +It is somewhat hard to believe, but with a few simple extensions we've +covered in the last chapters, we have grown a real-ish language. With +this, we can do a lot of interesting things, including I/O, math, and a +bunch of other things. For example, we can now add a nice sequencing +operator (assuming we import ``putchard`` as described in Chapter 4): + + +.. code-block:: python + + ready> def binary : 1 (x y) 0 # Low-precedence operator that ignores operands. + ... + ready> extern putchard(x) + ... + ready> def printd(x) putchard(x) : putchard(10) + .. + ready> printd(65) : printd(66) : printd(67) + A + B + C + Evaluated to: 0.0 + + + +We can also define a bunch of other "primitive" operations, such as: + + +.. code-block:: python + + # Logical unary not. + def unary!(v) + if v then + 0 + else + 1 + + # Unary negate. + def unary-(v) + 0-v + + # Define > with the same precedence as <. + def binary> 10 (LHS RHS) + RHS < LHS + + # Binary logical or, which does not short circuit. + def binary| 5 (LHS RHS) + if LHS then + 1 + else if RHS then + 1 + else + 0 + + # Binary logical and, which does not short circuit. + def binary& 6 (LHS RHS) + if !LHS then + 0 + else + !!RHS + + # Define = with slightly lower precedence than relationals. + def binary = 9 (LHS RHS) + !(LHS < RHS | LHS > RHS) + + + + + +Given the previous if/then/else support, we can also define interesting +functions for I/O. For example, the following prints out a character +whose "density" reflects the value passed in: the lower the value, the +denser the character: + + +.. code-block:: python + + ready> + + extern putchard(char) + def printdensity(d) + if d > 8 then + putchard(32) # ' ' + else if d > 4 then + putchard(46) # '.' + else if d > 2 then + putchard(43) # '+' + else + putchard(42); # '*' + ... + ready> printdensity(1): printdensity(2): printdensity(3) : + printdensity(4): printdensity(5): printdensity(9): putchard(10) + *++.. + Evaluated to 0.000000 + +Based on these simple primitive operations, we can start to define more +interesting things. For example, here's a little function that solves +for the number of iterations it takes a function in the complex plane to +converge: + +.. code-block:: python + + # determine whether the specific location diverges. + # Solve for z = z^2 + c in the complex plane. + def mandelconverger(real imag iters creal cimag) + if iters > 255 | + (real*real + imag* imag > 4) then iters else + mandelconverger(real*real - imag* imag + creal, 2\ *real* imag + + cimag, iters+1, creal, cimag) + + # return the number of iterations required for the iteration to escape + def mandelconverge(real imag) mandelconverger(real, imag, 0, real, imag) + + + +.. _example: + +This "z = z2 + c" function is a beautiful little creature that is the +basis for computation of the `Mandelbrot +Set `_. Our +``mandelconverge`` function returns the number of iterations that it +takes for a complex orbit to escape, saturating to 255. This is not a +very useful function by itself, but if you plot its value over a +two-dimensional plane, you can see the Mandelbrot set. Given that we are +limited to using putchard here, our amazing graphical output is limited, +but we can whip together something using the density plotter above: + + +.. code-block:: python + + # compute and plot the mandlebrot set with the + specified 2 dimensional range # info. def mandelhelp(xmin xmax xstep + ymin ymax ystep) for y = ymin, y < ymax, ystep in ( (for x = xmin, x < + xmax, xstep in printdensity(mandleconverge(x,y))) : putchard(10) ) + + # mandel - This is a convenient helper function for ploting the mandelbrot set + # from the specified position with the specified Magnification. + def mandel(realstart imagstart realmag imagmag) mandelhelp(realstart, + realstart+realmag\ *78, realmag, imagstart, imagstart+imagmag* 40, + imagmag); + + + +Given this, we can try plotting out the mandlebrot set! Lets try it out: + + +.. code-block:: bash + + ready> mandel(-2.3, -1.3, 0.05, 0.07) + ******************************************************************************* + ******************************************************************************* + ****************************************++++++********************************* + ************************************+++++...++++++***************************** + *********************************++++++++.. ...+++++*************************** + *******************************++++++++++.. ..+++++************************** + ******************************++++++++++. ..++++++************************* + ****************************+++++++++.... ..++++++************************ + **************************++++++++....... .....++++*********************** + *************************++++++++. . ... .++********************** + ***********************++++++++... ++********************** + *********************+++++++++.... .+++********************* + ******************+++..+++++.... ..+++******************** + **************++++++. .......... +++******************** + ***********++++++++.. .. .++******************** + *********++++++++++... .++++******************* + ********++++++++++.. .++++******************* + *******++++++..... ..++++******************* + *******+........ ...++++******************* + *******+... .... ...++++******************* + *******+++++...... ..++++******************* + *******++++++++++... .++++******************* + *********++++++++++... ++++******************* + **********+++++++++.. .. ..++******************** + *************++++++.. .......... +++******************** + ******************+++...+++..... ..+++******************** + *********************+++++++++.... ..++********************* + ***********************++++++++... +++********************* + *************************+++++++.. . ... .++********************** + **************************++++++++....... ......+++*********************** + ****************************+++++++++.... ..++++++************************ + *****************************++++++++++.. ..++++++************************* + *******************************++++++++++.. ...+++++************************** + *********************************++++++++.. ...+++++*************************** + ***********************************++++++....+++++***************************** + ***************************************++++++++******************************** + ******************************************************************************* + ******************************************************************************* + ******************************************************************************* + ******************************************************************************* + ******************************************************************************* + Evaluated to 0.0 + ready> mandel(-2, -1, 0.02, 0.04) + ******************************************************************+++++++++++++ + ****************************************************************+++++++++++++++ + *************************************************************++++++++++++++++++ + ***********************************************************++++++++++++++++++++ + ********************************************************+++++++++++++++++++++++ + ******************************************************++++++++++++++++++++++... + ***************************************************+++++++++++++++++++++....... + *************************************************++++++++++++++++++++.......... + ***********************************************+++++++++++++++++++... ... + ********************************************++++++++++++++++++++...... + ******************************************++++++++++++++++++++....... + ***************************************+++++++++++++++++++++.......... + ************************************++++++++++++++++++++++........... + ********************************++++++++++++++++++++++++......... + ***************************++++++++...........+++++.............. + *********************++++++++++++.... ......................... + ***************+++++++++++++++++.... ......... ............ + ***********+++++++++++++++++++++..... ...... + ********+++++++++++++++++++++++....... + ******+++++++++++++++++++++++++........ + ****+++++++++++++++++++++++++....... + ***+++++++++++++++++++++++......... + **++++++++++++++++........... + *++++++++++++................ + *++++.................... + + *++++.................... + *++++++++++++................ + **++++++++++++++++........... + ***+++++++++++++++++++++++......... + ****+++++++++++++++++++++++++....... + ******+++++++++++++++++++++++++........ + ********+++++++++++++++++++++++....... + ***********+++++++++++++++++++++..... ...... + ***************+++++++++++++++++.... ......... ............ + *********************++++++++++++.... ......................... + ***************************++++++++...........+++++.............. + ********************************++++++++++++++++++++++++......... + ************************************++++++++++++++++++++++........... + ***************************************+++++++++++++++++++++.......... + ******************************************++++++++++++++++++++....... + Evaluated to: 0.0 + ready> mandel(-0.9, -1.4, 0.02, 0.03) + ******************************************************************************* + ******************************************************************************* + ******************************************************************************* + ******************************************************************************* + ******************************************************************************* + ******************************************************************************* + ******************************************************************************* + ******************************************************************************* + ****************************+++++++++++++++++********************************** + ***********************+++++++++++...++++++++++++****************************** + ********************+++++++++++++.. . .++++++++++++++************************** + *****************++++++++++++++++... ......++++++++++++************************ + **************+++++++++++++++++++... .......+++++++++++********************** + ************++++++++++++++++++++.... .... ..++++++++++++******************** + **********++++++++++++++++++++++...... ...++++++++++++******************* + ********+++++++++++++++++++++++....... .....++++++++++++++***************** + ******++++++++++++++++++++++++....... .....+++++++++++++++**************** + ****+++++++++++++++++++++++++.... . .....+++++++++++++++*************** + **+++++++++++++++++++++++++.... ...++++++++++++++++************* + *+++++++++++++++++++++++....... ....++++++++++++++++************ + +++++++++++++++++++++.......... .....++++++++++++++++*********** + ++++++++++++++++++............. .......+++++++++++++++********** + +++++++++++++++................ ............++++++++++********** + +++++++++++++................. .................+++++********* + +++++++++++... .... .......... .+++++******** + ++++++++++..... ........ ...+++++******* + ++++++++...... ..++++++****** + +++++++........ ..+++++****** + +++++.......... ..++++++***** + ++++.......... ....++++++***** + ++.......... ....+++++++**** + .......... ......+++++++*** + .......... .....+++++++*** + .......... .....++++++*** + ......... .+++++++** + ........ .+++++++** + ...... ...+++++++* + . ....++++++++* + ...++++++++* + ..+++++++++ + ..+++++++++ + Evaluated to: 0.0 + ready> ^C + + + +At this point, you may be starting to realize that Kaleidoscope is a +real and powerful language. It may not be self-similar :), but it can be +used to plot things that are! + +With this, we conclude the "adding user-defined operators" chapter of +the tutorial. We have successfully augmented our language, adding the +ability to extend the language in the library, and we have shown how +this can be used to build a simple but interesting end-user application +in Kaleidoscope. At this point, Kaleidoscope can build a variety of +applications that are functional and can call functions with +side-effects, but it can't actually define and mutate a variable itself. + +Strikingly, variable mutation is an important feature of some languages, +and it is not at all obvious how to `add support for mutable +variables `_ without having to add an "SSA +construction" phase to your front-end. In the next chapter, we will +describe how you can add variable mutation without building SSA in your +front-end. + +-------------- + +Full Code Listing +=========================== + +Here is the complete code listing for our running example, enhanced with +the if/then/else and for expressions: + + +.. code-block:: python + + #!/usr/bin/env python + + import re + from llvm.core import Module, Constant, Type, Function, Builder + from llvm.ee import ExecutionEngine, TargetData + from llvm.passes import FunctionPassManager + + from llvm.core import FCMP_ULT, FCMP_ONE + from llvm.passes import (PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) + +Globals +------- + +.. code-block:: python + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + # The binary operator precedence chart. + g_binop_precedence = {} + +Lexer +----- + +.. code-block:: python + + # The lexer yields one of these types for each token. + class EOFToken(object): + pass + class DefToken(object): + pass + class ExternToken(object): + pass + class IfToken(object): + pass + class ThenToken(object): + pass + class ElseToken(object): + pass + class ForToken(object): + pass + class InToken(object): + pass + class BinaryToken(object): + pass + class UnaryToken(object): + pass + + class IdentifierToken(object): + def __init__(self, name): + self.name = name + + class NumberToken(object): + def __init__(self, value): + self.value = value + + class CharacterToken(object): + def __init__(self, char): + self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): + return not self == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') + REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +.. code-block:: python + + # Base class for all expression nodes. + class ExpressionNode(object): + pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def __init__(self, condition, then_branch, else_branch): + self.condition = condition + self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): + + condition = self.condition.CodeGen() + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def __init__(self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable + self.start = start + self.end = end + self.step = step + self.body = body + + def CodeGen(self): + # Output this as: + # ... + # start = startexpr + # goto loop + # loop: + # variable = phi [start, loopheader], [nextvariable, loopend] + # ... + # bodyexpr + # ... + # loopend: + # step = stepexpr + # nextvariable = variable + step + # endcond = endexpr + # br endcond, loop, endloop + # outloop: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + # Expression class for a unary operator. + class UnaryExpressionNode(ExpressionNode): + + def __init__(self, operator, operand): + self.operator = operator + self.operand = operand + + def CodeGen(self): + operand = self.operand.CodeGen() + function = g_llvm_module.get_function_named('unary' + self.operator) + return g_llvm_builder.call(function, [operand], 'unop') + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes), as well as if it is an operator. + class PrototypeNode(object): + + def __init__(self, name, args, is_operator=False, precedence=0): + self.name = name + self.args = args + self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): + return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): + assert self.is_operator + return self.name[-1] + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + +Parser +------ + +.. code-block:: python + + class Parser(object): + + def __init__(self, tokens): + self.tokens = tokens + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return g_binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression + def ParseIfExpr(self): + self.Next() # eat the if. + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression + def ParseForExpr(self): + self.Next() # eat the for. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # primary ::= identifierexpr | numberexpr | parenexpr | ifexpr | forexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif isinstance(self.current, ForToken): + return self.ParseForExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # unary ::= primary | unary_operator unary + def ParseUnary(self): + # If the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or + self.current in [CharacterToken('('), CharacterToken(',')]): + return self.ParsePrimary() + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + # binoprhs ::= (binary_operator unary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= unary binoprhs + def ParseExpression(self): + left = self.ParseUnary() + return self.ParseBinOpRHS(left, 0) + + # prototype # ::= id '(' id* ')' + # ::= binary LETTER number? (id, id) + # ::= unary LETTER (id) + def ParsePrototype(self): + precedence = None + if isinstance(self.current, IdentifierToken): + kind = 'normal' + function_name = self.current.name + self.Next() # eat function name. + elif isinstance(self.current, UnaryToken): + kind = 'unary' + self.Next() # eat 'unary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "unary".') + function_name = 'unary' + self.current.char + self.Next() # eat the operator. + elif isinstance(self.current, BinaryToken): + kind = 'binary' + self.Next() # eat 'binary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "binary".') + function_name = 'binary' + self.current.char + self.Next() # eat the operator. + if isinstance(self.current, NumberToken): + if not 1 <= self.current.value <= 100: + raise RuntimeError('Invalid precedence: must be in range [1, 100].') + precedence = self.current.value + self.Next() # eat the precedence. + else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +Main driver code. +----------------- + +.. code-block:: python + + def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 + g_binop_precedence['*'] = 40 + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. + print '', g_llvm_module + + if __name__ == '__main__': + main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst new file mode 100644 index 0000000..dee1c31 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst @@ -0,0 +1,1835 @@ +******************************************************************************* +Chapter 7: Extending the Language: Mutable Variables / SSA construction +******************************************************************************* + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction +======================= + +Welcome to Chapter 7 of the `Implementing a language with +LLVM `_ tutorial. In +chapters 1 through 6, we've built a very respectable, albeit simple, +`functional programming +language `_. In our +journey, we learned some parsing techniques, how to build and represent +an AST, how to build LLVM IR, and how to optimize the resultant code as +well as JIT compile it. + +While Kaleidoscope is interesting as a functional language, the fact +that it is functional makes it "too easy" to generate LLVM IR for it. In +particular, a functional language makes it very easy to build LLVM IR +directly in `SSA +form `_. +Since LLVM requires that the input code be in SSA form, this is a very +nice property and it is often unclear to newcomers how to generate code +for an imperative language with mutable variables. + +The short (and happy) summary of this chapter is that there is no need +for your front-end to build SSA form: LLVM provides highly tuned and +well tested support for this, though the way it works is a bit +unexpected for some. + +Why is this a hard problem? +==================================== + +To understand why mutable variables cause complexities in SSA +construction, consider this extremely simple C example: + + +.. code-block:: c + + int G, H; + int test(_Bool Condition) { + int X; + if (Condition) + X = G; + else + X = H; + return X; + } + + + +In this case, we have the variable "X", whose value depends on the path +executed in the program. Because there are two different possible values +for X before the return instruction, a PHI node is inserted to merge the +two values. The LLVM IR that we want for this example looks like this: + + +.. code-block:: llvm + + @G = weak global i32 0 ; type of @G is i32* + @H = weak global i32 0 ; type of @H is i32* + + define i32 @test(i1 %Condition) { + entry: + + br i1 %Condition, label %cond_true, label %cond_false + + cond_true: + %X.0 = load i32* @G + br label %cond_next + + cond_false: + %X.1 = load i32* @H + br label %cond_next + + cond_next: + %X.2 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ] + ret i32 %X.2 } + + + +In this example, the loads from the G and H global variables are +explicit in the LLVM IR, and they live in the then/else branches of the +if statement (cond\_true/cond\_false). In order to merge the incoming +values, the X.2 phi node in the cond\_next block selects the right value +to use based on where control flow is coming from: if control flow comes +from the cond\_false block, X.2 gets the value of X.1. Alternatively, if +control flow comes from cond\_true, it gets the value of X.0. The intent +of this chapter is not to explain the details of SSA form. For more +information, see one of the many `online +references `_. + +The question for this article is "who places the phi nodes when lowering +assignments to mutable variables?". The issue here is that LLVM +*requires* that its IR be in SSA form: there is no "non-ssa" mode for +it. However, SSA construction requires non-trivial algorithms and data +structures, so it is inconvenient and wasteful for every front-end to +have to reproduce this logic. + +Memory in LLVM +========================== + +The 'trick' here is that while LLVM does require all register values to +be in SSA form, it does not require (or permit) memory objects to be in +SSA form. In the example above, note that the loads from G and H are +direct accesses to G and H: they are not renamed or versioned. This +differs from some other compiler systems, which do try to version memory +objects. In LLVM, instead of encoding dataflow analysis of memory into +the LLVM IR, it is handled with `Analysis +Passes `_ which are +computed on demand. + +With this in mind, the high-level idea is that we want to make a stack +variable (which lives in memory, because it is on the stack) for each +mutable object in a function. To take advantage of this trick, we need +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 +*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 +instruction `_: + + +.. code-block:: llvm + + define i32 @example() { + entry: + %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 + ... + + + +This code shows an example of how you can declare and manipulate a stack +variable in the LLVM IR. Stack memory allocated with the alloca +instruction is fully general: you can pass the address of the stack slot +to functions, you can store it in other variables, etc. In our example +above, we could rewrite the example to use the alloca technique to avoid +using a PHI node: + + +.. code-block:: llvm + + @G = weak global i32 0 ; type of @G is i32* + @H = weak global i32 0 ; type of @H is i32* + + define i32 @test(i1 %Condition) { + entry: + %X = alloca i32 ; type of %X is i32 *. + br i1 %Condition, label %cond_true, label %cond_false + + cond_true: + %X.0 = load i32* @G + store i32 %X.0, i32* %X ; Update X + br label %cond_next + + cond_false: + %X.1 = load i32* @H + store i32 %X.1, i32* %X ; Update X + br label %cond_next + + cond_next: + %X.2 = load i32* %X ; Read X + ret i32 %X.2 + } + +With this, we have discovered a way to handle arbitrary mutable +variables without the need to create Phi nodes at all: + +#. Each mutable variable becomes a stack allocation. +#. Each read of the variable becomes a load from the stack. +#. Each update of the variable becomes a store to the stack. +#. Taking the address of a variable just uses the stack address directly. + +While this solution has solved our immediate problem, it introduced +another one: we have now apparently introduced a lot of stack traffic +for very simple and common operations, a major performance problem. +Fortunately for us, the LLVM optimizer has a highly-tuned optimization +pass named "mem2reg" that handles this case, promoting allocas like this +into SSA registers, inserting Phi nodes as appropriate. If you run this +example through the pass, for example, you'll get: + +.. code-block:: bash + + $ llvm-as < example.ll | opt -mem2reg | llvm-dis +.. code-block:: llvm + + @G = weak global i32 0 + @H = weak global i32 0 + + define i32 @test(i1 %Condition) { + entry: + br i1 %Condition, label %cond_true, label %cond_false + + cond_true: + %X.0 = load i32* @G + br label %cond_next + + cond_false: + %X.1 = load i32* @H + br label %cond_next + + cond_next: + %X.01 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ] + ret i32 %X.01 + } + + + +The mem2reg pass implements the standard "iterated dominance frontier" +algorithm for constructing SSA form and has a number of optimizations +that speed up (very common) degenerate cases. The mem2reg optimization +pass is the answer to dealing with mutable variables, and we highly +recommend that you depend on it. Note that mem2reg only works on +variables in certain circumstances: + +#. mem2reg is alloca-driven: it looks for allocas and if it can handle + them, it promotes them. It does not apply to global variables or heap + allocations. + +#. mem2reg only looks for alloca instructions in the entry block of the + function. Being in the entry block guarantees that the alloca is only + executed once, which makes analysis simpler. + +#. mem2reg only promotes allocas whose uses are direct loads and stores. + If the address of the stack object is passed to a function, or if any + funny pointer arithmetic is involved, the alloca will not be + promoted. + +#. mem2reg only works on allocas of `first class + `_ + values (such as pointers, scalars and vectors), and only if the array + size of the allocation is 1 (or missing in the .ll file). mem2reg is + not capable of promoting structs or arrays to registers. Note that + the "scalarrepl" pass is more powerful and can promote structs, + "unions", and arrays in many cases. + +All of these properties are easy to satisfy for most imperative +languages, and we'll illustrate it below with Kaleidoscope. The final +question you may be asking is: should I bother with this nonsense for my +front-end? Wouldn't it be better if I just did SSA construction +directly, avoiding use of the mem2reg optimization pass? In short, we +strongly recommend that you use this technique for building SSA form, +unless there is an extremely good reason not to. Using this technique +is: + +- Proven and well tested: llvm-gcc and clang both use this technique + for local mutable variables. As such, the most common clients of LLVM + are using this to handle a bulk of their variables. You can be sure + that bugs are found fast and fixed early. + +- Extremely Fast: mem2reg has a number of special cases that make it + fast in common cases as well as fully general. For example, it has + fast-paths for variables that are only used in a single block, + variables that only have one assignment point, good heuristics to + avoid insertion of unneeded phi nodes, etc. + +- Needed for debug info generation: `Debug information in + LLVM `_ relies on + having the address of the variable exposed so that debug info can be + attached to it. This technique dovetails very naturally with this + style of debug info. + +If nothing else, this makes it much easier to get your front-end up and +running, and is very simple to implement. Lets extend Kaleidoscope with +mutable variables now! + +-------------- + +Mutable Variables in Kaleidoscope +============================================== + +Now that we know the sort of problem we want to tackle, lets see what +this looks like in the context of our little Kaleidoscope language. +We're going to add two features: + +#. The ability to mutate variables with the '=' operator. +#. The ability to define new variables. + +While the first item is really what this is about, we only have +variables for incoming arguments as well as for induction variables, and +redefining those only goes so far :). Also, the ability to define new +variables is a useful thing regardless of whether you will be mutating +them. Here's a motivating example that shows how we could use these: + + +.. code-block:: none + + # Define ':' for sequencing: as a low-precedence operator that ignores operands + # and just returns the RHS. + def binary : 1 (x y) y; + + # Recursive fib, we could do this before. + def fib(x) + if (x < 3) then + 1 + else + fib(x-1) + fib(x-2) + + # Iterative fib. + def fibi(x) + var a = 1, b = 1, c in + (for i = 3, i < x in + c = a + b : + a = b : + b = c) : + b + + # Call it. + fibi(10) + + + +In order to mutate variables, we have to change our existing variables +to use the "alloca trick". Once we have that, we'll add our new +operator, then extend Kaleidoscope to support new variable definitions. + +-------------- + +Adjusting Existing Variables for Mutation +========================================================== + +The symbol table in Kaleidoscope is managed at code generation time by +the ``g_named_values`` map. This map currently keeps track of the LLVM +"Value" that holds the double value for the named variable. In order to +support mutation, we need to change this slightly, so that it holds the +*memory location* of the variable in question. Note that this change is +a refactoring: it changes the structure of the code, but does not (by +itself) change the behavior of the compiler. All of these changes are +isolated in the Kaleidoscope code generator. + +At this point in Kaleidoscope's development, it only supports variables +for two things: incoming arguments to functions and the induction +variable of 'for' loops. For consistency, we'll allow mutation of these +variables in addition to other user-defined variables. This means that +these will both need memory locations. + +To start our transformation of Kaleidoscope, we will need to create the +allocas that we will store in ``g_named_values``. We'll use a helper +function that ensures that the allocas are created in the entry block of +the function: + + +.. code-block:: python + + # Creates an alloca instruction in the entry block of the function. This is used + # for mutable variables. + def CreateEntryBlockAlloca(function, var_name): + entry = function.get_entry_basic_block() + builder = Builder.new(entry) + builder.position_at_beginning(entry) return + builder.alloca(Type.double(), var_name) + + + +This code creates a temporary ``llvm.core.Builder`` that is pointing at +the first instruction of the entry block. It then creates an alloca with +the expected name and returns it. Because all values in Kaleidoscope are +doubles, there is no need to pass in a type to use. + +With this in place, the first functionality change we want to make is to +variable references. In our new scheme, variables live on the stack, so +code generating a reference to them actually needs to produce a load +from the stack slot: + + +.. code-block:: python + + def CodeGen(self): + if self.name in g_named_values: + return g_llvm_builder.load(g_named_values[self.name], self.name) + else: + raise RuntimeError('Unknown variable name: ' + self.name) + +As you can see, this is pretty straightforward. Now we need to update +the things that define the variables to set up the alloca. We'll start +with ``ForExpressionNode.CodeGen`` (see the :ref:`full code listing ` +for the unabridged code): + +.. code-block:: python + + def CodeGen(self): + function = g_llvm_builder.basic_block.function + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + ... + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + ... + + + + + +This code is virtually identical to the code `before we allowed mutable +variables `_. The big difference is +that we no longer have to construct a PHI node, and we use load/store to +access the variable as needed. + +To support mutable argument variables, we need to also make allocas for +them. The code for this is also pretty simple: + + +.. code-block:: python + + class PrototypeNode(object): + ... + # Create an alloca for each argument and register the argument in the symbol + # table so that references to it will succeed. + def CreateArgumentAllocas(self, function): + for arg_name, arg in zip(self.args, function.args): + alloca = CreateEntryBlockAlloca(function, arg_name) + g_llvm_builder.store(arg, alloca) + g_named_values[arg_name] = alloca + + + +For each argument, we make an alloca, store the input value to the +function into the alloca, and register the alloca as the memory location +for the argument. This method gets invoked by ``FunctionNode.CodeGen`` +right after it sets up the entry block for the function. + +The final missing piece is adding the mem2reg pass, which allows us to +get good codegen once again: + + +.. code-block:: python + + from llvm.passes import (PASS_PROMOTE_MEMORY_TO_REGISTER, + PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) + ... + def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Promote allocas to registers. + g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + +It is interesting to see what the code looks like before and after the +mem2reg optimization runs. For example, this is the before/after code +for our recursive fib function. Before the optimization: + +.. code-block:: llvm + + define double @fib(double %x) { + entry: + %x1 = alloca double + store double %x, double* %x1 + %x2 = load double* %x1 + %cmptmp = fcmp ult double %x2, 3.000000e+00 + %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp one double %booltmp, 0.000000e+00 + br i1 %ifcond, label %then, label %else + + then: ; preds = %entry + br label %ifcont + + else: ; preds = %entry + %x3 = load double* %x1 + %subtmp = fsub double %x3, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) + %x4 = load double* %x1 + %subtmp5 = fsub double %x4, 2.000000e+00 + %calltmp6 = call double @fib(double %subtmp5) + %addtmp = fadd double %calltmp, %calltmp6 + br label %ifcont + + ifcont: ; preds = %else, %then + %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ] + ret double %iftmp } + +Here there is only one variable (x, the input argument) but you can +still see the extremely simple-minded code generation strategy we are +using. In the entry block, an alloca is created, and the initial input +value is stored into it. Each reference to the variable does a reload +from the stack. Also, note that we didn't modify the if/then/else +expression, so it still inserts a PHI node. While we could make an +alloca for it, it is actually easier to create a PHI node for it, so we +still just make the PHI. + +Here is the code after the mem2reg pass runs: + +.. code-block:: llvm + + define double @fib(double %x) { + entry: + %cmptmp = fcmp ult double %x, 3.000000e+00 + %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp one double %booltmp, 0.000000e+00 + br i1 %ifcond, label %then, label %else + + then: + br label %ifcont + + else: + %subtmp = fsub double %x, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) + %subtmp5 = fsub double %x, 2.000000e+00 + %calltmp6 = call double @fib(double %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 + br label %ifcont + + ifcont: ; preds = %else, %then + %iftmp = phi double [ 1.000000e+00, %then + ], [ %addtmp, %else ] + ret double %iftmp + } + + + +This is a trivial case for mem2reg, since there are no redefinitions of +the variable. The point of showing this is to calm your tension about +inserting such blatent inefficiencies :). + +After the rest of the optimizers run, we get: + + +.. code-block:: llvm + + define double @fib(double %x) { + entry: + %cmptmp = fcmp ult double %x, 3.000000e+00 + %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp ueq double %booltmp, 0.000000e+00 + br i1 %ifcond, label %else, label %ifcont + + else: + %subtmp = fsub double %x, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) + %subtmp5 = fsub double %x, 2.000000e+00 + %calltmp6 = call double @fib(double %subtmp5) + %addtmp = fadd double %calltmp, %calltmp6 + ret double %addtmp + + ifcont: + ret double 1.000000e+00 + } + + + +Here we see that the simplifycfg pass decided to clone the return +instruction into the end of the 'else' block. This allowed it to +eliminate some branches and the PHI node. + +Now that all symbol table references are updated to use stack variables, +we'll add the assignment operator. + +-------------- + +New Assignment Operator +======================================= + +With our current framework, adding a new assignment operator is really +simple. We will parse it just like any other binary operator, but handle +it internally (instead of allowing the user to define it). The first +step is to set a precedence: + + +.. code-block:: python + + def main(): + ... + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + g_binop_precedence['='] = 2 + g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 + +Now that the parser knows the precedence of the binary operator, it +takes care of all the parsing and AST generation. We just need to +implement codegen for the assignment operator. This looks like: + +.. code-block:: python + + class BinaryOperatorExpressionNode(ExpressionNode): + ... + def CodeGen(self): + # A special case for '=' because we don't want to emit the LHS as an + # expression. + if self.operator == '=': + # Assignment requires the LHS to be an identifier. + if not isinstance(self.left, VariableExpressionNode): + raise RuntimeError('Destination of "=" must be a variable.') + +Unlike the rest of the binary operators, our assignment operator doesn't +follow the "emit LHS, emit RHS, do computation" model. As such, it is +handled as a special case before the other binary operators are handled. +The other strange thing is that it requires the LHS to be a variable. It +is invalid to have ``(x+1) = expr`` -- only things like ``x = expr`` are +allowed. + +.. code-block:: python + + # Codegen the RHS. + value = self.right.CodeGen() + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + ... + + + + + +Once we have the variable, CodeGening the assignment is straightforward: +we emit the RHS of the assignment, create a store, and return the +computed value. Returning a value allows for chained assignments like +``X = (Y = Z)``. + +Now that we have an assignment operator, we can mutate loop variables +and arguments. For example, we can now run code like this: + + +.. code-block:: none + + # Function to print a double. + extern printd(x) + + # Define ':' for sequencing: as a low-precedence operator that ignores operands + # and just returns the RHS. + def binary : 1 (x y) y + + def test(x) + printd(x) : + x = 4 : + printd(x) + + test(123) + + + +When run, this example prints "123" and then "4", showing that we did +actually mutate the value! Okay, we have now officially implemented our +goal: getting this to work requires SSA construction in the general +case. However, to be really useful, we want the ability to define our +own local variables. Let's add this next! + +-------------- + +User-defined Local Variables +=========================================== + +Adding var/in is just like any other other extensions we made to +Kaleidoscope: we extend the lexer, the parser, the AST and the code +generator. The first step for adding our new 'var/in' construct is to +extend the lexer. As before, this is pretty trivial, the code looks like +this: + + +.. code-block:: python + + ... + class UnaryToken(object): + pass + class VarToken(object): + pass + ... + def Tokenize(string): + ... + elif identifier == 'unary': + yield UnaryToken() + elif identifier == 'var': + yield VarToken() + else: + yield IdentifierToken(identifier) + + + +The next step is to define the AST node that we will construct. For +var/in, it looks like this: + + +.. code-block:: python + + # Expression class for var/in. + class VarExpressionNode(ExpressionNode): + + def __init__(self, variables, body): + self.variables = variables + self.body = body + + def CodeGen(self): + ... + + + +var/in allows a list of names to be defined all at once, and each name +can optionally have an initializer value. As such, we capture this +information in the variables list. Also, var/in has a body, this body is +allowed to access the variables defined by the var/in. + +With this in place, we can define the parser pieces. The first thing we +do is add it as a primary expression: + + +.. code-block:: python + + # primary ::= + # dentifierexpr | numberexpr | parenexpr | ifexpr | forexpr | varexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif isinstance(self.current, ForToken): + return self.ParseForExpr() + elif isinstance(self.current, VarToken): + return self.ParseVarExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + + +Next we define ParseVarExpr: + + +.. code-block:: python + + # varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression + def ParseVarExpr(self): + self.Next() # eat 'var'. + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') + + + #The first part of this code parses the list of identifier/expr pairs + #into the local variables list. + + while True: + var_name = self.current.name + self.Next() # eat the identifier. + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') + + + # Once all the variables are parsed, we then parse the body and create the + # AST node: + + + # At this point, we have to have 'in'. + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" keyword after "var".') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) + + + + + +Now that we can parse and represent the code, we need to support +emission of LLVM IR for it. This code starts out with: + + +.. code-block:: python + + class VarExpressionNode(ExpressionNode): + ... + def CodeGen(self): + old_bindings = {} + function = g_llvm_builder.basic_block.function + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca + + + + + +Basically it loops over all the variables, installing them one at a +time. For each variable we put into the symbol table, we remember the +previous value that we replace in ``old_bindings``. + +There are more comments here than code. The basic idea is that we emit +the initializer, create the alloca, then update the symbol table to +point to it. Once all the variables are installed in the symbol table, +we evaluate the body of the var/in expression: + + +.. code-block:: python + + # Codegen the body, now that all vars are in scope. + body = self.body.CodeGen() + + + +Finally, before returning, we restore the previous variable bindings: + + +.. code-block:: python + + # Pop all our variables from scope. + for var_name in self.variables: + if old_bindings[var_name] is not None: + g_named_values[var_name] = old_bindings[var_name] + else: + del g_named_values[var_name] + + # Return the body computation. + return body + + + + + +The end result of all of this is that we get properly scoped variable +definitions, and we even (trivially) allow mutation of them :). + +With this, we completed what we set out to do. Our nice iterative fib +example from the intro compiles and runs just fine. The mem2reg pass +optimizes all of our stack variables into SSA registers, inserting PHI +nodes where needed, and our front-end remains simple: no "iterated +dominance frontier" computation anywhere in sight. + +-------------- + +.. _code: + +Full Code Listing +=========================== + +Here is the complete code listing for our running example, enhanced with +mutable variables and var/in support: + + +.. code-block:: python + + #!/usr/bin/env python + + import re + from llvm.core import Module, Constant, Type, Function, Builder + from llvm.ee import ExecutionEngine, TargetData + from llvm.passes import FunctionPassManager + + from llvm.core import FCMP_ULT, FCMP_ONE + from llvm.passes import(PASS_PROMOTE_MEMORY_TO_REGISTER, + PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) + +Globals +------- + +.. code-block:: python + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + # The binary operator precedence chart. + g_binop_precedence = {} + + # Creates an alloca instruction in the entry block of the function. This is used + # for mutable variables. + def CreateEntryBlockAlloca(function, var_name): + entry = function.get_entry_basic_block() + builder = Builder.new(entry) + builder.position_at_beginning(entry) + return builder.alloca(Type.double(), var_name) + +Lexer +----- + +.. code-block:: python + + # The lexer yields one of these types for each token. + class EOFToken(object): + pass + class DefToken(object): + pass + class ExternToken(object): + pass + class IfToken(object): + pass + class ThenToken(object): + pass + class ElseToken(object): + pass + class ForToken(object): + pass + class InToken(object): + pass + class BinaryToken(object): + pass + class UnaryToken(object): + pass + class VarToken(object): + pass + + class IdentifierToken(object): + def __init__(self, name): + self.name = name + + class NumberToken(object): + def __init__(self, value): + self.value = value + + class CharacterToken(object): + def __init__(self, char): + self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): + return not self == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9] *') + REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + elif identifier == 'var': + yield VarToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +.. code-block:: python + + # Base class for all expression nodes. + class ExpressionNode(object): + pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_llvm_builder.load(g_named_values[self.name], self.name) + else: + raise RuntimeError('Unknown variable name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + # A special case for '=' because we don't want to emit the LHS as an # expression. + if self.operator == '=': + # Assignment requires the LHS to be an identifier. + if not isinstance(self.left, VariableExpressionNode): + raise RuntimeError('Destination of "=" must be a variable.') + + # Codegen the RHS. + value = self.right.CodeGen() + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def __init__(self, condition, then_branch, else_branch): + self.condition = condition + self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): + condition = self.condition.CodeGen() + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def __init__(self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable + self.start = start + self.end = end + self.step = step + self.body = body + + def CodeGen(self): + # Output this as: + # var = alloca double + # ... + # start = startexpr + # store start -> var + # goto loop + # loop: + # ... + # bodyexpr + # ... + # loopend: + # step = stepexpr + # endcond = endexpr + # + # curvar = load var + # nextvar = curvar + step + # store nextvar -> var + # br endcond, loop, endloop + # outloop: + + function = g_llvm_builder.basic_block.function + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + + # Make the new basic block for the loop, inserting after current block. + loop_block = function.append_basic_block('loop') + + # Insert an explicit fall through from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Within the loop, the variable is defined equal to the alloca. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = alloca + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Restore the unshadowed variable. + if old_value is not None: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + # Expression class for a unary operator. + class UnaryExpressionNode(ExpressionNode): + + def __init__(self, operator, operand): + self.operator = operator + self.operand = operand + + def CodeGen(self): + operand = self.operand.CodeGen() + function = g_llvm_module.get_function_named('unary' + self.operator) + return g_llvm_builder.call(function, [operand], 'unop') + + # Expression class for var/in. + class VarExpressionNode(ExpressionNode): + + def __init__(self, variables, body): + self.variables = variables + self.body = body + + def CodeGen(self): + old_bindings = {} + function = g_llvm_builder.basic_block.function + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca + + # Codegen the body, now that all vars are in scope. + body = self.body.CodeGen() + + # Pop all our variables from scope. + for var_name in self.variables: + if old_bindings[var_name] is not None: + g_named_values[var_name] = old_bindings[var_name] + else: + del g_named_values[var_name] + + # Return the body computation. + return body + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes), as well as if it is an operator. + class PrototypeNode(object): + + def __init__(self, name, args, is_operator=False, precedence=0): + self.name = name + self.args = args + self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): + return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): + assert self.is_operator + return self.name[-1] + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + + return function + + # Create an alloca for each argument and register the argument in the symbol + # table so that references to it will succeed. + def CreateArgumentAllocas(self, function): + for arg_name, arg in zip(self.args, function.args): + alloca = CreateEntryBlockAlloca(function, arg_name) + g_llvm_builder.store(arg, alloca) + g_named_values[arg_name] = alloca + + # This class represents a function definition itself. + class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Add all arguments to the symbol table and create their allocas. + self.prototype.CreateArgumentAllocas(function) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + +Parser +------ + +.. code-block:: python + + class Parser(object): + + def __init__(self, tokens): + self.tokens = tokens + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return g_binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression + def ParseIfExpr(self): + self.Next() # eat the if. + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression + def ParseForExpr(self): + self.Next() # eat the for. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression + def ParseVarExpr(self): + self.Next() # eat 'var'. + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') + + while True: + var_name = self.current.name + self.Next() # eat the identifier. + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') + + # At this point, we have to have 'in'. + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" keyword after "var".') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) + + # primary ::= + # dentifierexpr | numberexpr | parenexpr | ifexpr | forexpr | varexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif isinstance(self.current, ForToken): + return self.ParseForExpr() + elif isinstance(self.current, VarToken): + return self.ParseVarExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # unary ::= primary | unary_operator unary + def ParseUnary(self): + # If the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or + self.current in [CharacterToken('('), CharacterToken(',')]): + return self.ParsePrimary() + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + # binoprhs ::= (binary_operator unary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= unary binoprhs + def ParseExpression(self): + left = self.ParseUnary() + return self.ParseBinOpRHS(left, 0) + + # prototype + # ::= id '(' id* ')' + # ::= binary LETTER number? (id, id) + # ::= unary LETTER (id) + def ParsePrototype(self): + precedence = None + if isinstance(self.current, IdentifierToken): + kind = 'normal' + function_name = self.current.name + self.Next() # eat function name. + elif isinstance(self.current, UnaryToken): + kind = 'unary' + self.Next() # eat 'unary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "unary".') + function_name = 'unary' + self.current.char + self.Next() # eat the operator. + elif isinstance(self.current, BinaryToken): + kind = 'binary' + self.Next() # eat 'binary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "binary".') + function_name = 'binary' + self.current.char + self.Next() # eat the operator. + if isinstance(self.current, NumberToken): + if not 1 <= self.current.value <= 100: + raise RuntimeError('Invalid precedence: must be in range [1, 100].') + precedence = self.current.value + self.Next() # eat the precedence. + else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + raise#print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + raise#print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +Main driver code. +----------------- + +.. code-block:: python + + def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Promote allocas to registers. + g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + g_binop_precedence['='] = 2 + g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 + g_binop_precedence['*'] = 40 + + # Run the main "interpreter loop". + while True: + print 'ready<', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. + print '', g_llvm_module + + if __name__ == '__main__': + main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl8.rst b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst new file mode 100644 index 0000000..eb13dd0 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst @@ -0,0 +1,275 @@ +*************************************************** +Chapter 8: Conclusion and other useful LLVM tidbits +*************************************************** + +Written by Chris Lattner + +Tutorial Conclusion +=================== + +Welcome to the the final chapter of the "`Implementing a language with LLVM +`_" tutorial. +In the course of this tutorial, we have grown our little Kaleidoscope language +from being a useless toy, to being a semi-interesting (but probably still useless) +toy. :) + +It is interesting to see how far we've come, and how little code it has taken. +We built the entire lexer, parser, AST, code generator, and an interactive run-loop +(with a JIT!) by-hand in under 540 lines of (non-comment/non-blank) code. + +Our little language supports a couple of interesting features: it supports user +defined binary and unary operators, it uses JIT compilation for immediate evaluation, +and it supports a few control flow constructs with SSA construction. + +Part of the idea of this tutorial was to show you how easy and fun it can be to +define, build, and play with languages. Building a compiler need not be a scary +or mystical process! Now that you've seen some of the basics, I strongly encourage +you to take the code and hack on it. For example, try adding: + + - ***global variables*** - While global variables have questional value in modern + software engineering, they are often useful when putting together quick + little hacks like the Kaleidoscope compiler itself. Fortunately, our + current setup makes it very easy to add global variables: just have value + lookup check to see if an unresolved variable is in the global variable + symbol table before rejecting it. To create a new global variable, make + an instance of the LLVM GlobalVariable class. + + - ***typed variables*** - Kaleidoscope currently only supports variables of type + double. This gives the language a very nice elegance, because only supporting + one type means that you never have to specify types. Different languages have + different ways of handling this. The easiest way is to require the user to + specify types for every variable definition, and record the type of the variable + in the symbol table along with its Value*. + + - ***arrays, structs, vectors, etc*** - Once you add types, you can + start extending the type system in all sorts of + interesting ways. Simple arrays are very easy and are quite useful + for many different applications. Adding them is mostly an + exercise in learning how the LLVM `getelementptr + `_ instruction works: + it is so nifty/unconventional, it `has its own FAQ! + `_ If you add + support for recursive types (e.g. linked lists), make sure to + read the `section in the LLVM Programmer's Manual + `_ that describes + how to construct them. + + - ***standard runtime*** - Our current language allows the user to + access arbitrary external functions, and we use it for things like "putchard". + As you extend the language to add higher-level constructs, often these + constructs make the most sense if they are lowered to calls into a + language-supplied runtime. For example, if you add hash tables to the + language, it would probably make sense to add the routines to a runtime, + instead of inlining them all the way. + + - ***memory management*** - Currently we can only access the stack in Kaleidoscope. + It would also be useful to be able to allocate heap memory, either with calls + to the standard libc malloc/free interface or with a garbage collector. + If you would like to use garbage collection, note that LLVM fully supports + `Accurate Garbage Collection `_ + including algorithms that move objects and need to scan/update the stack. + + - ***debugger support*** - LLVM supports generation of `DWARF Debug info + `_ which + is understood by common debuggers like GDB. Adding support for debug info is + fairly straightforward. The best way to understand it is to compile some C/C++ + code with ``llvm-gcc -g -O0`` and taking a look at what it produces. + + - ***exception handling support*** - LLVM supports generation of `zero cost exceptions + `_ which interoperate + with code compiled in other languages. You could also generate code by + implicitly making every function return an error value and checking it. + You could also make explicit use of setjmp/longjmp. There are many different + ways to go here. + + - ***object orientation, generics, database access, complex numbers, geometric + programming, ...*** - Really, there is no end of crazy features that you can + add to the language. + + - ***unusual domains*** - We've been talking about applying LLVM to a domain that + many people are interested in: building a compiler for a specific language. + However, there are many other domains that can use compiler technology that are + not typically considered. For example, LLVM has been used to implement OpenGL + graphics acceleration, translate C++ code to ActionScript, and many other cute + and clever things. Maybe you will be the first to JIT compile a regular expression + interpreter into native code with LLVM? + + - ***Have fun*** - try doing something crazy and unusual. Building a language like + everyone else always has, is much less fun than trying something a little crazy or + off the wall and seeing how it turns out. If you get stuck or want to talk about it, + feel free to email the `llvmdev mailing list + `_: it has lots of people who are + interested in languages and are often willing to help out. + +Before we end this tutorial, I want to talk about some "tips and tricks" for +generating LLVM IR. These are some of the more subtle things that may not be obvious, +but are very useful if you want to take advantage of LLVM's capabilities. + +Properties of the LLVM IR +========================= + +We have a couple common questions about code in the LLVM IR form - let's +just get these out of the way right now, shall we? + +-------------- + +Target Independence +------------------- + +Kaleidoscope is an example of a "portable language": any program +written in Kaleidoscope will work the same way on any target that it +runs on. Many other languages have this property, e.g. LISP, Java, Haskell, +Javascript, Python, etc. (note that while these languages are portable, +not all their libraries are). + +One nice aspect of LLVM is that it is often capable of preserving target +independence in the IR: you can take the LLVM IR for a Kaleidoscope-compiled +program and run it on any target that LLVM supports, even emitting C code and +compiling that on targets that LLVM doesn't support natively. +You can trivially tell that the Kaleidoscope compiler generates target- +independent code because it never queries for any target-specific +information when generating code. + +The fact that LLVM provides a compact, target-independent, +representation for code gets a lot of people excited. Unfortunately, +these people are usually thinking about C or a language from the +C family when they are asking questions about language portability. +I say "unfortunately", because there is really no way to make (fully general) C +code portable, other than shipping the source code around (and of course, C +source code is not actually portable in general either - ever port a really old +application from 32- to 64-bits?). + +The problem with C (again, in its full generality) is that it is heavily +laden with target specific assumptions. As one simple example, the +preprocessor often destructively removes target-independence from the code +when it processes the input text:: + + + #ifdef __i386__ + int X = 1; + #else + int X = 42; + #endif + +While it is possible to engineer more and more complex solutions to problems like +this, it cannot be solved in full generality in a way that is better than +shipping the actual source code. + +That said, there are interesting subsets of C that can be made portable. +If you are willing to fix primitive types to a fixed size (say int = 32-bits, and +long = 64-bits), don't care about ABI compatibility with existing binaries, and +are willing to give up some other minor features, you can have portable code. +This can make sense for specialized domains such as an in-kernel language. + +-------------- + +Safety Guarantees +----------------- + +Many of the languages above are also "safe" languages: it is +impossible for a program written in Java to corrupt its address space and +crash the process (assuming the JVM has no bugs). Safety is an +interesting property that requires a combination of language design, +runtime support, and often operating system support. + +It is certainly possible to implement a safe language in LLVM, but LLVM +IR does not itself guarantee safety. The LLVM IR allows unsafe pointer casts, +use after free bugs, buffer over-runs, and a variety of other problems. Safety +needs to be implemented as a layer on top of LLVM and, conveniently, several groups +have investigated this. Ask on the `llvmdev mailing list +`_ if you are interested +in more details. + +-------------- + +Language-Specific Optimizations +------------------------------- + +One thing about LLVM that turns off many people is that it does not solve all +the world's problems in one system (sorry 'world hunger', someone else will +have to solve you some other day). One specific complaint is that people perceive +LLVM as being incapable of performing high-level language-specific optimization: +LLVM "loses too much information". + +Unfortunately, this is really not the place to give you a full and unified +version of "Chris Lattner's theory of compiler design". Instead, +I'll make a few observations: + +First, you're right that LLVM does lose information. +For example, as of this writing, there is no way to +distinguish in the LLVM IR whether an SSA-value came +from a C "int" or a C "long" on an ILP32 machine +(other than debug info). Both get compiled down to an 'i32' +value and the information about what it came from is lost. +The more general issue here, is that the LLVM type system +uses "structural equivalence" instead of "name equivalence". +Another place this surprises people is if you have two types +in a high-level language that have the same structure (e.g. +two different structs that have a single int field): +these types will compile down into a single LLVM type and it +will be impossible to tell what it came from. + +Second, while LLVM does lose information, LLVM is not a +fixed target: we continue to enhance and improve it in many +different ways. In addition to adding new features (LLVM did not +always support exceptions or debug info), we also extend the IR to +capture important information for optimization (e.g. whether an argument +is sign or zero extended, information about pointers aliasing, etc). Many +of the enhancements are user-driven: people want LLVM to include some specific +feature, so they go ahead and extend it. + +Third, it is possible and easy to add language-specific optimizations, +and you have a number of choices in how to do it. As one trivial example, +it is easy to add language-specific optimization passes that "know" things +about code compiled for a language. In the case of the C family, there is an +optimization pass that "knows" about the standard C library functions. If you +call "exit(0)" in main(), it knows that it is safe to optimize that into "return +0;" because C specifies what the 'exit' function does. + +In addition to simple library knowledge, it is possible to embed a +variety of other language-specific information into the LLVM IR. If +you have a specific need and run into a wall, please bring the topic +up on the llvmdev list. At the very worst, you can always treat LLVM as +if it were a "dumb code generator" and implement the high-level optimizations +you desire in your front-end, on the language-specific AST. + +-------------- + +Tips and Tricks +=============== + +There is a variety of useful tips and tricks that you come to +know after working on/with LLVM that aren't obvious at first glance. +Instead of letting everyone rediscover them, this section talks about +some of these issues. + +-------------- + +Implementing portable offsetof/sizeof +------------------------------------- + +One interesting thing that comes up, if you are trying to keep the +code generated by your compiler "target independent", is that you often +need to know the size of some LLVM type or the offset of some field in an +llvm structure. For example, you might need to pass the size of a type into +a function that allocates memory. + +Unfortunately, this can vary widely across targets: for example the width +of a pointer is trivially target-specific. However, there is a `clever way +to use the getelementptr instruction +`_ that +allows you to compute this in a portable way. + +-------------- + +Garbage Collected Stack Frames +------------------------------ + +Some languages want to explicitly manage their stack frames, often +so that they are garbage collected or to allow easy implementation +of closures. There are often better ways to implement these features +than explicit stack frames, but `LLVM does support them +`_, if you want. +It requires your front-end to convert the code into `Continuation Passing +Style `_ +and the use of tail calls (which LLVM also supports). \ No newline at end of file diff --git a/docs/source/doc/kaleidoscope/index.rst b/docs/source/doc/kaleidoscope/index.rst new file mode 100644 index 0000000..6099fea --- /dev/null +++ b/docs/source/doc/kaleidoscope/index.rst @@ -0,0 +1,21 @@ +Kaleidoscope +-------------- + +Implementing a Language with LLVM + +The LLVM `Kaleidoscope `_ tutorial +has been ported to llvmpy by Max Shawabkeh. + +.. toctree:: + :titlesonly: + :numbered: + + PythonLangImpl1.rst + PythonLangImpl2.rst + PythonLangImpl3.rst + PythonLangImpl4.rst + PythonLangImpl5.rst + PythonLangImpl6.rst + PythonLangImpl7.rst + PythonLangImpl8.rst + diff --git a/docs/source/doc/llpython/articles.rst b/docs/source/doc/llpython/articles.rst new file mode 100644 index 0000000..ff7669c --- /dev/null +++ b/docs/source/doc/llpython/articles.rst @@ -0,0 +1,10 @@ +LLPython Articles +================= + +.. toctree:: + :titlesonly: + :maxdepth: 1 + + intro_llpython.rst + nobitey_dev.rst + ctmp_in_llpython.rst diff --git a/docs/source/doc/llpython/ctmp_in_llpython.rst b/docs/source/doc/llpython/ctmp_in_llpython.rst new file mode 100644 index 0000000..53f63bf --- /dev/null +++ b/docs/source/doc/llpython/ctmp_in_llpython.rst @@ -0,0 +1,5 @@ +Compile-time Metaprogramming in LLPython +======================================== + +In this article, we discuss how LLPython supports compile-time +metaprogramming. diff --git a/docs/source/doc/llpython/index.rst b/docs/source/doc/llpython/index.rst new file mode 100644 index 0000000..43ea17a --- /dev/null +++ b/docs/source/doc/llpython/index.rst @@ -0,0 +1,9 @@ +LLPython Documentation +====================== + +.. toctree:: + :titlesonly: + :maxdepth: 2 + + articles.rst + reference.rst diff --git a/docs/source/doc/llpython/intro_llpython.rst b/docs/source/doc/llpython/intro_llpython.rst new file mode 100644 index 0000000..47c0c2a --- /dev/null +++ b/docs/source/doc/llpython/intro_llpython.rst @@ -0,0 +1,46 @@ +==================== +Introducing LLPython +==================== + +In this article, we introduce the llpython package. The primary goal +of the llpython package is to provide a Python dialect/subset that +maps directly to LLVM code. LLPython differs from its originating +LLVM translator, Numba, in the following aspects: + + * LLPython code is not intended to work in Python if not translated + and wrapped. + * The LLPython translator only uses LLVM types. + * LLPython is explicitly typed, and does not support type inference. + LLPython does not support implicit casts, all casts must be explicit. + * LLPython supports code that directly calls the C API, the Python C + API, and the llvm.core.Builder methods. + +Additionally, we designed the sub-package to have the following +engineering properties: + + * Usable from Python 2.7, and 3.X. At the time of writing, we plan + to support Python 2.6. + * Clean from Numba dependencies (other than llvmpy), and can be used + as a standalone code generator without a full Numba installation. + * Provides a series of Python bytecode passes that can be easily + used by other projects. + + +LLPython Origins +================ + +We developed LLPython with the initial goal of simplifying writing +LLVM code. + + +LLPython Internals +================== + +In this section, we describe the various passes performed by the +LLPython translator. + + +Conclusions +=========== + +LLPython is neat. diff --git a/docs/source/doc/llpython/llpython.byte_control.rst b/docs/source/doc/llpython/llpython.byte_control.rst new file mode 100644 index 0000000..e851dac --- /dev/null +++ b/docs/source/doc/llpython/llpython.byte_control.rst @@ -0,0 +1,6 @@ +===================== +llpython.byte_control +===================== + +.. automodule:: llpython.byte_control + :members: diff --git a/docs/source/doc/llpython/llpython.byte_flow.rst b/docs/source/doc/llpython/llpython.byte_flow.rst new file mode 100644 index 0000000..783a54b --- /dev/null +++ b/docs/source/doc/llpython/llpython.byte_flow.rst @@ -0,0 +1,6 @@ +================== +llpython.byte_flow +================== + +.. automodule:: llpython.byte_flow + :members: diff --git a/docs/source/doc/llpython/llpython.byte_translator.rst b/docs/source/doc/llpython/llpython.byte_translator.rst new file mode 100644 index 0000000..2a5993c --- /dev/null +++ b/docs/source/doc/llpython/llpython.byte_translator.rst @@ -0,0 +1,6 @@ +======================== +llpython.byte_translator +======================== + +.. automodule:: llpython.byte_translator + :members: diff --git a/docs/source/doc/llpython/llpython.bytecode_visitor.rst b/docs/source/doc/llpython/llpython.bytecode_visitor.rst new file mode 100644 index 0000000..3479ff7 --- /dev/null +++ b/docs/source/doc/llpython/llpython.bytecode_visitor.rst @@ -0,0 +1,6 @@ +========================= +llpython.bytecode_visitor +========================= + +.. automodule:: llpython.bytecode_visitor + :members: diff --git a/docs/source/doc/llpython/llpython.bytetype.rst b/docs/source/doc/llpython/llpython.bytetype.rst new file mode 100644 index 0000000..81efe83 --- /dev/null +++ b/docs/source/doc/llpython/llpython.bytetype.rst @@ -0,0 +1,6 @@ +================= +llpython.bytetype +================= + +.. automodule:: llpython.bytetype + :members: diff --git a/docs/source/doc/llpython/llpython.control_flow.rst b/docs/source/doc/llpython/llpython.control_flow.rst new file mode 100644 index 0000000..c9aee7d --- /dev/null +++ b/docs/source/doc/llpython/llpython.control_flow.rst @@ -0,0 +1,6 @@ +===================== +llpython.control_flow +===================== + +.. automodule:: llpython.control_flow + :members: diff --git a/docs/source/doc/llpython/llpython.gen_bytecode_visitor.rst b/docs/source/doc/llpython/llpython.gen_bytecode_visitor.rst new file mode 100644 index 0000000..2bc19db --- /dev/null +++ b/docs/source/doc/llpython/llpython.gen_bytecode_visitor.rst @@ -0,0 +1,6 @@ +============================= +llpython.gen_bytecode_visitor +============================= + +.. automodule:: llpython.gen_bytecode_visitor + :members: diff --git a/docs/source/doc/llpython/llpython.nobitey.rst b/docs/source/doc/llpython/llpython.nobitey.rst new file mode 100644 index 0000000..59e052d --- /dev/null +++ b/docs/source/doc/llpython/llpython.nobitey.rst @@ -0,0 +1,6 @@ +================ +llpython.nobitey +================ + +.. automodule:: llpython.nobitey + :members: diff --git a/docs/source/doc/llpython/llpython.opcode_util.rst b/docs/source/doc/llpython/llpython.opcode_util.rst new file mode 100644 index 0000000..0fa5387 --- /dev/null +++ b/docs/source/doc/llpython/llpython.opcode_util.rst @@ -0,0 +1,6 @@ +==================== +llpython.opcode_util +==================== + +.. automodule:: llpython.opcode_util + :members: diff --git a/docs/source/doc/llpython/llpython.phi_injector.rst b/docs/source/doc/llpython/llpython.phi_injector.rst new file mode 100644 index 0000000..3db3863 --- /dev/null +++ b/docs/source/doc/llpython/llpython.phi_injector.rst @@ -0,0 +1,6 @@ +===================== +llpython.phi_injector +===================== + +.. automodule:: llpython.phi_injector + :members: diff --git a/docs/source/doc/llpython/llpython.pyaddfunc.rst b/docs/source/doc/llpython/llpython.pyaddfunc.rst new file mode 100644 index 0000000..39e0de7 --- /dev/null +++ b/docs/source/doc/llpython/llpython.pyaddfunc.rst @@ -0,0 +1,6 @@ +================== +llpython.pyaddfunc +================== + +.. automodule:: llpython.pyaddfunc + :members: diff --git a/docs/source/doc/llpython/llpython.rst b/docs/source/doc/llpython/llpython.rst new file mode 100644 index 0000000..87fd3d5 --- /dev/null +++ b/docs/source/doc/llpython/llpython.rst @@ -0,0 +1,6 @@ +======== +llpython +======== + +.. automodule:: llpython + :members: diff --git a/docs/source/doc/llpython/nobitey_dev.rst b/docs/source/doc/llpython/nobitey_dev.rst new file mode 100644 index 0000000..be7b4d8 --- /dev/null +++ b/docs/source/doc/llpython/nobitey_dev.rst @@ -0,0 +1,5 @@ +nobitey: Using ctypes and llvmpy to Bypass ctypes +================================================= + +In this article, we show how nobitey uses llvmpy to eliminate the +ctypes call overhead. diff --git a/docs/source/doc/llpython/reference.rst b/docs/source/doc/llpython/reference.rst new file mode 100644 index 0000000..7818100 --- /dev/null +++ b/docs/source/doc/llpython/reference.rst @@ -0,0 +1,21 @@ +LLPython Module Reference +========================= + +Contents: + +.. toctree:: + :titlesonly: + :maxdepth: 2 + + llpython.rst + llpython.bytecode_visitor.rst + llpython.byte_control.rst + llpython.byte_flow.rst + llpython.byte_translator.rst + llpython.bytetype.rst + llpython.control_flow.rst + llpython.gen_bytecode_visitor.rst + llpython.nobitey.rst + llpython.opcode_util.rst + llpython.phi_injector.rst + llpython.pyaddfunc.rst diff --git a/docs/source/doc/llvm.core.Argument.rst b/docs/source/doc/llvm.core.Argument.rst new file mode 100644 index 0000000..a2ffbfa --- /dev/null +++ b/docs/source/doc/llvm.core.Argument.rst @@ -0,0 +1,65 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: Argument (llvm.core) | ++-------------------------------+ + +The ``args`` property of ``llvm.core.Function`` objects yields +``llvm.core.Argument`` objects. This allows for setting attributes for +functions arguments. ``Argument`` objects cannot be constructed from +user code, the only way to get a reference to these are from +``Function`` objects. + +The method ``add_attribute`` and ``remove_attribute`` can be used to add +or remove the following attributes: + +Value\| Equivalent LLVM Assembly Keyword \| +-----\|----------------------------------\| ``ATTR_ZEXT``\ \| +``zeroext`` \| ``ATTR_SEXT``\ \| ``signext`` \| ``ATTR_IN_REG``\ \| +``inreg`` \| ``ATTR_BY_VAL``\ \| ``byval`` \| ``ATTR_STRUCT_RET``\ \| +``sret`` \| ``ATTR_NO_ALIAS``\ \| ``noalias`` \| ``ATTR_NO_CAPTURE``\ \| +``nocapture`` \| ``ATTR_NEST``\ \| ``nest`` \| + +These method work exactly like the `corresponding +methods `_ of the ``Function`` class above. Refer +`LLVM docs `_ for +information on what each attribute means. + +The alignment of any argument can be set via the ``alignment`` property, +to any power of 2. + +llvm.core.Argument +================== + +Base Class +---------- + +- `llvm.core.Value `_ + +Properties +---------- + +``alignment`` +~~~~~~~~~~~~~ + +The alignment of the argument. Must be a power of 2. + +Methods +------- + +``add_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Add an attribute ``attr`` to the argument, from the set listed above. + +``remove_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the attribute ``attr`` of the argument. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Argument + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.ArrayType.rst b/docs/source/doc/llvm.core.ArrayType.rst new file mode 100644 index 0000000..3a4e645 --- /dev/null +++ b/docs/source/doc/llvm.core.ArrayType.rst @@ -0,0 +1,37 @@ ++--------------------------------+ +| layout: page | ++--------------------------------+ +| title: ArrayType (llvm.core) | ++--------------------------------+ + +llvm.core.ArrayType +=================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``element`` +~~~~~~~~~~~ + +[read-only] + +A ``Type`` object representing the type of the element of the array. + +``count`` +~~~~~~~~~ + +[read-only] + +The number of elements in the array. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.ArrayType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.BasicBlock.rst b/docs/source/doc/llvm.core.BasicBlock.rst new file mode 100644 index 0000000..eb10be3 --- /dev/null +++ b/docs/source/doc/llvm.core.BasicBlock.rst @@ -0,0 +1,51 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: BasicBlock (llvm.core) | ++---------------------------------+ + +A basicblock is a list of instructions. A wellformed basicblock should +end with a terminator. ``Function.verify()`` will verify that. A +terminator is either a branch instruction or return instruction. It is +not possible to have instructions after a branch or return instruction. + +llvm.core.BasicBlock +==================== + +Base Class +---------- + +- `llvm.core.Value `_ + +Methods +------- + +``delete(self)`` +~~~~~~~~~~~~~~~~ + +Delete this basicblock from the function (``self.function``). + +``insert_before(self, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TODO + +Proporties +---------- + +``function`` +~~~~~~~~~~~~ + +The parent function of this basicblock. + +``instructions`` +~~~~~~~~~~~~~~~~ + +A list of instructions in this basicblock. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.BasicBlock + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Builder.rst b/docs/source/doc/llvm.core.Builder.rst new file mode 100644 index 0000000..24b9361 --- /dev/null +++ b/docs/source/doc/llvm.core.Builder.rst @@ -0,0 +1,418 @@ ++------------------------------+ +| layout: page | ++------------------------------+ +| title: Builder (llvm.core) | ++------------------------------+ + +The ``Builder`` class corresponds to the +`IRBuilder `_ +in C++ llvm. It provides an uniform API to populating +`BasicBlocks `_. Most of the methods in +``Builder`` correspond to the instructions in the LLVM IR. See `LLVM +documentation `_ for detail. These +methods have the ``name`` argument for overiding the name of the result +variable. When it is an empty string (default value), LLVM will set a +numeric ID for the result variable. + +llvm.core.Builder +================= + +- This will become a table of contents (this text will be scraped). + {:toc} + +Static Factor Method +-------------------- + +``new(basic_block)`` +~~~~~~~~~~~~~~~~~~~~ + +Create an instance of ``Builder`` at +`BasicBlock `_. + +Methods +------- + +``add(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs+rhs`` for integer values only. + +``alloca(self, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that allocates stack memory for a value of type +``ty``. + +``alloca_array(self, ty, size, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that allocates stack memory for a ``size`` +elements array of type ``ty``. + +``and_(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs & rhs``. + +``ashr(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs >> rhs`` using arithmetic +shift. + +``bitcast(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that cast ``value`` to type ``dest_ty``. + +``branch(self, bblk)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that branch to basicblock ``bblk``. + +``call(self, fn, args, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that call function ``fn`` with a iterable of +arguments ``args``. + +``cbranch(self, if_value, then_blk, else_blk)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that conditionally branch base on the predicate +``if_value``. If ``if_value`` is ``True``, branch to ``then_blk``; +Otherwise, branch to ``else_blk``. + +``extract_element(self, vec_val, idx_val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that extracts an element from a value ``vec_val`` +of `llvm.core.VectorType `_ at index +``idx_val``. + +``extract_value(self, retval, idx, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that extracts an element from an aggregate value +``retval`` at index ``idx``. + +``fadd(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs + rhs`` for floating-point +values. + +``fcmp(self, rpred, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that compares ``lhs`` and ``rhs`` using the +comparision operation defined by ``rpred``. See +`here `_ for a list of comparators. + +``fdiv(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs / rhs`` for floating-point +values. + +``fmul(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs * rhs`` for floating-point +values. + +``fpext(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that extends ``value`` to a float type +``dest_ty``. + +``fptosi(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a floating-point value ``value`` to +a signed integer type ``dest_ty``. + +``fptoui(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a floating-point value ``value`` to +an unsigned integer type ``dest_ty``. + +``fptrunc(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that truncates a floating-point value ``value`` to +a float type ``dest_ty``. + +``free(self, ptr)`` +~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that call performs heap deallocation on pointer +``ptr``. + +``frem(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs % rhs`` for floating-point +values. + +``fsub(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs - rhs`` for floating-point +values. + +``gep(self, ptr, indices, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See `GEP `_. + +``getresult(self, retval, idx, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +same as ``extract_value``. + +``icmp(self, ipred, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that compares ``lhs`` and ``rhs`` using the +comparision operation defined by ``ipred``. See +`here `_ for a list of comparators. + +``insert_element(self, vec_val, elt_val, idx_val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that inserts a value ``elt_val`` into ``vec_val`` +of `llvm.core.VectorType `_ at index +``idx_val``. + +``inttoptr(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts an integer ``value`` to pointer +``dest_ty``. + +``invoke(self, func, args, then_blk, catch_blk, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See `invoke `_ + +``load(self, ptr, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that loads a value at the memory pointed by +``ptr``. + +``lshr(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs >> rhs`` using logical shift. + +``malloc(self, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that allocates heap memory of type ``ty``. The +instruction returns a pointer that points to a value of type ``ty``. + +``malloc_array(self, ty, size, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similar to ``malloc`` but allocates an array of ``size`` elements. + +``mul(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs * rhs`` for integer types. + +``neg(self, val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``0 - val``. + +``not_(self, val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes an one's complement of ``val``. + +``or_(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs | rhs``. + +``phi(self, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a PHI node of type ``ty``. + +``position_at_beginning(self, bblk)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Position the builder at the beginning of the given block. Next +instruction inserted will be first one in the block. + +``position_at_end(self, bblk)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Position the builder at the end of the given block. Next instruction +inserted will be last one in the block. + +``position_before(self, instr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Position the builder before the given instruction. The instruction can +belong to a basic block other than the current one. + +``ptrtoint(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a pointer to an integer ``value`` of +type ``dest_ty``. + +``ret(self, value)`` +~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that returns ``value``. + +``ret_many(self, values)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that returns ``values`` which is an iterable of +`llvm.core.Value `_. + +``ret_void(self)`` +~~~~~~~~~~~~~~~~~~ + +Insert an instruction that returns nothing (void). + +``sdiv(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs / rhs`` for signed integers. + +``select(self, cond, then_value, else_value, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``cond ? then_value : else_value``. + +``sext(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that sign extends an integer ``value`` to type +``dest_ty``. + +``shl(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs << rhs``. + +``shuffle_vector(self, vecA, vecB, mask, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that performs a vector shuffle base on the two +vectors -- ``vecA`` and ``vecB``, base on a bit mask ``mask``. The mask +must be a constant. + +See `LLVM document `_ +for detail. + +``sitofp(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a signed integer ``value`` to a +floating-point type ``dest_ty``. + +``srem(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs % rhs`` for signed integers. + +``store(self, value, ptr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that stores ``value`` into the memory pointed by +``ptr``. + +``sub(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs - rhs``. + +``switch(self, value, else_blk, n=10)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that transfer control flow depending on the +``value``. ``else_blk`` is the default case. ``n`` sets the number of +additional cases. + +This method returns an instance of +`SwitchInstruction `_ for adding +cases to the switch. + +``trunc(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that truncates an integer ``value`` to the +destination integer type ``dest_ty``. + +``udiv(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs / rhs`` for unsigned integers. + +``uitofp(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts an unsigned integer ``value`` to a +floating-point type ``dest_ty``. + +``unreachable(self)`` +~~~~~~~~~~~~~~~~~~~~~ + +Insert an unreachabe instruction, which has no defined semantics. See +`LLVM document `_ for +detail. + +``urem(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs % rhs`` for unsigned integers. + +``vaarg(self, list_val, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is used to access variable arguments given as ``list_val`` of type +``ty``. see `LLVM +document `_ about +variable argument intrinsics. + +``xor(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs xor rhs``. + +``zext(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that zero extends ``value`` to type ``dest_ty``. + +Properties +---------- + +``basic_block`` +~~~~~~~~~~~~~~~ + +The `BasicBlock `_ where the builder is +positioned. + +``block`` +~~~~~~~~~ + +Deprecated. Same as ``basic_block`` + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Builder + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Constant.rst b/docs/source/doc/llvm.core.Constant.rst new file mode 100644 index 0000000..3822046 --- /dev/null +++ b/docs/source/doc/llvm.core.Constant.rst @@ -0,0 +1,363 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: Constant (llvm.core) | ++-------------------------------+ + +llvm.core.Constant +================== + +``Constant``-s represents constants that appear within the code. The +values of such objects are known at creation time. Constants can be +created from Python constants. A constant expression is also a constant +-- given a ``Constant`` object, an operation (like addition, subtraction +etc) can be specified, to yield a new ``Constant`` object. Let's see +some examples: + + +.. code-block:: python + + #!/usr/bin/env python + + ti = Type.int() # a 32-bit int type + + k1 = Constant.int(ti, 42) # "int k1 = 42;" k2 = k1.add( Constant.int( + ti, 10 ) ) # "int k2 = k1 + 10;" + + tr = Type.float() + + 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 +------------------------------------- +.. autoclass:: llvm.core.Constant + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Function.rst b/docs/source/doc/llvm.core.Function.rst new file mode 100644 index 0000000..cda101e --- /dev/null +++ b/docs/source/doc/llvm.core.Function.rst @@ -0,0 +1,158 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: Function (llvm.core) | ++-------------------------------+ + +llvm.core.Function +================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Base Class +---------- + +- `llvm.core.GlobalValue `_ + +Static Constructors +------------------- + +``new(module_obj, func_ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a function named ``name`` of type ``func_ty`` in the module +``module_obj`` and return a ``Function`` object that represents it. + +``get(module_obj, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Return a ``Function`` object to represent the function named ``name`` in +the module ``module_obj`` or raise ``LLVMException`` if such a function +does not exist. + +``get_or_insert(module_obj, func_ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similar to ``get``, except that if the function does not exist it is +added first, as though with ``new``. + +``intrinsic(module_obj, intrinsic_id, types)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create and return a ``Function`` object that refers to an intrinsic +function, as described `here `_. + +Properties +---------- + +``calling_convention`` +~~~~~~~~~~~~~~~~~~~~~~ + +The calling convention for the function, as listed +`here `_. + +``collector`` +~~~~~~~~~~~~~ + +A string holding the name of the garbage collection algorithm. See `LLVM +docs `_. + +``does_not_throw`` +~~~~~~~~~~~~~~~~~~ + +Setting to True sets the ``ATTR_NO_UNWIND`` attribute, False removes it. +Shortcut to using ``f.add_attribute(ATTR_NO_UNWIND)`` and +``f.remove_attribute(ATTR_NO_UNWIND)``. + +``args`` +~~~~~~~~ + +[read-only] + +List of `llvm.core.Argument `_ objects +representing the formal arguments of the function. + +``basic_block_count`` +~~~~~~~~~~~~~~~~~~~~~ + +[read-only] + +Number of basic blocks belonging to this function. Same as +``len(f.basic_blocks)`` but faster if you just want the count. + +``entry_basic_block`` +~~~~~~~~~~~~~~~~~~~~~ + +[read-only] + +The `llvm.core.BasicBlock `_ object +representing the entry basic block for this function, or ``None`` if +there are no basic blocks. + +``basic_blocks`` +~~~~~~~~~~~~~~~~ + +[read-only] + +List of `llvm.core.BasicBlock `_ objects +representing the basic blocks belonging to this function. + +``intrinsic_id`` +~~~~~~~~~~~~~~~~ + +[read-only] + +Returns the ID of the intrinsic if this object represents an intrinsic +instruction. Otherwise 0. + +Methods +------- + +``delete()`` +~~~~~~~~~~~~ + +Deletes the function from it's module. Do not hold any references to +this object after calling ``delete`` on it. + +``append_basic_block(name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a new basic block named ``name``, and return a corresponding +`llvm.core.BasicBlock `_ object. Note that if +this is not the entry basic block, you'll have to add appropriate branch +instructions from other basic blocks yourself. + +``add_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Add an attribute ``attr`` to the function, from the set listed above. + +``remove_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the attribute ``attr`` of the function. + +``viewCFG()`` +~~~~~~~~~~~~~ + +Displays the control flow graph using the GraphViz tool. + +``viewCFGOnly()`` +~~~~~~~~~~~~~~~~~ + +Displays the control flow graph using the GraphViz tool, but omitting +function bodies. + +``verify()`` +~~~~~~~~~~~~ + +Verifies the function. See `LLVM +docs `_. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Function + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.FunctionType.rst b/docs/source/doc/llvm.core.FunctionType.rst new file mode 100644 index 0000000..7b728a8 --- /dev/null +++ b/docs/source/doc/llvm.core.FunctionType.rst @@ -0,0 +1,55 @@ ++-----------------------------------+ +| layout: page | ++-----------------------------------+ +| title: FunctionType (llvm.core) | ++-----------------------------------+ + +llvm.core.FunctionType +====================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``return_type`` +~~~~~~~~~~~~~~~ + +[read-only] + +A `Type `_ object, representing the return type of +the function. + +``vararg`` +~~~~~~~~~~ + +[read-only] + +``True`` if the function is variadic. + +``args`` +~~~~~~~~ + +[read-only] + +Returns an iterable object that yields `Type `_ +objects that represent, in order, the types of the arguments accepted by +the function. Used like this: + + +.. code-block:: python + + func_type = Type.function( Type.int(), [ + Type.int(), Type.int() ] ) for arg in func_type.args: assert arg.kind + == TYPE_INTEGER assert arg == Type.int() assert func_type.arg_count + == len(func_type.args) + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.FunctionType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.GlobalValue.rst b/docs/source/doc/llvm.core.GlobalValue.rst new file mode 100644 index 0000000..a5c2383 --- /dev/null +++ b/docs/source/doc/llvm.core.GlobalValue.rst @@ -0,0 +1,103 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: GlobalValue (llvm.core) | ++----------------------------------+ + +The class ``llvm.core.GlobalValue`` represents module-scope aliases, +variables and functions. Global variables are represented by the +sub-class `llvm.core.GlobalVariable `_ +and functions by `llvm.core.Function `_. + +Global values have the read-write properties ``linkage``, ``section``, +``visibility`` and ``alignment``. Use one of the following constants +(from llvm.core) as values for ``linkage`` (see `LLVM +documentaion `_ for +details on each): + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| ``LINKAGE_EXTERNAL`` \| +``externally_visible`` \| ``LINKAGE_AVAILABLE_EXTERNALLY`` \| +``available_externally`` \| ``LINKAGE_LINKONCE_ANY`` \| ``linkonce`` \| +``LINKAGE_LINKONCE_ODR`` \| ``linkonce_odr`` \| ``LINKAGE_WEAK_ANY`` \| +``weak`` \| ``LINKAGE_WEAK_ODR`` \| ``weak_odr`` \| +``LINKAGE_APPENDING`` \| ``appending`` \| ``LINKAGE_INTERNAL`` \| +``internal`` \| ``LINKAGE_PRIVATE`` \| ``private`` \| +``LINKAGE_DLLIMPORT`` \| ``dllimport`` \| ``LINKAGE_DLLEXPORT`` \| +``dllexport`` \| ``LINKAGE_EXTERNAL_WEAK`` \| ``extern_weak`` \| +``LINKAGE_GHOST`` \| deprecated -- do not use \| ``LINKAGE_COMMON`` \| +``common`` \| ``LINKAGE_LINKER_PRIVATE`` \| ``linker_private`` \| + +The ``section`` property can be assigned strings (like ".rodata"), which +will be used if the target supports it. Visibility property can be set +to one of thse constants (from llvm.core, see also `LLVM +docs `_): + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| ``VISIBILITY_DEFAULT`` \| +``default`` \| ``VISIBILITY_HIDDEN`` \| ``hidden`` \| +``VISIBILITY_PROTECTED`` \| ``protected`` \| + +The ``alignment`` property can be 0 (default), or can be set to a power +of 2. The read-only property ``is_declaration`` can be used to check if +the global is a declaration or not. The module to which the global +belongs to can be retrieved using the ``module`` property (read-only). + +llvm.core.GlobalValue +===================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Base Class +---------- + +- `llvm.core.Constant `_ + +Properties +---------- + +``linkage`` +~~~~~~~~~~~ + +The linkage type, takes one of the constants listed above (LINKAGE\_\*). + +``section`` +~~~~~~~~~~~ + +A string like ".rodata", indicating the section into which the global is +placed into. + +``visibility`` +~~~~~~~~~~~~~~ + +The visibility type, takes one of the constants listed above +(VISIBILITY\_\*). + +``alignment`` +~~~~~~~~~~~~~ + +A power-of-2 integer indicating the boundary to align to. + +``is_declaration`` +~~~~~~~~~~~~~~~~~~ + +[read-only] + +``True`` if the global is a declaration, ``False`` otherwise. + +``module`` +~~~~~~~~~~ + +[read-only] + +:: + + The module object to which this global belongs to. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.GlobalValue + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.GlobalVariable.rst b/docs/source/doc/llvm.core.GlobalVariable.rst new file mode 100644 index 0000000..1ba69d8 --- /dev/null +++ b/docs/source/doc/llvm.core.GlobalVariable.rst @@ -0,0 +1,49 @@ ++-------------------------------------+ +| layout: page | ++-------------------------------------+ +| title: GlobalVariable (llvm.core) | ++-------------------------------------+ + +llvm.core.GlobalVariable +======================== + +Global variables (``llvm.core.GlobalVariable``) are subclasses of +`llvm.core.GlobalValue `_ and represent +module-level variables. These can have optional initializers and can be +marked as constants. Global variables can be created either by using the +``add_global_variable`` method of the `Module `_ +class, or by using the static method ``GlobalVariable.new``. + + +.. code-block:: python + + # create a global variable using + add_global_variable method gv1 = + module_obj.add_global_variable(Type.int(), "gv1") + + # or equivalently, using a static constructor method + gv2 = GlobalVariable.new(module_obj, Type.int(), "gv2") {% endhighlight + %} + + Existing global variables of a module can be accessed by name using + ``module_obj.get_global_variable_named(name)`` or + ``GlobalVariable.get``. All existing global variables can be enumerated + via iterating over the property ``module_obj.global_variables``. + + {% highlight python %} # retrieve a reference to the global variable + gv1, # using the get_global_variable_named method gv1 = + module_obj.get_global_variable_named("gv1") + + # or equivalently, using the static ``get`` method: + gv2 = GlobalVariable.get(module_obj, "gv2") + + # list all global variables in a module + for gv in module_obj.global_variables: print gv.name, "of type", + gv.type + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.GlobalVariable + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Instruction.rst b/docs/source/doc/llvm.core.Instruction.rst new file mode 100644 index 0000000..67c43f0 --- /dev/null +++ b/docs/source/doc/llvm.core.Instruction.rst @@ -0,0 +1,249 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: Instruction (llvm.core) | ++----------------------------------+ + +An ``llvm.core.Instruction`` object represents an LLVM instruction. This +class is the root of a small hierarchy: + +:: + + Instruction + CallOrInvokeInstruction + PHINode + SwitchInstruction + CompareInstruction + +Instructions are not created directly, but via a builder. The builder +both creates instructions and adds them to a basic block at the same +time. One way of getting instruction objects are from basic blocks. + +Being derived from `llvm.core.User `_, the +instruction is-a user, i.e., an instruction in turn uses other values. +The values an instruction uses are its operands. These may be accessed +using ``operands`` property from the +`llvm.core.User `_ base. + +The name of the instruction (like ``add``, ``mul`` etc) can be got via +the ``opcode_name`` property. The ``basic_block`` property gives the +basic block to which the instruction belongs to. Note that llvmpy does +not allow free-standing instruction objects (i.e., all instructions are +created contained within a basic block). + +Classes of instructions can be got via the properties ``is_terminator``, +``is_binary_op``, ``is_shift`` etc. See below for the full list. + +- This will become a table of contents (this text will be scraped). + {:toc} + +llvm.core.Instruction +===================== + +Base Class +---------- + +- `llvm.core.User `_ + +Properties +---------- + +``basic_block`` +~~~~~~~~~~~~~~~ + +[read-only] The basic block to which this instruction belongs to. + +``is_terminator`` +~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a terminator instruction. + +``is_binary_op`` +~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a binary operator. + +``is_shift`` +~~~~~~~~~~~~ + +[read-only] True if the instruction is a shift instruction. + +``is_cast`` +~~~~~~~~~~~ + +[read-only] True if the instruction is a cast instruction. + +``is_logical_shift`` +~~~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a logical shift instruction. + +``is_arithmetic_shift`` +~~~~~~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is an arithmetic shift instruction. + +``is_associative`` +~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is associative. + +``is_commutative`` +~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is commutative. + +``is_volatile`` +~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a volatile load or store. + +``opcode`` +~~~~~~~~~~ + +[read-only] The numeric opcode value of the instruction. Do not rely on +the absolute value of this number, it may change with LLVM version. + +``opcode_name`` +~~~~~~~~~~~~~~~ + +[read-only] The name of the instruction, like ``add``, ``sub`` etc. + +-------------- + +llvm.core.CallOrInvokeInstruction +================================= + +The ``llvm.core.CallOrInvokeInstruction`` is a subclass of +``llvm.core.Instruction``, and represents either a ``call`` or an +``invoke`` instruction. + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Properties +---------- + +``calling_convention`` Get or set the calling convention. See +`here `_ for possible values. + +Methods +------- + +``add_parameter_attribute(idx, attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add an attribute ``attr`` to the ``idx``-th argument. See +`here `_ for possible values of ``attr``. + +``remove_parameter_attribute(idx, attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove an attribute ``attr`` from the ``idx``-th argument. See +`here `_ for possible values of ``attr``. + +``set_parameter_alignment(idx, align)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Set the alignment of the ``idx``-th argument to ``align``. ``align`` +should be a power of two. + +-------------- + +llvm.core.PHINode +================= + +The ``llvm.core.PHINode`` is a subclass of ``llvm.core.Instruction``, +and represents the ``phi`` instruction. When created (using +``Builder.phi``) the phi node contains no incoming blocks (nor their +corresponding values). To add an incoming arc to the phi node, use the +``add_incoming`` method, which takes a source block +(`llvm.core.BasicBlock `_ object) and a value +(object of `llvm.core.Value `_ or of a class +derived from it) that the phi node will take on if control branches in +from that block. + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Properties +---------- + +``incoming_count`` [read-only] The number of incoming arcs for this phi +node. + +Methods +------- + +``add_incoming(value, block)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add an incoming arc, from the +`llvm.core.BasicBlock `_ object ``block``, +with the corresponding value ``value``. ``value`` should be an object of +`llvm.core.Value `_ (or of a descendent class). + +``get_incoming_value(idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the ``idx``-th incoming arc's value. + +``get_incoming_block(idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the ``idx``-th incoming arc's block. + +llvm.core.SwitchInstruction # {#switchinstr} +============================================ + +(TODO describe) + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Methods +------- + +``add_case(const, block)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add another case to the switch statement. When the expression being +evaluated equals ``const``, then control branches to ``block``. Here +``const`` must be of type +`llvm.core.ConstantInt `_. + +-------------- + +llvm.core.CompareInstruction +============================ + +(TODO describe) + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Properties +---------- + +``predicate`` +~~~~~~~~~~~~~ + +[read-only] + +The predicate of the compare instruction, one of the ``ICMP_*`` or +``FCMP_*`` constants. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Instruction + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.IntegerType.rst b/docs/source/doc/llvm.core.IntegerType.rst new file mode 100644 index 0000000..6f1e2b1 --- /dev/null +++ b/docs/source/doc/llvm.core.IntegerType.rst @@ -0,0 +1,30 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: IntegerType (llvm.core) | ++----------------------------------+ + +llvm.core.IntegerType +===================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``width`` +~~~~~~~~~ + +[read-only] + +The width of the integer type, in number of bits. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.IntegerType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Module.rst b/docs/source/doc/llvm.core.Module.rst new file mode 100644 index 0000000..75cc174 --- /dev/null +++ b/docs/source/doc/llvm.core.Module.rst @@ -0,0 +1,29 @@ ++-----------------------------+ +| layout: page | ++-----------------------------+ +| title: Module (llvm.core) | ++-----------------------------+ + +llvm.core.Module +================ + +Modules are top-level container objects. You need to create a module +object first, before you can add global variables, aliases or functions. +Modules are created using the static method ``Module.new``: + +.. code-block:: python + + #!/usr/bin/env python + + from llvm import * + from llvm.core import * + + # create a module + my_module = Module.new('my_module') + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Module + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.PointerType.rst b/docs/source/doc/llvm.core.PointerType.rst new file mode 100644 index 0000000..cc65139 --- /dev/null +++ b/docs/source/doc/llvm.core.PointerType.rst @@ -0,0 +1,38 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: PointerType (llvm.core) | ++----------------------------------+ + +llvm.core.PointerType +===================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``address_space`` +~~~~~~~~~~~~~~~~~ + +[read-only] + +The address space of the pointer. + +``pointee`` +~~~~~~~~~~~ + +[read-only] + +A `Type `_ object representing the type of the +value pointed to. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.PointerType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.StructType.rst b/docs/source/doc/llvm.core.StructType.rst new file mode 100644 index 0000000..f3b0786 --- /dev/null +++ b/docs/source/doc/llvm.core.StructType.rst @@ -0,0 +1,8 @@ +llvm.core.StructType +==================== + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.StructType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Type.rst b/docs/source/doc/llvm.core.Type.rst new file mode 100644 index 0000000..b1eb354 --- /dev/null +++ b/docs/source/doc/llvm.core.Type.rst @@ -0,0 +1,135 @@ ++---------------------------+ +| layout: page | ++---------------------------+ +| title: Type (llvm.core) | ++---------------------------+ + +llvm.core.Type +============== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Static Constructors +------------------- + +``int(n)`` +~~~~~~~~~~ + +Create an integer type of bit width ``n``. + +``float()`` +~~~~~~~~~~~ + +Create a 32-bit floating point type. + +``double()`` +~~~~~~~~~~~~ + +Create a 64-bit floating point type. + +``x86_fp80()`` +~~~~~~~~~~~~~~ + +Create a 80-bit 80x87-style floating point type. + +``fp128()`` +~~~~~~~~~~~ + +Create a 128-bit floating point type (112-bit mantissa). + +``ppc_fp128()`` +~~~~~~~~~~~~~~~ + +Create a 128-bit float (two 64-bits). + +``function(ret, params, vararg=False)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a function type, having the return type ``ret`` (must be a +``Type``), accepting the parameters ``params``, where ``params`` is an +iterable, that yields ``Type`` objects representing the type of each +function argument in order. If ``vararg`` is ``True``, function is +variadic. + +``struct(eltys, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create an unpacked structure. ``eltys`` is an iterable, that yields +``Type`` objects representing the type of each element in order. + +If ``name`` is evaulates ``True`` (not empty), create an *identified +structure*; otherwise, create a *literal structure* by default. + +``packed_struct(eltys, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Like ``struct(eltys)``, but creates a packed struct. + +``array(elty, count)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Creates an array type, holding ``count`` elements, each of type ``elty`` +(which should be a ``Type``). + +``pointer(pty, addrspc=0)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a pointer to type ``pty`` (which should be a ``Type``). +``addrspc`` is an integer that represents the address space of the +pointer (see LLVM docs or ask on llvm-dev for more info). + +``void()`` +~~~~~~~~~~ + +Creates a void type. Used for function return types. + +``label()`` +~~~~~~~~~~~ + +Creates a label type. + +``opaque(name)`` +~~~~~~~~~~~~~~~~ + +Opaque `StructType `_, used for creating +self-referencing types. + +Properties +---------- + +``kind`` +~~~~~~~~ + +[read-only] + +A value (enum) representing the "type" of the object. It will be one of +the following constants defined in ``llvm.core``: + + +.. code-block:: python + + # Warning: do not rely on actual numerical + values! TYPE_VOID = 0 TYPE_FLOAT = 1 TYPE_DOUBLE = 2 TYPE_X86_FP80 + = 3 TYPE_FP128 = 4 TYPE_PPC_FP128 = 5 TYPE_LABEL = 6 TYPE_INTEGER = + 7 TYPE_FUNCTION = 8 TYPE_STRUCT = 9 TYPE_ARRAY = 10 TYPE_POINTER = + 11 TYPE_OPAQUE = 12 TYPE_VECTOR = 13 TYPE_METADATA = 14 TYPE_UNION = + 15 + + + +Example: +^^^^^^^^ + + +.. code-block:: python + + assert Type.int().kind == TYPE_INTEGER assert + Type.void().kind == TYPE_VOID + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Type + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.User.rst b/docs/source/doc/llvm.core.User.rst new file mode 100644 index 0000000..12d40c5 --- /dev/null +++ b/docs/source/doc/llvm.core.User.rst @@ -0,0 +1,46 @@ ++---------------------------+ +| layout: page | ++---------------------------+ +| title: User (llvm.core) | ++---------------------------+ + +``User``-s are values that refer to other values. The values so refered +can be retrived by the properties of ``User``. This is the reverse of +the ``Value.uses``. Together these can be used to traverse the use-def +chains of the SSA. + +-------------- + +llvm.core.User # {#user} +======================== + +Base Class +---------- + +- `llvm.core.Value `_ + +Properties +---------- + +``operands`` +~~~~~~~~~~~~ + +[read-only] + +The list of operands (values, of type +`llvm.core.Value `_) that this value refers to. + +``operand_count`` +~~~~~~~~~~~~~~~~~ + +[read-only] + +The number of operands that this value referes to. Same as +``len(uses.operands)`` but faster if you just want the count. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.User + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Value.rst b/docs/source/doc/llvm.core.Value.rst new file mode 100644 index 0000000..081d328 --- /dev/null +++ b/docs/source/doc/llvm.core.Value.rst @@ -0,0 +1,72 @@ ++----------------------------+ +| layout: page | ++----------------------------+ +| title: Value (llvm.core) | ++----------------------------+ + +llvm.core.Value +=============== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Properties +---------- + +``name`` +~~~~~~~~ + +The name of the value. + +``type`` +~~~~~~~~ + +[read-only] + +An ``llvm.core.Type`` object representing the type of the value. + +``uses`` +~~~~~~~~ + +[read-only] + +The list of values (``llvm.core.Value``) that use this value. + +``use_count`` +~~~~~~~~~~~~~ + +[read-only] + +The number of values that use (refer) this value. Same as +``len(val.uses)`` but faster if you just want the count. + +``value_id`` +~~~~~~~~~~~~ + +[read-only] + +Returns ``llvmValuegetValueID()``. Refer LLVM documentation for more +info. + +Special Methods +--------------- + +``__str__`` +~~~~~~~~~~~ + +``Value`` objects can be stringified into it's LLVM assembly language +representation. + +``__eq__`` +~~~~~~~~~~ + +``Value`` objects can be compared for equality. Internally, this +converts both arguments into their LLVM assembly representations and +compares the resultant strings. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Value + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.VectorType.rst b/docs/source/doc/llvm.core.VectorType.rst new file mode 100644 index 0000000..a18f6ea --- /dev/null +++ b/docs/source/doc/llvm.core.VectorType.rst @@ -0,0 +1,38 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: VectorType (llvm.core) | ++---------------------------------+ + +llvm.core.VectorType +==================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``element`` +~~~~~~~~~~~ + +[read-only] + +A `Type `_ object representing the type of the +element of the vector. + +``count`` +~~~~~~~~~ + +[read-only] + +The number of elements in the vector. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.VectorType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.ee.EngineBuilder.rst b/docs/source/doc/llvm.ee.EngineBuilder.rst new file mode 100644 index 0000000..e317acc --- /dev/null +++ b/docs/source/doc/llvm.ee.EngineBuilder.rst @@ -0,0 +1,56 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: EngineBuilder (llvm.ee) | ++----------------------------------+ + +llvm.ee.EngineBuilder +===================== + +A convenient class for building +`llvm.ee.ExecutionEngine `_. Each +``EngineBuilder`` instance can only create one ``ExecutionEngine``. + +Methods +------- + +``create(self)`` +~~~~~~~~~~~~~~~~ + +Create and return a new +`ExecutionEngine `_ instance. + +Raise ``llvm.LLVMException`` if the builder cannot create an +``ExecutionEngine`` base on the given configuration. + +``force_interpreter(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Force the output the output ``ExecutionEngine`` to be an LLVM IR +interpreter. + +``force_jit(self)`` +~~~~~~~~~~~~~~~~~~~ + +Force the output the output ``ExecutionEngine`` to be a JIT engine. + +``opt(self, level)`` +~~~~~~~~~~~~~~~~~~~~ + +Set the code generation optimization level for a JIT engine. Valid value +of ``level`` is 0-3, inclusive. The default setting is 2. To use vector +instructions, such as SSE on Intel processors, ``level`` must be 3 +(aggressive). + +Static Factory Methods +---------------------- + +``new(module)`` +~~~~~~~~~~~~~~~ + +Create a new EngineBuilder. ``module`` must be a +`llvm.core.Module `_ instance. Its ownership is +transferred to the resulting +`ExecutionEngine `_. Therefore, it is +impossible to create more than one ``ExecutionEngine`` with a single +``EngineBuilder`` diff --git a/docs/source/doc/llvm.ee.ExecutionEngine.rst b/docs/source/doc/llvm.ee.ExecutionEngine.rst new file mode 100644 index 0000000..718358c --- /dev/null +++ b/docs/source/doc/llvm.ee.ExecutionEngine.rst @@ -0,0 +1,62 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: ExecutionEngine (llvm.ee) | ++------------------------------------+ + +llvm.ee.ExecutionEngine +======================= + +Methods +------- + +``add_module(self, module)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a new module to the ExecutionEngine. The ownership is of ``module`` +is transferred. When the ``ExecutionEngine`` is destroyed, the module is +destroyed. + +``free_machine_code_for(self, fn)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Release memory used for the machine code generated for the function +``fn``. + +``get_pointer_to_function(self, fn)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Obtain the pointer to the function ``fn``. This forces the +ExecutionEngine to generate the machine code in lazy mode. + +If ``fn`` is not defined, ``ExecutionEngine`` will lookup the symbol +through ``dlsym``. + +The returned function pointer can be wrapped as a ``ctypes`` function. + +``remove_module(self, module)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the ``module``. + +``run_function(self, fn, args)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Execute the function ``fn`` with an iterable of arguments ``args`` which +are of ``GenericValue``. This method returns whatever that is returned +by ``fn`` as a ``GenericValue``. + +``run_static_ctors(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``run_static_dtors(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Properties +---------- + +``target_data`` +~~~~~~~~~~~~~~~ + +Access the `TargetData `_ instance associated +with the ``ExecutionEngine``. diff --git a/docs/source/doc/llvm.ee.GenericValue.rst b/docs/source/doc/llvm.ee.GenericValue.rst new file mode 100644 index 0000000..8680093 --- /dev/null +++ b/docs/source/doc/llvm.ee.GenericValue.rst @@ -0,0 +1,64 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: GenericValue (llvm.ee) | ++---------------------------------+ + +llvm.ee.GenericValue +==================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Methods +------- + +``as_int(self)`` +~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as an unsigned +integer + +``as_int_signed(self)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as a signed integer. + +``as_pointer(self)`` +~~~~~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as a pointer. The +type of the return value is ``int``. + +``as_real(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as a real number +which type is specified by ``ty``. ``ty`` must be a +`Type `_ instance of a real number type. + +Static Factory Methods +---------------------- + +``int(ty, intval)`` +~~~~~~~~~~~~~~~~~~~ + +Create a ``GenericValue`` instance with a ``int`` value, which is +zero-extended if necessary. The type of the value is specified by +``ty``, which is a `Type `_ instance. + +``int_signed(ty, intval)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a ``GenericValue`` instance with a ``int`` value, which is +sign-extended if necessary. The type of the value is specified by +``ty``, which is a `Type `_ instance. + +``pointer(ty, addr)`` or ``pointer(addr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a ``GenericValue`` instance with a ``int`` value, which is +representing a pointer value. + +The two argument version is **deprecated**. The old code never used +``ty`` anyway. diff --git a/docs/source/doc/llvm.ee.TargetData.rst b/docs/source/doc/llvm.ee.TargetData.rst new file mode 100644 index 0000000..5a774b8 --- /dev/null +++ b/docs/source/doc/llvm.ee.TargetData.rst @@ -0,0 +1,70 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: TargetData (llvm.ee) | ++-------------------------------+ + +llvm.ee.TargetData +================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Methods +------- + +``abi_alignment(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the minimum ABI-required alignment for the specified type +``ty``. + +``abi_size(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~ + +``callframe_alignment(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the minimum ABI-required alignment for the specified type ``ty`` +when it is part of a call frame. + +``element_at_offset(self, ty, ofs)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``offset_of_element(self, ty, el)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``preferred_alignment(self, ty_or_gv)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``size(self, ty)`` +~~~~~~~~~~~~~~~~~~ + +``store_size(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +``__str__(self)`` +~~~~~~~~~~~~~~~~~ + +Returns the string representation. + +Static Factory Methods +---------------------- + +``new(strrep)`` +~~~~~~~~~~~~~~~ + +Construct a new ``TargetData`` instance from the string representation + +Properties +---------- + +``byte_order`` +~~~~~~~~~~~~~~ + +``pointer_size`` +~~~~~~~~~~~~~~~~ + +``target_integer_type`` +~~~~~~~~~~~~~~~~~~~~~~~ + diff --git a/docs/source/doc/llvm.passes.FunctionPassManager.rst b/docs/source/doc/llvm.passes.FunctionPassManager.rst new file mode 100644 index 0000000..137cf74 --- /dev/null +++ b/docs/source/doc/llvm.passes.FunctionPassManager.rst @@ -0,0 +1,42 @@ ++--------------------------------------------+ +| layout: page | ++--------------------------------------------+ +| title: FunctionPassManager (llvm.passes) | ++--------------------------------------------+ + +llvm.passes.FunctionPassManager +=============================== + +Base Classes +------------ + +- `llvm.passes.PassManager `_ + +Methods +------- + +``finalize(self)`` +~~~~~~~~~~~~~~~~~~ + +Finalizes all associated function passes in the LLVM system. + +Beware that this destroys all associated passes even if another pass +manager is using those passes. This may result is a segfault. + +``initialize(self)`` +~~~~~~~~~~~~~~~~~~~~ + +Initializes all associated function passes in the LLVM system. + +``run(self, fn)`` +~~~~~~~~~~~~~~~~~ + +Run all passes on the given function ``fn``. + +Static Factory Methods +---------------------- + +``new(module)`` +~~~~~~~~~~~~~~~ + +Create a ``FunctionPassManager`` instance for a given ``module``. diff --git a/docs/source/doc/llvm.passes.PassManager.rst b/docs/source/doc/llvm.passes.PassManager.rst new file mode 100644 index 0000000..e0a2536 --- /dev/null +++ b/docs/source/doc/llvm.passes.PassManager.rst @@ -0,0 +1,29 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: PassManager (llvm.passes) | ++------------------------------------+ + +llvm.passes.PassManager +======================= + +Methods +------- + +``add(self, tgt_data_or_pass_id)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a pass by its ID. A pass IDs are defined as ``PASS_*``. + +``run(self, module)`` +~~~~~~~~~~~~~~~~~~~~~ + +Run all passes on the given ``module``. + +Static Factory Methods +---------------------- + +``new()`` +~~~~~~~~~ + +Creates a new ``PassManager`` instance. diff --git a/docs/source/doc/llvm.passes.PassManagerBuilder.rst b/docs/source/doc/llvm.passes.PassManagerBuilder.rst new file mode 100644 index 0000000..99e1935 --- /dev/null +++ b/docs/source/doc/llvm.passes.PassManagerBuilder.rst @@ -0,0 +1,72 @@ ++-------------------------------------------+ +| layout: page | ++-------------------------------------------+ +| title: PassManagerBuilder (llvm.passes) | ++-------------------------------------------+ + +llvm.passes.PassManagerBuilder +============================== + +Provide a simple API to populate pass managers for language like C/C++. +Refer to `LLVM API +Documentation `_ +for detail. + +Methods +------- + +``populate(self, pm)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Populate a `FunctionPassManager `_ +or `PassManager `_ given as ``pm``. + +``use_inliner_with_threshold(self, threshold)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use an inliner pass with the given ``threshold``. + +Properties +---------- + +The following properties can be overriden to customize how pass managers +are populated. + +``disable_simplify_lib_calls`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean. Default is ``False``. + +``disable_unit_at_a_time`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean. Default is ``False``. + +``disable_unroll_loops`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean. Default is ``False``. + +``opt_level`` +~~~~~~~~~~~~~ + +Default is ``2``. Valid values are 0-3. Corresponds to O0, O1, O2, O3 as +in C/C++ optimization options. + +``size_level`` +~~~~~~~~~~~~~~ + +Default is ``0``. + +``vectorize`` +~~~~~~~~~~~~~ + +Default is ``False``. + +Static Factory Methods +---------------------- + +``new()`` +~~~~~~~~~ + +Creates a new ``PassManagerBuilder`` instance. diff --git a/docs/source/doc/llvm_cbuilder.rst b/docs/source/doc/llvm_cbuilder.rst new file mode 100644 index 0000000..c8623c2 --- /dev/null +++ b/docs/source/doc/llvm_cbuilder.rst @@ -0,0 +1,12 @@ +llvm_cbuilder +============= + +llvm_cbuilder is a set of Python-contexts you can use to write C-like +constructs in Python which generates llvmpy code directly. + +Similar to llpython it allows you to build llvm IR without using the +llvmpy interface directly. + +Look in the llvm_cbuilder tests directory for examples of use. + + diff --git a/docs/source/doc/llvm_concepts.rst b/docs/source/doc/llvm_concepts.rst new file mode 100644 index 0000000..8690e49 --- /dev/null +++ b/docs/source/doc/llvm_concepts.rst @@ -0,0 +1,239 @@ +******************** +LLVM Concepts +******************** + +This section explains a few concepts related to LLVM, not specific to +llvmpy. + +.. toctree:: + :hidden: + + + + +Intermediate Representation +=========================== + +The intermediate representation, or IR for short, is an in-memory data +structure that represents executable code. The IR data structures allow +for creation of types, constants, functions, function arguments, +instructions, global variables and so on. For example, to create a +function *sum* that takes two integers and returns their sum, we need to +follow these steps: + +- create an integer type *ti* of required bitwidth +- create a function type *tf* which takes two *ti* -s and returns + another *ti* +- create a function of type *tf* named *sum* +- add a *basic block* to the function +- using a helper object called an *instruction builder*, add two + instructions into the basic block: + + - an instruction to add the two + arguments and store the result into a temporary variable + - a return + instruction to return the value of the temporary variable + +(A basic block is a block of instructions.) + +LLVM has it's own instruction set; the instructions used above (*add* +and *ret*) are from this set. The LLVM instructions are at a higher +level than the usual assembly language; for example there are +instructions related to variable argument handling, exception handling, +and garbage collection. These allow high-level languages to be +represented cleanly in the IR. + + +SSA Form and PHI Nodes +====================== + +All LLVM instructions are represented in the *Static Single Assignment* +(SSA) form. Essentially, this means that any variable can be assigned to +only once. Such a representation facilitates better optimization, among +other benefits. + +A consequence of single assignment are PHI (Φ) nodes. These are required +when a variable can be assigned a different value based on the path of +control flow. For example, the value of *b* at the end of execution of +the snippet below: + +.. code-block:: c + + a = 1; + if (v < 10) + a = 2; + b = a; + +cannot be determined statically. The value of '2' cannot be assigned to +the 'original' *a*, since *a* can be assigned to only once. There are +two *a* 's in there, and the last assignment has to choose between which +version to pick. This is accomplished by adding a PHI node: + +.. code-block:: c + + a1 = 1; + if (v < 10) + a2 = 2; + b = PHI(a1, a2); + +The PHI node selects *a1* or *a2*, depending on where the control +reached the PHI node. The argument *a1* of the PHI node is associated +with the block *"a1 = 1;"* and *a2* with the block *"a2 = 2;"*. + +PHI nodes have to be explicitly created in the LLVM IR. Accordingly the +LLVM instruction set has an instruction called *phi*. + + +LLVM Assembly Language +====================== + +The LLVM IR can be represented offline in two formats + +- a textual, human-readable form, similar to assembly language, called + the LLVM assembly language (files with .ll extension) +- a binary form, called the LLVM bitcode (files with .bc extension) + +All three formats (the in-memory IR, the LLVM assembly language and the +LLVM bitcode) represent the *same* information. Each format can be +converted into the other two formats (using LLVM APIs). + +The `LLVM demo page `_ lets you type in C or +C++ code, converts it into LLVM IR and outputs the IR as LLVM assembly +language code. + +Just to get a feel of the LLVM assembly language, here's a function in +C, and the corresponding LLVM assembly (as generated by the demo page): + +.. code-block:: c + + /* compute sum of 1..n */ + unsigned sum(unsigned n) { + if (n == 0) + return 0; + else + return n + sum(n-1); + } + +The corresponding LLVM assembly: + +.. code-block:: llvm + + ; ModuleID = '/tmp/webcompile/_7149_0.bc' + target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" + target triple = "x86_64-linux-gnu" + + define i32 @sum(i32 %n) nounwind readnone { + entry: + %0 = icmp eq i32 %n, 0 ; [#uses=1] + br i1 %0, label %bb2, label %bb1 + + bb1: ; preds = %entry + %1 = add i32 %n, -1 ; [#uses=2] + %2 = icmp eq i32 %1, 0 ; [#uses=1] + br i1 %2, label %sum.exit, label %bb1.i + + bb1.i: ; preds = %bb1 + %3 = add i32 %n, -2 ; [#uses=1] + %4 = tail call i32 @sum(i32 %3) nounwind ; [#uses=1] + %5 = add i32 %4, %1 ; [#uses=1] + br label %sum.exit + + sum.exit: ; preds = %bb1.i, %bb1 + %6 = phi i32 [ %5, %bb1.i ], [ 0, %bb1 ] ; [#uses=1] + %7 = add i32 %6, %n ; [#uses=1] + ret i32 %7 + + bb2: ; preds = %entry + ret i32 0 + } + +Note the usage of SSA form. The long string called ``target datalayout`` +is a specification of the platform ABI (like endianness, sizes of types, +alignment etc.). + +The `LLVM Language Reference `_ +defines the LLVM assembly language including the entire instruction set. + + +Modules +======= + +`Modules <./llvm.core.Module.html>`_, in the LLVM IR, are similar to a +single *C* language source file (.c file). A module contains: + +- functions (declarations and definitions) +- global variables and constants +- global type aliases for structures + +Modules are top-level containers; all executable code representation is +contained within modules. Modules may be combined (linked) together to +give a bigger resultant module. During this process LLVM attempts to +reconcile the references between the combined modules. + + +Optimization and Passes +======================= + +LLVM provides quite a few optimization algorithms that work on the IR. +These algorithms are organized as *passes*. Each pass does something +specific, like combining redundant instructions. Passes need not always +optimize the IR, it can also do other operations like inserting +instrumentation code, or analyzing the IR (the result of which can be +used by passes that do optimizations) or even printing call graphs. + +This LLVM `documentation page `_ +describes all the available passes, and what they do. + +LLVM does not automatically choose to run any passes, anytime. Passes +have to be explicitly selected and run on each module. This gives you +the flexibility to choose transformations and optimizations that are +most suitable for the code in the module. + +There is an LLVM binary called +`opt `_, which lets you run passes on +bitcode files from the command line. You can write your own passes (in +C/C++, as a shared library). This can be loaded and executed by +opt+. +(Although llvmpy does not allow you to write your own passes, it does +allow you to navigate the entire IR at any stage, and perform any +transforms on it as you like.) + +A "pass manager" is responsible for loading passes, selecting the +correct objects to run them on (for example, a pass may work only on +functions, individually) and actually runs them. ``opt`` is a +command-line wrapper for the pass manager. + +LLVM defines two kinds of pass managers: + +- The + `FunctionPassManager `_ + manages function or basic-block passes. These lighter weight passes + can be used immediately after each generated function to reduce + memory footprint. + +- The + `PassManager `_ + manages module passes for optimizing the entire module. + + +Bitcode +======= + +LLVM IR can be represented as a bitcode format for disk storage. It is +`suitable for fast loading by JIT +compiler `_. See `LLVM +documentation `_ for detail +about the bitcode format. + + +Execution Engine, JIT and Interpreter +===================================== + +The *execution engine* implements execution of LLVM IR through an +interpreter or a JIT dynamic compiler. An *execution engine* can contain +multiple modules. + + **Note** + + Inter-module reference is not possible. That is module ``A`` cannot + call a function in module ``B``, directly. + diff --git a/docs/source/doc/llvmcore.rst b/docs/source/doc/llvmcore.rst new file mode 100644 index 0000000..a3b94b6 --- /dev/null +++ b/docs/source/doc/llvmcore.rst @@ -0,0 +1,9 @@ +******************************** +llvm.core +******************************** + +.. toctree:: + :titlesonly: + :glob: + + llvm.core.* \ No newline at end of file diff --git a/docs/source/doc/llvmee.rst b/docs/source/doc/llvmee.rst new file mode 100644 index 0000000..2145502 --- /dev/null +++ b/docs/source/doc/llvmee.rst @@ -0,0 +1,9 @@ +******************************** +llvm.ee +******************************** + +.. toctree:: + :titlesonly: + :glob: + + llvm.ee.* \ No newline at end of file diff --git a/docs/source/doc/llvmpasses.rst b/docs/source/doc/llvmpasses.rst new file mode 100644 index 0000000..0931467 --- /dev/null +++ b/docs/source/doc/llvmpasses.rst @@ -0,0 +1,9 @@ +******************************** +llvm.passes +******************************** + +.. toctree:: + :titlesonly: + :glob: + + llvm.passes.* \ No newline at end of file diff --git a/docs/source/doc/llvmpy_package.rst b/docs/source/doc/llvmpy_package.rst new file mode 100644 index 0000000..eac3814 --- /dev/null +++ b/docs/source/doc/llvmpy_package.rst @@ -0,0 +1,89 @@ +*********************** +The llvmpy Package +*********************** + +The llvmpy is a Python package, consisting of 6 modules, that wrap over +enough LLVM APIs to allow the implementation of your own compiler/VM +backend in pure Python. If you're come this far, you probably know why +this is a good idea. + +Out of the 6 modules, one is an "extension" module (i.e., it is written +in C), and another one is a small private utility module, which leaves 4 +public modules. These are: + +- *llvm* -- top-level package, common classes (like exceptions) +- *llvm.core* -- IR-related APIs +- *llvm.ee* -- execution engine related APIs +- *llvm.passes* -- pass manager and passes related APIs + +The modules contain only classes and (integer) constants. Mostly simple +Python constructs are used (deliberately) -- +`property() `_ and +`property +decorators `_ are +probably the most exotic animals around. All classes are "new style" +classes. The APIs are designed to be navigable (and guessable!) once you +know a few conventions. These conventions are highlighted in the +sections below. + +Here is a quick overview of the contents of each package: + +llvm +---- + +- LLVMException -- exception class (currently the only one) + +llvm.core +--------- + +- `Module `_ -- represents an LLVM Module +- `Type `_ -- represents an LLVM Type +- `Value `_ -- represents an LLVM Value, including: + globals, constants, variables, arguments, functions, instructions, + etc.. +- `BasicBlock `_ -- another derived of + Value, represents an LLVM basic block +- `Builder `_ -- used for creating + instructions, wraps LLVM IRBuilder helper class +- constants *TYPE\_\** that represents various types +- constants *CC\_\** that represent calling conventions +- constants *ICMP\_\** and *FCMP\_\** that represent integer and real + comparison predicates (like less than, greater than etc.) +- constants *LINKAGE\_\** that represent linkage of symbols (external, + internal etc.) +- constants *VISIBILITY\_\** that represents visibility of symbols + (default, hidden, protected) +- constants *ATTR\_\** that represent function parameter attributes + +llvm.ee +------- + +- `ExecutionEngine `_ -- represents an + execution engine (which can be an either an interpreter or a JIT) +- `TargetData `_ -- represents the ABI of the + target platform (details like sizes and alignment of primitive types, + endinanness etc) + +llvm.passes +----------- + +- `PassManager `_ -- represents an LLVM + pass manager +- `FunctionPassManager `_ -- + represents an LLVM function pass manager +- constants *PASS\_\** that represent various passes + +A note on the importing of these modules +---------------------------------------- + +Pythonically, modules are imported with the statement +``import llvm.core``. However, you might find it more convenient to +import llvmpy modules thus: + + +.. code-block:: python + + from llvm import * + from llvm.core import * + from llvm.ee import * + from llvm.passes import * diff --git a/docs/source/doc/types.rst b/docs/source/doc/types.rst new file mode 100644 index 0000000..f3b9da2 --- /dev/null +++ b/docs/source/doc/types.rst @@ -0,0 +1,123 @@ ++----------------+ +| layout: page | ++----------------+ +| title: Types | ++----------------+ + +Types are what you think they are. A instance of +`llvm.core.Type `_, or one of its derived classes, +represent a type. llvmpy does not use as many classes to represent +types as does LLVM itself. Some types are represented using +`llvm.core.Type `_ itself and the rest are +represented using derived classes of +`llvm.core.Type `_. As usual, an instance is +created via one of the static methods of `Type `_. +These methods return an instance of either +`llvm.core.Type `_ itself or one of its derived +classes. + +The following table lists all the available types along with the static +method which has to be used to construct it and the name of the class +whose object is actually returned by the static method. + +Name \| Constructor Method \| Class \| +-----\|:------------------:\|:-----:\| integer of bitwidth *n* \| +Type.int(n) \| `IntegerType `_ \| 32-bit +float \| Type.float() \| `Type `_ \| 64-bit double +\| Type.double() \| `Type `_ \| 80-bit float \| +Type.x86\_fp80() \| `Type `_ \| 128-bit float +(112-bit mantissa) \| Type.fp128() \| `Type `_ \| +128-bit float (two 64-bits) \| Type.ppc\_fp128() \| +`Type `_ \| function \| Type.function(r, p, v) \| +`FunctionType `_ \| unpacked struct \| +Type.struct(eltys, name) \| `StructType `_ \| +packed struct \| Type.packed\_struct(eltys, name) \| +`StructType `_ \| opaque struct \| +Type.opaque(name) \| `StructType `_ \| array +\| Type.array(elty, count) \| `ArrayType `_ \| +pointer to value of type *pty* \| Type.pointer(pty, addrspc) \| +`PointerType `_ \| vector \| +Type.vector(elty, count) \| `VectorType `_ \| +void \| Type.void() \| `Type `_ \| label \| +Type.label() \| `Type `_ \| + +The class hierarchy is: + +:: + + Type + IntegerType + FunctionType + StructType + ArrayType + PointerType + VectorType + +-------------- + +An Example +---------- + +Here is an example that demonstrates the creation of types: + + +.. code-block:: python + + #!/usr/bin/env python + + # integers + int_ty = Type.int() bool_ty = Type.int(1) int_64bit = Type.int(64) + + # floats + sprec_real = Type.float() dprec_real = Type.double() + + # arrays and vectors + intar_ty = Type.array( int_ty, 10 ) # "typedef int intar_ty[10];" + twodim = Type.array( intar_ty , 10 ) # "typedef int twodim[10][10];" + vec = Type.array( int_ty, 10 ) + + # structures + s1_ty = Type.struct( [ int_ty, sprec_real ] ) # "struct s1_ty { int + v1; float v2; };" + + # pointers + intptr_ty = Type.pointer(int_ty) # "typedef int \*intptr_ty;" + + # functions + f1 = Type.function( int_ty, [ int_ty ] ) # functions that take 1 + int_ty and return 1 int_ty + + f2 = Type.function( Type.void(), [ int_ty, int_ty ] ) # functions that + take 2 int_tys and return nothing + + f3 = Type.function( Type.void(), ( int_ty, int_ty ) ) # same as f2; + any iterable can be used + + fnargs = [ Type.pointer( Type.int(8) ) ] printf = Type.function( + Type.int(), fnargs, True ) # variadic function + + + +-------------- + +Another Example: Recursive Type +------------------------------- + +The type system was rewritten in LLVM 3.0. The old opaque type was +removed. Instead, identified ``StructType`` can now be defined without a +body. Doing so creates a opaque structure. One can then set the body +after the construction of a structure. + +(See `LLVM +Blog `_ +for detail about the new type system.) + +The following code defines a opaque structure, named "mystruct". The +body is defined after the construction using ``StructType.set_body``. +The second subtype is a pointer to a "mystruct" type. + + +.. code-block:: python + + ts = Type.opaque('mystruct') + ts.set_body([Type.int(), Type.pointer(ts)]) diff --git a/docs/source/doc/userguide.rst b/docs/source/doc/userguide.rst new file mode 100644 index 0000000..1bb4b4f --- /dev/null +++ b/docs/source/doc/userguide.rst @@ -0,0 +1,17 @@ +************ +User Guide +************ + +llvmpy provides Python bindings for LLVM. This document explains how +you can setup and use it. A working knowledge of Python and a basic idea +of LLVM is assumed. + +.. toctree:: + :maxdepth: 1 + + getting_started.rst + llvm_concepts.rst + llvmpy_package.rst + + + diff --git a/docs/source/doc/values.rst b/docs/source/doc/values.rst new file mode 100644 index 0000000..a999740 --- /dev/null +++ b/docs/source/doc/values.rst @@ -0,0 +1,78 @@ ++-----------------+ +| layout: page | ++-----------------+ +| title: Values | ++-----------------+ + +`llvm.core.Value `_ is the base class of all +values computed by a program that may be used as operands to other +values. A value has a type associated with it (an object of +`llvm.core.Type `_). + +The class hierarchy is: + +:: + + Value + User + Constant + ConstantExpr + ConstantAggregateZero + ConstantInt + ConstantFP + ConstantArray + ConstantStruct + ConstantVector + ConstantPointerNull + UndefValue + GlobalValue + GlobalVariable + Function + Instruction + CallOrInvokeInstruction + PHINode + SwitchInstruction + CompareInstruction + Argument + BasicBlock + +The `Value `_ class is abstract, it's not meant to +be instantiated. `User `_ is a +`Value `_ that in turn uses (i.e., can refer to) +other values (for e.g., a constant expression 1+2 refers to two constant +values 1 and 2). + +`Constant `_-s represent constants that appear +within code or as initializers of globals. They are constructed using +static methods of `Constant `_. Various types +of constants are represented by various subclasses of +`Constant `_. However, most of them are empty +and do not provide any additional attributes or methods over +`Constant `_. + +The `Function `_ object represents an instance of a +function type. Such objects contain +`Argument `_ objects, which represent the +actual, local-variable-like arguments of the function (not to be +confused with the arguments returned by a function *type* object -- +these represent the *type* of the arguments). + +The various `Instruction `_-s are created by +the `Builder `_ class. Most instructions are +represented by `Instruction `_ itself, but +there are a few subclasses that represent interesting instructions. + +`Value `_ objects have a type (read-only), and a +name (read-write). + +**Related Links** `functions `_, +`comparision `_, +`llvm.core.Value `_, +`llvm.core.User `_, +`llvm.core.Constant `_, +`llvm.core.GlobalValue `_, +`llvm.core.GlobalVariable `_, +`llvm.core.Argument `_, +`llvm.core.Instruction `_, +`llvm.core.Builder `_, +`llvm.core.BasicBlock `_ diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..fbf5c8b --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,30 @@ +.. llvmpy documentation master file, created by + sphinx-quickstart on Wed Aug 8 17:33:58 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +llvmpy +====== + +Contents: + +.. toctree:: + :titlesonly: + :maxdepth: 2 + + doc/userguide.rst + doc/llvm_cbuilder.rst + doc/llpython/index.rst + doc/examples.rst + doc/llvmcore.rst + doc/llvmee.rst + doc/llvmpasses.rst + + +Indices and tables +------------------ + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + 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/__init__.py b/llpython/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/llpython/byte_control.py b/llpython/byte_control.py new file mode 100644 index 0000000..8ca407e --- /dev/null +++ b/llpython/byte_control.py @@ -0,0 +1,125 @@ +# ______________________________________________________________________ +from __future__ import absolute_import +import opcode +from . import opcode_util +import pprint + +from .bytecode_visitor import BasicBlockVisitor, BenignBytecodeVisitorMixin +from .control_flow import ControlFlowGraph + +# ______________________________________________________________________ + +class ControlFlowBuilder (BenignBytecodeVisitorMixin, BasicBlockVisitor): + '''Visitor responsible for traversing a bytecode basic block map and + building a control flow graph (CFG). + + The primary purpose of this transformation is to create a CFG, + which is used by later transformers for dataflow analysis. + ''' + def visit (self, flow, nargs = 0, *args, **kws): + '''Given a bytecode flow, and an optional number of arguments, + return a :py:class:`llpython.control_flow.ControlFlowGraph` + instance describing the full control flow of the bytecode + flow.''' + self.nargs = nargs + ret_val = super(ControlFlowBuilder, self).visit(flow, *args, **kws) + del self.nargs + return ret_val + + def enter_blocks (self, blocks): + super(ControlFlowBuilder, self).enter_blocks(blocks) + self.blocks = blocks + self.block_list = list(blocks.keys()) + self.block_list.sort() + self.cfg = ControlFlowGraph() + self.loop_stack = [] + for block in self.block_list: + self.cfg.add_block(block, blocks[block]) + + def exit_blocks (self, blocks): + super(ControlFlowBuilder, self).exit_blocks(blocks) + assert self.blocks == blocks + self.cfg.compute_dataflow() + self.cfg.update_for_ssa() + ret_val = self.cfg + del self.loop_stack + del self.cfg + del self.block_list + del self.blocks + return ret_val + + def enter_block (self, block): + self.block = block + assert block in self.cfg.blocks + if block == 0: + for local_index in range(self.nargs): + self.op_STORE_FAST(0, opcode.opmap['STORE_FAST'], local_index) + return True + + def _get_next_block (self, block): + return self.block_list[self.block_list.index(block) + 1] + + def exit_block (self, block): + assert block == self.block + del self.block + i, op, arg = self.blocks[block][-1] + opname = opcode.opname[op] + if op in opcode.hasjabs: + self.cfg.add_edge(block, arg) + elif op in opcode.hasjrel: + self.cfg.add_edge(block, i + arg + 3) + elif opname == 'BREAK_LOOP': + loop_i, _, loop_arg = self.loop_stack[-1] + self.cfg.add_edge(block, loop_i + loop_arg + 3) + elif opname != 'RETURN_VALUE': + self.cfg.add_edge(block, self._get_next_block(block)) + if op in opcode_util.hascbranch: + self.cfg.add_edge(block, self._get_next_block(block)) + + def op_LOAD_FAST (self, i, op, arg, *args, **kws): + self.cfg.blocks_reads[self.block].add(arg) + return super(ControlFlowBuilder, self).op_LOAD_FAST(i, op, arg, *args, + **kws) + + def op_STORE_FAST (self, i, op, arg, *args, **kws): + self.cfg.writes_local(self.block, i, arg) + return super(ControlFlowBuilder, self).op_STORE_FAST(i, op, arg, *args, + **kws) + + def op_SETUP_LOOP (self, i, op, arg, *args, **kws): + self.loop_stack.append((i, op, arg)) + return super(ControlFlowBuilder, self).op_SETUP_LOOP(i, op, arg, *args, + **kws) + + def op_POP_BLOCK (self, i, op, arg, *args, **kws): + self.loop_stack.pop() + return super(ControlFlowBuilder, self).op_POP_BLOCK(i, op, arg, *args, + **kws) + +# ______________________________________________________________________ + +def build_cfg (func): + '''Given a Python function, create a bytecode flow, visit the flow + object, and return a control flow graph.''' + co_obj = opcode_util.get_code_object(func) + return ControlFlowBuilder().visit(opcode_util.build_basic_blocks(co_obj), + co_obj.co_argcount) + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args, **kws): + from tests import llfuncs + if not args: + args = ('doslice',) + for arg in args: + build_cfg(getattr(llfuncs, arg)).pprint() + +# ______________________________________________________________________ + +if __name__ == "__main__": + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of byte_control.py diff --git a/llpython/byte_flow.py b/llpython/byte_flow.py new file mode 100644 index 0000000..197c839 --- /dev/null +++ b/llpython/byte_flow.py @@ -0,0 +1,266 @@ +# ______________________________________________________________________ +from __future__ import absolute_import +import dis +import opcode + +from .bytecode_visitor import BasicBlockVisitor +from . import opcode_util + +# ______________________________________________________________________ + +class BytecodeFlowBuilder (BasicBlockVisitor): + '''Transforms a CFG into a bytecode "flow tree". + + The flow tree is a Python dictionary, described loosely by the + following set of productions: + + * `flow_tree` ``:=`` ``{`` `blocks` ``*`` ``}`` + * `blocks` ``:=`` `block_index` ``:`` ``[`` `bytecode_tree` ``*`` ``]`` + * `bytecode_tree` ``:=`` ``(`` `opcode_index` ``,`` `opcode` ``,`` + `opname` ``,`` `arg` ``,`` ``[`` `bytecode_tree` ``*`` ``]`` ``)`` + + The primary purpose of this transformation is to simulate the + value stack, removing it and any stack-specific opcodes.''' + + def __init__ (self, *args, **kws): + super(BytecodeFlowBuilder, self).__init__(*args, **kws) + om_items = opcode_util.OPCODE_MAP.items() + self.opmap = dict((opcode.opmap[opname], (opname, pops, pushes, stmt)) + for opname, (pops, pushes, stmt) in om_items + if opname in opcode.opmap) + + def _visit_op (self, i, op, arg, opname, pops, pushes, appends): + assert pops is not None, ('%s not well defined in opcode_util.' + 'OPCODE_MAP' % opname) + if pops: + if pops < 0: + pops = arg - pops - 1 + assert pops <= len(self.stack), ("Stack underflow at instruction " + "%d (%s)!" % (i, opname)) + stk_args = self.stack[-pops:] + del self.stack[-pops:] + else: + stk_args = [] + ret_val = (i, op, opname, arg, stk_args) + if pushes: + self.stack.append(ret_val) + if appends: + self.block.append(ret_val) + return ret_val + + def _op (self, i, op, arg): + opname, pops, pushes, appends = self.opmap[op] + return self._visit_op(i, op, arg, opname, pops, pushes, appends) + + def visit_cfg (self, cfg): + self.cfg = cfg + ret_val = self.visit(cfg.blocks) + del self.cfg + return ret_val + + def enter_blocks (self, blocks): + labels = list(blocks.keys()) + labels.sort() + self.blocks = dict((index, []) + for index in labels) + self.loop_stack = [] + self.stacks = {} + + def exit_blocks (self, blocks): + ret_val = self.blocks + del self.stacks + del self.loop_stack + del self.blocks + return ret_val + + def enter_block (self, block): + self.block_no = block + self.block = self.blocks[block] + in_blocks = self.cfg.blocks_in[block] + if len(in_blocks) == 0: + self.stack = [] + else: + pred_stack = None + for pred in in_blocks: + if pred in self.stacks: + pred_stack = self.stacks[pred] + break + if pred_stack is not None: + self.stack = pred_stack[:] + else: + raise NotImplementedError() + + def exit_block (self, block): + assert self.block_no == block + self.stacks[block] = self.stack + del self.stack + del self.block + del self.block_no + + op_BINARY_ADD = _op + op_BINARY_AND = _op + op_BINARY_DIVIDE = _op + op_BINARY_FLOOR_DIVIDE = _op + op_BINARY_LSHIFT = _op + op_BINARY_MODULO = _op + op_BINARY_MULTIPLY = _op + op_BINARY_OR = _op + op_BINARY_POWER = _op + op_BINARY_RSHIFT = _op + op_BINARY_SUBSCR = _op + op_BINARY_SUBTRACT = _op + op_BINARY_TRUE_DIVIDE = _op + op_BINARY_XOR = _op + + def op_BREAK_LOOP (self, i, op, arg): + loop_i, _, loop_arg = self.loop_stack[-1] + assert arg is None + return self._op(i, op, loop_i + loop_arg + 3) + + #op_BUILD_CLASS = _op + op_BUILD_LIST = _op + op_BUILD_MAP = _op + op_BUILD_SLICE = _op + op_BUILD_TUPLE = _op + op_CALL_FUNCTION = _op + op_CALL_FUNCTION_KW = _op + op_CALL_FUNCTION_VAR = _op + op_CALL_FUNCTION_VAR_KW = _op + op_COMPARE_OP = _op + #op_CONTINUE_LOOP = _op + op_DELETE_ATTR = _op + op_DELETE_FAST = _op + op_DELETE_GLOBAL = _op + op_DELETE_NAME = _op + op_DELETE_SLICE = _op + op_DELETE_SUBSCR = _op + + def op_DUP_TOP (self, i, op, arg): + self.stack.append(self.stack[-1]) + + def op_DUP_TOPX (self, i, op, arg): + self.stack += self.stack[-arg:] + + #op_END_FINALLY = _op + op_EXEC_STMT = _op + #op_EXTENDED_ARG = _op + op_FOR_ITER = _op + op_GET_ITER = _op + op_IMPORT_FROM = _op + op_IMPORT_NAME = _op + op_IMPORT_STAR = _op + op_INPLACE_ADD = _op + op_INPLACE_AND = _op + op_INPLACE_DIVIDE = _op + op_INPLACE_FLOOR_DIVIDE = _op + op_INPLACE_LSHIFT = _op + op_INPLACE_MODULO = _op + op_INPLACE_MULTIPLY = _op + op_INPLACE_OR = _op + op_INPLACE_POWER = _op + op_INPLACE_RSHIFT = _op + op_INPLACE_SUBTRACT = _op + op_INPLACE_TRUE_DIVIDE = _op + op_INPLACE_XOR = _op + op_JUMP_ABSOLUTE = _op + op_JUMP_FORWARD = _op + + def op_JUMP_IF_FALSE (self, i, op, arg): + opname, _, _, _ = self.opmap[op] + ret_val = (i, op, opname, arg, [self.stack[-1]]) + self.block.append(ret_val) + return ret_val + + op_JUMP_IF_TRUE = op_JUMP_IF_FALSE + op_LIST_APPEND = _op + op_LOAD_ATTR = _op + op_LOAD_CLOSURE = _op + op_LOAD_CONST = _op + op_LOAD_DEREF = _op + op_LOAD_FAST = _op + op_LOAD_GLOBAL = _op + op_LOAD_LOCALS = _op + op_LOAD_NAME = _op + op_MAKE_CLOSURE = _op + op_MAKE_FUNCTION = _op + op_NOP = _op + + def op_POP_BLOCK (self, i, op, arg): + self.loop_stack.pop() + return self._op(i, op, arg) + + op_POP_JUMP_IF_FALSE = _op + op_POP_JUMP_IF_TRUE = _op + op_POP_TOP = _op + op_PRINT_EXPR = _op + op_PRINT_ITEM = _op + op_PRINT_ITEM_TO = _op + op_PRINT_NEWLINE = _op + op_PRINT_NEWLINE_TO = _op + op_RAISE_VARARGS = _op + op_RETURN_VALUE = _op + + def op_ROT_FOUR (self, i, op, arg): + self.stack[-4:] = (self.stack[-1], self.stack[-4], self.stack[-3], + self.stack[-2]) + + def op_ROT_THREE (self, i, op, arg): + self.stack[-3:] = (self.stack[-1], self.stack[-3], self.stack[-2]) + + def op_ROT_TWO (self, i, op, arg): + self.stack[-2:] = (self.stack[-1], self.stack[-2]) + + #op_SETUP_EXCEPT = _op + #op_SETUP_FINALLY = _op + + def op_SETUP_LOOP (self, i, op, arg): + self.loop_stack.append((i, op, arg)) + self.block.append((i, op, self.opnames[op], arg, [])) + + op_SLICE = _op + #op_STOP_CODE = _op + op_STORE_ATTR = _op + op_STORE_DEREF = _op + op_STORE_FAST = _op + op_STORE_GLOBAL = _op + op_STORE_MAP = _op + op_STORE_NAME = _op + op_STORE_SLICE = _op + op_STORE_SUBSCR = _op + op_UNARY_CONVERT = _op + op_UNARY_INVERT = _op + op_UNARY_NEGATIVE = _op + op_UNARY_NOT = _op + op_UNARY_POSITIVE = _op + op_UNPACK_SEQUENCE = _op + #op_WITH_CLEANUP = _op + op_YIELD_VALUE = _op + +# ______________________________________________________________________ + +def build_flow (func): + '''Given a Python function, return a bytecode flow tree for that + function.''' + import byte_control + cfg = byte_control.build_cfg(func) + return BytecodeFlowBuilder().visit_cfg(cfg) + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args): + import pprint + from tests import llfuncs + if not args: + args = ('doslice',) + for arg in args: + pprint.pprint(build_flow(getattr(llfuncs, arg))) + +# ______________________________________________________________________ + +if __name__ == '__main__': + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of byte_flow.py diff --git a/llpython/byte_translator.py b/llpython/byte_translator.py new file mode 100644 index 0000000..a6e5864 --- /dev/null +++ b/llpython/byte_translator.py @@ -0,0 +1,612 @@ +# ______________________________________________________________________ +'''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 + +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 + +logger = logging.getLogger(__name__) + +# XXX Stolen from numba.translate: + +_compare_mapping_float = {'>':lc.FCMP_OGT, + '<':lc.FCMP_OLT, + '==':lc.FCMP_OEQ, + '>=':lc.FCMP_OGE, + '<=':lc.FCMP_OLE, + '!=':lc.FCMP_ONE} + +_compare_mapping_sint = {'>':lc.ICMP_SGT, + '<':lc.ICMP_SLT, + '==':lc.ICMP_EQ, + '>=':lc.ICMP_SGE, + '<=':lc.ICMP_SLE, + '!=':lc.ICMP_NE} + +# XXX Stolen from numba.llvm_types: + +class LLVMCaster (object): + def build_pointer_cast(_, builder, lval1, lty2): + return builder.bitcast(lval1, lty2) + + def build_int_cast(_, builder, lval1, lty2, unsigned = False): + width1 = lval1.type.width + width2 = lty2.width + ret_val = lval1 + if width2 > width1: + if unsigned: + ret_val = builder.zext(lval1, lty2) + else: + ret_val = builder.sext(lval1, lty2) + elif width2 < width1: + ret_val = builder.trunc(lval1, lty2) + return ret_val + + def build_float_ext(_, builder, lval1, lty2): + return builder.fpext(lval1, lty2) + + def build_float_trunc(_, builder, lval1, lty2): + return builder.fptrunc(lval1, lty2) + + def build_int_to_float_cast(_, builder, lval1, lty2, unsigned = False): + ret_val = None + if unsigned: + ret_val = builder.uitofp(lval1, lty2) + else: + ret_val = builder.sitofp(lval1, lty2) + return ret_val + + def build_int_to_ptr_cast(_, builder, lval1, lty2): + return builder.inttoptr(lval1, lty2) + + def build_float_to_int_cast(_, builder, lval1, lty2, unsigned = False): + ret_val = None + if unsigned: + ret_val = builder.fptoui(lval1, lty2) + else: + ret_val = builder.fptosi(lval1, lty2) + return ret_val + + CAST_MAP = { + lc.TYPE_POINTER : build_pointer_cast, + lc.TYPE_INTEGER: build_int_cast, + (lc.TYPE_FLOAT, lc.TYPE_DOUBLE) : build_float_ext, + (lc.TYPE_DOUBLE, lc.TYPE_FLOAT) : build_float_trunc, + (lc.TYPE_INTEGER, lc.TYPE_FLOAT) : build_int_to_float_cast, + (lc.TYPE_INTEGER, lc.TYPE_DOUBLE) : build_int_to_float_cast, + (lc.TYPE_INTEGER, lc.TYPE_POINTER) : build_int_to_ptr_cast, + (lc.TYPE_FLOAT, lc.TYPE_INTEGER) : build_float_to_int_cast, + (lc.TYPE_DOUBLE, lc.TYPE_INTEGER) : build_float_to_int_cast, + + } + + @classmethod + def build_cast(cls, builder, lval1, lty2, *args, **kws): + ret_val = lval1 + lty1 = lval1.type + lkind1 = lty1.kind + lkind2 = lty2.kind + + if lkind1 == lkind2: + + if lkind1 in cls.CAST_MAP: + ret_val = cls.CAST_MAP[lkind1](cls, builder, lval1, lty2, + *args, **kws) + else: + raise NotImplementedError(lkind1) + else: + map_index = (lkind1, lkind2) + if map_index in cls.CAST_MAP: + ret_val = cls.CAST_MAP[map_index](cls, builder, lval1, lty2, + *args, **kws) + else: + raise NotImplementedError(lkind1, lkind2) + return ret_val + +# ______________________________________________________________________ +# Class definitions + +class LLVMTranslator (BytecodeFlowVisitor): + '''Transformer responsible for visiting a set of bytecode flow + trees, emitting LLVM code. + + Unlike other translators in :py:mod:`llpython`, this + incorporates the full transformation chain, starting with + :py:class:`llpython.byte_flow.BytecodeFlowBuilder`, then + :py:class:`llpython.byte_control.ControlFlowBuilder`, and + then :py:class:`llpython.phi_injector.PhiInjector`.''' + + def __init__ (self, llvm_module = None, *args, **kws): + '''Constructor for LLVMTranslator.''' + super(LLVMTranslator, self).__init__(*args, **kws) + if llvm_module is None: + llvm_module = lc.Module.new('Translated_Module_%d' % (id(self),)) + self.llvm_module = llvm_module + self.bytecode_flow_builder = BytecodeFlowBuilder() + self.control_flow_builder = ControlFlowBuilder() + self.phi_injector = PhiInjector() + + def translate (self, function, llvm_type = None, llvm_function = None, + env = None): + '''Translate a function to the given LLVM function type. + + If no type is given, then assume the function is of LLVM type + "void ()". + + The optional env parameter allows extension of the global + environment.''' + if llvm_type is None: + if llvm_function is None: + llvm_type = lc.Type.function(bytetype.lvoid, ()) + else: + llvm_type = llvm_function.type.pointee + if env is None: + env = {} + else: + env = env.copy() + env.update((name, method) + for name, method in lc.Builder.__dict__.items() + if not name.startswith('_')) + env.update((name, value) + for name, value in bytetype.__dict__.items() + if not name.startswith('_')) + self.loop_stack = [] + self.llvm_type = llvm_type + self.target_function_name = env.get('target_function_name', + function.__name__) + self.function = function + self.code_obj = opcode_util.get_code_object(function) + func_globals = getattr(function, 'func_globals', + getattr(function, '__globals__', {})).copy() + func_globals.update(env) + self.globals = func_globals + nargs = self.code_obj.co_argcount + self.cfg = self.control_flow_builder.visit( + opcode_util.build_basic_blocks(self.code_obj), nargs) + self.cfg.blocks = self.bytecode_flow_builder.visit_cfg(self.cfg) + self.llvm_function = llvm_function + flow = self.phi_injector.visit_cfg(self.cfg, nargs) + ret_val = self.visit(flow) + del self.cfg + del self.globals + del self.code_obj + del self.target_function_name + del self.function + del self.llvm_type + del self.loop_stack + return ret_val + + def enter_flow_object (self, flow): + super(LLVMTranslator, self).enter_flow_object(flow) + if self.llvm_function is None: + self.llvm_function = self.llvm_module.add_function( + self.llvm_type, self.target_function_name) + self.llvm_blocks = {} + self.llvm_definitions = {} + self.pending_phis = {} + for block in self.block_list: + if 0 in self.cfg.blocks_reaching[block]: + bb = self.llvm_function.append_basic_block( + 'BLOCK_%d' % (block,)) + self.llvm_blocks[block] = bb + + def exit_flow_object (self, flow): + super(LLVMTranslator, self).exit_flow_object(flow) + ret_val = self.llvm_function + del self.pending_phis + del self.llvm_definitions + del self.llvm_blocks + if __debug__ and logger.getEffectiveLevel() < logging.DEBUG: + logger.debug(str(ret_val)) + return ret_val + + def enter_block (self, block): + ret_val = False + if block in self.llvm_blocks: + self.llvm_block = self.llvm_blocks[block] + self.builder = lc.Builder.new(self.llvm_block) + ret_val = True + return ret_val + + def exit_block (self, block): + bb_instrs = self.llvm_block.instructions + if ((len(bb_instrs) == 0) or + (not bb_instrs[-1].is_terminator)): + out_blocks = list(self.cfg.blocks_out[block]) + assert len(out_blocks) == 1 + self.builder.branch(self.llvm_blocks[out_blocks[0]]) + del self.llvm_block + del self.builder + + def visit_synthetic_op (self, i, op, arg, *args, **kws): + method = getattr(self, 'op_%s' % (synthetic_opname[op],)) + return method(i, op, arg, *args, **kws) + + def op_REF_ARG (self, i, op, arg, *args, **kws): + return [self.llvm_function.args[arg]] + + def op_BUILD_PHI (self, i, op, arg, *args, **kws): + phi_type = None + incoming = [] + pending = [] + for child_arg in arg: + child_block, _, child_opname, child_arg, _ = child_arg + assert child_opname == 'REF_DEF' + if child_arg in self.llvm_definitions: + child_def = self.llvm_definitions[child_arg] + if phi_type is None: + phi_type = child_def.type + incoming.append((child_block, child_def)) + else: + pending.append((child_arg, child_block)) + phi = self.builder.phi(phi_type) + for block_index, defn in incoming: + phi.add_incoming(defn, self.llvm_blocks[block_index]) + for defn_index, block_index in pending: + if defn_index not in self.pending_phis: + self.pending_phis[defn_index] = [] + self.pending_phis[defn_index].append((phi, block_index)) + return [phi] + + def op_DEFINITION (self, i, op, def_index, *args, **kws): + assert len(args) == 1 + arg = args[0] + if def_index in self.pending_phis: + for phi, block_index in self.pending_phis[def_index]: + phi.add_incoming(arg, self.llvm_blocks[block_index]) + self.llvm_definitions[def_index] = arg + return args + + def op_REF_DEF (self, i, op, arg, *args, **kws): + return [self.llvm_definitions[arg]] + + def op_BINARY_ADD (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.add(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fadd(arg1, arg2)] + elif arg1.type.kind == lc.TYPE_POINTER: + ret_val = [self.builder.gep(arg1, [arg2])] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_ADD for %r" % + (args,)) + return ret_val + + def op_BINARY_AND (self, i, op, arg, *args, **kws): + return [self.builder.and_(args[0], args[1])] + + def op_BINARY_DIVIDE (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.sdiv(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fdiv(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_DIVIDE for %r" + % (args,)) + return ret_val + + def op_BINARY_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_BINARY_FLOOR_DIVIDE") + + def op_BINARY_LSHIFT (self, i, op, arg, *args, **kws): + return [self.builder.shl(args[0], args[1])] + + def op_BINARY_MODULO (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.srem(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.frem(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_MODULO for %r" + % (args,)) + return ret_val + + def op_BINARY_MULTIPLY (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.mul(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fmul(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_MULTIPLY for " + "%r" % (args,)) + return ret_val + + def op_BINARY_OR (self, i, op, arg, *args, **kws): + return [self.builder.or_(args[0], args[1])] + + def op_BINARY_POWER (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_BINARY_POWER") + + def op_BINARY_RSHIFT (self, i, op, arg, *args, **kws): + return [self.builder.lshr(args[0], args[1])] + + def op_BINARY_SUBSCR (self, i, op, arg, *args, **kws): + arr_val = args[0] + index_vals = args[1:] + ret_val = gep_result = self.builder.gep(arr_val, index_vals) + if (gep_result.type.kind == lc.TYPE_POINTER and + gep_result.type.pointee.kind != lc.TYPE_POINTER): + ret_val = self.builder.load(gep_result) + return [ret_val] + + def op_BINARY_SUBTRACT (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.sub(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fsub(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_SUBTRACT for " + "%r" % (args,)) + return ret_val + + op_BINARY_TRUE_DIVIDE = op_BINARY_DIVIDE + + def op_BINARY_XOR (self, i, op, arg, *args, **kws): + return [self.builder.xor(args[0], args[1])] + + def op_BREAK_LOOP (self, i, op, arg, *args, **kws): + return [self.builder.branch(self.llvm_blocks[arg])] + + def op_BUILD_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_BUILD_SLICE") + + def op_BUILD_TUPLE (self, i, op, arg, *args, **kws): + return args + + def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): + fn = args[0] + args = args[1:] + fn_name = getattr(fn, '__name__', None) + if isinstance(fn, (types.FunctionType, types.MethodType)): + ret_val = [fn(self.builder, *args)] + elif isinstance(fn, lc.Value): + ret_val = [self.builder.call(fn, args)] + elif isinstance(fn, lc.Type): + if isinstance(fn, lc.FunctionType): + ret_val = [self.builder.call( + self.llvm_module.get_or_insert_function(fn, fn_name), + args)] + else: + assert len(args) == 1 + ret_val = [LLVMCaster.build_cast(self.builder, args[0], fn)] + else: + raise NotImplementedError("Don't know how to call %s() (%r @ %d)!" + % (fn_name, fn, i)) + return ret_val + + def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_KW") + + def op_CALL_FUNCTION_VAR (self, i, op, arg, *args, **kws): + args = list(args) + var_args = list(args.pop()) + args.extend(var_args) + return self.op_CALL_FUNCTION(i, op, arg, *args, **kws) + + def op_CALL_FUNCTION_VAR_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_VAR_KW") + + def op_COMPARE_OP (self, i, op, arg, *args, **kws): + arg1, arg2 = args + cmp_kind = opcode.cmp_op[arg] + if isinstance(arg1.type, lc.IntegerType): + ret_val = [self.builder.icmp(_compare_mapping_sint[cmp_kind], + arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fcmp(_compare_mapping_float[cmp_kind], + arg1, arg2)] + else: + raise NotImplementedError('Comparison of type %r' % (arg1.type,)) + return ret_val + + def op_CONTINUE_LOOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CONTINUE_LOOP") + + def op_DELETE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_DELETE_ATTR") + + def op_DELETE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_DELETE_SLICE") + + def op_FOR_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_FOR_ITER") + + def op_GET_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_GET_ITER") + + op_INPLACE_ADD = op_BINARY_ADD + op_INPLACE_AND = op_BINARY_AND + op_INPLACE_DIVIDE = op_BINARY_DIVIDE + op_INPLACE_FLOOR_DIVIDE = op_BINARY_FLOOR_DIVIDE + op_INPLACE_LSHIFT = op_BINARY_LSHIFT + op_INPLACE_MODULO = op_BINARY_MODULO + op_INPLACE_MULTIPLY = op_BINARY_MULTIPLY + op_INPLACE_OR = op_BINARY_OR + op_INPLACE_POWER = op_BINARY_POWER + op_INPLACE_RSHIFT = op_BINARY_RSHIFT + op_INPLACE_SUBTRACT = op_BINARY_SUBTRACT + op_INPLACE_TRUE_DIVIDE = op_BINARY_TRUE_DIVIDE + op_INPLACE_XOR = op_BINARY_XOR + + def op_JUMP_ABSOLUTE (self, i, op, arg, *args, **kws): + return [self.builder.branch(self.llvm_blocks[arg])] + + def op_JUMP_FORWARD (self, i, op, arg, *args, **kws): + return [self.builder.branch(self.llvm_blocks[i + arg + 3])] + + def op_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + cond = args[0] + block_false = self.llvm_blocks[i + 3 + arg] + block_true = self.llvm_blocks[i + 3] + return [self.builder.cbranch(cond, block_true, block_false)] + # raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE") + + def op_JUMP_IF_FALSE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE_OR_POP") + + def op_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_TRUE") + + def op_JUMP_IF_TRUE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_TRUE_OR_POP") + + def op_LOAD_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_LOAD_ATTR") + + def op_LOAD_CONST (self, i, op, arg, *args, **kws): + py_val = self.code_obj.co_consts[arg] + if isinstance(py_val, int): + ret_val = [lc.Constant.int(bytetype.lc_int, py_val)] + elif isinstance(py_val, float): + ret_val = [lc.Constant.double(py_val)] + elif py_val == None: + ret_val = [None] + else: + raise NotImplementedError('Constant converstion for %r' % + (py_val,)) + return ret_val + + def op_LOAD_DEREF (self, i, op, arg, *args, **kws): + name = self.code_obj.co_freevars[arg] + ret_val = self.globals[name] + if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): + ret_val.__name__ = name + return [ret_val] + + def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): + name = self.code_obj.co_names[arg] + ret_val = self.globals[name] + if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): + ret_val.__name__ = name + return [ret_val] + + def op_POP_BLOCK (self, i, op, arg, *args, **kws): + self.loop_stack.pop() + return [self.builder.branch(self.llvm_blocks[i + 1])] + + def op_POP_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + return [self.builder.cbranch(args[0], self.llvm_blocks[i + 3], + self.llvm_blocks[arg])] + + def op_POP_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_POP_JUMP_IF_TRUE") + + def op_POP_TOP (self, i, op, arg, *args, **kws): + return args + + def op_RETURN_VALUE (self, i, op, arg, *args, **kws): + if args[0] is None: + ret_val = [self.builder.ret_void()] + else: + ret_val = [self.builder.ret(args[0])] + return ret_val + + def op_SETUP_LOOP (self, i, op, arg, *args, **kws): + self.loop_stack.append((i, arg)) + return [self.builder.branch(self.llvm_blocks[i + 3])] + + def op_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_SLICE") + + def op_STORE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_STORE_ATTR") + + def op_STORE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_STORE_SLICE") + + def op_STORE_SUBSCR (self, i, op, arg, *args, **kws): + store_val, arr_val, index_val = args + dest_addr = self.builder.gep(arr_val, [index_val]) + return [self.builder.store(store_val, dest_addr)] + + def op_UNARY_CONVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_CONVERT") + + def op_UNARY_INVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_INVERT") + + def op_UNARY_NEGATIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_NEGATIVE") + + def op_UNARY_NOT (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_NOT") + + def op_UNARY_POSITIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_POSITIVE") + +# ______________________________________________________________________ + +def translate_function (func, lltype, llvm_module = None, **kws): + '''Given a function and an LLVM function type, emit LLVM code for + that function using a new LLVMTranslator instance.''' + translator = LLVMTranslator(llvm_module) + ret_val = translator.translate(func, lltype, env = kws) + return ret_val + +# ______________________________________________________________________ + +def translate_into_function (py_function, llvm_function, **kws): + translator = LLVMTranslator(llvm_function.module) + ret_val = translator.translate(py_function, llvm_function = llvm_function, + env = kws) + return ret_val + +# ______________________________________________________________________ + +def llpython (lltype, llvm_module = None, **kws): + '''Decorator version of translate_function().''' + def _llpython (func): + return translate_function(func, lltype, llvm_module, **kws) + return _llpython + +# ______________________________________________________________________ + +def llpython_into (llvm_function, **kws): + def _llpython_into (func): + return translate_into_function(llvm_function, func, **kws) + return _llpython_into + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args): + from tests import llfuncs, llfunctys + if not args: + args = ('doslice',) + elif 'all' in args: + args = [llfunc + for llfunc in dir(llfuncs) if not llfunc.startswith('_')] + llvm_module = lc.Module.new('test_module') + for arg in args: + translate_function(getattr(llfuncs, arg), getattr(llfunctys, arg), + llvm_module) + print(llvm_module) + +# ______________________________________________________________________ + +if __name__ == '__main__': + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of byte_translator.py diff --git a/llpython/bytecode_visitor.py b/llpython/bytecode_visitor.py new file mode 100644 index 0000000..3fa3f48 --- /dev/null +++ b/llpython/bytecode_visitor.py @@ -0,0 +1,360 @@ +# ______________________________________________________________________ +from __future__ import absolute_import +import itertools + +import opcode +from .opcode_util import itercode + +# ______________________________________________________________________ + +class BytecodeVisitor (object): + opnames = [name.split('+')[0] for name in opcode.opname] + + def visit_op (self, i, op, arg, *args, **kws): + if op < 0: + ret_val = self.visit_synthetic_op(i, op, arg, *args, **kws) + else: + method = getattr(self, 'op_' + self.opnames[op]) + ret_val = method(i, op, arg, *args, **kws) + return ret_val + + def visit_synthetic_op (self, i, op, arg, *args, **kws): + raise NotImplementedError( + 'BytecodeVisitor.visit_synthetic_op() must be overloaded if using ' + 'synthetic opcodes.') + + def _not_implemented (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_%s (@ bytecode index %d)" + % (self.opnames[op], i)) + + op_BINARY_ADD = _not_implemented + op_BINARY_AND = _not_implemented + op_BINARY_DIVIDE = _not_implemented + op_BINARY_FLOOR_DIVIDE = _not_implemented + op_BINARY_LSHIFT = _not_implemented + op_BINARY_MODULO = _not_implemented + op_BINARY_MULTIPLY = _not_implemented + op_BINARY_OR = _not_implemented + op_BINARY_POWER = _not_implemented + op_BINARY_RSHIFT = _not_implemented + op_BINARY_SUBSCR = _not_implemented + op_BINARY_SUBTRACT = _not_implemented + op_BINARY_TRUE_DIVIDE = _not_implemented + op_BINARY_XOR = _not_implemented + op_BREAK_LOOP = _not_implemented + op_BUILD_CLASS = _not_implemented + op_BUILD_LIST = _not_implemented + op_BUILD_MAP = _not_implemented + op_BUILD_SET = _not_implemented + op_BUILD_SLICE = _not_implemented + op_BUILD_TUPLE = _not_implemented + op_CALL_FUNCTION = _not_implemented + op_CALL_FUNCTION_KW = _not_implemented + op_CALL_FUNCTION_VAR = _not_implemented + op_CALL_FUNCTION_VAR_KW = _not_implemented + op_COMPARE_OP = _not_implemented + op_CONTINUE_LOOP = _not_implemented + op_DELETE_ATTR = _not_implemented + op_DELETE_DEREF = _not_implemented + op_DELETE_FAST = _not_implemented + op_DELETE_GLOBAL = _not_implemented + op_DELETE_NAME = _not_implemented + op_DELETE_SLICE = _not_implemented + op_DELETE_SUBSCR = _not_implemented + op_DUP_TOP = _not_implemented + op_DUP_TOPX = _not_implemented + op_DUP_TOP_TWO = _not_implemented + op_END_FINALLY = _not_implemented + op_EXEC_STMT = _not_implemented + op_EXTENDED_ARG = _not_implemented + op_FOR_ITER = _not_implemented + op_GET_ITER = _not_implemented + op_IMPORT_FROM = _not_implemented + op_IMPORT_NAME = _not_implemented + op_IMPORT_STAR = _not_implemented + op_INPLACE_ADD = _not_implemented + op_INPLACE_AND = _not_implemented + op_INPLACE_DIVIDE = _not_implemented + op_INPLACE_FLOOR_DIVIDE = _not_implemented + op_INPLACE_LSHIFT = _not_implemented + op_INPLACE_MODULO = _not_implemented + op_INPLACE_MULTIPLY = _not_implemented + op_INPLACE_OR = _not_implemented + op_INPLACE_POWER = _not_implemented + op_INPLACE_RSHIFT = _not_implemented + op_INPLACE_SUBTRACT = _not_implemented + op_INPLACE_TRUE_DIVIDE = _not_implemented + op_INPLACE_XOR = _not_implemented + op_JUMP_ABSOLUTE = _not_implemented + op_JUMP_FORWARD = _not_implemented + op_JUMP_IF_FALSE = _not_implemented + op_JUMP_IF_FALSE_OR_POP = _not_implemented + op_JUMP_IF_TRUE = _not_implemented + op_JUMP_IF_TRUE_OR_POP = _not_implemented + op_LIST_APPEND = _not_implemented + op_LOAD_ATTR = _not_implemented + op_LOAD_BUILD_CLASS = _not_implemented + op_LOAD_CLOSURE = _not_implemented + op_LOAD_CONST = _not_implemented + op_LOAD_DEREF = _not_implemented + op_LOAD_FAST = _not_implemented + op_LOAD_GLOBAL = _not_implemented + op_LOAD_LOCALS = _not_implemented + op_LOAD_NAME = _not_implemented + op_MAKE_CLOSURE = _not_implemented + op_MAKE_FUNCTION = _not_implemented + op_MAP_ADD = _not_implemented + op_NOP = _not_implemented + op_POP_BLOCK = _not_implemented + op_POP_EXCEPT = _not_implemented + op_POP_JUMP_IF_FALSE = _not_implemented + op_POP_JUMP_IF_TRUE = _not_implemented + op_POP_TOP = _not_implemented + op_PRINT_EXPR = _not_implemented + op_PRINT_ITEM = _not_implemented + op_PRINT_ITEM_TO = _not_implemented + op_PRINT_NEWLINE = _not_implemented + op_PRINT_NEWLINE_TO = _not_implemented + op_RAISE_VARARGS = _not_implemented + op_RETURN_VALUE = _not_implemented + op_ROT_FOUR = _not_implemented + op_ROT_THREE = _not_implemented + op_ROT_TWO = _not_implemented + op_SETUP_EXCEPT = _not_implemented + op_SETUP_FINALLY = _not_implemented + op_SETUP_LOOP = _not_implemented + op_SETUP_WITH = _not_implemented + op_SET_ADD = _not_implemented + op_SLICE = _not_implemented + op_STOP_CODE = _not_implemented + op_STORE_ATTR = _not_implemented + op_STORE_DEREF = _not_implemented + op_STORE_FAST = _not_implemented + op_STORE_GLOBAL = _not_implemented + op_STORE_LOCALS = _not_implemented + op_STORE_MAP = _not_implemented + op_STORE_NAME = _not_implemented + op_STORE_SLICE = _not_implemented + op_STORE_SUBSCR = _not_implemented + op_UNARY_CONVERT = _not_implemented + op_UNARY_INVERT = _not_implemented + op_UNARY_NEGATIVE = _not_implemented + op_UNARY_NOT = _not_implemented + op_UNARY_POSITIVE = _not_implemented + op_UNPACK_EX = _not_implemented + op_UNPACK_SEQUENCE = _not_implemented + op_WITH_CLEANUP = _not_implemented + op_YIELD_VALUE = _not_implemented + +# ______________________________________________________________________ + +class BytecodeIterVisitor (BytecodeVisitor): + def visit (self, co_obj): + self.enter_code_object(co_obj) + for i, op, arg in itercode(co_obj.co_code): + self.visit_op(i, op, arg) + return self.exit_code_object(co_obj) + + def enter_code_object (self, co_obj): + pass + + def exit_code_object (self, co_obj): + pass + +# ______________________________________________________________________ + +class BasicBlockVisitor (BytecodeVisitor): + def visit (self, blocks): + self.enter_blocks(blocks) + block_indices = list(blocks.keys()) + block_indices.sort() + for block_index in block_indices: + self.enter_block(block_index) + for i, op, arg in blocks[block_index]: + self.visit_op(i, op, arg) + self.exit_block(block_index) + return self.exit_blocks(blocks) + + def enter_blocks (self, blocks): + pass + + def exit_blocks (self, blocks): + pass + + def enter_block (self, block_index): + pass + + def exit_block (self, block_index): + pass + +# ______________________________________________________________________ + +class BytecodeFlowVisitor (BytecodeVisitor): + def visit (self, flow): + self.block_list = list(flow.keys()) + self.block_list.sort() + self.enter_flow_object(flow) + for block in self.block_list: + prelude = self.enter_block(block) + prelude_isa_list = isinstance(prelude, list) + if prelude or prelude_isa_list: + if not prelude_isa_list: + prelude = [] + new_stmts = list(self.visit_op(i, op, arg, *args) + for i, op, _, arg, args in flow[block]) + self.new_flow[block] = list(itertools.chain( + prelude, *new_stmts)) + self.exit_block(block) + del self.block_list + return self.exit_flow_object(flow) + + def visit_op (self, i, op, arg, *args, **kws): + new_args = [] + for child_i, child_op, _, child_arg, child_args in args: + new_args.extend(self.visit_op(child_i, child_op, child_arg, + *child_args)) + ret_val = super(BytecodeFlowVisitor, self).visit_op(i, op, arg, + *new_args) + return ret_val + + def enter_flow_object (self, flow): + self.new_flow = {} + + def exit_flow_object (self, flow): + ret_val = self.new_flow + del self.new_flow + return ret_val + + def enter_block (self, block): + pass + + def exit_block (self, block): + pass + +# ______________________________________________________________________ + +class BenignBytecodeVisitorMixin (object): + def _do_nothing (self, i, op, arg, *args, **kws): + return [(i, op, self.opnames[op], arg, args)] + + op_BINARY_ADD = _do_nothing + op_BINARY_AND = _do_nothing + op_BINARY_DIVIDE = _do_nothing + op_BINARY_FLOOR_DIVIDE = _do_nothing + op_BINARY_LSHIFT = _do_nothing + op_BINARY_MODULO = _do_nothing + op_BINARY_MULTIPLY = _do_nothing + op_BINARY_OR = _do_nothing + op_BINARY_POWER = _do_nothing + op_BINARY_RSHIFT = _do_nothing + op_BINARY_SUBSCR = _do_nothing + op_BINARY_SUBTRACT = _do_nothing + op_BINARY_TRUE_DIVIDE = _do_nothing + op_BINARY_XOR = _do_nothing + op_BREAK_LOOP = _do_nothing + op_BUILD_CLASS = _do_nothing + op_BUILD_LIST = _do_nothing + op_BUILD_MAP = _do_nothing + op_BUILD_SET = _do_nothing + op_BUILD_SLICE = _do_nothing + op_BUILD_TUPLE = _do_nothing + op_CALL_FUNCTION = _do_nothing + op_CALL_FUNCTION_KW = _do_nothing + op_CALL_FUNCTION_VAR = _do_nothing + op_CALL_FUNCTION_VAR_KW = _do_nothing + op_COMPARE_OP = _do_nothing + op_CONTINUE_LOOP = _do_nothing + op_DELETE_ATTR = _do_nothing + op_DELETE_DEREF = _do_nothing + op_DELETE_FAST = _do_nothing + op_DELETE_GLOBAL = _do_nothing + op_DELETE_NAME = _do_nothing + op_DELETE_SLICE = _do_nothing + op_DELETE_SUBSCR = _do_nothing + op_DUP_TOP = _do_nothing + op_DUP_TOPX = _do_nothing + op_DUP_TOP_TWO = _do_nothing + op_END_FINALLY = _do_nothing + op_EXEC_STMT = _do_nothing + op_EXTENDED_ARG = _do_nothing + op_FOR_ITER = _do_nothing + op_GET_ITER = _do_nothing + op_IMPORT_FROM = _do_nothing + op_IMPORT_NAME = _do_nothing + op_IMPORT_STAR = _do_nothing + op_INPLACE_ADD = _do_nothing + op_INPLACE_AND = _do_nothing + op_INPLACE_DIVIDE = _do_nothing + op_INPLACE_FLOOR_DIVIDE = _do_nothing + op_INPLACE_LSHIFT = _do_nothing + op_INPLACE_MODULO = _do_nothing + op_INPLACE_MULTIPLY = _do_nothing + op_INPLACE_OR = _do_nothing + op_INPLACE_POWER = _do_nothing + op_INPLACE_RSHIFT = _do_nothing + op_INPLACE_SUBTRACT = _do_nothing + op_INPLACE_TRUE_DIVIDE = _do_nothing + op_INPLACE_XOR = _do_nothing + op_JUMP_ABSOLUTE = _do_nothing + op_JUMP_FORWARD = _do_nothing + op_JUMP_IF_FALSE = _do_nothing + op_JUMP_IF_FALSE_OR_POP = _do_nothing + op_JUMP_IF_TRUE = _do_nothing + op_JUMP_IF_TRUE_OR_POP = _do_nothing + op_LIST_APPEND = _do_nothing + op_LOAD_ATTR = _do_nothing + op_LOAD_BUILD_CLASS = _do_nothing + op_LOAD_CLOSURE = _do_nothing + op_LOAD_CONST = _do_nothing + op_LOAD_DEREF = _do_nothing + op_LOAD_FAST = _do_nothing + op_LOAD_GLOBAL = _do_nothing + op_LOAD_LOCALS = _do_nothing + op_LOAD_NAME = _do_nothing + op_MAKE_CLOSURE = _do_nothing + op_MAKE_FUNCTION = _do_nothing + op_MAP_ADD = _do_nothing + op_NOP = _do_nothing + op_POP_BLOCK = _do_nothing + op_POP_EXCEPT = _do_nothing + op_POP_JUMP_IF_FALSE = _do_nothing + op_POP_JUMP_IF_TRUE = _do_nothing + op_POP_TOP = _do_nothing + op_PRINT_EXPR = _do_nothing + op_PRINT_ITEM = _do_nothing + op_PRINT_ITEM_TO = _do_nothing + op_PRINT_NEWLINE = _do_nothing + op_PRINT_NEWLINE_TO = _do_nothing + op_RAISE_VARARGS = _do_nothing + op_RETURN_VALUE = _do_nothing + op_ROT_FOUR = _do_nothing + op_ROT_THREE = _do_nothing + op_ROT_TWO = _do_nothing + op_SETUP_EXCEPT = _do_nothing + op_SETUP_FINALLY = _do_nothing + op_SETUP_LOOP = _do_nothing + op_SETUP_WITH = _do_nothing + op_SET_ADD = _do_nothing + op_SLICE = _do_nothing + op_STOP_CODE = _do_nothing + op_STORE_ATTR = _do_nothing + op_STORE_DEREF = _do_nothing + op_STORE_FAST = _do_nothing + op_STORE_GLOBAL = _do_nothing + op_STORE_LOCALS = _do_nothing + op_STORE_MAP = _do_nothing + op_STORE_NAME = _do_nothing + op_STORE_SLICE = _do_nothing + op_STORE_SUBSCR = _do_nothing + op_UNARY_CONVERT = _do_nothing + op_UNARY_INVERT = _do_nothing + op_UNARY_NEGATIVE = _do_nothing + op_UNARY_NOT = _do_nothing + op_UNARY_POSITIVE = _do_nothing + op_UNPACK_EX = _do_nothing + op_UNPACK_SEQUENCE = _do_nothing + op_WITH_CLEANUP = _do_nothing + op_YIELD_VALUE = _do_nothing + +# ______________________________________________________________________ +# End of bytecode_visitor.py diff --git a/llpython/bytetype.py b/llpython/bytetype.py new file mode 100644 index 0000000..484d09e --- /dev/null +++ b/llpython/bytetype.py @@ -0,0 +1,42 @@ +# ______________________________________________________________________ + +import ctypes + +import llvm.core as lc + +# ______________________________________________________________________ + +lvoid = lc.Type.void() +li1 = lc.Type.int(1) +li8 = lc.Type.int(8) +li16 = lc.Type.int(16) +li32 = lc.Type.int(32) +li64 = lc.Type.int(64) +liptr = lc.Type.int(ctypes.sizeof(ctypes.c_void_p) * 8) +lc_size_t = lc.Type.int(ctypes.sizeof( + getattr(ctypes, 'c_ssize_t', getattr(ctypes, 'c_size_t'))) * 8) +lfloat = lc.Type.float() +ldouble = lc.Type.double() +li8_ptr = lc.Type.pointer(li8) + +lc_int = lc.Type.int(ctypes.sizeof(ctypes.c_int) * 8) +lc_long = lc.Type.int(ctypes.sizeof(ctypes.c_long) * 8) + +l_pyobject_head = [lc_size_t, lc.Type.pointer(li32)] +l_pyobject_head_struct = lc.Type.struct(l_pyobject_head) +l_pyobj_p = l_pyobject_head_struct_p = lc.Type.pointer(l_pyobject_head_struct) +l_pyfunc = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p)) + +strlen = lc.Type.function(lc_size_t, (li8_ptr,)) +strncpy = lc.Type.function(li8_ptr, (li8_ptr, li8_ptr, lc_size_t)) +strndup = lc.Type.function(li8_ptr, (li8_ptr, lc_size_t)) +malloc = lc.Type.function(li8_ptr, (lc_size_t,)) +free = lc.Type.function(lvoid, (li8_ptr,)) + +Py_BuildValue = lc.Type.function(l_pyobj_p, [li8_ptr], True) +PyArg_ParseTuple = lc.Type.function(lc_int, [l_pyobj_p, li8_ptr], True) +PyEval_SaveThread = lc.Type.function(li8_ptr, []) +PyEval_RestoreThread = lc.Type.function(lc.Type.void(), [li8_ptr]) + +# ______________________________________________________________________ +# End of bytetype.py diff --git a/llpython/control_flow.py b/llpython/control_flow.py new file mode 100644 index 0000000..8026aba --- /dev/null +++ b/llpython/control_flow.py @@ -0,0 +1,217 @@ +# ______________________________________________________________________ + +import pprint + +# ______________________________________________________________________ + +class ControlFlowGraph (object): + def __init__ (self): + self.blocks = {} + self.blocks_in = {} + self.blocks_out = {} + self.blocks_reads = {} + self.blocks_writes = {} + self.blocks_writer = {} + self.blocks_dom = {} + self.blocks_reaching = {} + + def add_block (self, key, value = None): + self.blocks[key] = value + if key not in self.blocks_in: + self.blocks_in[key] = set() + self.blocks_out[key] = set() + self.blocks_reads[key] = set() + self.blocks_writes[key] = set() + self.blocks_writer[key] = {} + + def add_edge (self, from_block, to_block): + self.blocks_out[from_block].add(to_block) + self.blocks_in[to_block].add(from_block) + + def unlink_unreachables (self): + changed = True + next_blocks = self.blocks.keys() + next_blocks.remove(0) + while changed: + changed = False + blocks = next_blocks + next_blocks = blocks[:] + for block in blocks: + if len(self.blocks_in[block]) == 0: + blocks_out = self.blocks_out[block] + for out_edge in blocks_out: + self.blocks_in[out_edge].discard(block) + blocks_out.clear() + next_blocks.remove(block) + changed = True + + def compute_dataflow (self): + '''Compute the dominator and reaching dataflow relationships + in the CFG.''' + blocks = set(self.blocks.keys()) + nonentry_blocks = blocks.copy() + for block in blocks: + self.blocks_dom[block] = blocks + self.blocks_reaching[block] = set((block,)) + if len(self.blocks_in[block]) == 0: + self.blocks_dom[block] = set((block,)) + nonentry_blocks.remove(block) + changed = True + while changed: + changed = False + for block in nonentry_blocks: + olddom = self.blocks_dom[block] + newdom = set.intersection(*[self.blocks_dom[pred] + for pred in self.blocks_in[block]]) + newdom.add(block) + if newdom != olddom: + changed = True + self.blocks_dom[block] = newdom + oldreaching = self.blocks_reaching[block] + newreaching = set.union( + *[self.blocks_reaching[pred] + for pred in self.blocks_in[block]]) + newreaching.add(block) + if newreaching != oldreaching: + changed = True + self.blocks_reaching[block] = newreaching + return self.blocks_dom, self.blocks_reaching + + def update_for_ssa (self): + '''Modify the blocks_writes map to reflect phi nodes inserted + for static single assignment representations.''' + joins = [block for block in self.blocks.keys() + if len(self.blocks_in[block]) > 1] + changed = True + while changed: + changed = False + for block in joins: + phis_needed = self.phi_needed(block) + for affected_local in phis_needed: + if affected_local not in self.blocks_writes[block]: + changed = True + # NOTE: For this to work, we assume that basic + # blocks are indexed by their instruction + # index in the VM bytecode. + self.writes_local(block, block, affected_local) + if changed: + # Any modifications have invalidated the reaching + # definitions, so delete any memoized results. + if hasattr(self, 'reaching_definitions'): + del self.reaching_definitions + + def idom (self, block): + '''Compute the immediate dominator (idom) of the given block + key. Returns None if the block has no in edges. + + Note that in the case where there are multiple immediate + dominators (a join after a non-loop branch), this returns one + of the predecessors, but is not guaranteed to reliably select + one over the others (depends on the ordering of the set type + iterator).''' + preds = self.blocks_in[block] + npreds = len(preds) + if npreds == 0: + ret_val = None + elif npreds == 1: + ret_val = tuple(preds)[0] + else: + ret_val = [pred for pred in preds + if block not in self.blocks_dom[pred]][0] + return ret_val + + def block_writes_to_writer_map (self, block): + ret_val = {} + for local in self.blocks_writes[block]: + ret_val[local] = block + return ret_val + + def get_reaching_definitions (self, block): + '''Return a nested map for the given block + s.t. ret_val[pred][local] equals the block key for the + definition of local that reaches the argument block via that + predecessor. + + Useful for actually populating phi nodes, once you know you + need them.''' + has_memoized = hasattr(self, 'reaching_definitions') + if has_memoized and block in self.reaching_definitions: + ret_val = self.reaching_definitions[block] + else: + preds = self.blocks_in[block] + ret_val = {} + for pred in preds: + ret_val[pred] = self.block_writes_to_writer_map(pred) + crnt = self.idom(pred) + while crnt != None: + crnt_writer_map = self.block_writes_to_writer_map(crnt) + # This order of update favors the first definitions + # encountered in the traversal since the traversal + # visits blocks in reverse execution order. + crnt_writer_map.update(ret_val[pred]) + ret_val[pred] = crnt_writer_map + crnt = self.idom(crnt) + if not has_memoized: + self.reaching_definitions = {} + self.reaching_definitions[block] = ret_val + return ret_val + + def nreaches (self, block): + '''For each local, find the number of unique reaching + definitions the current block has.''' + reaching_definitions = self.get_reaching_definitions(block) + definition_map = {} + for pred in self.blocks_in[block]: + reaching_from_pred = reaching_definitions[pred] + for local in reaching_from_pred.keys(): + if local not in definition_map: + definition_map[local] = set() + definition_map[local].add(reaching_from_pred[local]) + ret_val = {} + for local in definition_map.keys(): + ret_val[local] = len(definition_map[local]) + return ret_val + + def writes_local (self, block, write_instr_index, local_index): + self.blocks_writes[block].add(local_index) + block_writers = self.blocks_writer[block] + old_index = block_writers.get(local_index, -1) + # This checks for a corner case that would impact + # numba.translate.Translate.build_phi_nodes(). + assert old_index != write_instr_index, ( + "Found corner case for STORE_FAST at a CFG join!") + block_writers[local_index] = max(write_instr_index, old_index) + + def phi_needed (self, join): + '''Return the set of locals that will require a phi node to be + generated at the given join.''' + nreaches = self.nreaches(join) + return set([local for local in nreaches.keys() + if nreaches[local] > 1]) + + def pprint (self, *args, **kws): + pprint.pprint(self.__dict__, *args, **kws) + + def pformat (self, *args, **kws): + return pprint.pformat(self.__dict__, *args, **kws) + + def to_dot (self, graph_name = None): + '''Return a dot (digraph visualizer in Graphviz) graph + description as a string.''' + if graph_name is None: + graph_name = 'CFG_%d' % id(self) + lines_out = [] + for block_index in self.blocks: + lines_out.append( + 'BLOCK_%r [shape=box, label="BLOCK_%r\\nr: %r, w: %r"];' % + (block_index, block_index, + tuple(self.blocks_reads[block_index]), + tuple(self.blocks_writes[block_index]))) + for block_index in self.blocks: + for out_edge in self.blocks_out[block_index]: + lines_out.append('BLOCK_%r -> BLOCK_%r;' % + (block_index, out_edge)) + return 'digraph %s {\n%s\n}\n' % (graph_name, '\n'.join(lines_out)) + +# ______________________________________________________________________ +# End of control_flow.py diff --git a/llpython/gen_bytecode_visitor.py b/llpython/gen_bytecode_visitor.py new file mode 100644 index 0000000..a60b345 --- /dev/null +++ b/llpython/gen_bytecode_visitor.py @@ -0,0 +1,26 @@ +# ______________________________________________________________________ +from __future__ import absolute_import +from . import opcode_util + +# ______________________________________________________________________ + +def generate_bytecode_visitor (classname = 'BytecodeVisitor', + baseclass = 'object'): + opnames = list(set((opname.split('+')[0] + for opname in opcode_util.OPCODE_MAP.keys()))) + opnames.sort() + return 'class %s (%s):\n%s\n' % ( + classname, baseclass, + '\n\n'.join((' def op_%s (self, i, op, arg):\n' + ' raise NotImplementedError("%s.op_%s")' % + (opname, classname, opname) + for opname in opnames))) + +# ______________________________________________________________________ + +if __name__ == "__main__": + import sys + print(generate_bytecode_visitor(*sys.argv[1:])) + +# ______________________________________________________________________ +# End of gen_bytecode_visitor.py diff --git a/llpython/nobitey.py b/llpython/nobitey.py new file mode 100644 index 0000000..4236d29 --- /dev/null +++ b/llpython/nobitey.py @@ -0,0 +1,367 @@ +# ______________________________________________________________________ +from __future__ import absolute_import +import sys +import os.path +import imp +import io +import types + +import llvm.core as lc +import llvm.ee as le + +from . import bytetype, byte_translator +from .pyaddfunc import pyaddfunc + +LLVM_TO_INT_PARSE_STR_MAP = { + 8 : 'b', + 16 : 'h', + 32 : 'i', # Note that on 32-bit systems sizeof(int) == sizeof(long) + 64 : 'L', # Seeing sizeof(long long) == 8 on both 32 and 64-bit platforms +} + +LLVM_TO_PARSE_STR_MAP = { + lc.TYPE_FLOAT : 'f', + lc.TYPE_DOUBLE : 'd', +} + +# ______________________________________________________________________ + +# XXX Stolen from numba.translate + +def get_string_constant (module, const_str): + const_name = "__STR_%x" % (hash(const_str),) + try: + ret_val = module.get_global_variable_named(const_name) + except: + lconst_str = lc.Constant.stringz(const_str) + ret_val = module.add_global_variable(lconst_str.type, const_name) + ret_val.initializer = lconst_str + ret_val.linkage = lc.LINKAGE_INTERNAL + return ret_val + +# ______________________________________________________________________ + +class NoBitey (object): + def __init__ (self, target_module = None, type_annotations = None): + if target_module is None: + target_module = lc.Module.new('NoBitey_%d' % id(self)) + if type_annotations is None: + type_annotations = {} + self.target_module = target_module + self.type_aliases = type_annotations # Reserved for future use. + + def _build_parse_string (self, llvm_type): + kind = llvm_type.kind + if kind == lc.TYPE_INTEGER: + ret_val = LLVM_TO_INT_PARSE_STR_MAP[llvm_type.width] + elif kind in LLVM_TO_PARSE_STR_MAP: + ret_val = LLVM_TO_PARSE_STR_MAP[kind] + else: + raise TypeError('Unsupported LLVM type: %s' % str(llvm_type)) + return ret_val + + def build_parse_string (self, llvm_tys): + """Given a set of LLVM types, return a string for parsing + them via PyArg_ParseTuple.""" + return ''.join((self._build_parse_string(ty) + for ty in llvm_tys)) + + def handle_abi_casts (self, builder, result): + if result.type.kind == lc.TYPE_FLOAT: + # NOTE: The C ABI apparently casts floats to doubles when + # an argument must be pushed on the stack, as is the case + # when calling a variable argument function. + # XXX Is there documentation on this where I can find all + # coercion rules? Do we still need some libffi + # integration? + result = builder.fpext(result, bytetype.ldouble) + return result + + def build_wrapper_function (self, llvm_function, engine = None): + arg_types = llvm_function.type.pointee.args + return_type = llvm_function.type.pointee.return_type + li32_0 = lc.Constant.int(bytetype.li32, 0) + def get_llvm_function (builder): + if self.target_module != llvm_function.module: + llvm_function_ptr = self.target_module.add_global_variable( + llvm_function.type, llvm_function.name) + llvm_function_ptr.initializer = lc.Constant.inttoptr( + lc.Constant.int( + bytetype.liptr, + engine.get_pointer_to_function(llvm_function)), + llvm_function.type) + llvm_function_ptr.linkage = lc.LINKAGE_INTERNAL + ret_val = builder.load(llvm_function_ptr) + else: + ret_val = llvm_function + return ret_val + def build_parse_args (builder): + return [builder.alloca(arg_type) for arg_type in arg_types] + def build_parse_string (builder): + parse_str = get_string_constant( + self.target_module, self.build_parse_string(arg_types)) + return builder.gep(parse_str, (li32_0, li32_0)) + def load_target_args (builder, args): + return [builder.load(arg) for arg in args] + def build_build_string (builder): + build_str = get_string_constant( + self.target_module, self._build_parse_string(return_type)) + return builder.gep(build_str, (li32_0, li32_0)) + handle_abi_casts = self.handle_abi_casts + target_function_name = llvm_function.name + "_wrapper" + # __________________________________________________ + @byte_translator.llpython(bytetype.l_pyfunc, self.target_module, + **locals()) + def _wrapper (self, args): + ret_val = l_pyobj_p(0) + parse_args = build_parse_args() + parse_result = PyArg_ParseTuple(args, build_parse_string(), + *parse_args) + if parse_result != li32(0): + thread_state = PyEval_SaveThread() + target_args = load_target_args(parse_args) + llresult = handle_abi_casts(get_llvm_function()(*target_args)) + PyEval_RestoreThread(thread_state) + ret_val = Py_BuildValue(build_build_string(), llresult) + return ret_val + # __________________________________________________ + return _wrapper + + def wrap_llvm_module (self, llvm_module, engine = None, py_module = None): + ''' + Shamefully adapted from bitey.bind.wrap_llvm_module(). + ''' + functions = [func for func in llvm_module.functions + if not func.name.startswith("_") + and not func.is_declaration + and func.linkage == lc.LINKAGE_EXTERNAL] + if engine is None: + engine = le.ExecutionEngine.new(llvm_module) + wrappers = [self.build_wrapper_function(func, engine) + for func in functions] + if __debug__: print(self.target_module) + if self.target_module != llvm_module: + engine.add_module(self.target_module) + py_wrappers = [pyaddfunc(wrapper.name, + engine.get_pointer_to_function(wrapper)) + for wrapper in wrappers] + if py_module: + for py_wrapper in py_wrappers: + setattr(py_module, py_wrapper.__name__[:-8], py_wrapper) + setattr(py_module, '_llvm_module', llvm_module) + setattr(py_module, '_llvm_engine', engine) + if self.target_module != llvm_module: + setattr(py_module, '_llvm_wrappers', self.target_module) + return engine, py_wrappers + + def wrap_llvm_module_in_python (self, llvm_module, py_module = None): + ''' + Mildly reworked and abstracted bitey.bind.wrap_llvm_bitcode(). + Abstracted to accept any existing LLVM Module object, and + return a Python wrapper module (even if one wasn't originally + specified). + ''' + if py_module is None: + py_module = types.ModuleType(str(llvm_module.id)) + engine = le.ExecutionEngine.new(llvm_module) + self.wrap_llvm_module(llvm_module, engine, py_module) + return py_module + + def wrap_llvm_bitcode (self, bitcode, py_module = None): + ''' + Intended to be drop-in replacement of + bitey.bind.wrap_llvm_bitcode(). + ''' + return self.wrap_llvm_module_in_python( + lc.Module.from_bitcode(io.BytesIO(bitcode)), py_module) + + def wrap_llvm_assembly (self, llvm_asm, py_module = None): + return self.wrap_llvm_module_in_python( + lc.Module.from_assembly(io.BytesIO(llvm_asm)), py_module) + +# ______________________________________________________________________ + +class NoBiteyLoader(object): + """ + Load LLVM compiled bitcode and autogenerate a ctypes binding. + + Initially copied and adapted from bitey.loader module. + """ + def __init__(self, pkg, name, source, preload, postload): + self.package = pkg + self.name = name + self.fullname = '.'.join((pkg,name)) + self.source = source + self.preload = preload + self.postload = postload + + @classmethod + def _check_magic(cls, filename): + if os.path.exists(filename): + magic = open(filename,"rb").read(4) + if magic == b'\xde\xc0\x17\x0b': + return True + elif magic[:2] == b'\x42\x43': + return True + else: + return False + else: + return False + + @classmethod + def build_module(cls, fullname, source_path, source_data, preload=None, + postload=None): + name = fullname.split(".")[-1] + mod = imp.new_module(name) + if preload: + exec(preload, mod.__dict__, mod.__dict__) + type_annotations = getattr(mod, '_type_annotations', None) + nb = NoBitey(type_annotations = type_annotations) + if source_path.endswith(('.o', '.bc')): + nb.wrap_llvm_bitcode(source_data, mod) + elif source_path.endswith('.s'): + nb.wrap_llvm_assembly(source_data, mod) + if postload: + exec(postload, mod.__dict__, mod.__dict__) + return mod + + @classmethod + def find_module(cls, fullname, paths = None): + if paths is None: + paths = sys.path + names = fullname.split('.') + modname = names[-1] + source_paths = None + for f in paths: + path = os.path.join(os.path.realpath(f), modname) + source = path + '.o' + if cls._check_magic(source): + source_paths = path, source + break + source = path + '.bc' + if os.path.exists(source): + source_paths = path, source + break + source = path + '.s' + if os.path.exists(source): + source_paths = path, source + break + if source_paths: + path, source = source_paths + return cls('.'.join(names[:-1]), modname, source, + path + ".pre.py", path + ".post.py") + + def get_code(self, module): + pass + + def get_data(self, module): + pass + + def get_filename(self, name): + return self.source + + def get_source(self, name): + with open(self.source, 'rb') as f: + return f.read() + + def is_package(self, *args, **kw): + return False + + def load_module(self, fullname): + if fullname in sys.modules: + return sys.modules[fullname] + + preload = None + postload = None + + # Get the preload file (if any) + if os.path.exists(self.preload): + with open(self.preload) as f: + preload = f.read() + + # Get the source + with open(self.source, 'rb') as f: + source_data = f.read() + + # Get the postload file (if any) + if os.path.exists(self.postload): + with open(self.postload) as f: + postload = f.read() + + mod = self.build_module(fullname, self.get_filename(None), source_data, + preload, postload) + sys.modules[fullname] = mod + mod.__loader__ = self + mod.__file__ = self.source + return mod + + @classmethod + def install(cls): + if cls not in sys.meta_path: + sys.meta_path.append(cls) + + @classmethod + def remove(cls): + sys.meta_path.remove(cls) + +# ______________________________________________________________________ + +def _mk_add_42 (llvm_module, at_type = bytetype.lc_long): + f = llvm_module.add_function( + lc.Type.function(at_type, [at_type]), 'add_42_%s' % str(at_type)) + block = f.append_basic_block('entry') + builder = lc.Builder.new(block) + if at_type.kind == lc.TYPE_INTEGER: + const_42 = lc.Constant.int(at_type, 42) + add = builder.add + elif at_type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + const_42 = lc.Constant.real(at_type, 42.) + add = builder.fadd + else: + raise TypeError('Unsupported type: %s' % str(at_type)) + builder.ret(add(f.args[0], const_42)) + return f + +# ______________________________________________________________________ + +def build_test_module (): + llvm_module = lc.Module.new('nobitey_test') + for ty in (bytetype.li32, bytetype.li64, bytetype.lfloat, + bytetype.ldouble): + fn = _mk_add_42(llvm_module, ty) + return llvm_module + +# ______________________________________________________________________ + +def test_wrap_module (arg = None): + # Build up a module. + m = build_test_module() + if arg and arg.lower() == 'separated': + wrap_module = NoBitey().wrap_llvm_module_in_python(m) + else: + wrap_module = NoBitey(m).wrap_llvm_module_in_python(m) + # Now try running the generated wrappers. + for py_wf_name in ('add_42_i32', 'add_42_i64', 'add_42_float', + 'add_42_double'): + py_wf = getattr(wrap_module, py_wf_name) + for i in range(42): + result = py_wf(i) + expected = i + 42 + assert result == expected, "%r != %r in %r" % ( + result, expected, py_wf) + return wrap_module + +# ______________________________________________________________________ + +def main (*args): + if args: + for arg in args: + test_wrap_module(arg) + else: + test_wrap_module() + +if __name__ == "__main__": + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of nobitey.py diff --git a/llpython/opcode_util.py b/llpython/opcode_util.py new file mode 100644 index 0000000..7a1972b --- /dev/null +++ b/llpython/opcode_util.py @@ -0,0 +1,225 @@ +# ______________________________________________________________________ + +import dis +import opcode + +# ______________________________________________________________________ +# Module data + +hasjump = opcode.hasjrel + opcode.hasjabs +hascbranch = [op for op in hasjump + if 'IF' in opcode.opname[op] + or opcode.opname[op] in ('FOR_ITER', 'SETUP_LOOP')] + +# Since the actual opcode value may change, manage opcode abstraction +# data by opcode name. + +OPCODE_MAP = { + 'BINARY_ADD': (2, 1, None), + 'BINARY_AND': (2, 1, None), + 'BINARY_DIVIDE': (2, 1, None), + 'BINARY_FLOOR_DIVIDE': (2, 1, None), + 'BINARY_LSHIFT': (2, 1, None), + 'BINARY_MODULO': (2, 1, None), + 'BINARY_MULTIPLY': (2, 1, None), + 'BINARY_OR': (2, 1, None), + 'BINARY_POWER': (2, 1, None), + 'BINARY_RSHIFT': (2, 1, None), + 'BINARY_SUBSCR': (2, 1, None), + 'BINARY_SUBTRACT': (2, 1, None), + 'BINARY_TRUE_DIVIDE': (2, 1, None), + 'BINARY_XOR': (2, 1, None), + 'BREAK_LOOP': (0, None, 1), + 'BUILD_CLASS': (None, None, None), + 'BUILD_LIST': (-1, 1, None), + 'BUILD_MAP': (None, None, None), + 'BUILD_SET': (None, None, None), + 'BUILD_SLICE': (None, None, None), + 'BUILD_TUPLE': (-1, 1, None), + 'CALL_FUNCTION': (-2, 1, None), + 'CALL_FUNCTION_KW': (-3, 1, None), + 'CALL_FUNCTION_VAR': (-3, 1, None), + 'CALL_FUNCTION_VAR_KW': (-4, 1, None), + 'COMPARE_OP': (2, 1, None), + 'CONTINUE_LOOP': (None, None, None), + 'DELETE_ATTR': (1, None, 1), + 'DELETE_DEREF': (None, None, None), + 'DELETE_FAST': (0, None, 1), + 'DELETE_GLOBAL': (0, None, 1), + 'DELETE_NAME': (0, None, 1), + 'DELETE_SLICE+0': (1, None, 1), + 'DELETE_SLICE+1': (2, None, 1), + 'DELETE_SLICE+2': (2, None, 1), + 'DELETE_SLICE+3': (3, None, 1), + 'DELETE_SUBSCR': (2, None, 1), + 'DUP_TOP': (None, None, None), + 'DUP_TOPX': (None, None, None), + 'DUP_TOP_TWO': (None, None, None), + 'END_FINALLY': (None, None, None), + 'EXEC_STMT': (None, None, None), + 'EXTENDED_ARG': (None, None, None), + 'FOR_ITER': (1, 1, 1), + 'GET_ITER': (1, 1, None), + 'IMPORT_FROM': (None, None, None), + 'IMPORT_NAME': (None, None, None), + 'IMPORT_STAR': (1, None, 1), + 'INPLACE_ADD': (2, 1, None), + 'INPLACE_AND': (2, 1, None), + 'INPLACE_DIVIDE': (2, 1, None), + 'INPLACE_FLOOR_DIVIDE': (2, 1, None), + 'INPLACE_LSHIFT': (2, 1, None), + 'INPLACE_MODULO': (2, 1, None), + 'INPLACE_MULTIPLY': (2, 1, None), + 'INPLACE_OR': (2, 1, None), + 'INPLACE_POWER': (2, 1, None), + 'INPLACE_RSHIFT': (2, 1, None), + 'INPLACE_SUBTRACT': (2, 1, None), + 'INPLACE_TRUE_DIVIDE': (2, 1, None), + 'INPLACE_XOR': (2, 1, None), + 'JUMP_ABSOLUTE': (0, None, 1), + 'JUMP_FORWARD': (0, None, 1), + 'JUMP_IF_FALSE': (1, 1, 1), + 'JUMP_IF_FALSE_OR_POP': (None, None, None), + 'JUMP_IF_TRUE': (1, 1, 1), + 'JUMP_IF_TRUE_OR_POP': (None, None, None), + 'LIST_APPEND': (2, 0, 1), + 'LOAD_ATTR': (1, 1, None), + 'LOAD_BUILD_CLASS': (None, None, None), + 'LOAD_CLOSURE': (None, None, None), + 'LOAD_CONST': (0, 1, None), + 'LOAD_DEREF': (0, 1, None), + 'LOAD_FAST': (0, 1, None), + 'LOAD_GLOBAL': (0, 1, None), + 'LOAD_LOCALS': (None, None, None), + 'LOAD_NAME': (0, 1, None), + 'MAKE_CLOSURE': (None, None, None), + 'MAKE_FUNCTION': (-2, 1, None), + 'MAP_ADD': (None, None, None), + 'NOP': (0, None, None), + 'POP_BLOCK': (0, None, 1), + 'POP_EXCEPT': (None, None, None), + 'POP_JUMP_IF_FALSE': (1, None, 1), + 'POP_JUMP_IF_TRUE': (1, None, 1), + 'POP_TOP': (1, None, 1), + 'PRINT_EXPR': (1, None, 1), + 'PRINT_ITEM': (1, None, 1), + 'PRINT_ITEM_TO': (2, None, 1), + 'PRINT_NEWLINE': (0, None, 1), + 'PRINT_NEWLINE_TO': (1, None, 1), + 'RAISE_VARARGS': (None, None, None), + 'RETURN_VALUE': (1, None, 1), + 'ROT_FOUR': (None, None, None), + 'ROT_THREE': (None, None, None), + 'ROT_TWO': (None, None, None), + 'SETUP_EXCEPT': (None, None, None), + 'SETUP_FINALLY': (None, None, None), + 'SETUP_LOOP': (None, None, None), + 'SETUP_WITH': (None, None, None), + 'SET_ADD': (None, None, None), + 'SLICE+0': (1, 1, None), + 'SLICE+1': (2, 1, None), + 'SLICE+2': (2, 1, None), + 'SLICE+3': (3, 1, None), + 'STOP_CODE': (None, None, None), + 'STORE_ATTR': (2, None, 1), + 'STORE_DEREF': (1, 0, 1), + 'STORE_FAST': (1, None, 1), + 'STORE_GLOBAL': (1, None, 1), + 'STORE_LOCALS': (None, None, None), + 'STORE_MAP': (1, None, 1), + 'STORE_NAME': (1, None, 1), + 'STORE_SLICE+0': (1, None, 1), + 'STORE_SLICE+1': (2, None, 1), + 'STORE_SLICE+2': (2, None, 1), + 'STORE_SLICE+3': (3, None, 1), + 'STORE_SUBSCR': (3, None, 1), + 'UNARY_CONVERT': (1, 1, None), + 'UNARY_INVERT': (1, 1, None), + 'UNARY_NEGATIVE': (1, 1, None), + 'UNARY_NOT': (1, 1, None), + 'UNARY_POSITIVE': (1, 1, None), + 'UNPACK_EX': (None, None, None), + 'UNPACK_SEQUENCE': (None, None, None), + 'WITH_CLEANUP': (None, None, None), + 'YIELD_VALUE': (1, None, 1), +} + +# ______________________________________________________________________ +# Module functions + +def itercode(code, start = 0): + """Return a generator of byte-offset, opcode, and argument + from a byte-code-string + """ + i = 0 + extended_arg = 0 + if isinstance(code[0], str): + code = [ord(c) for c in code] + n = len(code) + while i < n: + op = code[i] + num = i + start + i = i + 1 + oparg = None + if op >= opcode.HAVE_ARGUMENT: + oparg = code[i] + (code[i + 1] * 256) + extended_arg + extended_arg = 0 + i = i + 2 + if op == opcode.EXTENDED_ARG: + extended_arg = oparg * 65536 + + delta = yield num, op, oparg + if delta is not None: + abs_rel, dst = delta + assert abs_rel == 'abs' or abs_rel == 'rel' + i = dst if abs_rel == 'abs' else i + dst + +# ______________________________________________________________________ + +def extendlabels(code, labels = None): + """Extend the set of jump target labels to account for the + passthrough targets of conditional branches. + + This allows us to create a control flow graph where there is at + most one branch per basic block. + """ + if labels is None: + labels = [] + if isinstance(code[0], str): + code = [ord(c) for c in code] + n = len(code) + i = 0 + while i < n: + op = code[i] + i += 1 + if op >= dis.HAVE_ARGUMENT: + i += 2 + label = -1 + if op in hasjump: + label = i + if label >= 0: + if label not in labels: + labels.append(label) + elif op == opcode.opmap['BREAK_LOOP']: + if i not in labels: + labels.append(i) + return labels + +# ______________________________________________________________________ + +def get_code_object (func): + return getattr(func, '__code__', getattr(func, 'func_code', None)) + +# ______________________________________________________________________ + +def build_basic_blocks (co_obj): + co_code = co_obj.co_code + labels = extendlabels(co_code, dis.findlabels(co_code)) + labels.sort() + blocks = dict((index, list(itercode(co_code[index:next_index], index))) + for index, next_index in zip([0] + labels, + labels + [len(co_code)])) + return blocks + +# ______________________________________________________________________ +# End of opcode_util.py diff --git a/llpython/phi_injector.py b/llpython/phi_injector.py new file mode 100644 index 0000000..dfa1061 --- /dev/null +++ b/llpython/phi_injector.py @@ -0,0 +1,153 @@ +# ______________________________________________________________________ + +from .bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin + +# ______________________________________________________________________ + +synthetic_opname = [] +synthetic_opmap = {} + +def def_synth_op (opname): + global synthetic_opname, synthetic_opmap + ret_val = -(len(synthetic_opname) + 1) + synthetic_opname.insert(0, opname) + synthetic_opmap[opname] = ret_val + return ret_val + +REF_ARG = def_synth_op('REF_ARG') +BUILD_PHI = def_synth_op('BUILD_PHI') +DEFINITION = def_synth_op('DEFINITION') +REF_DEF = def_synth_op('REF_DEF') + +# ______________________________________________________________________ + +class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): + '''Transformer responsible for modifying a bytecode flow, removing + LOAD_FAST and STORE_FAST opcodes, and replacing them with a static + single assignment (SSA) representation. + + In order to support SSA, PhiInjector adds the following synthetic + opcodes to transformed flows: + + * REF_ARG: Specifically reference an incomming argument value. + + * BUILD_PHI: Build a phi node to disambiguate between several + possible definitions at a control flow join. + + * DEFINITION: Unique value definition indexed by the "arg" field + in the tuple. + + * REF_DEF: Reference a specific value definition.''' + + def visit_cfg (self, cfg, nargs = 0, *args, **kws): + self.cfg = cfg + ret_val = self.visit(cfg.blocks, nargs) + del self.cfg + return ret_val + + def visit (self, flow, nargs = 0, *args, **kws): + self.nargs = nargs + self.definitions = [] + self.phis = [] + self.prev_blocks = [] + self.blocks_locals = dict((block, {}) + for block in self.cfg.blocks.keys()) + ret_val = super(PhiInjector, self).visit(flow, *args, **kws) + for block, _, _, args, _ in self.phis: + local = args.pop() + reaching_definitions = self.cfg.reaching_definitions[block] + for prev in reaching_definitions.keys(): + if 0 in self.cfg.blocks_reaching[prev]: + args.append((prev, REF_DEF, 'REF_DEF', + self.blocks_locals[prev][local], ())) + args.sort() + del self.blocks_locals + del self.prev_blocks + del self.phis + del self.definitions + del self.nargs + return ret_val + + def add_definition (self, index, local, arg): + definition_index = len(self.definitions) + definition = (index, DEFINITION, 'DEFINITION', definition_index, + (arg,)) + self.definitions.append(definition) + self.blocks_locals[self.block][local] = definition_index + return definition + + def add_phi (self, index, local): + ret_val = (index, BUILD_PHI, 'BUILD_PHI', [local], ()) + self.phis.append(ret_val) + return ret_val + + def enter_block (self, block): + ret_val = False + self.block = block + if block == 0: + if self.nargs > 0: + ret_val = [self.add_definition(-1, arg, + (-1, REF_ARG, 'REF_ARG', arg, + ())) + for arg in range(self.nargs)] + else: + ret_val = True + elif 0 in self.cfg.blocks_reaching[block]: + ret_val = True + prev_block_locals = None + for pred_block in self.cfg.blocks_in[block]: + if pred_block in self.prev_blocks: + prev_block_locals = self.blocks_locals[pred_block] + break + assert prev_block_locals is not None, "Internal translation error" + self.blocks_locals[block] = prev_block_locals.copy() + phis_needed = self.cfg.phi_needed(block) + if phis_needed: + ret_val = [self.add_definition(block, local, + self.add_phi(block, local)) + for local in phis_needed] + return ret_val + + def exit_block (self, block): + if 0 in self.cfg.blocks_reaching[block]: + self.prev_blocks.append(block) + del self.block + + def op_STORE_FAST (self, i, op, arg, *args, **kws): + assert len(args) == 1 + return [self.add_definition(i, arg, args[0])] + + def op_LOAD_FAST (self, i, op, arg, *args, **kws): + return [(i, REF_DEF, 'REF_DEF', self.blocks_locals[self.block][arg], + args)] + +# ______________________________________________________________________ + +def inject_phis (func): + '''Given a Python function, return a bytecode flow object that has + been transformed by a fresh PhiInjector instance.''' + import byte_control, byte_flow + argcount = byte_control.opcode_util.get_code_object(func).co_argcount + cfg = byte_control.build_cfg(func) + cfg.blocks = byte_flow.BytecodeFlowBuilder().visit_cfg(cfg) + return PhiInjector().visit_cfg(cfg, argcount) + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args): + import pprint + from tests import llfuncs + if not args: + args = ('doslice',) + for arg in args: + pprint.pprint(inject_phis(getattr(llfuncs, arg))) + +# ______________________________________________________________________ + +if __name__ == "__main__": + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of phi_injector.py diff --git a/llpython/pyaddfunc.py b/llpython/pyaddfunc.py new file mode 100644 index 0000000..d6a2945 --- /dev/null +++ b/llpython/pyaddfunc.py @@ -0,0 +1,40 @@ +# ______________________________________________________________________ + +import ctypes + +# ______________________________________________________________________ +class PyMethodDef (ctypes.Structure): + _fields_ = [ + ('ml_name', ctypes.c_char_p), + ('ml_meth', ctypes.c_void_p), + ('ml_flags', ctypes.c_int), + ('ml_doc', ctypes.c_char_p), + ] + +PyCFunction_NewEx = ctypes.pythonapi.PyCFunction_NewEx +PyCFunction_NewEx.argtypes = (ctypes.POINTER(PyMethodDef), + ctypes.c_void_p, + ctypes.c_void_p) +PyCFunction_NewEx.restype = ctypes.py_object + +cache = {} # Unsure if this is necessary to keep the PyMethodDef + # structures from being garbage collected. Assuming so... + +def pyaddfunc (func_name, func_ptr, func_doc = None): + global cache + if bytes != str: + func_name = bytes(ord(ch) for ch in func_name) + key = (func_name, func_ptr) + if key in cache: + _, ret_val = cache[key] + else: + mdef = PyMethodDef(bytes(func_name), + func_ptr, + 1, # == METH_VARARGS (hopefully remains so...) + func_doc) + ret_val = PyCFunction_NewEx(ctypes.byref(mdef), 0, 0) + cache[key] = (mdef, ret_val) + return ret_val + +# ______________________________________________________________________ +# End of pyaddfunc.py diff --git a/llpython/tests/__init__.py b/llpython/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/llpython/tests/llfuncs.py b/llpython/tests/llfuncs.py new file mode 100644 index 0000000..8b5b1f3 --- /dev/null +++ b/llpython/tests/llfuncs.py @@ -0,0 +1,41 @@ +# ______________________________________________________________________ + +def doslice (in_string, lower, upper): + l = strlen(in_string) + if lower < lc_size_t(0): + lower += l + if upper < lc_size_t(0): + upper += l + temp_len = upper - lower + if temp_len < lc_size_t(0): + temp_len = lc_size_t(0) + ret_val = alloca_array(li8, temp_len + lc_size_t(1)) + strncpy(ret_val, in_string + lower, temp_len) + ret_val[temp_len] = li8(0) + return ret_val + +def ipow (val, exp): + ret_val = 1 + temp = val + w = exp + while w > 0: + if (w & 1) != 0: + ret_val *= temp + # TODO: Overflow check on ret_val + w >>= 1 + if w == 0: break + temp *= temp + # TODO: Overflow check on temp + return ret_val + +def pymod (arg1, arg2): + ret_val = arg1 % arg2 + if ret_val < 0: + if arg2 > 0: + ret_val += arg2 + elif arg2 < 0: + ret_val += arg2 + return ret_val + +# ______________________________________________________________________ +# End of llfuncs.py diff --git a/llpython/tests/llfunctys.py b/llpython/tests/llfunctys.py new file mode 100644 index 0000000..8335044 --- /dev/null +++ b/llpython/tests/llfunctys.py @@ -0,0 +1,19 @@ +# ______________________________________________________________________ + +import llvm.core as lc + +from llpython import bytetype + +# ______________________________________________________________________ + +doslice = lc.Type.function(bytetype.li8_ptr, ( + bytetype.li8_ptr, bytetype.lc_size_t, bytetype.lc_size_t)) + +ipow = lc.Type.function(bytetype.li32, (bytetype.li32, + bytetype.li32)) + +pymod = lc.Type.function(bytetype.li32, (bytetype.li32, + bytetype.li32)) + +# ______________________________________________________________________ +# End of llfunctys.py 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 new file mode 100644 index 0000000..3f756ee --- /dev/null +++ b/llvm-config-win32.py @@ -0,0 +1,88 @@ +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 + + +def find_llvm_tblgen(): + path = find_executable('llvm-tblgen') + if path is None: + sys.exit('Error: could not locate llvm-tblgen') + return path + + +def find_llvm_prefix(): + return abspath(dirname(dirname(find_llvm_tblgen()))) + + +def ensure_file(path): + if not isfile(path): + sys.exit('Error: no file: %r' % path) + + +def get_llvm_version(): + args = [find_llvm_tblgen(), '--version'] + p = Popen(args, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + if stderr: + sys.exit("Error: %r stderr is:\n%s" % (args, stderr.decode())) + out = stdout.decode().strip() + pat = re.compile(r'llvm\s+version\s+(\d+\.\d+\S*)', re.I) + m = pat.search(out) + if m is None: + sys.exit('Error: could not parse version in:' + out) + return m.group(1) + + +def libs_options(): + # NOTE: instead of actually looking at the components requested, + # we just print out a bunch of libs + for lib in """ +Advapi32 +Shell32 +""".split(): + print('-l%s' % lib) + + 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: + option = sys.argv[1] + except IndexError: + sys.exit('Error: option missing') + + 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' , 'Linker.h')) + print(incdir) + + elif option == '--libdir': + libdir = join(find_llvm_prefix(), 'lib') + ensure_file(join(libdir, 'LLVMCore.lib')) + print(libdir) + + elif option in ('--ldflags', '--components'): + pass + + else: + sys.exit('Error: Unrecognized llvm-config option %r' % option) + + +if __name__ == '__main__': + main() diff --git a/llvm/2.9_update.diff b/llvm/2.9_update.diff deleted file mode 100644 index 5572286..0000000 --- a/llvm/2.9_update.diff +++ /dev/null @@ -1,2117 +0,0 @@ -Index: core.py -=================================================================== ---- core.py (revision 105) -+++ core.py (working copy) -@@ -51,14 +51,15 @@ - TYPE_FP128 = 4 - TYPE_PPC_FP128 = 5 - TYPE_LABEL = 6 --TYPE_INTEGER = 7 --TYPE_FUNCTION = 8 --TYPE_STRUCT = 9 --TYPE_ARRAY = 10 --TYPE_POINTER = 11 --TYPE_OPAQUE = 12 --TYPE_VECTOR = 13 --TYPE_METADATA = 14 -+TYPE_METADATA = 7 -+TYPE_X86_MMX = 8 -+TYPE_INTEGER = 9 -+TYPE_FUNCTION = 10 -+TYPE_STRUCT = 11 -+TYPE_ARRAY = 12 -+TYPE_POINTER = 13 -+TYPE_OPAQUE = 14 -+TYPE_VECTOR = 15 - - # value IDs (llvm::Value::ValueTy enum) - VALUE_ARGUMENT = 0 -@@ -140,11 +141,21 @@ - OPCODE_INSERTVALUE = 54 - - # calling conventions --CC_C = 0 --CC_FASTCALL = 8 --CC_COLDCALL = 9 --CC_X86_STDCALL = 64 --CC_X86_FASTCALL = 65 -+CC_C = 0 -+CC_FASTCALL = 8 -+CC_COLDCALL = 9 -+CC_GHC = 10 -+CC_X86_STDCALL = 64 -+CC_X86_FASTCALL = 65 -+CC_ARM_APCS = 66 -+CC_ARM_AAPCS = 67 -+CC_ARM_AAPCS_VFP = 68 -+CC_MSP430_INTR = 69 -+CC_X86_THISCALL = 70 -+CC_PTX_KERNEL = 71 -+CC_PTX_DEVICE = 72 -+CC_MBLAZE_INTR = 73 -+CC_MBLAZE_SVOL = 74 - - # int predicates - ICMP_EQ = 32 -@@ -248,11 +259,14 @@ - ATTR_OPTIMIZE_FOR_SIZE = 1<<13 - ATTR_STACK_PROTECT = 1<<14 - ATTR_STACK_PROTECT_REQ = 1<<15 -+ATTR_ALIGNMENT = 1<<16 - ATTR_NO_CAPTURE = 1<<21 - ATTR_NO_REDZONE = 1<<22 - ATTR_NO_IMPLICIT_FLOAT = 1<<23 - ATTR_NAKED = 1<<24 - ATTR_INLINE_HINT = 1<<25 -+ATTR_STACK_ALIGNMENT = 7<<26 -+ATTR_HOTPATCH = 1<<29 - - # intrinsic IDs - from llvm._intrinsic_ids import * -Index: extra.cpp -=================================================================== ---- extra.cpp (revision 105) -+++ extra.cpp (working copy) -@@ -54,7 +54,7 @@ - #include "llvm/IntrinsicInst.h" - #include "llvm/Analysis/Verifier.h" - #include "llvm/Assembly/Parser.h" --#include "llvm/System/DynamicLibrary.h" -+#include "llvm/Support/DynamicLibrary.h" - #include "llvm/PassManager.h" - #include "llvm/ExecutionEngine/ExecutionEngine.h" - #include "llvm/Analysis/LoopPass.h" -@@ -452,12 +452,19 @@ - return eep->getPointerToFunction(fnp); - } - -+ - int LLVMInlineFunction(LLVMValueRef call) - { - llvm::Value *callp = llvm::unwrap(call); - assert(callp); - -- llvm::CallSite cs = llvm::CallSite::get(callp); -+// llvm::CallSite cs = llvm::CallSite::get(callp); -+ llvm::CallSite cs; -+ llvm::Instruction *II = llvm::dyn_cast(callp); -+ if (II->getOpcode() == llvm::Instruction::Call) -+ cs = llvm::CallSite(static_cast(II)); -+ else if (II->getOpcode() == llvm::Instruction::Invoke) -+ cs = llvm::CallSite(static_cast(II)); - - llvm::InlineFunctionInfo unused; - return llvm::InlineFunction(cs, unused); -@@ -501,13 +508,13 @@ - define_pass( DomPrinter ) - define_pass( DomViewer ) - define_pass( EdgeProfiler ) --define_pass( GEPSplitter ) -+//define_pass( GEPSplitter ) - define_pass( GlobalsModRef ) - define_pass( InstCount ) - define_pass( InstructionNamer ) - define_pass( LazyValueInfo ) - define_pass( LCSSA ) --define_pass( LiveValues ) -+//define_pass( LiveValues ) - define_pass( LoopDependenceAnalysis ) - define_pass( LoopExtractor ) - define_pass( LoopSimplify ) -@@ -519,7 +526,7 @@ - define_pass( NoProfileInfo ) - define_pass( OptimalEdgeProfiler ) - define_pass( PartialInlining ) --define_pass( PartialSpecialization ) -+//define_pass( PartialSpecialization ) - define_pass( PostDomOnlyPrinter ) - define_pass( PostDomOnlyViewer ) - define_pass( PostDomPrinter ) -@@ -528,7 +535,7 @@ - define_pass( ProfileLoader ) - define_pass( ProfileVerifier ) - define_pass( ScalarEvolutionAliasAnalysis ) --define_pass( SimplifyHalfPowrLibCalls ) -+//define_pass( SimplifyHalfPowrLibCalls ) - define_pass( SingleLoopExtractor ) - define_pass( StripNonDebugSymbols ) - define_pass( StructRetPromotion ) -Index: passes.py -=================================================================== ---- passes.py (revision 105) -+++ passes.py (working copy) -@@ -68,7 +68,7 @@ - PASS_EDGE_PROFILER = 25 - PASS_FUNCTION_ATTRS = 26 - PASS_FUNCTION_INLINING = 27 --PASS_GEP_SPLITTER = 28 -+#PASS_GEP_SPLITTER = 28 - PASS_GLOBAL_DCE = 29 - PASS_GLOBAL_OPTIMIZER = 30 - PASS_GLOBALS_MOD_REF = 31 -@@ -83,11 +83,11 @@ - PASS_LAZY_VALUE_INFO = 40 - PASS_LCSSA = 41 - PASS_LICM = 42 --PASS_LIVE_VALUES = 43 -+#PASS_LIVE_VALUES = 43 - PASS_LOOP_DELETION = 44 - PASS_LOOP_DEPENDENCE_ANALYSIS = 45 - PASS_LOOP_EXTRACTOR = 46 --PASS_LOOP_INDEX_SPLIT = 47 -+#PASS_LOOP_INDEX_SPLIT = 47 - PASS_LOOP_ROTATE = 48 - PASS_LOOP_SIMPLIFY = 49 - PASS_LOOP_STRENGTH_REDUCE = 50 -@@ -102,11 +102,11 @@ - PASS_NO_PROFILE_INFO = 59 - PASS_OPTIMAL_EDGE_PROFILER = 60 - PASS_PARTIAL_INLINING = 61 --PASS_PARTIAL_SPECIALIZATION = 62 --PASS_POST_DOM_ONLY_PRINTER = 63 --PASS_POST_DOM_ONLY_VIEWER = 64 --PASS_POST_DOM_PRINTER = 65 --PASS_POST_DOM_VIEWER = 66 -+#PASS_PARTIAL_SPECIALIZATION = 62 -+#PASS_POST_DOM_ONLY_PRINTER = 63 -+#PASS_POST_DOM_ONLY_VIEWER = 64 -+#PASS_POST_DOM_PRINTER = 65 -+#PASS_POST_DOM_VIEWER = 66 - PASS_PROFILE_ESTIMATOR = 67 - PASS_PROFILE_LOADER = 68 - PASS_PROFILE_VERIFIER = 69 -@@ -116,7 +116,7 @@ - PASS_SCALAR_EVOLUTION_ALIAS_ANALYSIS = 73 - PASS_SCALAR_REPL_AGGREGATES = 74 - PASS_SCCP = 76 --PASS_SIMPLIFY_HALF_POWR_LIB_CALLS = 77 -+#PASS_SIMPLIFY_HALF_POWR_LIB_CALLS = 77 - PASS_SIMPLIFY_LIB_CALLS = 78 - PASS_SINGLE_LOOP_EXTRACTOR = 79 - PASS_STRIP_DEAD_PROTOTYPES = 82 -@@ -161,7 +161,7 @@ - PASS_EDGE_PROFILER : _core.LLVMAddEdgeProfilerPass, - PASS_FUNCTION_ATTRS : _core.LLVMAddFunctionAttrsPass, - PASS_FUNCTION_INLINING : _core.LLVMAddFunctionInliningPass, -- PASS_GEP_SPLITTER : _core.LLVMAddGEPSplitterPass, -+ #PASS_GEP_SPLITTER : _core.LLVMAddGEPSplitterPass, - PASS_GLOBAL_DCE : _core.LLVMAddGlobalDCEPass, - PASS_GLOBAL_OPTIMIZER : _core.LLVMAddGlobalOptimizerPass, - PASS_GLOBALS_MOD_REF : _core.LLVMAddGlobalsModRefPass, -@@ -176,11 +176,11 @@ - PASS_LAZY_VALUE_INFO : _core.LLVMAddLazyValueInfoPass, - PASS_LCSSA : _core.LLVMAddLCSSAPass, - PASS_LICM : _core.LLVMAddLICMPass, -- PASS_LIVE_VALUES : _core.LLVMAddLiveValuesPass, -+ #PASS_LIVE_VALUES : _core.LLVMAddLiveValuesPass, - PASS_LOOP_DELETION : _core.LLVMAddLoopDeletionPass, - PASS_LOOP_DEPENDENCE_ANALYSIS : _core.LLVMAddLoopDependenceAnalysisPass, - PASS_LOOP_EXTRACTOR : _core.LLVMAddLoopExtractorPass, -- PASS_LOOP_INDEX_SPLIT : _core.LLVMAddLoopIndexSplitPass, -+ #PASS_LOOP_INDEX_SPLIT : _core.LLVMAddLoopIndexSplitPass, - PASS_LOOP_ROTATE : _core.LLVMAddLoopRotatePass, - PASS_LOOP_SIMPLIFY : _core.LLVMAddLoopSimplifyPass, - PASS_LOOP_STRENGTH_REDUCE : _core.LLVMAddLoopStrengthReducePass, -@@ -195,11 +195,11 @@ - PASS_NO_PROFILE_INFO : _core.LLVMAddNoProfileInfoPass, - PASS_OPTIMAL_EDGE_PROFILER : _core.LLVMAddOptimalEdgeProfilerPass, - PASS_PARTIAL_INLINING : _core.LLVMAddPartialInliningPass, -- PASS_PARTIAL_SPECIALIZATION : _core.LLVMAddPartialSpecializationPass, -- PASS_POST_DOM_ONLY_PRINTER : _core.LLVMAddPostDomOnlyPrinterPass, -- PASS_POST_DOM_ONLY_VIEWER : _core.LLVMAddPostDomOnlyViewerPass, -- PASS_POST_DOM_PRINTER : _core.LLVMAddPostDomPrinterPass, -- PASS_POST_DOM_VIEWER : _core.LLVMAddPostDomViewerPass, -+ #PASS_PARTIAL_SPECIALIZATION : _core.LLVMAddPartialSpecializationPass, -+ #PASS_POST_DOM_ONLY_PRINTER : _core.LLVMAddPostDomOnlyPrinterPass, -+ #PASS_POST_DOM_ONLY_VIEWER : _core.LLVMAddPostDomOnlyViewerPass, -+ #PASS_POST_DOM_PRINTER : _core.LLVMAddPostDomPrinterPass, -+ #PASS_POST_DOM_VIEWER : _core.LLVMAddPostDomViewerPass, - PASS_PROFILE_ESTIMATOR : _core.LLVMAddProfileEstimatorPass, - PASS_PROFILE_LOADER : _core.LLVMAddProfileLoaderPass, - PASS_PROFILE_VERIFIER : _core.LLVMAddProfileVerifierPass, -@@ -209,7 +209,7 @@ - PASS_SCALAR_EVOLUTION_ALIAS_ANALYSIS : _core.LLVMAddScalarEvolutionAliasAnalysisPass, - PASS_SCALAR_REPL_AGGREGATES : _core.LLVMAddScalarReplAggregatesPass, - PASS_SCCP : _core.LLVMAddSCCPPass, -- PASS_SIMPLIFY_HALF_POWR_LIB_CALLS : _core.LLVMAddSimplifyHalfPowrLibCallsPass, -+ #PASS_SIMPLIFY_HALF_POWR_LIB_CALLS : _core.LLVMAddSimplifyHalfPowrLibCallsPass, - PASS_SIMPLIFY_LIB_CALLS : _core.LLVMAddSimplifyLibCallsPass, - PASS_SINGLE_LOOP_EXTRACTOR : _core.LLVMAddSingleLoopExtractorPass, - PASS_STRIP_DEAD_PROTOTYPES : _core.LLVMAddStripDeadPrototypesPass, -Index: _intrinsic_ids.py -=================================================================== ---- _intrinsic_ids.py (revision 105) -+++ _intrinsic_ids.py (working copy) -@@ -49,854 +49,879 @@ - INTR_ARM_NEON_VCNT = 14 - INTR_ARM_NEON_VCVTFP2FXS = 15 - INTR_ARM_NEON_VCVTFP2FXU = 16 --INTR_ARM_NEON_VCVTFXS2FP = 17 --INTR_ARM_NEON_VCVTFXU2FP = 18 --INTR_ARM_NEON_VHADDS = 19 --INTR_ARM_NEON_VHADDU = 20 --INTR_ARM_NEON_VHSUBS = 21 --INTR_ARM_NEON_VHSUBU = 22 --INTR_ARM_NEON_VLD1 = 23 --INTR_ARM_NEON_VLD2 = 24 --INTR_ARM_NEON_VLD2LANE = 25 --INTR_ARM_NEON_VLD3 = 26 --INTR_ARM_NEON_VLD3LANE = 27 --INTR_ARM_NEON_VLD4 = 28 --INTR_ARM_NEON_VLD4LANE = 29 --INTR_ARM_NEON_VMAXS = 30 --INTR_ARM_NEON_VMAXU = 31 --INTR_ARM_NEON_VMINS = 32 --INTR_ARM_NEON_VMINU = 33 --INTR_ARM_NEON_VMULLP = 34 --INTR_ARM_NEON_VMULP = 35 --INTR_ARM_NEON_VPADALS = 36 --INTR_ARM_NEON_VPADALU = 37 --INTR_ARM_NEON_VPADD = 38 --INTR_ARM_NEON_VPADDLS = 39 --INTR_ARM_NEON_VPADDLU = 40 --INTR_ARM_NEON_VPMAXS = 41 --INTR_ARM_NEON_VPMAXU = 42 --INTR_ARM_NEON_VPMINS = 43 --INTR_ARM_NEON_VPMINU = 44 --INTR_ARM_NEON_VQABS = 45 --INTR_ARM_NEON_VQADDS = 46 --INTR_ARM_NEON_VQADDU = 47 --INTR_ARM_NEON_VQDMLAL = 48 --INTR_ARM_NEON_VQDMLSL = 49 --INTR_ARM_NEON_VQDMULH = 50 --INTR_ARM_NEON_VQDMULL = 51 --INTR_ARM_NEON_VQMOVNS = 52 --INTR_ARM_NEON_VQMOVNSU = 53 --INTR_ARM_NEON_VQMOVNU = 54 --INTR_ARM_NEON_VQNEG = 55 --INTR_ARM_NEON_VQRDMULH = 56 --INTR_ARM_NEON_VQRSHIFTNS = 57 --INTR_ARM_NEON_VQRSHIFTNSU = 58 --INTR_ARM_NEON_VQRSHIFTNU = 59 --INTR_ARM_NEON_VQRSHIFTS = 60 --INTR_ARM_NEON_VQRSHIFTU = 61 --INTR_ARM_NEON_VQSHIFTNS = 62 --INTR_ARM_NEON_VQSHIFTNSU = 63 --INTR_ARM_NEON_VQSHIFTNU = 64 --INTR_ARM_NEON_VQSHIFTS = 65 --INTR_ARM_NEON_VQSHIFTSU = 66 --INTR_ARM_NEON_VQSHIFTU = 67 --INTR_ARM_NEON_VQSUBS = 68 --INTR_ARM_NEON_VQSUBU = 69 --INTR_ARM_NEON_VRADDHN = 70 --INTR_ARM_NEON_VRECPE = 71 --INTR_ARM_NEON_VRECPS = 72 --INTR_ARM_NEON_VRHADDS = 73 --INTR_ARM_NEON_VRHADDU = 74 --INTR_ARM_NEON_VRSHIFTN = 75 --INTR_ARM_NEON_VRSHIFTS = 76 --INTR_ARM_NEON_VRSHIFTU = 77 --INTR_ARM_NEON_VRSQRTE = 78 --INTR_ARM_NEON_VRSQRTS = 79 --INTR_ARM_NEON_VRSUBHN = 80 --INTR_ARM_NEON_VSHIFTINS = 81 --INTR_ARM_NEON_VSHIFTLS = 82 --INTR_ARM_NEON_VSHIFTLU = 83 --INTR_ARM_NEON_VSHIFTN = 84 --INTR_ARM_NEON_VSHIFTS = 85 --INTR_ARM_NEON_VSHIFTU = 86 --INTR_ARM_NEON_VST1 = 87 --INTR_ARM_NEON_VST2 = 88 --INTR_ARM_NEON_VST2LANE = 89 --INTR_ARM_NEON_VST3 = 90 --INTR_ARM_NEON_VST3LANE = 91 --INTR_ARM_NEON_VST4 = 92 --INTR_ARM_NEON_VST4LANE = 93 --INTR_ARM_NEON_VSUBHN = 94 --INTR_ARM_NEON_VTBL1 = 95 --INTR_ARM_NEON_VTBL2 = 96 --INTR_ARM_NEON_VTBL3 = 97 --INTR_ARM_NEON_VTBL4 = 98 --INTR_ARM_NEON_VTBX1 = 99 --INTR_ARM_NEON_VTBX2 = 100 --INTR_ARM_NEON_VTBX3 = 101 --INTR_ARM_NEON_VTBX4 = 102 --INTR_ARM_QADD = 103 --INTR_ARM_QSUB = 104 --INTR_ARM_SET_FPSCR = 105 --INTR_ARM_SSAT = 106 --INTR_ARM_THREAD_POINTER = 107 --INTR_ARM_USAT = 108 --INTR_ARM_VCVTR = 109 --INTR_ARM_VCVTRU = 110 --INTR_ATOMIC_CMP_SWAP = 111 --INTR_ATOMIC_LOAD_ADD = 112 --INTR_ATOMIC_LOAD_AND = 113 --INTR_ATOMIC_LOAD_MAX = 114 --INTR_ATOMIC_LOAD_MIN = 115 --INTR_ATOMIC_LOAD_NAND = 116 --INTR_ATOMIC_LOAD_OR = 117 --INTR_ATOMIC_LOAD_SUB = 118 --INTR_ATOMIC_LOAD_UMAX = 119 --INTR_ATOMIC_LOAD_UMIN = 120 --INTR_ATOMIC_LOAD_XOR = 121 --INTR_ATOMIC_SWAP = 122 --INTR_BSWAP = 123 --INTR_CONVERT_FROM_FP16 = 124 --INTR_CONVERT_TO_FP16 = 125 --INTR_CONVERTFF = 126 --INTR_CONVERTFSI = 127 --INTR_CONVERTFUI = 128 --INTR_CONVERTSIF = 129 --INTR_CONVERTSS = 130 --INTR_CONVERTSU = 131 --INTR_CONVERTUIF = 132 --INTR_CONVERTUS = 133 --INTR_CONVERTUU = 134 --INTR_COS = 135 --INTR_CTLZ = 136 --INTR_CTPOP = 137 --INTR_CTTZ = 138 --INTR_DBG_DECLARE = 139 --INTR_DBG_VALUE = 140 --INTR_EH_DWARF_CFA = 141 --INTR_EH_EXCEPTION = 142 --INTR_EH_RETURN_I32 = 143 --INTR_EH_RETURN_I64 = 144 --INTR_EH_SELECTOR = 145 --INTR_EH_SJLJ_CALLSITE = 146 --INTR_EH_SJLJ_LONGJMP = 147 --INTR_EH_SJLJ_LSDA = 148 --INTR_EH_SJLJ_SETJMP = 149 --INTR_EH_TYPEID_FOR = 150 --INTR_EH_UNWIND_INIT = 151 --INTR_EXP = 152 --INTR_EXP2 = 153 --INTR_FLT_ROUNDS = 154 --INTR_FRAMEADDRESS = 155 --INTR_GCREAD = 156 --INTR_GCROOT = 157 --INTR_GCWRITE = 158 --INTR_INIT_TRAMPOLINE = 159 --INTR_INVARIANT_END = 160 --INTR_INVARIANT_START = 161 --INTR_LIFETIME_END = 162 --INTR_LIFETIME_START = 163 --INTR_LOG = 164 --INTR_LOG10 = 165 --INTR_LOG2 = 166 --INTR_LONGJMP = 167 --INTR_MEMCPY = 168 --INTR_MEMMOVE = 169 --INTR_MEMORY_BARRIER = 170 --INTR_MEMSET = 171 --INTR_OBJECTSIZE = 172 --INTR_PCMARKER = 173 --INTR_POW = 174 --INTR_POWI = 175 --INTR_PPC_ALTIVEC_DSS = 176 --INTR_PPC_ALTIVEC_DSSALL = 177 --INTR_PPC_ALTIVEC_DST = 178 --INTR_PPC_ALTIVEC_DSTST = 179 --INTR_PPC_ALTIVEC_DSTSTT = 180 --INTR_PPC_ALTIVEC_DSTT = 181 --INTR_PPC_ALTIVEC_LVEBX = 182 --INTR_PPC_ALTIVEC_LVEHX = 183 --INTR_PPC_ALTIVEC_LVEWX = 184 --INTR_PPC_ALTIVEC_LVSL = 185 --INTR_PPC_ALTIVEC_LVSR = 186 --INTR_PPC_ALTIVEC_LVX = 187 --INTR_PPC_ALTIVEC_LVXL = 188 --INTR_PPC_ALTIVEC_MFVSCR = 189 --INTR_PPC_ALTIVEC_MTVSCR = 190 --INTR_PPC_ALTIVEC_STVEBX = 191 --INTR_PPC_ALTIVEC_STVEHX = 192 --INTR_PPC_ALTIVEC_STVEWX = 193 --INTR_PPC_ALTIVEC_STVX = 194 --INTR_PPC_ALTIVEC_STVXL = 195 --INTR_PPC_ALTIVEC_VADDCUW = 196 --INTR_PPC_ALTIVEC_VADDSBS = 197 --INTR_PPC_ALTIVEC_VADDSHS = 198 --INTR_PPC_ALTIVEC_VADDSWS = 199 --INTR_PPC_ALTIVEC_VADDUBS = 200 --INTR_PPC_ALTIVEC_VADDUHS = 201 --INTR_PPC_ALTIVEC_VADDUWS = 202 --INTR_PPC_ALTIVEC_VAVGSB = 203 --INTR_PPC_ALTIVEC_VAVGSH = 204 --INTR_PPC_ALTIVEC_VAVGSW = 205 --INTR_PPC_ALTIVEC_VAVGUB = 206 --INTR_PPC_ALTIVEC_VAVGUH = 207 --INTR_PPC_ALTIVEC_VAVGUW = 208 --INTR_PPC_ALTIVEC_VCFSX = 209 --INTR_PPC_ALTIVEC_VCFUX = 210 --INTR_PPC_ALTIVEC_VCMPBFP = 211 --INTR_PPC_ALTIVEC_VCMPBFP_P = 212 --INTR_PPC_ALTIVEC_VCMPEQFP = 213 --INTR_PPC_ALTIVEC_VCMPEQFP_P = 214 --INTR_PPC_ALTIVEC_VCMPEQUB = 215 --INTR_PPC_ALTIVEC_VCMPEQUB_P = 216 --INTR_PPC_ALTIVEC_VCMPEQUH = 217 --INTR_PPC_ALTIVEC_VCMPEQUH_P = 218 --INTR_PPC_ALTIVEC_VCMPEQUW = 219 --INTR_PPC_ALTIVEC_VCMPEQUW_P = 220 --INTR_PPC_ALTIVEC_VCMPGEFP = 221 --INTR_PPC_ALTIVEC_VCMPGEFP_P = 222 --INTR_PPC_ALTIVEC_VCMPGTFP = 223 --INTR_PPC_ALTIVEC_VCMPGTFP_P = 224 --INTR_PPC_ALTIVEC_VCMPGTSB = 225 --INTR_PPC_ALTIVEC_VCMPGTSB_P = 226 --INTR_PPC_ALTIVEC_VCMPGTSH = 227 --INTR_PPC_ALTIVEC_VCMPGTSH_P = 228 --INTR_PPC_ALTIVEC_VCMPGTSW = 229 --INTR_PPC_ALTIVEC_VCMPGTSW_P = 230 --INTR_PPC_ALTIVEC_VCMPGTUB = 231 --INTR_PPC_ALTIVEC_VCMPGTUB_P = 232 --INTR_PPC_ALTIVEC_VCMPGTUH = 233 --INTR_PPC_ALTIVEC_VCMPGTUH_P = 234 --INTR_PPC_ALTIVEC_VCMPGTUW = 235 --INTR_PPC_ALTIVEC_VCMPGTUW_P = 236 --INTR_PPC_ALTIVEC_VCTSXS = 237 --INTR_PPC_ALTIVEC_VCTUXS = 238 --INTR_PPC_ALTIVEC_VEXPTEFP = 239 --INTR_PPC_ALTIVEC_VLOGEFP = 240 --INTR_PPC_ALTIVEC_VMADDFP = 241 --INTR_PPC_ALTIVEC_VMAXFP = 242 --INTR_PPC_ALTIVEC_VMAXSB = 243 --INTR_PPC_ALTIVEC_VMAXSH = 244 --INTR_PPC_ALTIVEC_VMAXSW = 245 --INTR_PPC_ALTIVEC_VMAXUB = 246 --INTR_PPC_ALTIVEC_VMAXUH = 247 --INTR_PPC_ALTIVEC_VMAXUW = 248 --INTR_PPC_ALTIVEC_VMHADDSHS = 249 --INTR_PPC_ALTIVEC_VMHRADDSHS = 250 --INTR_PPC_ALTIVEC_VMINFP = 251 --INTR_PPC_ALTIVEC_VMINSB = 252 --INTR_PPC_ALTIVEC_VMINSH = 253 --INTR_PPC_ALTIVEC_VMINSW = 254 --INTR_PPC_ALTIVEC_VMINUB = 255 --INTR_PPC_ALTIVEC_VMINUH = 256 --INTR_PPC_ALTIVEC_VMINUW = 257 --INTR_PPC_ALTIVEC_VMLADDUHM = 258 --INTR_PPC_ALTIVEC_VMSUMMBM = 259 --INTR_PPC_ALTIVEC_VMSUMSHM = 260 --INTR_PPC_ALTIVEC_VMSUMSHS = 261 --INTR_PPC_ALTIVEC_VMSUMUBM = 262 --INTR_PPC_ALTIVEC_VMSUMUHM = 263 --INTR_PPC_ALTIVEC_VMSUMUHS = 264 --INTR_PPC_ALTIVEC_VMULESB = 265 --INTR_PPC_ALTIVEC_VMULESH = 266 --INTR_PPC_ALTIVEC_VMULEUB = 267 --INTR_PPC_ALTIVEC_VMULEUH = 268 --INTR_PPC_ALTIVEC_VMULOSB = 269 --INTR_PPC_ALTIVEC_VMULOSH = 270 --INTR_PPC_ALTIVEC_VMULOUB = 271 --INTR_PPC_ALTIVEC_VMULOUH = 272 --INTR_PPC_ALTIVEC_VNMSUBFP = 273 --INTR_PPC_ALTIVEC_VPERM = 274 --INTR_PPC_ALTIVEC_VPKPX = 275 --INTR_PPC_ALTIVEC_VPKSHSS = 276 --INTR_PPC_ALTIVEC_VPKSHUS = 277 --INTR_PPC_ALTIVEC_VPKSWSS = 278 --INTR_PPC_ALTIVEC_VPKSWUS = 279 --INTR_PPC_ALTIVEC_VPKUHUS = 280 --INTR_PPC_ALTIVEC_VPKUWUS = 281 --INTR_PPC_ALTIVEC_VREFP = 282 --INTR_PPC_ALTIVEC_VRFIM = 283 --INTR_PPC_ALTIVEC_VRFIN = 284 --INTR_PPC_ALTIVEC_VRFIP = 285 --INTR_PPC_ALTIVEC_VRFIZ = 286 --INTR_PPC_ALTIVEC_VRLB = 287 --INTR_PPC_ALTIVEC_VRLH = 288 --INTR_PPC_ALTIVEC_VRLW = 289 --INTR_PPC_ALTIVEC_VRSQRTEFP = 290 --INTR_PPC_ALTIVEC_VSEL = 291 --INTR_PPC_ALTIVEC_VSL = 292 --INTR_PPC_ALTIVEC_VSLB = 293 --INTR_PPC_ALTIVEC_VSLH = 294 --INTR_PPC_ALTIVEC_VSLO = 295 --INTR_PPC_ALTIVEC_VSLW = 296 --INTR_PPC_ALTIVEC_VSR = 297 --INTR_PPC_ALTIVEC_VSRAB = 298 --INTR_PPC_ALTIVEC_VSRAH = 299 --INTR_PPC_ALTIVEC_VSRAW = 300 --INTR_PPC_ALTIVEC_VSRB = 301 --INTR_PPC_ALTIVEC_VSRH = 302 --INTR_PPC_ALTIVEC_VSRO = 303 --INTR_PPC_ALTIVEC_VSRW = 304 --INTR_PPC_ALTIVEC_VSUBCUW = 305 --INTR_PPC_ALTIVEC_VSUBSBS = 306 --INTR_PPC_ALTIVEC_VSUBSHS = 307 --INTR_PPC_ALTIVEC_VSUBSWS = 308 --INTR_PPC_ALTIVEC_VSUBUBS = 309 --INTR_PPC_ALTIVEC_VSUBUHS = 310 --INTR_PPC_ALTIVEC_VSUBUWS = 311 --INTR_PPC_ALTIVEC_VSUM2SWS = 312 --INTR_PPC_ALTIVEC_VSUM4SBS = 313 --INTR_PPC_ALTIVEC_VSUM4SHS = 314 --INTR_PPC_ALTIVEC_VSUM4UBS = 315 --INTR_PPC_ALTIVEC_VSUMSWS = 316 --INTR_PPC_ALTIVEC_VUPKHPX = 317 --INTR_PPC_ALTIVEC_VUPKHSB = 318 --INTR_PPC_ALTIVEC_VUPKHSH = 319 --INTR_PPC_ALTIVEC_VUPKLPX = 320 --INTR_PPC_ALTIVEC_VUPKLSB = 321 --INTR_PPC_ALTIVEC_VUPKLSH = 322 --INTR_PPC_DCBA = 323 --INTR_PPC_DCBF = 324 --INTR_PPC_DCBI = 325 --INTR_PPC_DCBST = 326 --INTR_PPC_DCBT = 327 --INTR_PPC_DCBTST = 328 --INTR_PPC_DCBZ = 329 --INTR_PPC_DCBZL = 330 --INTR_PPC_SYNC = 331 --INTR_PREFETCH = 332 --INTR_PTR_ANNOTATION = 333 --INTR_READCYCLECOUNTER = 334 --INTR_RETURNADDRESS = 335 --INTR_SADD_WITH_OVERFLOW = 336 --INTR_SETJMP = 337 --INTR_SIGLONGJMP = 338 --INTR_SIGSETJMP = 339 --INTR_SIN = 340 --INTR_SMUL_WITH_OVERFLOW = 341 --INTR_SPU_SI_A = 342 --INTR_SPU_SI_ADDX = 343 --INTR_SPU_SI_AH = 344 --INTR_SPU_SI_AHI = 345 --INTR_SPU_SI_AI = 346 --INTR_SPU_SI_AND = 347 --INTR_SPU_SI_ANDBI = 348 --INTR_SPU_SI_ANDC = 349 --INTR_SPU_SI_ANDHI = 350 --INTR_SPU_SI_ANDI = 351 --INTR_SPU_SI_BG = 352 --INTR_SPU_SI_BGX = 353 --INTR_SPU_SI_CEQ = 354 --INTR_SPU_SI_CEQB = 355 --INTR_SPU_SI_CEQBI = 356 --INTR_SPU_SI_CEQH = 357 --INTR_SPU_SI_CEQHI = 358 --INTR_SPU_SI_CEQI = 359 --INTR_SPU_SI_CG = 360 --INTR_SPU_SI_CGT = 361 --INTR_SPU_SI_CGTB = 362 --INTR_SPU_SI_CGTBI = 363 --INTR_SPU_SI_CGTH = 364 --INTR_SPU_SI_CGTHI = 365 --INTR_SPU_SI_CGTI = 366 --INTR_SPU_SI_CGX = 367 --INTR_SPU_SI_CLGT = 368 --INTR_SPU_SI_CLGTB = 369 --INTR_SPU_SI_CLGTBI = 370 --INTR_SPU_SI_CLGTH = 371 --INTR_SPU_SI_CLGTHI = 372 --INTR_SPU_SI_CLGTI = 373 --INTR_SPU_SI_DFA = 374 --INTR_SPU_SI_DFM = 375 --INTR_SPU_SI_DFMA = 376 --INTR_SPU_SI_DFMS = 377 --INTR_SPU_SI_DFNMA = 378 --INTR_SPU_SI_DFNMS = 379 --INTR_SPU_SI_DFS = 380 --INTR_SPU_SI_FA = 381 --INTR_SPU_SI_FCEQ = 382 --INTR_SPU_SI_FCGT = 383 --INTR_SPU_SI_FCMEQ = 384 --INTR_SPU_SI_FCMGT = 385 --INTR_SPU_SI_FM = 386 --INTR_SPU_SI_FMA = 387 --INTR_SPU_SI_FMS = 388 --INTR_SPU_SI_FNMS = 389 --INTR_SPU_SI_FS = 390 --INTR_SPU_SI_FSMBI = 391 --INTR_SPU_SI_MPY = 392 --INTR_SPU_SI_MPYA = 393 --INTR_SPU_SI_MPYH = 394 --INTR_SPU_SI_MPYHH = 395 --INTR_SPU_SI_MPYHHA = 396 --INTR_SPU_SI_MPYHHAU = 397 --INTR_SPU_SI_MPYHHU = 398 --INTR_SPU_SI_MPYI = 399 --INTR_SPU_SI_MPYS = 400 --INTR_SPU_SI_MPYU = 401 --INTR_SPU_SI_MPYUI = 402 --INTR_SPU_SI_NAND = 403 --INTR_SPU_SI_NOR = 404 --INTR_SPU_SI_OR = 405 --INTR_SPU_SI_ORBI = 406 --INTR_SPU_SI_ORC = 407 --INTR_SPU_SI_ORHI = 408 --INTR_SPU_SI_ORI = 409 --INTR_SPU_SI_SF = 410 --INTR_SPU_SI_SFH = 411 --INTR_SPU_SI_SFHI = 412 --INTR_SPU_SI_SFI = 413 --INTR_SPU_SI_SFX = 414 --INTR_SPU_SI_SHLI = 415 --INTR_SPU_SI_SHLQBI = 416 --INTR_SPU_SI_SHLQBII = 417 --INTR_SPU_SI_SHLQBY = 418 --INTR_SPU_SI_SHLQBYI = 419 --INTR_SPU_SI_XOR = 420 --INTR_SPU_SI_XORBI = 421 --INTR_SPU_SI_XORHI = 422 --INTR_SPU_SI_XORI = 423 --INTR_SQRT = 424 --INTR_SSUB_WITH_OVERFLOW = 425 --INTR_STACKPROTECTOR = 426 --INTR_STACKRESTORE = 427 --INTR_STACKSAVE = 428 --INTR_TRAP = 429 --INTR_UADD_WITH_OVERFLOW = 430 --INTR_UMUL_WITH_OVERFLOW = 431 --INTR_USUB_WITH_OVERFLOW = 432 --INTR_VACOPY = 433 --INTR_VAEND = 434 --INTR_VAR_ANNOTATION = 435 --INTR_VASTART = 436 --INTR_X86_AESNI_AESDEC = 437 --INTR_X86_AESNI_AESDECLAST = 438 --INTR_X86_AESNI_AESENC = 439 --INTR_X86_AESNI_AESENCLAST = 440 --INTR_X86_AESNI_AESIMC = 441 --INTR_X86_AESNI_AESKEYGENASSIST = 442 --INTR_X86_AVX_ADDSUB_PD_256 = 443 --INTR_X86_AVX_ADDSUB_PS_256 = 444 --INTR_X86_AVX_BLEND_PD_256 = 445 --INTR_X86_AVX_BLEND_PS_256 = 446 --INTR_X86_AVX_BLENDV_PD_256 = 447 --INTR_X86_AVX_BLENDV_PS_256 = 448 --INTR_X86_AVX_CMP_PD_256 = 449 --INTR_X86_AVX_CMP_PS_256 = 450 --INTR_X86_AVX_CVT_PD2_PS_256 = 451 --INTR_X86_AVX_CVT_PD2DQ_256 = 452 --INTR_X86_AVX_CVT_PS2_PD_256 = 453 --INTR_X86_AVX_CVT_PS2DQ_256 = 454 --INTR_X86_AVX_CVTDQ2_PD_256 = 455 --INTR_X86_AVX_CVTDQ2_PS_256 = 456 --INTR_X86_AVX_CVTT_PD2DQ_256 = 457 --INTR_X86_AVX_CVTT_PS2DQ_256 = 458 --INTR_X86_AVX_DP_PS_256 = 459 --INTR_X86_AVX_HADD_PD_256 = 460 --INTR_X86_AVX_HADD_PS_256 = 461 --INTR_X86_AVX_HSUB_PD_256 = 462 --INTR_X86_AVX_HSUB_PS_256 = 463 --INTR_X86_AVX_LDU_DQ_256 = 464 --INTR_X86_AVX_LOADU_DQ_256 = 465 --INTR_X86_AVX_LOADU_PD_256 = 466 --INTR_X86_AVX_LOADU_PS_256 = 467 --INTR_X86_AVX_MASKLOAD_PD = 468 --INTR_X86_AVX_MASKLOAD_PD_256 = 469 --INTR_X86_AVX_MASKLOAD_PS = 470 --INTR_X86_AVX_MASKLOAD_PS_256 = 471 --INTR_X86_AVX_MASKSTORE_PD = 472 --INTR_X86_AVX_MASKSTORE_PD_256 = 473 --INTR_X86_AVX_MASKSTORE_PS = 474 --INTR_X86_AVX_MASKSTORE_PS_256 = 475 --INTR_X86_AVX_MAX_PD_256 = 476 --INTR_X86_AVX_MAX_PS_256 = 477 --INTR_X86_AVX_MIN_PD_256 = 478 --INTR_X86_AVX_MIN_PS_256 = 479 --INTR_X86_AVX_MOVMSK_PD_256 = 480 --INTR_X86_AVX_MOVMSK_PS_256 = 481 --INTR_X86_AVX_MOVNT_DQ_256 = 482 --INTR_X86_AVX_MOVNT_PD_256 = 483 --INTR_X86_AVX_MOVNT_PS_256 = 484 --INTR_X86_AVX_PTESTC_256 = 485 --INTR_X86_AVX_PTESTNZC_256 = 486 --INTR_X86_AVX_PTESTZ_256 = 487 --INTR_X86_AVX_RCP_PS_256 = 488 --INTR_X86_AVX_ROUND_PD_256 = 489 --INTR_X86_AVX_ROUND_PS_256 = 490 --INTR_X86_AVX_RSQRT_PS_256 = 491 --INTR_X86_AVX_SQRT_PD_256 = 492 --INTR_X86_AVX_SQRT_PS_256 = 493 --INTR_X86_AVX_STOREU_DQ_256 = 494 --INTR_X86_AVX_STOREU_PD_256 = 495 --INTR_X86_AVX_STOREU_PS_256 = 496 --INTR_X86_AVX_VBROADCAST_SD_256 = 497 --INTR_X86_AVX_VBROADCASTF128_PD_256 = 498 --INTR_X86_AVX_VBROADCASTF128_PS_256 = 499 --INTR_X86_AVX_VBROADCASTSS = 500 --INTR_X86_AVX_VBROADCASTSS_256 = 501 --INTR_X86_AVX_VEXTRACTF128_PD_256 = 502 --INTR_X86_AVX_VEXTRACTF128_PS_256 = 503 --INTR_X86_AVX_VEXTRACTF128_SI_256 = 504 --INTR_X86_AVX_VINSERTF128_PD_256 = 505 --INTR_X86_AVX_VINSERTF128_PS_256 = 506 --INTR_X86_AVX_VINSERTF128_SI_256 = 507 --INTR_X86_AVX_VPERM2F128_PD_256 = 508 --INTR_X86_AVX_VPERM2F128_PS_256 = 509 --INTR_X86_AVX_VPERM2F128_SI_256 = 510 --INTR_X86_AVX_VPERMIL_PD = 511 --INTR_X86_AVX_VPERMIL_PD_256 = 512 --INTR_X86_AVX_VPERMIL_PS = 513 --INTR_X86_AVX_VPERMIL_PS_256 = 514 --INTR_X86_AVX_VPERMILVAR_PD = 515 --INTR_X86_AVX_VPERMILVAR_PD_256 = 516 --INTR_X86_AVX_VPERMILVAR_PS = 517 --INTR_X86_AVX_VPERMILVAR_PS_256 = 518 --INTR_X86_AVX_VTESTC_PD = 519 --INTR_X86_AVX_VTESTC_PD_256 = 520 --INTR_X86_AVX_VTESTC_PS = 521 --INTR_X86_AVX_VTESTC_PS_256 = 522 --INTR_X86_AVX_VTESTNZC_PD = 523 --INTR_X86_AVX_VTESTNZC_PD_256 = 524 --INTR_X86_AVX_VTESTNZC_PS = 525 --INTR_X86_AVX_VTESTNZC_PS_256 = 526 --INTR_X86_AVX_VTESTZ_PD = 527 --INTR_X86_AVX_VTESTZ_PD_256 = 528 --INTR_X86_AVX_VTESTZ_PS = 529 --INTR_X86_AVX_VTESTZ_PS_256 = 530 --INTR_X86_AVX_VZEROALL = 531 --INTR_X86_AVX_VZEROUPPER = 532 --INTR_X86_INT = 533 --INTR_X86_MMX_CVTSI32_SI64 = 534 --INTR_X86_MMX_CVTSI64_SI32 = 535 --INTR_X86_MMX_EMMS = 536 --INTR_X86_MMX_FEMMS = 537 --INTR_X86_MMX_MASKMOVQ = 538 --INTR_X86_MMX_MOVNT_DQ = 539 --INTR_X86_MMX_PACKSSDW = 540 --INTR_X86_MMX_PACKSSWB = 541 --INTR_X86_MMX_PACKUSWB = 542 --INTR_X86_MMX_PADD_B = 543 --INTR_X86_MMX_PADD_D = 544 --INTR_X86_MMX_PADD_Q = 545 --INTR_X86_MMX_PADD_W = 546 --INTR_X86_MMX_PADDS_B = 547 --INTR_X86_MMX_PADDS_W = 548 --INTR_X86_MMX_PADDUS_B = 549 --INTR_X86_MMX_PADDUS_W = 550 --INTR_X86_MMX_PAND = 551 --INTR_X86_MMX_PANDN = 552 --INTR_X86_MMX_PAVG_B = 553 --INTR_X86_MMX_PAVG_W = 554 --INTR_X86_MMX_PCMPEQ_B = 555 --INTR_X86_MMX_PCMPEQ_D = 556 --INTR_X86_MMX_PCMPEQ_W = 557 --INTR_X86_MMX_PCMPGT_B = 558 --INTR_X86_MMX_PCMPGT_D = 559 --INTR_X86_MMX_PCMPGT_W = 560 --INTR_X86_MMX_PEXTR_W = 561 --INTR_X86_MMX_PINSR_W = 562 --INTR_X86_MMX_PMADD_WD = 563 --INTR_X86_MMX_PMAXS_W = 564 --INTR_X86_MMX_PMAXU_B = 565 --INTR_X86_MMX_PMINS_W = 566 --INTR_X86_MMX_PMINU_B = 567 --INTR_X86_MMX_PMOVMSKB = 568 --INTR_X86_MMX_PMULH_W = 569 --INTR_X86_MMX_PMULHU_W = 570 --INTR_X86_MMX_PMULL_W = 571 --INTR_X86_MMX_PMULU_DQ = 572 --INTR_X86_MMX_POR = 573 --INTR_X86_MMX_PSAD_BW = 574 --INTR_X86_MMX_PSLL_D = 575 --INTR_X86_MMX_PSLL_Q = 576 --INTR_X86_MMX_PSLL_W = 577 --INTR_X86_MMX_PSLLI_D = 578 --INTR_X86_MMX_PSLLI_Q = 579 --INTR_X86_MMX_PSLLI_W = 580 --INTR_X86_MMX_PSRA_D = 581 --INTR_X86_MMX_PSRA_W = 582 --INTR_X86_MMX_PSRAI_D = 583 --INTR_X86_MMX_PSRAI_W = 584 --INTR_X86_MMX_PSRL_D = 585 --INTR_X86_MMX_PSRL_Q = 586 --INTR_X86_MMX_PSRL_W = 587 --INTR_X86_MMX_PSRLI_D = 588 --INTR_X86_MMX_PSRLI_Q = 589 --INTR_X86_MMX_PSRLI_W = 590 --INTR_X86_MMX_PSUB_B = 591 --INTR_X86_MMX_PSUB_D = 592 --INTR_X86_MMX_PSUB_Q = 593 --INTR_X86_MMX_PSUB_W = 594 --INTR_X86_MMX_PSUBS_B = 595 --INTR_X86_MMX_PSUBS_W = 596 --INTR_X86_MMX_PSUBUS_B = 597 --INTR_X86_MMX_PSUBUS_W = 598 --INTR_X86_MMX_PUNPCKHBW = 599 --INTR_X86_MMX_PUNPCKHDQ = 600 --INTR_X86_MMX_PUNPCKHWD = 601 --INTR_X86_MMX_PUNPCKLBW = 602 --INTR_X86_MMX_PUNPCKLDQ = 603 --INTR_X86_MMX_PUNPCKLWD = 604 --INTR_X86_MMX_PXOR = 605 --INTR_X86_MMX_VEC_EXT_D = 606 --INTR_X86_MMX_VEC_INIT_B = 607 --INTR_X86_MMX_VEC_INIT_D = 608 --INTR_X86_MMX_VEC_INIT_W = 609 --INTR_X86_SSE2_ADD_SD = 610 --INTR_X86_SSE2_CLFLUSH = 611 --INTR_X86_SSE2_CMP_PD = 612 --INTR_X86_SSE2_CMP_SD = 613 --INTR_X86_SSE2_COMIEQ_SD = 614 --INTR_X86_SSE2_COMIGE_SD = 615 --INTR_X86_SSE2_COMIGT_SD = 616 --INTR_X86_SSE2_COMILE_SD = 617 --INTR_X86_SSE2_COMILT_SD = 618 --INTR_X86_SSE2_COMINEQ_SD = 619 --INTR_X86_SSE2_CVTDQ2PD = 620 --INTR_X86_SSE2_CVTDQ2PS = 621 --INTR_X86_SSE2_CVTPD2DQ = 622 --INTR_X86_SSE2_CVTPD2PS = 623 --INTR_X86_SSE2_CVTPS2DQ = 624 --INTR_X86_SSE2_CVTPS2PD = 625 --INTR_X86_SSE2_CVTSD2SI = 626 --INTR_X86_SSE2_CVTSD2SI64 = 627 --INTR_X86_SSE2_CVTSD2SS = 628 --INTR_X86_SSE2_CVTSI2SD = 629 --INTR_X86_SSE2_CVTSI642SD = 630 --INTR_X86_SSE2_CVTSS2SD = 631 --INTR_X86_SSE2_CVTTPD2DQ = 632 --INTR_X86_SSE2_CVTTPS2DQ = 633 --INTR_X86_SSE2_CVTTSD2SI = 634 --INTR_X86_SSE2_CVTTSD2SI64 = 635 --INTR_X86_SSE2_DIV_SD = 636 --INTR_X86_SSE2_LFENCE = 637 --INTR_X86_SSE2_LOADU_DQ = 638 --INTR_X86_SSE2_LOADU_PD = 639 --INTR_X86_SSE2_MASKMOV_DQU = 640 --INTR_X86_SSE2_MAX_PD = 641 --INTR_X86_SSE2_MAX_SD = 642 --INTR_X86_SSE2_MFENCE = 643 --INTR_X86_SSE2_MIN_PD = 644 --INTR_X86_SSE2_MIN_SD = 645 --INTR_X86_SSE2_MOVMSK_PD = 646 --INTR_X86_SSE2_MOVNT_DQ = 647 --INTR_X86_SSE2_MOVNT_I = 648 --INTR_X86_SSE2_MOVNT_PD = 649 --INTR_X86_SSE2_MUL_SD = 650 --INTR_X86_SSE2_PACKSSDW_128 = 651 --INTR_X86_SSE2_PACKSSWB_128 = 652 --INTR_X86_SSE2_PACKUSWB_128 = 653 --INTR_X86_SSE2_PADDS_B = 654 --INTR_X86_SSE2_PADDS_W = 655 --INTR_X86_SSE2_PADDUS_B = 656 --INTR_X86_SSE2_PADDUS_W = 657 --INTR_X86_SSE2_PAVG_B = 658 --INTR_X86_SSE2_PAVG_W = 659 --INTR_X86_SSE2_PCMPEQ_B = 660 --INTR_X86_SSE2_PCMPEQ_D = 661 --INTR_X86_SSE2_PCMPEQ_W = 662 --INTR_X86_SSE2_PCMPGT_B = 663 --INTR_X86_SSE2_PCMPGT_D = 664 --INTR_X86_SSE2_PCMPGT_W = 665 --INTR_X86_SSE2_PMADD_WD = 666 --INTR_X86_SSE2_PMAXS_W = 667 --INTR_X86_SSE2_PMAXU_B = 668 --INTR_X86_SSE2_PMINS_W = 669 --INTR_X86_SSE2_PMINU_B = 670 --INTR_X86_SSE2_PMOVMSKB_128 = 671 --INTR_X86_SSE2_PMULH_W = 672 --INTR_X86_SSE2_PMULHU_W = 673 --INTR_X86_SSE2_PMULU_DQ = 674 --INTR_X86_SSE2_PSAD_BW = 675 --INTR_X86_SSE2_PSLL_D = 676 --INTR_X86_SSE2_PSLL_DQ = 677 --INTR_X86_SSE2_PSLL_DQ_BS = 678 --INTR_X86_SSE2_PSLL_Q = 679 --INTR_X86_SSE2_PSLL_W = 680 --INTR_X86_SSE2_PSLLI_D = 681 --INTR_X86_SSE2_PSLLI_Q = 682 --INTR_X86_SSE2_PSLLI_W = 683 --INTR_X86_SSE2_PSRA_D = 684 --INTR_X86_SSE2_PSRA_W = 685 --INTR_X86_SSE2_PSRAI_D = 686 --INTR_X86_SSE2_PSRAI_W = 687 --INTR_X86_SSE2_PSRL_D = 688 --INTR_X86_SSE2_PSRL_DQ = 689 --INTR_X86_SSE2_PSRL_DQ_BS = 690 --INTR_X86_SSE2_PSRL_Q = 691 --INTR_X86_SSE2_PSRL_W = 692 --INTR_X86_SSE2_PSRLI_D = 693 --INTR_X86_SSE2_PSRLI_Q = 694 --INTR_X86_SSE2_PSRLI_W = 695 --INTR_X86_SSE2_PSUBS_B = 696 --INTR_X86_SSE2_PSUBS_W = 697 --INTR_X86_SSE2_PSUBUS_B = 698 --INTR_X86_SSE2_PSUBUS_W = 699 --INTR_X86_SSE2_SQRT_PD = 700 --INTR_X86_SSE2_SQRT_SD = 701 --INTR_X86_SSE2_STOREL_DQ = 702 --INTR_X86_SSE2_STOREU_DQ = 703 --INTR_X86_SSE2_STOREU_PD = 704 --INTR_X86_SSE2_SUB_SD = 705 --INTR_X86_SSE2_UCOMIEQ_SD = 706 --INTR_X86_SSE2_UCOMIGE_SD = 707 --INTR_X86_SSE2_UCOMIGT_SD = 708 --INTR_X86_SSE2_UCOMILE_SD = 709 --INTR_X86_SSE2_UCOMILT_SD = 710 --INTR_X86_SSE2_UCOMINEQ_SD = 711 --INTR_X86_SSE3_ADDSUB_PD = 712 --INTR_X86_SSE3_ADDSUB_PS = 713 --INTR_X86_SSE3_HADD_PD = 714 --INTR_X86_SSE3_HADD_PS = 715 --INTR_X86_SSE3_HSUB_PD = 716 --INTR_X86_SSE3_HSUB_PS = 717 --INTR_X86_SSE3_LDU_DQ = 718 --INTR_X86_SSE3_MONITOR = 719 --INTR_X86_SSE3_MWAIT = 720 --INTR_X86_SSE41_BLENDPD = 721 --INTR_X86_SSE41_BLENDPS = 722 --INTR_X86_SSE41_BLENDVPD = 723 --INTR_X86_SSE41_BLENDVPS = 724 --INTR_X86_SSE41_DPPD = 725 --INTR_X86_SSE41_DPPS = 726 --INTR_X86_SSE41_EXTRACTPS = 727 --INTR_X86_SSE41_INSERTPS = 728 --INTR_X86_SSE41_MOVNTDQA = 729 --INTR_X86_SSE41_MPSADBW = 730 --INTR_X86_SSE41_PACKUSDW = 731 --INTR_X86_SSE41_PBLENDVB = 732 --INTR_X86_SSE41_PBLENDW = 733 --INTR_X86_SSE41_PCMPEQQ = 734 --INTR_X86_SSE41_PEXTRB = 735 --INTR_X86_SSE41_PEXTRD = 736 --INTR_X86_SSE41_PEXTRQ = 737 --INTR_X86_SSE41_PHMINPOSUW = 738 --INTR_X86_SSE41_PMAXSB = 739 --INTR_X86_SSE41_PMAXSD = 740 --INTR_X86_SSE41_PMAXUD = 741 --INTR_X86_SSE41_PMAXUW = 742 --INTR_X86_SSE41_PMINSB = 743 --INTR_X86_SSE41_PMINSD = 744 --INTR_X86_SSE41_PMINUD = 745 --INTR_X86_SSE41_PMINUW = 746 --INTR_X86_SSE41_PMOVSXBD = 747 --INTR_X86_SSE41_PMOVSXBQ = 748 --INTR_X86_SSE41_PMOVSXBW = 749 --INTR_X86_SSE41_PMOVSXDQ = 750 --INTR_X86_SSE41_PMOVSXWD = 751 --INTR_X86_SSE41_PMOVSXWQ = 752 --INTR_X86_SSE41_PMOVZXBD = 753 --INTR_X86_SSE41_PMOVZXBQ = 754 --INTR_X86_SSE41_PMOVZXBW = 755 --INTR_X86_SSE41_PMOVZXDQ = 756 --INTR_X86_SSE41_PMOVZXWD = 757 --INTR_X86_SSE41_PMOVZXWQ = 758 --INTR_X86_SSE41_PMULDQ = 759 --INTR_X86_SSE41_PTESTC = 760 --INTR_X86_SSE41_PTESTNZC = 761 --INTR_X86_SSE41_PTESTZ = 762 --INTR_X86_SSE41_ROUND_PD = 763 --INTR_X86_SSE41_ROUND_PS = 764 --INTR_X86_SSE41_ROUND_SD = 765 --INTR_X86_SSE41_ROUND_SS = 766 --INTR_X86_SSE42_CRC32_16 = 767 --INTR_X86_SSE42_CRC32_32 = 768 --INTR_X86_SSE42_CRC32_8 = 769 --INTR_X86_SSE42_CRC64_64 = 770 --INTR_X86_SSE42_CRC64_8 = 771 --INTR_X86_SSE42_PCMPESTRI128 = 772 --INTR_X86_SSE42_PCMPESTRIA128 = 773 --INTR_X86_SSE42_PCMPESTRIC128 = 774 --INTR_X86_SSE42_PCMPESTRIO128 = 775 --INTR_X86_SSE42_PCMPESTRIS128 = 776 --INTR_X86_SSE42_PCMPESTRIZ128 = 777 --INTR_X86_SSE42_PCMPESTRM128 = 778 --INTR_X86_SSE42_PCMPGTQ = 779 --INTR_X86_SSE42_PCMPISTRI128 = 780 --INTR_X86_SSE42_PCMPISTRIA128 = 781 --INTR_X86_SSE42_PCMPISTRIC128 = 782 --INTR_X86_SSE42_PCMPISTRIO128 = 783 --INTR_X86_SSE42_PCMPISTRIS128 = 784 --INTR_X86_SSE42_PCMPISTRIZ128 = 785 --INTR_X86_SSE42_PCMPISTRM128 = 786 --INTR_X86_SSE_ADD_SS = 787 --INTR_X86_SSE_CMP_PS = 788 --INTR_X86_SSE_CMP_SS = 789 --INTR_X86_SSE_COMIEQ_SS = 790 --INTR_X86_SSE_COMIGE_SS = 791 --INTR_X86_SSE_COMIGT_SS = 792 --INTR_X86_SSE_COMILE_SS = 793 --INTR_X86_SSE_COMILT_SS = 794 --INTR_X86_SSE_COMINEQ_SS = 795 --INTR_X86_SSE_CVTPD2PI = 796 --INTR_X86_SSE_CVTPI2PD = 797 --INTR_X86_SSE_CVTPI2PS = 798 --INTR_X86_SSE_CVTPS2PI = 799 --INTR_X86_SSE_CVTSI2SS = 800 --INTR_X86_SSE_CVTSI642SS = 801 --INTR_X86_SSE_CVTSS2SI = 802 --INTR_X86_SSE_CVTSS2SI64 = 803 --INTR_X86_SSE_CVTTPD2PI = 804 --INTR_X86_SSE_CVTTPS2PI = 805 --INTR_X86_SSE_CVTTSS2SI = 806 --INTR_X86_SSE_CVTTSS2SI64 = 807 --INTR_X86_SSE_DIV_SS = 808 --INTR_X86_SSE_LDMXCSR = 809 --INTR_X86_SSE_LOADU_PS = 810 --INTR_X86_SSE_MAX_PS = 811 --INTR_X86_SSE_MAX_SS = 812 --INTR_X86_SSE_MIN_PS = 813 --INTR_X86_SSE_MIN_SS = 814 --INTR_X86_SSE_MOVMSK_PS = 815 --INTR_X86_SSE_MOVNT_PS = 816 --INTR_X86_SSE_MUL_SS = 817 --INTR_X86_SSE_RCP_PS = 818 --INTR_X86_SSE_RCP_SS = 819 --INTR_X86_SSE_RSQRT_PS = 820 --INTR_X86_SSE_RSQRT_SS = 821 --INTR_X86_SSE_SFENCE = 822 --INTR_X86_SSE_SQRT_PS = 823 --INTR_X86_SSE_SQRT_SS = 824 --INTR_X86_SSE_STMXCSR = 825 --INTR_X86_SSE_STOREU_PS = 826 --INTR_X86_SSE_SUB_SS = 827 --INTR_X86_SSE_UCOMIEQ_SS = 828 --INTR_X86_SSE_UCOMIGE_SS = 829 --INTR_X86_SSE_UCOMIGT_SS = 830 --INTR_X86_SSE_UCOMILE_SS = 831 --INTR_X86_SSE_UCOMILT_SS = 832 --INTR_X86_SSE_UCOMINEQ_SS = 833 --INTR_X86_SSSE3_PABS_B = 834 --INTR_X86_SSSE3_PABS_B_128 = 835 --INTR_X86_SSSE3_PABS_D = 836 --INTR_X86_SSSE3_PABS_D_128 = 837 --INTR_X86_SSSE3_PABS_W = 838 --INTR_X86_SSSE3_PABS_W_128 = 839 --INTR_X86_SSSE3_PHADD_D = 840 --INTR_X86_SSSE3_PHADD_D_128 = 841 --INTR_X86_SSSE3_PHADD_SW = 842 --INTR_X86_SSSE3_PHADD_SW_128 = 843 --INTR_X86_SSSE3_PHADD_W = 844 --INTR_X86_SSSE3_PHADD_W_128 = 845 --INTR_X86_SSSE3_PHSUB_D = 846 --INTR_X86_SSSE3_PHSUB_D_128 = 847 --INTR_X86_SSSE3_PHSUB_SW = 848 --INTR_X86_SSSE3_PHSUB_SW_128 = 849 --INTR_X86_SSSE3_PHSUB_W = 850 --INTR_X86_SSSE3_PHSUB_W_128 = 851 --INTR_X86_SSSE3_PMADD_UB_SW = 852 --INTR_X86_SSSE3_PMADD_UB_SW_128 = 853 --INTR_X86_SSSE3_PMUL_HR_SW = 854 --INTR_X86_SSSE3_PMUL_HR_SW_128 = 855 --INTR_X86_SSSE3_PSHUF_B = 856 --INTR_X86_SSSE3_PSHUF_B_128 = 857 --INTR_X86_SSSE3_PSHUF_W = 858 --INTR_X86_SSSE3_PSIGN_B = 859 --INTR_X86_SSSE3_PSIGN_B_128 = 860 --INTR_X86_SSSE3_PSIGN_D = 861 --INTR_X86_SSSE3_PSIGN_D_128 = 862 --INTR_X86_SSSE3_PSIGN_W = 863 --INTR_X86_SSSE3_PSIGN_W_128 = 864 --INTR_XCORE_BITREV = 865 --INTR_XCORE_GETID = 866 -- -+INTR_ARM_NEON_VCVTFP2HF = 17 -+INTR_ARM_NEON_VCVTFXS2FP = 18 -+INTR_ARM_NEON_VCVTFXU2FP = 19 -+INTR_ARM_NEON_VCVTHF2FP = 20 -+INTR_ARM_NEON_VHADDS = 21 -+INTR_ARM_NEON_VHADDU = 22 -+INTR_ARM_NEON_VHSUBS = 23 -+INTR_ARM_NEON_VHSUBU = 24 -+INTR_ARM_NEON_VLD1 = 25 -+INTR_ARM_NEON_VLD2 = 26 -+INTR_ARM_NEON_VLD2LANE = 27 -+INTR_ARM_NEON_VLD3 = 28 -+INTR_ARM_NEON_VLD3LANE = 29 -+INTR_ARM_NEON_VLD4 = 30 -+INTR_ARM_NEON_VLD4LANE = 31 -+INTR_ARM_NEON_VMAXS = 32 -+INTR_ARM_NEON_VMAXU = 33 -+INTR_ARM_NEON_VMINS = 34 -+INTR_ARM_NEON_VMINU = 35 -+INTR_ARM_NEON_VMULLP = 36 -+INTR_ARM_NEON_VMULP = 37 -+INTR_ARM_NEON_VPADALS = 38 -+INTR_ARM_NEON_VPADALU = 39 -+INTR_ARM_NEON_VPADD = 40 -+INTR_ARM_NEON_VPADDLS = 41 -+INTR_ARM_NEON_VPADDLU = 42 -+INTR_ARM_NEON_VPMAXS = 43 -+INTR_ARM_NEON_VPMAXU = 44 -+INTR_ARM_NEON_VPMINS = 45 -+INTR_ARM_NEON_VPMINU = 46 -+INTR_ARM_NEON_VQABS = 47 -+INTR_ARM_NEON_VQADDS = 48 -+INTR_ARM_NEON_VQADDU = 49 -+INTR_ARM_NEON_VQDMLAL = 50 -+INTR_ARM_NEON_VQDMLSL = 51 -+INTR_ARM_NEON_VQDMULH = 52 -+INTR_ARM_NEON_VQDMULL = 53 -+INTR_ARM_NEON_VQMOVNS = 54 -+INTR_ARM_NEON_VQMOVNSU = 55 -+INTR_ARM_NEON_VQMOVNU = 56 -+INTR_ARM_NEON_VQNEG = 57 -+INTR_ARM_NEON_VQRDMULH = 58 -+INTR_ARM_NEON_VQRSHIFTNS = 59 -+INTR_ARM_NEON_VQRSHIFTNSU = 60 -+INTR_ARM_NEON_VQRSHIFTNU = 61 -+INTR_ARM_NEON_VQRSHIFTS = 62 -+INTR_ARM_NEON_VQRSHIFTU = 63 -+INTR_ARM_NEON_VQSHIFTNS = 64 -+INTR_ARM_NEON_VQSHIFTNSU = 65 -+INTR_ARM_NEON_VQSHIFTNU = 66 -+INTR_ARM_NEON_VQSHIFTS = 67 -+INTR_ARM_NEON_VQSHIFTSU = 68 -+INTR_ARM_NEON_VQSHIFTU = 69 -+INTR_ARM_NEON_VQSUBS = 70 -+INTR_ARM_NEON_VQSUBU = 71 -+INTR_ARM_NEON_VRADDHN = 72 -+INTR_ARM_NEON_VRECPE = 73 -+INTR_ARM_NEON_VRECPS = 74 -+INTR_ARM_NEON_VRHADDS = 75 -+INTR_ARM_NEON_VRHADDU = 76 -+INTR_ARM_NEON_VRSHIFTN = 77 -+INTR_ARM_NEON_VRSHIFTS = 78 -+INTR_ARM_NEON_VRSHIFTU = 79 -+INTR_ARM_NEON_VRSQRTE = 80 -+INTR_ARM_NEON_VRSQRTS = 81 -+INTR_ARM_NEON_VRSUBHN = 82 -+INTR_ARM_NEON_VSHIFTINS = 83 -+INTR_ARM_NEON_VSHIFTLS = 84 -+INTR_ARM_NEON_VSHIFTLU = 85 -+INTR_ARM_NEON_VSHIFTN = 86 -+INTR_ARM_NEON_VSHIFTS = 87 -+INTR_ARM_NEON_VSHIFTU = 88 -+INTR_ARM_NEON_VST1 = 89 -+INTR_ARM_NEON_VST2 = 90 -+INTR_ARM_NEON_VST2LANE = 91 -+INTR_ARM_NEON_VST3 = 92 -+INTR_ARM_NEON_VST3LANE = 93 -+INTR_ARM_NEON_VST4 = 94 -+INTR_ARM_NEON_VST4LANE = 95 -+INTR_ARM_NEON_VSUBHN = 96 -+INTR_ARM_NEON_VTBL1 = 97 -+INTR_ARM_NEON_VTBL2 = 98 -+INTR_ARM_NEON_VTBL3 = 99 -+INTR_ARM_NEON_VTBL4 = 100 -+INTR_ARM_NEON_VTBX1 = 101 -+INTR_ARM_NEON_VTBX2 = 102 -+INTR_ARM_NEON_VTBX3 = 103 -+INTR_ARM_NEON_VTBX4 = 104 -+INTR_ARM_QADD = 105 -+INTR_ARM_QSUB = 106 -+INTR_ARM_SET_FPSCR = 107 -+INTR_ARM_SSAT = 108 -+INTR_ARM_THREAD_POINTER = 109 -+INTR_ARM_USAT = 110 -+INTR_ARM_VCVTR = 111 -+INTR_ARM_VCVTRU = 112 -+INTR_ATOMIC_CMP_SWAP = 113 -+INTR_ATOMIC_LOAD_ADD = 114 -+INTR_ATOMIC_LOAD_AND = 115 -+INTR_ATOMIC_LOAD_MAX = 116 -+INTR_ATOMIC_LOAD_MIN = 117 -+INTR_ATOMIC_LOAD_NAND = 118 -+INTR_ATOMIC_LOAD_OR = 119 -+INTR_ATOMIC_LOAD_SUB = 120 -+INTR_ATOMIC_LOAD_UMAX = 121 -+INTR_ATOMIC_LOAD_UMIN = 122 -+INTR_ATOMIC_LOAD_XOR = 123 -+INTR_ATOMIC_SWAP = 124 -+INTR_BSWAP = 125 -+INTR_CONVERT_FROM_FP16 = 126 -+INTR_CONVERT_TO_FP16 = 127 -+INTR_CONVERTFF = 128 -+INTR_CONVERTFSI = 129 -+INTR_CONVERTFUI = 130 -+INTR_CONVERTSIF = 131 -+INTR_CONVERTSS = 132 -+INTR_CONVERTSU = 133 -+INTR_CONVERTUIF = 134 -+INTR_CONVERTUS = 135 -+INTR_CONVERTUU = 136 -+INTR_COS = 137 -+INTR_CTLZ = 138 -+INTR_CTPOP = 139 -+INTR_CTTZ = 140 -+INTR_DBG_DECLARE = 141 -+INTR_DBG_VALUE = 142 -+INTR_EH_DWARF_CFA = 143 -+INTR_EH_EXCEPTION = 144 -+INTR_EH_RETURN_I32 = 145 -+INTR_EH_RETURN_I64 = 146 -+INTR_EH_SELECTOR = 147 -+INTR_EH_SJLJ_CALLSITE = 148 -+INTR_EH_SJLJ_DISPATCH_SETUP = 149 -+INTR_EH_SJLJ_LONGJMP = 150 -+INTR_EH_SJLJ_LSDA = 151 -+INTR_EH_SJLJ_SETJMP = 152 -+INTR_EH_TYPEID_FOR = 153 -+INTR_EH_UNWIND_INIT = 154 -+INTR_EXP = 155 -+INTR_EXP2 = 156 -+INTR_FLT_ROUNDS = 157 -+INTR_FRAMEADDRESS = 158 -+INTR_GCREAD = 159 -+INTR_GCROOT = 160 -+INTR_GCWRITE = 161 -+INTR_INIT_TRAMPOLINE = 162 -+INTR_INVARIANT_END = 163 -+INTR_INVARIANT_START = 164 -+INTR_LIFETIME_END = 165 -+INTR_LIFETIME_START = 166 -+INTR_LOG = 167 -+INTR_LOG10 = 168 -+INTR_LOG2 = 169 -+INTR_LONGJMP = 170 -+INTR_MEMCPY = 171 -+INTR_MEMMOVE = 172 -+INTR_MEMORY_BARRIER = 173 -+INTR_MEMSET = 174 -+INTR_OBJECTSIZE = 175 -+INTR_PCMARKER = 176 -+INTR_POW = 177 -+INTR_POWI = 178 -+INTR_PPC_ALTIVEC_DSS = 179 -+INTR_PPC_ALTIVEC_DSSALL = 180 -+INTR_PPC_ALTIVEC_DST = 181 -+INTR_PPC_ALTIVEC_DSTST = 182 -+INTR_PPC_ALTIVEC_DSTSTT = 183 -+INTR_PPC_ALTIVEC_DSTT = 184 -+INTR_PPC_ALTIVEC_LVEBX = 185 -+INTR_PPC_ALTIVEC_LVEHX = 186 -+INTR_PPC_ALTIVEC_LVEWX = 187 -+INTR_PPC_ALTIVEC_LVSL = 188 -+INTR_PPC_ALTIVEC_LVSR = 189 -+INTR_PPC_ALTIVEC_LVX = 190 -+INTR_PPC_ALTIVEC_LVXL = 191 -+INTR_PPC_ALTIVEC_MFVSCR = 192 -+INTR_PPC_ALTIVEC_MTVSCR = 193 -+INTR_PPC_ALTIVEC_STVEBX = 194 -+INTR_PPC_ALTIVEC_STVEHX = 195 -+INTR_PPC_ALTIVEC_STVEWX = 196 -+INTR_PPC_ALTIVEC_STVX = 197 -+INTR_PPC_ALTIVEC_STVXL = 198 -+INTR_PPC_ALTIVEC_VADDCUW = 199 -+INTR_PPC_ALTIVEC_VADDSBS = 200 -+INTR_PPC_ALTIVEC_VADDSHS = 201 -+INTR_PPC_ALTIVEC_VADDSWS = 202 -+INTR_PPC_ALTIVEC_VADDUBS = 203 -+INTR_PPC_ALTIVEC_VADDUHS = 204 -+INTR_PPC_ALTIVEC_VADDUWS = 205 -+INTR_PPC_ALTIVEC_VAVGSB = 206 -+INTR_PPC_ALTIVEC_VAVGSH = 207 -+INTR_PPC_ALTIVEC_VAVGSW = 208 -+INTR_PPC_ALTIVEC_VAVGUB = 209 -+INTR_PPC_ALTIVEC_VAVGUH = 210 -+INTR_PPC_ALTIVEC_VAVGUW = 211 -+INTR_PPC_ALTIVEC_VCFSX = 212 -+INTR_PPC_ALTIVEC_VCFUX = 213 -+INTR_PPC_ALTIVEC_VCMPBFP = 214 -+INTR_PPC_ALTIVEC_VCMPBFP_P = 215 -+INTR_PPC_ALTIVEC_VCMPEQFP = 216 -+INTR_PPC_ALTIVEC_VCMPEQFP_P = 217 -+INTR_PPC_ALTIVEC_VCMPEQUB = 218 -+INTR_PPC_ALTIVEC_VCMPEQUB_P = 219 -+INTR_PPC_ALTIVEC_VCMPEQUH = 220 -+INTR_PPC_ALTIVEC_VCMPEQUH_P = 221 -+INTR_PPC_ALTIVEC_VCMPEQUW = 222 -+INTR_PPC_ALTIVEC_VCMPEQUW_P = 223 -+INTR_PPC_ALTIVEC_VCMPGEFP = 224 -+INTR_PPC_ALTIVEC_VCMPGEFP_P = 225 -+INTR_PPC_ALTIVEC_VCMPGTFP = 226 -+INTR_PPC_ALTIVEC_VCMPGTFP_P = 227 -+INTR_PPC_ALTIVEC_VCMPGTSB = 228 -+INTR_PPC_ALTIVEC_VCMPGTSB_P = 229 -+INTR_PPC_ALTIVEC_VCMPGTSH = 230 -+INTR_PPC_ALTIVEC_VCMPGTSH_P = 231 -+INTR_PPC_ALTIVEC_VCMPGTSW = 232 -+INTR_PPC_ALTIVEC_VCMPGTSW_P = 233 -+INTR_PPC_ALTIVEC_VCMPGTUB = 234 -+INTR_PPC_ALTIVEC_VCMPGTUB_P = 235 -+INTR_PPC_ALTIVEC_VCMPGTUH = 236 -+INTR_PPC_ALTIVEC_VCMPGTUH_P = 237 -+INTR_PPC_ALTIVEC_VCMPGTUW = 238 -+INTR_PPC_ALTIVEC_VCMPGTUW_P = 239 -+INTR_PPC_ALTIVEC_VCTSXS = 240 -+INTR_PPC_ALTIVEC_VCTUXS = 241 -+INTR_PPC_ALTIVEC_VEXPTEFP = 242 -+INTR_PPC_ALTIVEC_VLOGEFP = 243 -+INTR_PPC_ALTIVEC_VMADDFP = 244 -+INTR_PPC_ALTIVEC_VMAXFP = 245 -+INTR_PPC_ALTIVEC_VMAXSB = 246 -+INTR_PPC_ALTIVEC_VMAXSH = 247 -+INTR_PPC_ALTIVEC_VMAXSW = 248 -+INTR_PPC_ALTIVEC_VMAXUB = 249 -+INTR_PPC_ALTIVEC_VMAXUH = 250 -+INTR_PPC_ALTIVEC_VMAXUW = 251 -+INTR_PPC_ALTIVEC_VMHADDSHS = 252 -+INTR_PPC_ALTIVEC_VMHRADDSHS = 253 -+INTR_PPC_ALTIVEC_VMINFP = 254 -+INTR_PPC_ALTIVEC_VMINSB = 255 -+INTR_PPC_ALTIVEC_VMINSH = 256 -+INTR_PPC_ALTIVEC_VMINSW = 257 -+INTR_PPC_ALTIVEC_VMINUB = 258 -+INTR_PPC_ALTIVEC_VMINUH = 259 -+INTR_PPC_ALTIVEC_VMINUW = 260 -+INTR_PPC_ALTIVEC_VMLADDUHM = 261 -+INTR_PPC_ALTIVEC_VMSUMMBM = 262 -+INTR_PPC_ALTIVEC_VMSUMSHM = 263 -+INTR_PPC_ALTIVEC_VMSUMSHS = 264 -+INTR_PPC_ALTIVEC_VMSUMUBM = 265 -+INTR_PPC_ALTIVEC_VMSUMUHM = 266 -+INTR_PPC_ALTIVEC_VMSUMUHS = 267 -+INTR_PPC_ALTIVEC_VMULESB = 268 -+INTR_PPC_ALTIVEC_VMULESH = 269 -+INTR_PPC_ALTIVEC_VMULEUB = 270 -+INTR_PPC_ALTIVEC_VMULEUH = 271 -+INTR_PPC_ALTIVEC_VMULOSB = 272 -+INTR_PPC_ALTIVEC_VMULOSH = 273 -+INTR_PPC_ALTIVEC_VMULOUB = 274 -+INTR_PPC_ALTIVEC_VMULOUH = 275 -+INTR_PPC_ALTIVEC_VNMSUBFP = 276 -+INTR_PPC_ALTIVEC_VPERM = 277 -+INTR_PPC_ALTIVEC_VPKPX = 278 -+INTR_PPC_ALTIVEC_VPKSHSS = 279 -+INTR_PPC_ALTIVEC_VPKSHUS = 280 -+INTR_PPC_ALTIVEC_VPKSWSS = 281 -+INTR_PPC_ALTIVEC_VPKSWUS = 282 -+INTR_PPC_ALTIVEC_VPKUHUS = 283 -+INTR_PPC_ALTIVEC_VPKUWUS = 284 -+INTR_PPC_ALTIVEC_VREFP = 285 -+INTR_PPC_ALTIVEC_VRFIM = 286 -+INTR_PPC_ALTIVEC_VRFIN = 287 -+INTR_PPC_ALTIVEC_VRFIP = 288 -+INTR_PPC_ALTIVEC_VRFIZ = 289 -+INTR_PPC_ALTIVEC_VRLB = 290 -+INTR_PPC_ALTIVEC_VRLH = 291 -+INTR_PPC_ALTIVEC_VRLW = 292 -+INTR_PPC_ALTIVEC_VRSQRTEFP = 293 -+INTR_PPC_ALTIVEC_VSEL = 294 -+INTR_PPC_ALTIVEC_VSL = 295 -+INTR_PPC_ALTIVEC_VSLB = 296 -+INTR_PPC_ALTIVEC_VSLH = 297 -+INTR_PPC_ALTIVEC_VSLO = 298 -+INTR_PPC_ALTIVEC_VSLW = 299 -+INTR_PPC_ALTIVEC_VSR = 300 -+INTR_PPC_ALTIVEC_VSRAB = 301 -+INTR_PPC_ALTIVEC_VSRAH = 302 -+INTR_PPC_ALTIVEC_VSRAW = 303 -+INTR_PPC_ALTIVEC_VSRB = 304 -+INTR_PPC_ALTIVEC_VSRH = 305 -+INTR_PPC_ALTIVEC_VSRO = 306 -+INTR_PPC_ALTIVEC_VSRW = 307 -+INTR_PPC_ALTIVEC_VSUBCUW = 308 -+INTR_PPC_ALTIVEC_VSUBSBS = 309 -+INTR_PPC_ALTIVEC_VSUBSHS = 310 -+INTR_PPC_ALTIVEC_VSUBSWS = 311 -+INTR_PPC_ALTIVEC_VSUBUBS = 312 -+INTR_PPC_ALTIVEC_VSUBUHS = 313 -+INTR_PPC_ALTIVEC_VSUBUWS = 314 -+INTR_PPC_ALTIVEC_VSUM2SWS = 315 -+INTR_PPC_ALTIVEC_VSUM4SBS = 316 -+INTR_PPC_ALTIVEC_VSUM4SHS = 317 -+INTR_PPC_ALTIVEC_VSUM4UBS = 318 -+INTR_PPC_ALTIVEC_VSUMSWS = 319 -+INTR_PPC_ALTIVEC_VUPKHPX = 320 -+INTR_PPC_ALTIVEC_VUPKHSB = 321 -+INTR_PPC_ALTIVEC_VUPKHSH = 322 -+INTR_PPC_ALTIVEC_VUPKLPX = 323 -+INTR_PPC_ALTIVEC_VUPKLSB = 324 -+INTR_PPC_ALTIVEC_VUPKLSH = 325 -+INTR_PPC_DCBA = 326 -+INTR_PPC_DCBF = 327 -+INTR_PPC_DCBI = 328 -+INTR_PPC_DCBST = 329 -+INTR_PPC_DCBT = 330 -+INTR_PPC_DCBTST = 331 -+INTR_PPC_DCBZ = 332 -+INTR_PPC_DCBZL = 333 -+INTR_PPC_SYNC = 334 -+INTR_PREFETCH = 335 -+INTR_PTR_ANNOTATION = 336 -+INTR_PTX_BAR_SYNC = 337 -+INTR_PTX_READ_TID_R64 = 338 -+INTR_PTX_READ_TID_V4I16 = 339 -+INTR_PTX_READ_TID_W = 340 -+INTR_PTX_READ_TID_X = 341 -+INTR_PTX_READ_TID_Y = 342 -+INTR_PTX_READ_TID_Z = 343 -+INTR_READCYCLECOUNTER = 344 -+INTR_RETURNADDRESS = 345 -+INTR_SADD_WITH_OVERFLOW = 346 -+INTR_SETJMP = 347 -+INTR_SIGLONGJMP = 348 -+INTR_SIGSETJMP = 349 -+INTR_SIN = 350 -+INTR_SMUL_WITH_OVERFLOW = 351 -+INTR_SPU_SI_A = 352 -+INTR_SPU_SI_ADDX = 353 -+INTR_SPU_SI_AH = 354 -+INTR_SPU_SI_AHI = 355 -+INTR_SPU_SI_AI = 356 -+INTR_SPU_SI_AND = 357 -+INTR_SPU_SI_ANDBI = 358 -+INTR_SPU_SI_ANDC = 359 -+INTR_SPU_SI_ANDHI = 360 -+INTR_SPU_SI_ANDI = 361 -+INTR_SPU_SI_BG = 362 -+INTR_SPU_SI_BGX = 363 -+INTR_SPU_SI_CEQ = 364 -+INTR_SPU_SI_CEQB = 365 -+INTR_SPU_SI_CEQBI = 366 -+INTR_SPU_SI_CEQH = 367 -+INTR_SPU_SI_CEQHI = 368 -+INTR_SPU_SI_CEQI = 369 -+INTR_SPU_SI_CG = 370 -+INTR_SPU_SI_CGT = 371 -+INTR_SPU_SI_CGTB = 372 -+INTR_SPU_SI_CGTBI = 373 -+INTR_SPU_SI_CGTH = 374 -+INTR_SPU_SI_CGTHI = 375 -+INTR_SPU_SI_CGTI = 376 -+INTR_SPU_SI_CGX = 377 -+INTR_SPU_SI_CLGT = 378 -+INTR_SPU_SI_CLGTB = 379 -+INTR_SPU_SI_CLGTBI = 380 -+INTR_SPU_SI_CLGTH = 381 -+INTR_SPU_SI_CLGTHI = 382 -+INTR_SPU_SI_CLGTI = 383 -+INTR_SPU_SI_DFA = 384 -+INTR_SPU_SI_DFM = 385 -+INTR_SPU_SI_DFMA = 386 -+INTR_SPU_SI_DFMS = 387 -+INTR_SPU_SI_DFNMA = 388 -+INTR_SPU_SI_DFNMS = 389 -+INTR_SPU_SI_DFS = 390 -+INTR_SPU_SI_FA = 391 -+INTR_SPU_SI_FCEQ = 392 -+INTR_SPU_SI_FCGT = 393 -+INTR_SPU_SI_FCMEQ = 394 -+INTR_SPU_SI_FCMGT = 395 -+INTR_SPU_SI_FM = 396 -+INTR_SPU_SI_FMA = 397 -+INTR_SPU_SI_FMS = 398 -+INTR_SPU_SI_FNMS = 399 -+INTR_SPU_SI_FS = 400 -+INTR_SPU_SI_FSMBI = 401 -+INTR_SPU_SI_MPY = 402 -+INTR_SPU_SI_MPYA = 403 -+INTR_SPU_SI_MPYH = 404 -+INTR_SPU_SI_MPYHH = 405 -+INTR_SPU_SI_MPYHHA = 406 -+INTR_SPU_SI_MPYHHAU = 407 -+INTR_SPU_SI_MPYHHU = 408 -+INTR_SPU_SI_MPYI = 409 -+INTR_SPU_SI_MPYS = 410 -+INTR_SPU_SI_MPYU = 411 -+INTR_SPU_SI_MPYUI = 412 -+INTR_SPU_SI_NAND = 413 -+INTR_SPU_SI_NOR = 414 -+INTR_SPU_SI_OR = 415 -+INTR_SPU_SI_ORBI = 416 -+INTR_SPU_SI_ORC = 417 -+INTR_SPU_SI_ORHI = 418 -+INTR_SPU_SI_ORI = 419 -+INTR_SPU_SI_SF = 420 -+INTR_SPU_SI_SFH = 421 -+INTR_SPU_SI_SFHI = 422 -+INTR_SPU_SI_SFI = 423 -+INTR_SPU_SI_SFX = 424 -+INTR_SPU_SI_SHLI = 425 -+INTR_SPU_SI_SHLQBI = 426 -+INTR_SPU_SI_SHLQBII = 427 -+INTR_SPU_SI_SHLQBY = 428 -+INTR_SPU_SI_SHLQBYI = 429 -+INTR_SPU_SI_XOR = 430 -+INTR_SPU_SI_XORBI = 431 -+INTR_SPU_SI_XORHI = 432 -+INTR_SPU_SI_XORI = 433 -+INTR_SQRT = 434 -+INTR_SSUB_WITH_OVERFLOW = 435 -+INTR_STACKPROTECTOR = 436 -+INTR_STACKRESTORE = 437 -+INTR_STACKSAVE = 438 -+INTR_TRAP = 439 -+INTR_UADD_WITH_OVERFLOW = 440 -+INTR_UMUL_WITH_OVERFLOW = 441 -+INTR_USUB_WITH_OVERFLOW = 442 -+INTR_VACOPY = 443 -+INTR_VAEND = 444 -+INTR_VAR_ANNOTATION = 445 -+INTR_VASTART = 446 -+INTR_X86_AESNI_AESDEC = 447 -+INTR_X86_AESNI_AESDECLAST = 448 -+INTR_X86_AESNI_AESENC = 449 -+INTR_X86_AESNI_AESENCLAST = 450 -+INTR_X86_AESNI_AESIMC = 451 -+INTR_X86_AESNI_AESKEYGENASSIST = 452 -+INTR_X86_AVX_ADDSUB_PD_256 = 453 -+INTR_X86_AVX_ADDSUB_PS_256 = 454 -+INTR_X86_AVX_BLEND_PD_256 = 455 -+INTR_X86_AVX_BLEND_PS_256 = 456 -+INTR_X86_AVX_BLENDV_PD_256 = 457 -+INTR_X86_AVX_BLENDV_PS_256 = 458 -+INTR_X86_AVX_CMP_PD_256 = 459 -+INTR_X86_AVX_CMP_PS_256 = 460 -+INTR_X86_AVX_CVT_PD2_PS_256 = 461 -+INTR_X86_AVX_CVT_PD2DQ_256 = 462 -+INTR_X86_AVX_CVT_PS2_PD_256 = 463 -+INTR_X86_AVX_CVT_PS2DQ_256 = 464 -+INTR_X86_AVX_CVTDQ2_PD_256 = 465 -+INTR_X86_AVX_CVTDQ2_PS_256 = 466 -+INTR_X86_AVX_CVTT_PD2DQ_256 = 467 -+INTR_X86_AVX_CVTT_PS2DQ_256 = 468 -+INTR_X86_AVX_DP_PS_256 = 469 -+INTR_X86_AVX_HADD_PD_256 = 470 -+INTR_X86_AVX_HADD_PS_256 = 471 -+INTR_X86_AVX_HSUB_PD_256 = 472 -+INTR_X86_AVX_HSUB_PS_256 = 473 -+INTR_X86_AVX_LDU_DQ_256 = 474 -+INTR_X86_AVX_LOADU_DQ_256 = 475 -+INTR_X86_AVX_LOADU_PD_256 = 476 -+INTR_X86_AVX_LOADU_PS_256 = 477 -+INTR_X86_AVX_MASKLOAD_PD = 478 -+INTR_X86_AVX_MASKLOAD_PD_256 = 479 -+INTR_X86_AVX_MASKLOAD_PS = 480 -+INTR_X86_AVX_MASKLOAD_PS_256 = 481 -+INTR_X86_AVX_MASKSTORE_PD = 482 -+INTR_X86_AVX_MASKSTORE_PD_256 = 483 -+INTR_X86_AVX_MASKSTORE_PS = 484 -+INTR_X86_AVX_MASKSTORE_PS_256 = 485 -+INTR_X86_AVX_MAX_PD_256 = 486 -+INTR_X86_AVX_MAX_PS_256 = 487 -+INTR_X86_AVX_MIN_PD_256 = 488 -+INTR_X86_AVX_MIN_PS_256 = 489 -+INTR_X86_AVX_MOVMSK_PD_256 = 490 -+INTR_X86_AVX_MOVMSK_PS_256 = 491 -+INTR_X86_AVX_MOVNT_DQ_256 = 492 -+INTR_X86_AVX_MOVNT_PD_256 = 493 -+INTR_X86_AVX_MOVNT_PS_256 = 494 -+INTR_X86_AVX_PTESTC_256 = 495 -+INTR_X86_AVX_PTESTNZC_256 = 496 -+INTR_X86_AVX_PTESTZ_256 = 497 -+INTR_X86_AVX_RCP_PS_256 = 498 -+INTR_X86_AVX_ROUND_PD_256 = 499 -+INTR_X86_AVX_ROUND_PS_256 = 500 -+INTR_X86_AVX_RSQRT_PS_256 = 501 -+INTR_X86_AVX_SQRT_PD_256 = 502 -+INTR_X86_AVX_SQRT_PS_256 = 503 -+INTR_X86_AVX_STOREU_DQ_256 = 504 -+INTR_X86_AVX_STOREU_PD_256 = 505 -+INTR_X86_AVX_STOREU_PS_256 = 506 -+INTR_X86_AVX_VBROADCAST_SD_256 = 507 -+INTR_X86_AVX_VBROADCASTF128_PD_256 = 508 -+INTR_X86_AVX_VBROADCASTF128_PS_256 = 509 -+INTR_X86_AVX_VBROADCASTSS = 510 -+INTR_X86_AVX_VBROADCASTSS_256 = 511 -+INTR_X86_AVX_VEXTRACTF128_PD_256 = 512 -+INTR_X86_AVX_VEXTRACTF128_PS_256 = 513 -+INTR_X86_AVX_VEXTRACTF128_SI_256 = 514 -+INTR_X86_AVX_VINSERTF128_PD_256 = 515 -+INTR_X86_AVX_VINSERTF128_PS_256 = 516 -+INTR_X86_AVX_VINSERTF128_SI_256 = 517 -+INTR_X86_AVX_VPERM2F128_PD_256 = 518 -+INTR_X86_AVX_VPERM2F128_PS_256 = 519 -+INTR_X86_AVX_VPERM2F128_SI_256 = 520 -+INTR_X86_AVX_VPERMIL_PD = 521 -+INTR_X86_AVX_VPERMIL_PD_256 = 522 -+INTR_X86_AVX_VPERMIL_PS = 523 -+INTR_X86_AVX_VPERMIL_PS_256 = 524 -+INTR_X86_AVX_VPERMILVAR_PD = 525 -+INTR_X86_AVX_VPERMILVAR_PD_256 = 526 -+INTR_X86_AVX_VPERMILVAR_PS = 527 -+INTR_X86_AVX_VPERMILVAR_PS_256 = 528 -+INTR_X86_AVX_VTESTC_PD = 529 -+INTR_X86_AVX_VTESTC_PD_256 = 530 -+INTR_X86_AVX_VTESTC_PS = 531 -+INTR_X86_AVX_VTESTC_PS_256 = 532 -+INTR_X86_AVX_VTESTNZC_PD = 533 -+INTR_X86_AVX_VTESTNZC_PD_256 = 534 -+INTR_X86_AVX_VTESTNZC_PS = 535 -+INTR_X86_AVX_VTESTNZC_PS_256 = 536 -+INTR_X86_AVX_VTESTZ_PD = 537 -+INTR_X86_AVX_VTESTZ_PD_256 = 538 -+INTR_X86_AVX_VTESTZ_PS = 539 -+INTR_X86_AVX_VTESTZ_PS_256 = 540 -+INTR_X86_AVX_VZEROALL = 541 -+INTR_X86_AVX_VZEROUPPER = 542 -+INTR_X86_INT = 543 -+INTR_X86_MMX_EMMS = 544 -+INTR_X86_MMX_FEMMS = 545 -+INTR_X86_MMX_MASKMOVQ = 546 -+INTR_X86_MMX_MOVNT_DQ = 547 -+INTR_X86_MMX_PACKSSDW = 548 -+INTR_X86_MMX_PACKSSWB = 549 -+INTR_X86_MMX_PACKUSWB = 550 -+INTR_X86_MMX_PADD_B = 551 -+INTR_X86_MMX_PADD_D = 552 -+INTR_X86_MMX_PADD_Q = 553 -+INTR_X86_MMX_PADD_W = 554 -+INTR_X86_MMX_PADDS_B = 555 -+INTR_X86_MMX_PADDS_W = 556 -+INTR_X86_MMX_PADDUS_B = 557 -+INTR_X86_MMX_PADDUS_W = 558 -+INTR_X86_MMX_PALIGNR_B = 559 -+INTR_X86_MMX_PAND = 560 -+INTR_X86_MMX_PANDN = 561 -+INTR_X86_MMX_PAVG_B = 562 -+INTR_X86_MMX_PAVG_W = 563 -+INTR_X86_MMX_PCMPEQ_B = 564 -+INTR_X86_MMX_PCMPEQ_D = 565 -+INTR_X86_MMX_PCMPEQ_W = 566 -+INTR_X86_MMX_PCMPGT_B = 567 -+INTR_X86_MMX_PCMPGT_D = 568 -+INTR_X86_MMX_PCMPGT_W = 569 -+INTR_X86_MMX_PEXTR_W = 570 -+INTR_X86_MMX_PINSR_W = 571 -+INTR_X86_MMX_PMADD_WD = 572 -+INTR_X86_MMX_PMAXS_W = 573 -+INTR_X86_MMX_PMAXU_B = 574 -+INTR_X86_MMX_PMINS_W = 575 -+INTR_X86_MMX_PMINU_B = 576 -+INTR_X86_MMX_PMOVMSKB = 577 -+INTR_X86_MMX_PMULH_W = 578 -+INTR_X86_MMX_PMULHU_W = 579 -+INTR_X86_MMX_PMULL_W = 580 -+INTR_X86_MMX_PMULU_DQ = 581 -+INTR_X86_MMX_POR = 582 -+INTR_X86_MMX_PSAD_BW = 583 -+INTR_X86_MMX_PSLL_D = 584 -+INTR_X86_MMX_PSLL_Q = 585 -+INTR_X86_MMX_PSLL_W = 586 -+INTR_X86_MMX_PSLLI_D = 587 -+INTR_X86_MMX_PSLLI_Q = 588 -+INTR_X86_MMX_PSLLI_W = 589 -+INTR_X86_MMX_PSRA_D = 590 -+INTR_X86_MMX_PSRA_W = 591 -+INTR_X86_MMX_PSRAI_D = 592 -+INTR_X86_MMX_PSRAI_W = 593 -+INTR_X86_MMX_PSRL_D = 594 -+INTR_X86_MMX_PSRL_Q = 595 -+INTR_X86_MMX_PSRL_W = 596 -+INTR_X86_MMX_PSRLI_D = 597 -+INTR_X86_MMX_PSRLI_Q = 598 -+INTR_X86_MMX_PSRLI_W = 599 -+INTR_X86_MMX_PSUB_B = 600 -+INTR_X86_MMX_PSUB_D = 601 -+INTR_X86_MMX_PSUB_Q = 602 -+INTR_X86_MMX_PSUB_W = 603 -+INTR_X86_MMX_PSUBS_B = 604 -+INTR_X86_MMX_PSUBS_W = 605 -+INTR_X86_MMX_PSUBUS_B = 606 -+INTR_X86_MMX_PSUBUS_W = 607 -+INTR_X86_MMX_PUNPCKHBW = 608 -+INTR_X86_MMX_PUNPCKHDQ = 609 -+INTR_X86_MMX_PUNPCKHWD = 610 -+INTR_X86_MMX_PUNPCKLBW = 611 -+INTR_X86_MMX_PUNPCKLDQ = 612 -+INTR_X86_MMX_PUNPCKLWD = 613 -+INTR_X86_MMX_PXOR = 614 -+INTR_X86_SSE2_ADD_SD = 615 -+INTR_X86_SSE2_CLFLUSH = 616 -+INTR_X86_SSE2_CMP_PD = 617 -+INTR_X86_SSE2_CMP_SD = 618 -+INTR_X86_SSE2_COMIEQ_SD = 619 -+INTR_X86_SSE2_COMIGE_SD = 620 -+INTR_X86_SSE2_COMIGT_SD = 621 -+INTR_X86_SSE2_COMILE_SD = 622 -+INTR_X86_SSE2_COMILT_SD = 623 -+INTR_X86_SSE2_COMINEQ_SD = 624 -+INTR_X86_SSE2_CVTDQ2PD = 625 -+INTR_X86_SSE2_CVTDQ2PS = 626 -+INTR_X86_SSE2_CVTPD2DQ = 627 -+INTR_X86_SSE2_CVTPD2PS = 628 -+INTR_X86_SSE2_CVTPS2DQ = 629 -+INTR_X86_SSE2_CVTPS2PD = 630 -+INTR_X86_SSE2_CVTSD2SI = 631 -+INTR_X86_SSE2_CVTSD2SI64 = 632 -+INTR_X86_SSE2_CVTSD2SS = 633 -+INTR_X86_SSE2_CVTSI2SD = 634 -+INTR_X86_SSE2_CVTSI642SD = 635 -+INTR_X86_SSE2_CVTSS2SD = 636 -+INTR_X86_SSE2_CVTTPD2DQ = 637 -+INTR_X86_SSE2_CVTTPS2DQ = 638 -+INTR_X86_SSE2_CVTTSD2SI = 639 -+INTR_X86_SSE2_CVTTSD2SI64 = 640 -+INTR_X86_SSE2_DIV_SD = 641 -+INTR_X86_SSE2_LFENCE = 642 -+INTR_X86_SSE2_LOADU_DQ = 643 -+INTR_X86_SSE2_LOADU_PD = 644 -+INTR_X86_SSE2_MASKMOV_DQU = 645 -+INTR_X86_SSE2_MAX_PD = 646 -+INTR_X86_SSE2_MAX_SD = 647 -+INTR_X86_SSE2_MFENCE = 648 -+INTR_X86_SSE2_MIN_PD = 649 -+INTR_X86_SSE2_MIN_SD = 650 -+INTR_X86_SSE2_MOVMSK_PD = 651 -+INTR_X86_SSE2_MOVNT_DQ = 652 -+INTR_X86_SSE2_MOVNT_I = 653 -+INTR_X86_SSE2_MOVNT_PD = 654 -+INTR_X86_SSE2_MUL_SD = 655 -+INTR_X86_SSE2_PACKSSDW_128 = 656 -+INTR_X86_SSE2_PACKSSWB_128 = 657 -+INTR_X86_SSE2_PACKUSWB_128 = 658 -+INTR_X86_SSE2_PADDS_B = 659 -+INTR_X86_SSE2_PADDS_W = 660 -+INTR_X86_SSE2_PADDUS_B = 661 -+INTR_X86_SSE2_PADDUS_W = 662 -+INTR_X86_SSE2_PAVG_B = 663 -+INTR_X86_SSE2_PAVG_W = 664 -+INTR_X86_SSE2_PCMPEQ_B = 665 -+INTR_X86_SSE2_PCMPEQ_D = 666 -+INTR_X86_SSE2_PCMPEQ_W = 667 -+INTR_X86_SSE2_PCMPGT_B = 668 -+INTR_X86_SSE2_PCMPGT_D = 669 -+INTR_X86_SSE2_PCMPGT_W = 670 -+INTR_X86_SSE2_PMADD_WD = 671 -+INTR_X86_SSE2_PMAXS_W = 672 -+INTR_X86_SSE2_PMAXU_B = 673 -+INTR_X86_SSE2_PMINS_W = 674 -+INTR_X86_SSE2_PMINU_B = 675 -+INTR_X86_SSE2_PMOVMSKB_128 = 676 -+INTR_X86_SSE2_PMULH_W = 677 -+INTR_X86_SSE2_PMULHU_W = 678 -+INTR_X86_SSE2_PMULU_DQ = 679 -+INTR_X86_SSE2_PSAD_BW = 680 -+INTR_X86_SSE2_PSLL_D = 681 -+INTR_X86_SSE2_PSLL_DQ = 682 -+INTR_X86_SSE2_PSLL_DQ_BS = 683 -+INTR_X86_SSE2_PSLL_Q = 684 -+INTR_X86_SSE2_PSLL_W = 685 -+INTR_X86_SSE2_PSLLI_D = 686 -+INTR_X86_SSE2_PSLLI_Q = 687 -+INTR_X86_SSE2_PSLLI_W = 688 -+INTR_X86_SSE2_PSRA_D = 689 -+INTR_X86_SSE2_PSRA_W = 690 -+INTR_X86_SSE2_PSRAI_D = 691 -+INTR_X86_SSE2_PSRAI_W = 692 -+INTR_X86_SSE2_PSRL_D = 693 -+INTR_X86_SSE2_PSRL_DQ = 694 -+INTR_X86_SSE2_PSRL_DQ_BS = 695 -+INTR_X86_SSE2_PSRL_Q = 696 -+INTR_X86_SSE2_PSRL_W = 697 -+INTR_X86_SSE2_PSRLI_D = 698 -+INTR_X86_SSE2_PSRLI_Q = 699 -+INTR_X86_SSE2_PSRLI_W = 700 -+INTR_X86_SSE2_PSUBS_B = 701 -+INTR_X86_SSE2_PSUBS_W = 702 -+INTR_X86_SSE2_PSUBUS_B = 703 -+INTR_X86_SSE2_PSUBUS_W = 704 -+INTR_X86_SSE2_SQRT_PD = 705 -+INTR_X86_SSE2_SQRT_SD = 706 -+INTR_X86_SSE2_STOREL_DQ = 707 -+INTR_X86_SSE2_STOREU_DQ = 708 -+INTR_X86_SSE2_STOREU_PD = 709 -+INTR_X86_SSE2_SUB_SD = 710 -+INTR_X86_SSE2_UCOMIEQ_SD = 711 -+INTR_X86_SSE2_UCOMIGE_SD = 712 -+INTR_X86_SSE2_UCOMIGT_SD = 713 -+INTR_X86_SSE2_UCOMILE_SD = 714 -+INTR_X86_SSE2_UCOMILT_SD = 715 -+INTR_X86_SSE2_UCOMINEQ_SD = 716 -+INTR_X86_SSE3_ADDSUB_PD = 717 -+INTR_X86_SSE3_ADDSUB_PS = 718 -+INTR_X86_SSE3_HADD_PD = 719 -+INTR_X86_SSE3_HADD_PS = 720 -+INTR_X86_SSE3_HSUB_PD = 721 -+INTR_X86_SSE3_HSUB_PS = 722 -+INTR_X86_SSE3_LDU_DQ = 723 -+INTR_X86_SSE3_MONITOR = 724 -+INTR_X86_SSE3_MWAIT = 725 -+INTR_X86_SSE41_BLENDPD = 726 -+INTR_X86_SSE41_BLENDPS = 727 -+INTR_X86_SSE41_BLENDVPD = 728 -+INTR_X86_SSE41_BLENDVPS = 729 -+INTR_X86_SSE41_DPPD = 730 -+INTR_X86_SSE41_DPPS = 731 -+INTR_X86_SSE41_EXTRACTPS = 732 -+INTR_X86_SSE41_INSERTPS = 733 -+INTR_X86_SSE41_MOVNTDQA = 734 -+INTR_X86_SSE41_MPSADBW = 735 -+INTR_X86_SSE41_PACKUSDW = 736 -+INTR_X86_SSE41_PBLENDVB = 737 -+INTR_X86_SSE41_PBLENDW = 738 -+INTR_X86_SSE41_PCMPEQQ = 739 -+INTR_X86_SSE41_PEXTRB = 740 -+INTR_X86_SSE41_PEXTRD = 741 -+INTR_X86_SSE41_PEXTRQ = 742 -+INTR_X86_SSE41_PHMINPOSUW = 743 -+INTR_X86_SSE41_PMAXSB = 744 -+INTR_X86_SSE41_PMAXSD = 745 -+INTR_X86_SSE41_PMAXUD = 746 -+INTR_X86_SSE41_PMAXUW = 747 -+INTR_X86_SSE41_PMINSB = 748 -+INTR_X86_SSE41_PMINSD = 749 -+INTR_X86_SSE41_PMINUD = 750 -+INTR_X86_SSE41_PMINUW = 751 -+INTR_X86_SSE41_PMOVSXBD = 752 -+INTR_X86_SSE41_PMOVSXBQ = 753 -+INTR_X86_SSE41_PMOVSXBW = 754 -+INTR_X86_SSE41_PMOVSXDQ = 755 -+INTR_X86_SSE41_PMOVSXWD = 756 -+INTR_X86_SSE41_PMOVSXWQ = 757 -+INTR_X86_SSE41_PMOVZXBD = 758 -+INTR_X86_SSE41_PMOVZXBQ = 759 -+INTR_X86_SSE41_PMOVZXBW = 760 -+INTR_X86_SSE41_PMOVZXDQ = 761 -+INTR_X86_SSE41_PMOVZXWD = 762 -+INTR_X86_SSE41_PMOVZXWQ = 763 -+INTR_X86_SSE41_PMULDQ = 764 -+INTR_X86_SSE41_PTESTC = 765 -+INTR_X86_SSE41_PTESTNZC = 766 -+INTR_X86_SSE41_PTESTZ = 767 -+INTR_X86_SSE41_ROUND_PD = 768 -+INTR_X86_SSE41_ROUND_PS = 769 -+INTR_X86_SSE41_ROUND_SD = 770 -+INTR_X86_SSE41_ROUND_SS = 771 -+INTR_X86_SSE42_CRC32_16 = 772 -+INTR_X86_SSE42_CRC32_32 = 773 -+INTR_X86_SSE42_CRC32_8 = 774 -+INTR_X86_SSE42_CRC64_64 = 775 -+INTR_X86_SSE42_CRC64_8 = 776 -+INTR_X86_SSE42_PCMPESTRI128 = 777 -+INTR_X86_SSE42_PCMPESTRIA128 = 778 -+INTR_X86_SSE42_PCMPESTRIC128 = 779 -+INTR_X86_SSE42_PCMPESTRIO128 = 780 -+INTR_X86_SSE42_PCMPESTRIS128 = 781 -+INTR_X86_SSE42_PCMPESTRIZ128 = 782 -+INTR_X86_SSE42_PCMPESTRM128 = 783 -+INTR_X86_SSE42_PCMPGTQ = 784 -+INTR_X86_SSE42_PCMPISTRI128 = 785 -+INTR_X86_SSE42_PCMPISTRIA128 = 786 -+INTR_X86_SSE42_PCMPISTRIC128 = 787 -+INTR_X86_SSE42_PCMPISTRIO128 = 788 -+INTR_X86_SSE42_PCMPISTRIS128 = 789 -+INTR_X86_SSE42_PCMPISTRIZ128 = 790 -+INTR_X86_SSE42_PCMPISTRM128 = 791 -+INTR_X86_SSE_ADD_SS = 792 -+INTR_X86_SSE_CMP_PS = 793 -+INTR_X86_SSE_CMP_SS = 794 -+INTR_X86_SSE_COMIEQ_SS = 795 -+INTR_X86_SSE_COMIGE_SS = 796 -+INTR_X86_SSE_COMIGT_SS = 797 -+INTR_X86_SSE_COMILE_SS = 798 -+INTR_X86_SSE_COMILT_SS = 799 -+INTR_X86_SSE_COMINEQ_SS = 800 -+INTR_X86_SSE_CVTPD2PI = 801 -+INTR_X86_SSE_CVTPI2PD = 802 -+INTR_X86_SSE_CVTPI2PS = 803 -+INTR_X86_SSE_CVTPS2PI = 804 -+INTR_X86_SSE_CVTSI2SS = 805 -+INTR_X86_SSE_CVTSI642SS = 806 -+INTR_X86_SSE_CVTSS2SI = 807 -+INTR_X86_SSE_CVTSS2SI64 = 808 -+INTR_X86_SSE_CVTTPD2PI = 809 -+INTR_X86_SSE_CVTTPS2PI = 810 -+INTR_X86_SSE_CVTTSS2SI = 811 -+INTR_X86_SSE_CVTTSS2SI64 = 812 -+INTR_X86_SSE_DIV_SS = 813 -+INTR_X86_SSE_LDMXCSR = 814 -+INTR_X86_SSE_LOADU_PS = 815 -+INTR_X86_SSE_MAX_PS = 816 -+INTR_X86_SSE_MAX_SS = 817 -+INTR_X86_SSE_MIN_PS = 818 -+INTR_X86_SSE_MIN_SS = 819 -+INTR_X86_SSE_MOVMSK_PS = 820 -+INTR_X86_SSE_MOVNT_PS = 821 -+INTR_X86_SSE_MUL_SS = 822 -+INTR_X86_SSE_PSHUF_W = 823 -+INTR_X86_SSE_RCP_PS = 824 -+INTR_X86_SSE_RCP_SS = 825 -+INTR_X86_SSE_RSQRT_PS = 826 -+INTR_X86_SSE_RSQRT_SS = 827 -+INTR_X86_SSE_SFENCE = 828 -+INTR_X86_SSE_SQRT_PS = 829 -+INTR_X86_SSE_SQRT_SS = 830 -+INTR_X86_SSE_STMXCSR = 831 -+INTR_X86_SSE_STOREU_PS = 832 -+INTR_X86_SSE_SUB_SS = 833 -+INTR_X86_SSE_UCOMIEQ_SS = 834 -+INTR_X86_SSE_UCOMIGE_SS = 835 -+INTR_X86_SSE_UCOMIGT_SS = 836 -+INTR_X86_SSE_UCOMILE_SS = 837 -+INTR_X86_SSE_UCOMILT_SS = 838 -+INTR_X86_SSE_UCOMINEQ_SS = 839 -+INTR_X86_SSSE3_PABS_B = 840 -+INTR_X86_SSSE3_PABS_B_128 = 841 -+INTR_X86_SSSE3_PABS_D = 842 -+INTR_X86_SSSE3_PABS_D_128 = 843 -+INTR_X86_SSSE3_PABS_W = 844 -+INTR_X86_SSSE3_PABS_W_128 = 845 -+INTR_X86_SSSE3_PHADD_D = 846 -+INTR_X86_SSSE3_PHADD_D_128 = 847 -+INTR_X86_SSSE3_PHADD_SW = 848 -+INTR_X86_SSSE3_PHADD_SW_128 = 849 -+INTR_X86_SSSE3_PHADD_W = 850 -+INTR_X86_SSSE3_PHADD_W_128 = 851 -+INTR_X86_SSSE3_PHSUB_D = 852 -+INTR_X86_SSSE3_PHSUB_D_128 = 853 -+INTR_X86_SSSE3_PHSUB_SW = 854 -+INTR_X86_SSSE3_PHSUB_SW_128 = 855 -+INTR_X86_SSSE3_PHSUB_W = 856 -+INTR_X86_SSSE3_PHSUB_W_128 = 857 -+INTR_X86_SSSE3_PMADD_UB_SW = 858 -+INTR_X86_SSSE3_PMADD_UB_SW_128 = 859 -+INTR_X86_SSSE3_PMUL_HR_SW = 860 -+INTR_X86_SSSE3_PMUL_HR_SW_128 = 861 -+INTR_X86_SSSE3_PSHUF_B = 862 -+INTR_X86_SSSE3_PSHUF_B_128 = 863 -+INTR_X86_SSSE3_PSIGN_B = 864 -+INTR_X86_SSSE3_PSIGN_B_128 = 865 -+INTR_X86_SSSE3_PSIGN_D = 866 -+INTR_X86_SSSE3_PSIGN_D_128 = 867 -+INTR_X86_SSSE3_PSIGN_W = 868 -+INTR_X86_SSSE3_PSIGN_W_128 = 869 -+INTR_XCORE_BITREV = 870 -+INTR_XCORE_CHKCT = 871 -+INTR_XCORE_CLRE = 872 -+INTR_XCORE_EEU = 873 -+INTR_XCORE_FREER = 874 -+INTR_XCORE_GETID = 875 -+INTR_XCORE_GETR = 876 -+INTR_XCORE_GETTS = 877 -+INTR_XCORE_IN = 878 -+INTR_XCORE_INCT = 879 -+INTR_XCORE_INSHR = 880 -+INTR_XCORE_INT = 881 -+INTR_XCORE_OUT = 882 -+INTR_XCORE_OUTCT = 883 -+INTR_XCORE_OUTSHR = 884 -+INTR_XCORE_OUTT = 885 -+INTR_XCORE_SETC = 886 -+INTR_XCORE_SETD = 887 -+INTR_XCORE_SETPT = 888 -+INTR_XCORE_SETTW = 889 -+INTR_XCORE_SETV = 890 -+INTR_XCORE_SYNCR = 891 -+INTR_XCORE_WAITEVENT = 892 -Index: _core.c -=================================================================== ---- _core.c (revision 105) -+++ _core.c (working copy) -@@ -807,7 +807,7 @@ - _wrap_pass( EdgeProfiler ) - _wrap_pass( FunctionAttrs ) - _wrap_pass( FunctionInlining ) --_wrap_pass( GEPSplitter ) -+//_wrap_pass( GEPSplitter ) - _wrap_pass( GlobalDCE ) - _wrap_pass( GlobalOptimizer ) - _wrap_pass( GlobalsModRef ) -@@ -822,11 +822,11 @@ - _wrap_pass( LazyValueInfo ) - _wrap_pass( LCSSA ) - _wrap_pass( LICM ) --_wrap_pass( LiveValues ) -+//_wrap_pass( LiveValues ) - _wrap_pass( LoopDeletion ) - _wrap_pass( LoopDependenceAnalysis ) - _wrap_pass( LoopExtractor ) --_wrap_pass( LoopIndexSplit ) -+//_wrap_pass( LoopIndexSplit ) - _wrap_pass( LoopRotate ) - _wrap_pass( LoopSimplify ) - _wrap_pass( LoopStrengthReduce ) -@@ -841,7 +841,7 @@ - _wrap_pass( NoProfileInfo ) - _wrap_pass( OptimalEdgeProfiler ) - _wrap_pass( PartialInlining ) --_wrap_pass( PartialSpecialization ) -+//_wrap_pass( PartialSpecialization ) - _wrap_pass( PostDomOnlyPrinter ) - _wrap_pass( PostDomOnlyViewer ) - _wrap_pass( PostDomPrinter ) -@@ -855,7 +855,7 @@ - _wrap_pass( ScalarEvolutionAliasAnalysis ) - _wrap_pass( ScalarReplAggregates ) - _wrap_pass( SCCP ) --_wrap_pass( SimplifyHalfPowrLibCalls ) -+//_wrap_pass( SimplifyHalfPowrLibCalls ) - _wrap_pass( SimplifyLibCalls ) - _wrap_pass( SingleLoopExtractor ) - _wrap_pass( StripDeadPrototypes ) -@@ -1162,7 +1162,7 @@ - Py_RETURN_NONE; - } - --_wrap_obj2obj(LLVMInlineFunction, LLVMValueRef, int) -+//_wrap_obj2obj(LLVMInlineFunction, LLVMValueRef, int) - - /* Expose the void* inside a PyCObject as a PyLong. This allows us to - * use it as a unique ID. */ -@@ -1569,7 +1569,7 @@ - _pass( EdgeProfiler ) - _pass( FunctionAttrs ) - _pass( FunctionInlining ) -- _pass( GEPSplitter ) -+ //_pass( GEPSplitter ) - _pass( GlobalDCE ) - _pass( GlobalOptimizer ) - _pass( GlobalsModRef ) -@@ -1584,11 +1584,11 @@ - _pass( LazyValueInfo ) - _pass( LCSSA ) - _pass( LICM ) -- _pass( LiveValues ) -+ //_pass( LiveValues ) - _pass( LoopDeletion ) - _pass( LoopDependenceAnalysis ) - _pass( LoopExtractor ) -- _pass( LoopIndexSplit ) -+ //_pass( LoopIndexSplit ) - _pass( LoopRotate ) - _pass( LoopSimplify ) - _pass( LoopStrengthReduce ) -@@ -1603,7 +1603,7 @@ - _pass( NoProfileInfo ) - _pass( OptimalEdgeProfiler ) - _pass( PartialInlining ) -- _pass( PartialSpecialization ) -+ //_pass( PartialSpecialization ) - _pass( PostDomOnlyPrinter ) - _pass( PostDomOnlyViewer ) - _pass( PostDomPrinter ) -@@ -1617,7 +1617,7 @@ - _pass( ScalarEvolutionAliasAnalysis ) - _pass( ScalarReplAggregates ) - _pass( SCCP ) -- _pass( SimplifyHalfPowrLibCalls ) -+ //_pass( SimplifyHalfPowrLibCalls ) - _pass( SimplifyLibCalls ) - _pass( SingleLoopExtractor ) - _pass( StripDeadPrototypes ) -@@ -1672,7 +1672,7 @@ - /* Misc */ - _method( LLVMGetIntrinsic ) - _method( LLVMLoadLibraryPermanently ) -- _method( LLVMInlineFunction ) -+ //_method( LLVMInlineFunction ) - _method( PyCObjectVoidPtrToPyLong ) - - { NULL } -Index: extra.h -=================================================================== ---- extra.h (revision 105) -+++ extra.h (working copy) -@@ -181,7 +181,7 @@ - /* Wraps llvm::InlineFunction(). Inlines a function. C is the call - * instruction, created by LLVMBuildCall. Even if it fails, the Function - * containing the call is still in a proper state (not changed). */ --int LLVMInlineFunction(LLVMValueRef call); -+//int LLVMInlineFunction(LLVMValueRef call); - - /* Wraps llvm::getAlignmentFromAttrs from Attributes.h. Compliments the - * already available LLVMSetParamAlignment(). */ -@@ -209,13 +209,13 @@ - declare_pass( DomPrinter ) - declare_pass( DomViewer ) - declare_pass( EdgeProfiler ) --declare_pass( GEPSplitter ) -+//declare_pass( GEPSplitter ) - declare_pass( GlobalsModRef ) - declare_pass( InstCount ) - declare_pass( InstructionNamer ) - declare_pass( LazyValueInfo ) - declare_pass( LCSSA ) --declare_pass( LiveValues ) -+//declare_pass( LiveValues ) - declare_pass( LoopDependenceAnalysis ) - declare_pass( LoopExtractor ) - declare_pass( LoopSimplify ) -@@ -227,7 +227,7 @@ - declare_pass( NoProfileInfo ) - declare_pass( OptimalEdgeProfiler ) - declare_pass( PartialInlining ) --declare_pass( PartialSpecialization ) -+//declare_pass( PartialSpecialization ) - declare_pass( PostDomOnlyPrinter ) - declare_pass( PostDomOnlyViewer ) - declare_pass( PostDomPrinter ) diff --git a/llvm/__init__.py b/llvm/__init__.py index 9128c70..9b24112 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -1,149 +1,47 @@ -# -# Copyright (c) 2008-10, Mahadevan R All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of this software, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -"""Common classes related to LLVM. - -""" - -VERSION = '0.7' - -from weakref import WeakValueDictionary +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions -#===----------------------------------------------------------------------=== -# Exceptions -#===----------------------------------------------------------------------=== +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 + + @property + def _ptr(self): + try: + return self.__ptr + except AttributeError: + raise AttributeError("_ptr resource has been removed") + + @_ptr.deleter + def _ptr(self): + del self.__ptr + + +def _extract_ptrs(objs): + return [(x._ptr if x is not None else None) + for x in objs] class LLVMException(Exception): - """Generic LLVM exception.""" - - def __init__(self, msg=""): - Exception.__init__(self, msg) - - -#===----------------------------------------------------------------------=== -# Ownables -#===----------------------------------------------------------------------=== - -class Ownable(object): - """Objects that can be owned. - - Modules and Module Providers can be owned, i.e., the responsibility of - destruction of ownable objects can be handed over to other objects. The - llvm.Ownable class represents objects that can be so owned. This class - is NOT intended for public use. - """ - - def __init__(self, ptr, del_fn): - self.ptr = ptr - self.owner = None - self.del_fn = del_fn - - def _own(self, owner): - if self.owner: - raise LLVMException("object already owned") - self.owner = owner - - def _disown(self): - if not self.owner: - raise LLVMException("not owned") - self.owner = None - - def __del__(self): - if not self.owner: - self.del_fn(self.ptr) - - -#===----------------------------------------------------------------------=== -# Dummy owner, will not delete ownee. Be careful. -#===----------------------------------------------------------------------=== - -class DummyOwner(object): pass +def test(verbosity=3, run_isolated=True): + """test(verbosity=1) -> TextTestResult -#===----------------------------------------------------------------------=== -# A metaclass to prevent aliasing. It stores a (weak) reference to objects -# constructed based on a PyCObject. If an object is constructed based on a -# PyCObject with the same underlying pointer as a previous object, a reference -# to the previous object is returned rather than a new one. -#===----------------------------------------------------------------------=== + Run self-test, and return the number of failures + errors + """ + from llvm.tests import run -class _ObjectCache(type): - """A metaclass to prevent aliasing. - - Classes using 'ObjectCache' as a metaclass must have constructors - that take a PyCObject as their first argument. When the class is - called (to create a new instance of the class), the value of the - pointer wrapped by the PyCObj is checked: - - If no previous object has been created based on the same - underlying pointer (note that different PyCObject objects can - wrap the same pointer), the object will be initialized as - usual and returned. - - If a previous has been created based on the same pointer, - then a reference to that object will be returned, and no - object initialization is performed. - """ - - __instances = WeakValueDictionary() - - def __call__(cls, ptr, *args, **kwargs): - objid = _core.PyCObjectVoidPtrToPyLong(ptr) - key = "%s:%d" % (cls.__name__, objid) - obj = _ObjectCache.__instances.get(key) - if obj is None: - obj = super(_ObjectCache, cls).__call__(ptr, *args, **kwargs) - _ObjectCache.__instances[key] = obj - return obj - - @staticmethod - def forget(obj): - objid = _core.PyCObjectVoidPtrToPyLong(obj.ptr) - if objid in _ObjectCache.__instances: - del _ObjectCache.__instances[objid] - - -#===----------------------------------------------------------------------=== -# Cacheables -#===----------------------------------------------------------------------=== - -class Cacheable(object): - __metaclass__ = _ObjectCache - """Objects that can be cached. - - Objects that wrap a PyCObject are cached to avoid "aliasing", i.e., - two Python objects each containing a PyCObject which internally points - to the same C pointer.""" - - def forget(self): - _ObjectCache.forget(self) + result = run(verbosity=verbosity, run_isolated=run_isolated) + errct = len(result.failures) + len(result.errors) + return errct diff --git a/llvm/_core.c b/llvm/_core.c deleted file mode 100644 index f9e76fe..0000000 --- a/llvm/_core.c +++ /dev/null @@ -1,1840 +0,0 @@ -/* - * Copyright (c) 2008-10, Mahadevan R All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of this software, nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* our includes */ -#include "wrap.h" -#include "extra.h" - - - -// Python include -#include "Python.h" - -/* LLVM includes */ -#include "llvm-c/Analysis.h" -#include "llvm-c/Transforms/Scalar.h" -#include "llvm-c/ExecutionEngine.h" -#include "llvm-c/Target.h" -#include "llvm-c/Transforms/IPO.h" - -/* libc includes */ -#include /* for malloc(), free() */ - -/* Compatibility with Python 2.4: Py_ssize_t is not available. */ -#ifndef PY_SSIZE_T_MAX -typedef int Py_ssize_t; -#endif - -/* Project-wide setting */ -#if (PY_MAJOR_VERSION >= 3) -#define LLVM_PY_USE_PYCAPSULE -#endif - -/*===----------------------------------------------------------------------===*/ -/* Modules */ -/*===----------------------------------------------------------------------===*/ - -static PyObject * -_wLLVMModuleCreateWithName(PyObject *self, PyObject *args) -{ - const char *s; - LLVMModuleRef module; - -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *s_; - if (!PyArg_ParseTuple(args, "U:LLVMModuleCreateWithName", &s_)) { - return NULL; - } - - s = PyUnicode_AS_DATA(s_); -#else - if (!PyArg_ParseTuple(args, "s", &s)) - return NULL; -#endif - - module = LLVMModuleCreateWithName(s); - return ctor_LLVMModuleRef(module); -} - -_wrap_obj2str(LLVMGetDataLayout, LLVMModuleRef) -_wrap_objstr2none(LLVMSetDataLayout, LLVMModuleRef) -_wrap_obj2str(LLVMGetTarget, LLVMModuleRef) -_wrap_objstr2none(LLVMSetTarget, LLVMModuleRef) -_wrap_objstr2none(LLVMModuleAddLibrary, LLVMModuleRef) -_wrap_objstr2obj(LLVMGetTypeByName, LLVMModuleRef, LLVMTypeRef) -_wrap_obj2none(LLVMDumpModule, LLVMModuleRef) -_wrap_obj2none(LLVMDisposeModule, LLVMModuleRef) -_wrap_dumper(LLVMDumpModuleToString, LLVMModuleRef) -_wrap_obj2obj(LLVMModuleGetPointerSize, LLVMModuleRef, int) -_wrap_objstrobj2obj(LLVMModuleGetOrInsertFunction, LLVMModuleRef, - LLVMTypeRef, LLVMValueRef) - -static PyObject * -_wLLVMVerifyModule(PyObject *self, PyObject *args) -{ - char *outmsg; - PyObject *ret; - LLVMModuleRef m; - - if (!(m = (LLVMModuleRef)get_object_arg(args))) - return NULL; - - outmsg = 0; - (void) LLVMVerifyModule(m, LLVMReturnStatusAction, &outmsg); - - if (outmsg) { - ret = PyBytes_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } else { - ret = PyBytes_FromString(""); - } - - return ret; -} - -typedef LLVMModuleRef (*asm_or_bc_fn_t)(const char *A, unsigned Len, - char **OutMessage); - -static PyObject * -_get_asm_or_bc(asm_or_bc_fn_t fn, PyObject *self, PyObject *args) -{ - PyObject *obj, *ret; - Py_ssize_t len; - char *start, *outmsg; - LLVMModuleRef m; - - if (!PyArg_ParseTuple(args, "O", &obj)) - return NULL; - - start = PyBytes_AsString(obj); - len = PyBytes_Size(obj); - - outmsg = 0; - m = fn(start, len, &outmsg); - if (!m) { - if (outmsg) { - ret = PyBytes_FromString(outmsg); - LLVMDisposeMessage(outmsg); - return ret; - } else { - Py_RETURN_NONE; - } - } - - return ctor_LLVMModuleRef(m); -} - -static PyObject * -_wLLVMGetModuleFromAssembly(PyObject *self, PyObject *args) -{ - return _get_asm_or_bc(LLVMGetModuleFromAssembly, self, args); -} - -static PyObject * -_wLLVMGetModuleFromBitcode(PyObject *self, PyObject *args) -{ - return _get_asm_or_bc(LLVMGetModuleFromBitcode, self, args); -} - -static PyObject * -_wLLVMGetBitcodeFromModule(PyObject *self, PyObject *args) -{ - PyObject *ret; - unsigned len; - unsigned char *bytes; - LLVMModuleRef m; - - if (!(m = (LLVMModuleRef)get_object_arg(args))) - return NULL; - - if (!(bytes = LLVMGetBitcodeFromModule(m, &len))) - Py_RETURN_NONE; - - ret = PyBytes_FromStringAndSize((char *)bytes, (Py_ssize_t)len); - LLVMDisposeMessage((char *)bytes); - return ret; -} - -static PyObject * -_wLLVMLinkModules(PyObject *self, PyObject *args) -{ - PyObject *dest_obj, *src_obj, *ret; - LLVMModuleRef dest, src; - char *errmsg; - unsigned int mode = 0; - - if (!PyArg_ParseTuple(args, "OO|I", &dest_obj, &src_obj, &mode)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - dest = (LLVMModuleRef) PyCapsule_GetPointer(dest_obj, NULL); - src = (LLVMModuleRef) PyCapsule_GetPointer(src_obj, NULL); -#else - dest = (LLVMModuleRef) PyCObject_AsVoidPtr(dest_obj); - src = (LLVMModuleRef) PyCObject_AsVoidPtr(src_obj); -#endif - - if (!LLVMLinkModules(dest, src, mode, &errmsg)) { - if (errmsg) { - ret = PyBytes_FromString(errmsg); - LLVMDisposeMessage(errmsg); - } else { - ret = PyBytes_FromString("Link error"); - } - return ret; - } - - /* note: success => None, failure => string with error message */ - Py_RETURN_NONE; -} - -/*===----------------------------------------------------------------------===*/ -/* Types */ -/*===----------------------------------------------------------------------===*/ - -/*===-- General ----------------------------------------------------------===*/ - -_wrap_obj2obj(LLVMGetTypeKind, LLVMTypeRef, int) -_wrap_dumper(LLVMDumpTypeToString, LLVMTypeRef) - -/*===-- Integer types ----------------------------------------------------===*/ - -_wrap_none2obj(LLVMInt1Type, LLVMTypeRef) -_wrap_none2obj(LLVMInt8Type, LLVMTypeRef) -_wrap_none2obj(LLVMInt16Type, LLVMTypeRef) -_wrap_none2obj(LLVMInt32Type, LLVMTypeRef) -_wrap_none2obj(LLVMInt64Type, LLVMTypeRef) -_wrap_int2obj(LLVMIntType, LLVMTypeRef) -_wrap_obj2obj(LLVMGetIntTypeWidth, LLVMTypeRef, int) - -/*===-- Floating-point types ---------------------------------------------===*/ - -_wrap_none2obj(LLVMFloatType, LLVMTypeRef) -_wrap_none2obj(LLVMDoubleType, LLVMTypeRef) -_wrap_none2obj(LLVMX86FP80Type, LLVMTypeRef) -_wrap_none2obj(LLVMFP128Type, LLVMTypeRef) -_wrap_none2obj(LLVMPPCFP128Type, LLVMTypeRef) - -/*===-- Function types ---------------------------------------------------===*/ - -_wrap_objlistint2obj(LLVMFunctionType, LLVMTypeRef, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMIsFunctionVarArg, LLVMTypeRef, int) -_wrap_obj2obj(LLVMGetReturnType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMCountParamTypes, LLVMTypeRef, int) - -/* The LLVMGetParamTypes and LLVMGetStructElementTypes functions both - * have the same signatures. The following implementation takes advantage - * of this. - */ - -typedef void (*obj2arr_fn_t)(LLVMTypeRef ty, LLVMTypeRef *outv); -typedef unsigned (*arrcnt_fn_t)(LLVMTypeRef ty); - -static PyObject * -obj2arr(PyObject *self, PyObject *args, arrcnt_fn_t cntfunc, obj2arr_fn_t arrfunc) -{ - LLVMTypeRef type, *param_types; - unsigned param_count; - PyObject *list; - - /* get the function object ptr */ - if (!(type = (LLVMTypeRef)get_object_arg(args))) - return NULL; - - /* get param count */ - param_count = cntfunc(type); - - /* alloc enough space for all of them */ - if (!(param_types = (LLVMTypeRef *)malloc(sizeof(LLVMTypeRef) * param_count))) - return PyErr_NoMemory(); - - /* call LLVM func */ - arrfunc(type, param_types); - - /* create a list from the array */ - list = make_list_from_LLVMTypeRef_array(param_types, param_count); - - /* free temp storage */ - free(param_types); - - return list; -} - -static PyObject * -_wLLVMGetFunctionTypeParams(PyObject *self, PyObject *args) -{ - return obj2arr(self, args, LLVMCountParamTypes, LLVMGetParamTypes); -} - -/*===-- Struct types -----------------------------------------------------===*/ - -_wrap_listint2obj(LLVMStructType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMCountStructElementTypes, LLVMTypeRef, int) - -/* -static PyObject * -_wLLVMGetStructElementTypes(PyObject *self, PyObject *args) -{ - return obj2arr(self, args, LLVMCountStructElementTypes, LLVMGetStructElementTypes); -} -*/ - -_wrap_obj2obj(LLVMIsPackedStruct, LLVMTypeRef, int) - -/*===-- Array types ------------------------------------------------------===*/ - -_wrap_objint2obj(LLVMArrayType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMGetElementType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMGetArrayLength, LLVMTypeRef, int) - -/*===-- Pointer types ----------------------------------------------------===*/ - -_wrap_objint2obj(LLVMPointerType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMGetPointerAddressSpace, LLVMTypeRef, int) - -/*===-- Vector type ------------------------------------------------------===*/ - -_wrap_objint2obj(LLVMVectorType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMGetVectorSize, LLVMTypeRef, int) - -/*===-- Other types ------------------------------------------------------===*/ - -_wrap_none2obj(LLVMVoidType, LLVMTypeRef) -_wrap_none2obj(LLVMLabelType, LLVMTypeRef) - -/*===-- Type handles -----------------------------------------------------===*/ - -/* -_wrap_obj2obj(LLVMCreateTypeHandle, LLVMTypeRef, LLVMTypeHandleRef) -_wrap_obj2obj(LLVMResolveTypeHandle, LLVMTypeHandleRef, LLVMTypeRef) -_wrap_obj2none(LLVMDisposeTypeHandle, LLVMTypeHandleRef) -*/ - - -/*===----------------------------------------------------------------------===*/ -/* Values */ -/*===----------------------------------------------------------------------===*/ - -/* Operations on all values */ - -_wrap_obj2obj(LLVMTypeOf, LLVMValueRef, LLVMTypeRef) -_wrap_obj2str(LLVMGetValueName, LLVMValueRef) -_wrap_objstr2none(LLVMSetValueName, LLVMValueRef) -_wrap_obj2none(LLVMDumpValue, LLVMValueRef) -_wrap_dumper(LLVMDumpValueToString, LLVMValueRef) -_wrap_obj2obj(LLVMValueGetID, LLVMValueRef, int) -_wrap_obj2obj(LLVMValueGetNumUses, LLVMValueRef, int) - -static PyObject * -_wLLVMValueGetUses(PyObject *self, PyObject *args) -{ - LLVMValueRef value; - - if (!(value = (LLVMValueRef)get_object_arg(args))) - return NULL; - - LLVMValueRef *uses = 0; - unsigned n = LLVMValueGetUses(value, &uses); - - PyObject *list = make_list_from_LLVMValueRef_array(uses, n); - if (n > 0) - LLVMDisposeValueRefArray(uses); - - return list; -} - -/*===-- Users ------------------------------------------------------------===*/ - -_wrap_obj2obj(LLVMUserGetNumOperands, LLVMValueRef, int) -_wrap_objint2obj(LLVMUserGetOperand, LLVMValueRef, LLVMValueRef) - -/*===-- Constant Values --------------------------------------------------===*/ - -/* Operations on constants of any type */ - -_wrap_obj2obj(LLVMConstNull, LLVMTypeRef, LLVMValueRef) -_wrap_obj2obj(LLVMConstAllOnes, LLVMTypeRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetUndef, LLVMTypeRef, LLVMValueRef) -_wrap_obj2obj(LLVMIsConstant, LLVMValueRef, int) -_wrap_obj2obj(LLVMIsNull, LLVMValueRef, int) -_wrap_obj2obj(LLVMIsUndef, LLVMValueRef, int) - -/* Operations on scalar constants */ - -static PyObject * -_wLLVMConstInt(PyObject *self, PyObject *args) -{ - PyObject *obj; - unsigned long long n; - int sign_extend; - LLVMTypeRef ty; - LLVMValueRef val; - - if (!PyArg_ParseTuple(args, "OKi", &obj, &n, &sign_extend)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - ty = (LLVMTypeRef) PyCapsule_GetPointer(obj, NULL); -#else - ty = (LLVMTypeRef)(PyCObject_AsVoidPtr(obj)); -#endif - - val = LLVMConstInt(ty, n, sign_extend); - return ctor_LLVMValueRef(val); -} - -static PyObject * -_wLLVMConstReal(PyObject *self, PyObject *args) -{ - PyObject *obj; - double d; - LLVMTypeRef ty; - LLVMValueRef val; - - if (!PyArg_ParseTuple(args, "Od", &obj, &d)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - ty = (LLVMTypeRef) PyCapsule_GetPointer(obj, NULL); -#else - ty = (LLVMTypeRef)(PyCObject_AsVoidPtr(obj)); -#endif - - val = LLVMConstReal(ty, d); - return ctor_LLVMValueRef(val); -} - -_wrap_objstr2obj(LLVMConstRealOfString, LLVMTypeRef, LLVMValueRef) - -/* Operations on composite constants */ - -static PyObject * -_wLLVMConstString(PyObject *self, PyObject *args) -{ - const char *s; - int dont_null_terminate; - LLVMValueRef val; - -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *s_; - if (!PyArg_ParseTuple(args, "Ui:LLVMConstString", &s_, &dont_null_terminate)) { - return NULL; - } - - s = PyUnicode_AS_DATA(s_); -#else - if (!PyArg_ParseTuple(args, "si", &s, &dont_null_terminate)) - return NULL; -#endif - - val = LLVMConstString(s, strlen(s), dont_null_terminate); - return ctor_LLVMValueRef(val); -} - -_wrap_objlist2obj(LLVMConstArray, LLVMTypeRef, LLVMValueRef, LLVMValueRef) -_wrap_listint2obj(LLVMConstStruct, LLVMValueRef, LLVMValueRef) -_wrap_list2obj(LLVMConstVector, LLVMValueRef, LLVMValueRef) - -/* Constant expressions */ - -_wrap_obj2obj(LLVMSizeOf, LLVMTypeRef, LLVMValueRef) -_wrap_obj2obj(LLVMConstNeg, LLVMValueRef, LLVMValueRef) -_wrap_obj2obj(LLVMConstNot, LLVMValueRef, LLVMValueRef) - -_wrap_objobj2obj(LLVMConstAdd, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFAdd, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSub, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFSub, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstMul, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFMul, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstUDiv, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSDiv, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFDiv, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstURem, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSRem, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFRem, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstAnd, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstOr, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstXor, LLVMValueRef, LLVMValueRef, LLVMValueRef) - -_wrap_enumobjobj2obj(LLVMConstICmp, LLVMIntPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_enumobjobj2obj(LLVMConstFCmp, LLVMRealPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) - -_wrap_objobj2obj(LLVMConstShl, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstLShr, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstAShr, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objlist2obj(LLVMConstGEP, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstTrunc, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSExt, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstZExt, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFPTrunc, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFPExt, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstUIToFP, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSIToFP, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFPToUI, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFPToSI, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstPtrToInt, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstIntToPtr, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstBitCast, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobj2obj(LLVMConstSelect, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstExtractElement, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobj2obj(LLVMConstInsertElement, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobj2obj(LLVMConstShuffleVector, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) - - -/*===----------------------------------------------------------------------===*/ -/* Globals */ -/*===----------------------------------------------------------------------===*/ - -/*===-- Globals ----------------------------------------------------------===*/ - -_wrap_obj2obj(LLVMGetGlobalParent, LLVMValueRef, LLVMModuleRef) -_wrap_obj2obj(LLVMIsDeclaration, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetLinkage, LLVMValueRef, int) -_wrap_objenum2none(LLVMSetLinkage, LLVMValueRef, LLVMLinkage) -_wrap_obj2str(LLVMGetSection, LLVMValueRef) -_wrap_objstr2none(LLVMSetSection, LLVMValueRef) -_wrap_obj2obj(LLVMGetVisibility, LLVMValueRef, int) -_wrap_objenum2none(LLVMSetVisibility, LLVMValueRef, LLVMVisibility) -_wrap_obj2obj(LLVMGetAlignment, LLVMValueRef, int) -_wrap_objint2none(LLVMSetAlignment, LLVMValueRef) - -/*===-- Global Variables -------------------------------------------------===*/ - -_wrap_objobjstr2obj(LLVMAddGlobal, LLVMModuleRef, LLVMTypeRef, LLVMValueRef) -_wrap_objstr2obj(LLVMGetNamedGlobal, LLVMModuleRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetFirstGlobal, LLVMModuleRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetNextGlobal, LLVMValueRef, LLVMValueRef) -_wrap_obj2none(LLVMDeleteGlobal, LLVMValueRef) -_wrap_obj2obj(LLVMHasInitializer, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetInitializer, LLVMValueRef, LLVMValueRef) -_wrap_objobj2none(LLVMSetInitializer, LLVMValueRef, LLVMValueRef) -_wrap_objint2none(LLVMSetThreadLocal, LLVMValueRef) -_wrap_objint2none(LLVMSetGlobalConstant, LLVMValueRef) -_wrap_obj2obj(LLVMIsThreadLocal, LLVMValueRef, int) -_wrap_obj2obj(LLVMIsGlobalConstant, LLVMValueRef, int) - -/*===-- Functions --------------------------------------------------------===*/ - -_wrap_objstrobj2obj(LLVMAddFunction, LLVMModuleRef, LLVMTypeRef, LLVMValueRef) -_wrap_objstr2obj(LLVMGetNamedFunction, LLVMModuleRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetFirstFunction, LLVMModuleRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetNextFunction, LLVMValueRef, LLVMValueRef) -_wrap_obj2none(LLVMDeleteFunction, LLVMValueRef) -_wrap_obj2obj(LLVMGetIntrinsicID, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetFunctionCallConv, LLVMValueRef, int) -_wrap_objint2none(LLVMSetFunctionCallConv, LLVMValueRef) -_wrap_obj2str(LLVMGetGC, LLVMValueRef) -_wrap_objstr2none(LLVMSetGC, LLVMValueRef) -_wrap_obj2obj(LLVMGetDoesNotThrow, LLVMValueRef, int) -_wrap_objint2none(LLVMSetDoesNotThrow, LLVMValueRef) -_wrap_obj2none(LLVMViewFunctionCFG, LLVMValueRef) -_wrap_obj2none(LLVMViewFunctionCFGOnly, LLVMValueRef) -_wrap_objenum2none(LLVMAddFunctionAttr, LLVMValueRef, LLVMAttribute) -_wrap_objenum2none(LLVMRemoveFunctionAttr, LLVMValueRef, LLVMAttribute) - - -static PyObject * -_wLLVMVerifyFunction(PyObject *self, PyObject *args) -{ - LLVMValueRef fn; - - if (!(fn = (LLVMValueRef)get_object_arg(args))) - return NULL; - - return ctor_int(LLVMVerifyFunction(fn, LLVMReturnStatusAction)); -} - - -/*===-- Arguments --------------------------------------------------------===*/ - -_wrap_obj2obj(LLVMCountParams, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetFirstParam, LLVMValueRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetNextParam, LLVMValueRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetParamParent, LLVMValueRef, LLVMValueRef) -_wrap_objenum2none(LLVMAddAttribute, LLVMValueRef, LLVMAttribute) -_wrap_objenum2none(LLVMRemoveAttribute, LLVMValueRef, LLVMAttribute) -_wrap_objenum2none(LLVMSetParamAlignment, LLVMValueRef, LLVMAttribute) -_wrap_obj2obj(LLVMGetParamAlignment, LLVMValueRef, int) - -/*===-- Basic Blocks -----------------------------------------------------===*/ - -_wrap_obj2obj(LLVMGetBasicBlockParent, LLVMBasicBlockRef, LLVMValueRef) -_wrap_obj2obj(LLVMCountBasicBlocks, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetFirstBasicBlock, LLVMValueRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMGetNextBasicBlock, LLVMBasicBlockRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMGetEntryBasicBlock, LLVMValueRef, LLVMBasicBlockRef) -_wrap_objstr2obj(LLVMAppendBasicBlock, LLVMValueRef, LLVMBasicBlockRef) -_wrap_objstr2obj(LLVMInsertBasicBlock, LLVMBasicBlockRef, LLVMBasicBlockRef) -_wrap_obj2none(LLVMDeleteBasicBlock, LLVMBasicBlockRef) - -/*===-- Instructions -----------------------------------------------------===*/ - -_wrap_obj2obj(LLVMGetInstructionParent, LLVMValueRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMGetFirstInstruction, LLVMBasicBlockRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetNextInstruction, LLVMValueRef, LLVMValueRef) -_wrap_obj2obj(LLVMInstIsTerminator, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsBinaryOp, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsShift, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsCast, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsLogicalShift, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsArithmeticShift, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsAssociative, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsCommutative, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsVolatile, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstGetOpcode, LLVMValueRef, int) -_wrap_obj2str(LLVMInstGetOpcodeName, LLVMValueRef) - -/*===-- Call Sites (Call or Invoke) --------------------------------------===*/ - -_wrap_objint2none(LLVMSetInstructionCallConv, LLVMValueRef) -_wrap_obj2obj(LLVMGetInstructionCallConv, LLVMValueRef, int) -_wrap_objintenum2none(LLVMAddInstrAttribute, LLVMValueRef, LLVMAttribute) -_wrap_objintenum2none(LLVMRemoveInstrAttribute, LLVMValueRef, LLVMAttribute) -_wrap_objintint2none(LLVMSetInstrParamAlignment, LLVMValueRef) -_wrap_obj2obj(LLVMIsTailCall, LLVMValueRef, int) -_wrap_objint2none(LLVMSetTailCall, LLVMValueRef) - - -/*===-- PHI Nodes --------------------------------------------------------===*/ - -static void LLVMAddIncoming1(LLVMValueRef PhiNode, LLVMValueRef IncomingValue, LLVMBasicBlockRef IncomingBlock) -{ - LLVMAddIncoming(PhiNode, &IncomingValue, &IncomingBlock, 1); -} - -_wrap_objobjobj2none(LLVMAddIncoming1, LLVMValueRef, LLVMValueRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMCountIncoming, LLVMValueRef, int) -_wrap_objint2obj(LLVMGetIncomingValue, LLVMValueRef, LLVMValueRef) -_wrap_objint2obj(LLVMGetIncomingBlock, LLVMValueRef, LLVMBasicBlockRef) - -/*===-- Compare Instructions ---------------------------------------------===*/ - -_wrap_obj2obj(LLVMCmpInstGetPredicate, LLVMValueRef, int) - -/*===-- Instruction builders ----------------------------------------------===*/ - -_wrap_none2obj(LLVMCreateBuilder, LLVMBuilderRef) -_wrap_objobj2none(LLVMPositionBuilderBefore, LLVMBuilderRef, LLVMValueRef) -_wrap_objobj2none(LLVMPositionBuilderAtEnd, LLVMBuilderRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMGetInsertBlock, LLVMBuilderRef, LLVMBasicBlockRef) -_wrap_obj2none(LLVMDisposeBuilder, LLVMBuilderRef) - -/* Terminators */ - -_wrap_obj2obj(LLVMBuildRetVoid, LLVMBuilderRef, LLVMValueRef) -_wrap_objobj2obj(LLVMBuildRet, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objlist2obj(LLVMBuildRetMultiple, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMBuildBr, LLVMBuilderRef, LLVMBasicBlockRef, LLVMValueRef) -_wrap_objobjobjobj2obj(LLVMBuildCondBr, LLVMBuilderRef, LLVMValueRef, LLVMBasicBlockRef, LLVMBasicBlockRef, LLVMValueRef) -_wrap_objobjobjint2obj(LLVMBuildSwitch, LLVMBuilderRef, LLVMValueRef, LLVMBasicBlockRef, LLVMValueRef) - -static PyObject * -_wLLVMBuildInvoke(PyObject *self, PyObject *args) -{ - PyObject *obj1, *obj2, *obj3, *obj4, *obj5; - const char *name; - LLVMBuilderRef builder; - LLVMValueRef func; - LLVMValueRef *fnargs; - unsigned fnarg_count; - LLVMBasicBlockRef then_blk, catch_blk; - LLVMValueRef inst; - -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *name_; - if (!PyArg_ParseTuple(args, "OOOOOU:LLVMBuildInvoke", &obj1, &obj2, &obj3, &obj4, &obj5, &name_)) { - return NULL; - } - - name = PyUnicode_AS_DATA(name_); -#else - if (!PyArg_ParseTuple(args, "OOOOOs", &obj1, &obj2, &obj3, &obj4, &obj5, &name)) - return NULL; -#endif - -#ifdef LLVM_PY_USE_PYCAPSULE - builder = (LLVMBuilderRef) PyCapsule_GetPointer(obj1, NULL); - func = (LLVMValueRef) PyCapsule_GetPointer(obj2, NULL); -#else - builder = (LLVMBuilderRef)(PyCObject_AsVoidPtr(obj1)); - func = (LLVMValueRef)(PyCObject_AsVoidPtr(obj2)); -#endif - - fnarg_count = (unsigned) PyList_Size(obj3); - fnargs = (LLVMValueRef *)make_array_from_list(obj3, fnarg_count); - if (!fnargs) - return PyErr_NoMemory(); - -#ifdef LLVM_PY_USE_PYCAPSULE - then_blk = (LLVMBasicBlockRef) PyCapsule_GetPointer(obj4, NULL); - catch_blk = (LLVMBasicBlockRef) PyCapsule_GetPointer(obj5, NULL); -#else - then_blk = (LLVMBasicBlockRef)(PyCObject_AsVoidPtr(obj4)); - catch_blk = (LLVMBasicBlockRef)(PyCObject_AsVoidPtr(obj5)); -#endif - - inst = LLVMBuildInvoke(builder, func, fnargs, fnarg_count, then_blk, catch_blk, name); - - free(fnargs); - - return ctor_LLVMValueRef(inst); -} - -_wrap_obj2obj(LLVMBuildUnreachable, LLVMBuilderRef, LLVMValueRef) - -/* Add a case to the switch instruction */ - -_wrap_objobjobj2none(LLVMAddCase, LLVMValueRef, LLVMValueRef, LLVMBasicBlockRef) - -/* Arithmetic */ - -_wrap_objobjobjstr2obj(LLVMBuildAdd, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFAdd, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSub, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFSub, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildMul, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFMul, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildUDiv, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSDiv, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFDiv, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildURem, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSRem, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFRem, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildShl, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildLShr, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildAShr, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildAnd, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildOr, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildXor, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildNeg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildNot, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) - -/* Memory */ - -_wrap_objobjstr2obj(LLVMBuildMalloc, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildArrayMalloc, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildAlloca, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildArrayAlloca, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMBuildFree, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildLoad, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobj2obj(LLVMBuildStore, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjliststr2obj(LLVMBuildGEP, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) - -/* Casts */ - -_wrap_objobjobjstr2obj(LLVMBuildTrunc, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildZExt, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSExt, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFPToUI, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFPToSI, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildUIToFP, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSIToFP, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFPTrunc, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFPExt, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildPtrToInt, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildIntToPtr, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildBitCast, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) - -/* Comparisons */ - -_wrap_objenumobjobjstr2obj(LLVMBuildICmp, LLVMBuilderRef, LLVMIntPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objenumobjobjstr2obj(LLVMBuildFCmp, LLVMBuilderRef, LLVMRealPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) - -/* Miscellaneous instructions */ - -_wrap_objobjintstr2obj(LLVMBuildGetResult, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildPhi, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjliststr2obj(LLVMBuildCall, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjobjstr2obj(LLVMBuildSelect, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildVAArg, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildExtractElement, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjobjstr2obj(LLVMBuildInsertElement, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjobjstr2obj(LLVMBuildShuffleVector, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) - - -/*===----------------------------------------------------------------------===*/ -/* Memory Buffer */ -/*===----------------------------------------------------------------------===*/ - -static PyObject * -_wLLVMCreateMemoryBufferWithContentsOfFile(PyObject *self, PyObject *args) -{ - const char *path; - LLVMMemoryBufferRef ref; - char *outmsg; - PyObject *ret; - -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *path_; - if (!PyArg_ParseTuple(args, "U:LLVMCreateMemoryBufferWithContentsOfFile", &path_)) { - return NULL; - } - - path = PyUnicode_AS_DATA(path_); -#else - if (!PyArg_ParseTuple(args, "s", &path)) - return NULL; -#endif - - if (!LLVMCreateMemoryBufferWithContentsOfFile(path, &ref, &outmsg)) { - ret = ctor_LLVMMemoryBufferRef(ref); - } else { - ret = PyBytes_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } - - return ret; -} - -static PyObject * -_wLLVMCreateMemoryBufferWithSTDIN(PyObject *self, PyObject *args) -{ - LLVMMemoryBufferRef ref; - char *outmsg; - PyObject *ret; - - if (!LLVMCreateMemoryBufferWithSTDIN(&ref, &outmsg)) { - ret = ctor_LLVMMemoryBufferRef(ref); - } else { - ret = PyBytes_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } - - return ret; -} - -_wrap_obj2none(LLVMDisposeMemoryBuffer, LLVMMemoryBufferRef) - - -/*===----------------------------------------------------------------------===*/ -/* Pass Manager */ -/*===----------------------------------------------------------------------===*/ - -_wrap_none2obj(LLVMCreatePassManager, LLVMPassManagerRef) -_wrap_obj2obj(LLVMCreateFunctionPassManagerForModule, LLVMModuleRef, LLVMPassManagerRef) -_wrap_objobj2obj(LLVMRunPassManager, LLVMPassManagerRef, LLVMModuleRef, int) -_wrap_obj2obj(LLVMInitializeFunctionPassManager, LLVMPassManagerRef, int) -_wrap_objobj2obj(LLVMRunFunctionPassManager, LLVMPassManagerRef, LLVMValueRef, int) -_wrap_obj2obj(LLVMFinalizeFunctionPassManager, LLVMPassManagerRef, int) -_wrap_obj2none(LLVMDisposePassManager, LLVMPassManagerRef) - - -/*===----------------------------------------------------------------------===*/ -/* Passes */ -/*===----------------------------------------------------------------------===*/ - -#define _wrap_pass(P) \ -_wrap_obj2none( LLVMAdd ## P ## Pass, LLVMPassManagerRef) - -_wrap_pass( AAEval ) -_wrap_pass( AggressiveDCE ) -_wrap_pass( AliasAnalysisCounter ) -_wrap_pass( AlwaysInliner ) -_wrap_pass( ArgumentPromotion ) -_wrap_pass( BasicAliasAnalysis ) -_wrap_pass( BlockPlacement ) -_wrap_pass( BreakCriticalEdges ) -_wrap_pass( CFGSimplification ) -_wrap_pass( CodeGenPrepare ) -_wrap_pass( ConstantMerge ) -_wrap_pass( ConstantPropagation ) -_wrap_pass( DbgInfoPrinter ) -_wrap_pass( DeadArgElimination ) -_wrap_pass( DeadCodeElimination ) -_wrap_pass( DeadInstElimination ) -_wrap_pass( DeadStoreElimination ) -_wrap_pass( DemoteRegisterToMemory ) -_wrap_pass( DomOnlyPrinter ) -_wrap_pass( DomOnlyViewer ) -_wrap_pass( DomPrinter ) -_wrap_pass( DomViewer ) -_wrap_pass( EdgeProfiler ) -_wrap_pass( FunctionAttrs ) -_wrap_pass( FunctionInlining ) -//_wrap_pass( GEPSplitter ) -_wrap_pass( GlobalDCE ) -_wrap_pass( GlobalOptimizer ) -_wrap_pass( GlobalsModRef ) -_wrap_pass( GVN ) -_wrap_pass( IndVarSimplify ) -_wrap_pass( InstCount ) -_wrap_pass( InstructionCombining ) -_wrap_pass( InstructionNamer ) -_wrap_pass( IPConstantPropagation ) -_wrap_pass( IPSCCP ) -_wrap_pass( JumpThreading ) -_wrap_pass( LazyValueInfo ) -_wrap_pass( LCSSA ) -_wrap_pass( LICM ) -//_wrap_pass( LiveValues ) -_wrap_pass( LoopDeletion ) -_wrap_pass( LoopDependenceAnalysis ) -_wrap_pass( LoopExtractor ) -//_wrap_pass( LoopIndexSplit ) -_wrap_pass( LoopRotate ) -_wrap_pass( LoopSimplify ) -_wrap_pass( LoopStrengthReduce ) -_wrap_pass( LoopUnroll ) -_wrap_pass( LoopUnswitch ) -_wrap_pass( LowerInvoke ) -_wrap_pass( LowerSwitch ) -_wrap_pass( MemCpyOpt ) -_wrap_pass( MergeFunctions ) -_wrap_pass( NoAA ) -_wrap_pass( NoProfileInfo ) -_wrap_pass( OptimalEdgeProfiler ) -_wrap_pass( PartialInlining ) -//_wrap_pass( PartialSpecialization ) -_wrap_pass( PostDomOnlyPrinter ) -_wrap_pass( PostDomOnlyViewer ) -_wrap_pass( PostDomPrinter ) -_wrap_pass( PostDomViewer ) -_wrap_pass( ProfileEstimator ) -_wrap_pass( ProfileLoader ) -_wrap_pass( ProfileVerifier ) -_wrap_pass( PromoteMemoryToRegister ) -_wrap_pass( PruneEH ) -_wrap_pass( Reassociate ) -_wrap_pass( ScalarEvolutionAliasAnalysis ) -_wrap_pass( ScalarReplAggregates ) -_wrap_pass( SCCP ) -//_wrap_pass( SimplifyHalfPowrLibCalls ) -_wrap_pass( SimplifyLibCalls ) -_wrap_pass( SingleLoopExtractor ) -_wrap_pass( StripDeadPrototypes ) -_wrap_pass( StripNonDebugSymbols ) -_wrap_pass( StripSymbols ) -//_wrap_pass( StructRetPromotion ) -_wrap_pass( TailCallElimination ) -//_wrap_pass( TailDuplication ) -_wrap_pass( UnifyFunctionExitNodes ) - -_wrap_pass( Internalize2 ) - -/*===----------------------------------------------------------------------===*/ -/* Target Data */ -/*===----------------------------------------------------------------------===*/ - -_wrap_str2obj(LLVMCreateTargetData, LLVMTargetDataRef) -_wrap_obj2none(LLVMDisposeTargetData, LLVMTargetDataRef) - -static PyObject * -_wLLVMTargetDataAsString(PyObject *self, PyObject *args) -{ - LLVMTargetDataRef td; - char *tdrep = 0; - PyObject *ret; - - if (!(td = (LLVMTargetDataRef)get_object_arg(args))) - return NULL; - - tdrep = LLVMCopyStringRepOfTargetData(td); - ret = PyBytes_FromString(tdrep); - LLVMDisposeMessage(tdrep); - return ret; -} - -_wrap_objobj2none(LLVMAddTargetData, LLVMTargetDataRef, LLVMPassManagerRef) -_wrap_obj2obj(LLVMByteOrder, LLVMTargetDataRef, int) -_wrap_obj2obj(LLVMPointerSize, LLVMTargetDataRef, int) -_wrap_obj2obj(LLVMIntPtrType, LLVMTargetDataRef, LLVMTypeRef) -_wrap_objobj2obj(LLVMSizeOfTypeInBits, LLVMTargetDataRef, LLVMTypeRef, - llvmwrap_ull) -_wrap_objobj2obj(LLVMStoreSizeOfType, LLVMTargetDataRef, LLVMTypeRef, - llvmwrap_ull) -_wrap_objobj2obj(LLVMABISizeOfType, LLVMTargetDataRef, LLVMTypeRef, - llvmwrap_ull) -_wrap_objobj2obj(LLVMABIAlignmentOfType, LLVMTargetDataRef, LLVMTypeRef, - int) -_wrap_objobj2obj(LLVMCallFrameAlignmentOfType, LLVMTargetDataRef, LLVMTypeRef, - int) -_wrap_objobj2obj(LLVMPreferredAlignmentOfType, LLVMTargetDataRef, LLVMTypeRef, - int) -_wrap_objobj2obj(LLVMPreferredAlignmentOfGlobal, LLVMTargetDataRef, - LLVMValueRef, int) -_wrap_objobjull2obj(LLVMElementAtOffset, LLVMTargetDataRef, LLVMTypeRef, int) -_wrap_objobjint2obj(LLVMOffsetOfElement, LLVMTargetDataRef, LLVMTypeRef, - llvmwrap_ull) - - -/*===----------------------------------------------------------------------===*/ -/* Execution Engine */ -/*===----------------------------------------------------------------------===*/ - -static PyObject * -_wLLVMCreateExecutionEngine(PyObject *self, PyObject *args) -{ - LLVMModuleRef mod; - PyObject *obj; - int force_interpreter; - LLVMExecutionEngineRef ee; - char *outmsg = 0; - PyObject *ret; - int error; - - if (!PyArg_ParseTuple(args, "Oi", &obj, &force_interpreter)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - mod = (LLVMModuleRef) PyCapsule_GetPointer(obj, NULL); -#else - mod = (LLVMModuleRef) PyCObject_AsVoidPtr(obj); -#endif - - if (force_interpreter) - error = LLVMCreateInterpreterForModule(&ee, mod, &outmsg); - else - error = LLVMCreateJITCompilerForModule(&ee, mod, 1 /*fast*/, &outmsg); - - if (error) { - ret = PyBytes_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } else { - ret = ctor_LLVMExecutionEngineRef(ee); - } - - return ret; -} - -static PyObject * -_wLLVMGetPointerToFunction(PyObject *self, PyObject *args) -{ - PyObject *obj_ee; - PyObject *obj_fn; - LLVMExecutionEngineRef ee; - LLVMValueRef fn; - - if (!PyArg_ParseTuple(args, "OO", &obj_ee, &obj_fn)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - ee = (LLVMExecutionEngineRef) PyCapsule_GetPointer(obj_ee, NULL); - fn = (LLVMValueRef) PyCapsule_GetPointer(obj_fn, NULL); -#else - ee = (LLVMExecutionEngineRef) PyCObject_AsVoidPtr(obj_ee); - fn = (LLVMValueRef) PyCObject_AsVoidPtr(obj_fn); -#endif - - return PyLong_FromVoidPtr(LLVMGetPointerToFunction(ee,fn)); -} - -/* the args should have been ptr, num */ -LLVMGenericValueRef LLVMRunFunction2(LLVMExecutionEngineRef EE, - LLVMValueRef F, LLVMGenericValueRef *Args, unsigned NumArgs) -{ - return LLVMRunFunction(EE, F, NumArgs, Args); -} - -static PyObject * -_wLLVMRemoveModule2(PyObject *self, PyObject *args) -{ - PyObject *obj_ee; - PyObject *obj_mod; - LLVMExecutionEngineRef ee; - LLVMModuleRef mod, mod_new = 0; - char *outmsg = 0; - PyObject *ret; - - if (!PyArg_ParseTuple(args, "OO", &obj_ee, &obj_mod)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - ee = (LLVMExecutionEngineRef) PyCapsule_GetPointer(obj_ee, NULL); - mod = (LLVMModuleRef) PyCapsule_GetPointer(obj_mod, NULL); -#else - ee = (LLVMExecutionEngineRef) PyCObject_AsVoidPtr(obj_ee); - mod = (LLVMModuleRef) PyCObject_AsVoidPtr(obj_mod); -#endif - - LLVMRemoveModule(ee, mod, &mod_new, &outmsg); - if (mod_new) { - ret = ctor_LLVMModuleRef(mod_new); - } else { - if (outmsg) { - ret = PyBytes_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } else { - ret = PyBytes_FromString("error"); - } - } - - return ret; -} - -_wrap_obj2none(LLVMDisposeExecutionEngine, LLVMExecutionEngineRef) -_wrap_objobjlist2obj(LLVMRunFunction2, LLVMExecutionEngineRef, - LLVMValueRef, LLVMGenericValueRef, LLVMGenericValueRef) -_wrap_obj2obj(LLVMGetExecutionEngineTargetData, LLVMExecutionEngineRef, - LLVMTargetDataRef) -_wrap_obj2none(LLVMRunStaticConstructors, LLVMExecutionEngineRef) -_wrap_obj2none(LLVMRunStaticDestructors, LLVMExecutionEngineRef) -_wrap_objobj2none(LLVMFreeMachineCodeForFunction, LLVMExecutionEngineRef, - LLVMValueRef) -_wrap_objobj2none(LLVMAddModule, LLVMExecutionEngineRef, - LLVMModuleRef) - - -/*===----------------------------------------------------------------------===*/ -/* Generic Value */ -/*===----------------------------------------------------------------------===*/ - -static PyObject * -_wLLVMCreateGenericValueOfInt(PyObject *self, PyObject *args) -{ - PyObject *obj1; - LLVMTypeRef ty; - unsigned long long n; - int is_signed; - LLVMGenericValueRef gv; - - if (!PyArg_ParseTuple(args, "OLi", &obj1, &n, &is_signed)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); -#else - ty = (LLVMTypeRef) PyCObject_AsVoidPtr(obj1); -#endif - - gv = LLVMCreateGenericValueOfInt(ty, n, is_signed); - return ctor_LLVMGenericValueRef(gv); -} - -static PyObject * -_wLLVMCreateGenericValueOfFloat(PyObject *self, PyObject *args) -{ - PyObject *obj1; - LLVMTypeRef ty; - double d; - LLVMGenericValueRef gv; - - if (!PyArg_ParseTuple(args, "Od", &obj1, &d)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); -#else - ty = (LLVMTypeRef) PyCObject_AsVoidPtr(obj1); -#endif - - gv = LLVMCreateGenericValueOfFloat(ty, d); - return ctor_LLVMGenericValueRef(gv); -} - -static PyObject * -_wLLVMCreateGenericValueOfPointer(PyObject *self, PyObject *args) -{ - PyObject *obj1; - LLVMTypeRef ty; - unsigned long long n_; - size_t n; - LLVMGenericValueRef gv; - - if (!PyArg_ParseTuple(args, "OL", &obj1, &n_)) - return NULL; - - n=n_; - -#ifdef LLVM_PY_USE_PYCAPSULE - ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); -#else - ty = (LLVMTypeRef) PyCObject_AsVoidPtr(obj1); -#endif - - gv = LLVMCreateGenericValueOfPointer((void*)n); - return ctor_LLVMGenericValueRef(gv); -} - -static PyObject * -_wLLVMGenericValueToInt(PyObject *self, PyObject *args) -{ - PyObject *obj1; - int is_signed; - LLVMGenericValueRef gv; - unsigned long long val; - - if (!PyArg_ParseTuple(args, "Oi", &obj1, &is_signed)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - gv = (LLVMGenericValueRef) PyCapsule_GetPointer(obj1, NULL); -#else - gv = (LLVMGenericValueRef) PyCObject_AsVoidPtr(obj1); -#endif - - val = LLVMGenericValueToInt(gv, is_signed); - return is_signed ? - PyLong_FromLongLong((long long)val) : - PyLong_FromUnsignedLongLong(val); -} - -static PyObject * -_wLLVMGenericValueToFloat(PyObject *self, PyObject *args) -{ - PyObject *obj1, *obj2; - LLVMTypeRef ty; - LLVMGenericValueRef gv; - double val; - - if (!PyArg_ParseTuple(args, "OO", &obj1, &obj2)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); - gv = (LLVMGenericValueRef) PyCapsule_GetPointer(obj2, NULL); -#else - ty = (LLVMTypeRef) PyCObject_AsVoidPtr(obj1); - gv = (LLVMGenericValueRef) PyCObject_AsVoidPtr(obj2); -#endif - - val = LLVMGenericValueToFloat(ty, gv); - return PyFloat_FromDouble(val); -} - -static PyObject * -_wLLVMGenericValueToPointer(PyObject *self, PyObject *args) -{ - PyObject *obj1; - LLVMGenericValueRef gv; - void * val; - - if (!PyArg_ParseTuple(args, "O", &obj1)) - return NULL; - -#ifdef LLVM_PY_USE_PYCAPSULE - gv = (LLVMGenericValueRef) PyCapsule_GetPointer(obj1, NULL); -#else - gv = (LLVMGenericValueRef) PyCObject_AsVoidPtr(obj1); -#endif - - val = LLVMGenericValueToPointer(gv); - return PyLong_FromVoidPtr(val); -} - -_wrap_obj2none(LLVMDisposeGenericValue, LLVMGenericValueRef) - - -/*===----------------------------------------------------------------------===*/ -/* Misc */ -/*===----------------------------------------------------------------------===*/ - -_wrap_objintlist2obj(LLVMGetIntrinsic, LLVMModuleRef, LLVMTypeRef, - LLVMValueRef) - -static PyObject * -_wLLVMLoadLibraryPermanently(PyObject *self, PyObject *args) -{ - const char *filename; - char *outmsg; - PyObject *ret; - -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *filename_; - if (!PyArg_ParseTuple(args, "U:LLVMLoadLibraryPermanently", &filename_)) { - return NULL; - } - - filename = PyUnicode_AS_DATA(filename_); -#else - if (!PyArg_ParseTuple(args, "s", &filename)) { - return NULL; - } -#endif - - outmsg = 0; - if (!LLVMLoadLibraryPermanently(filename, &outmsg)) { - if (outmsg) { - ret = PyBytes_FromString(outmsg); - LLVMDisposeMessage(outmsg); - return ret; - } - } - - /* note: success => None, failure => string with error message */ - Py_RETURN_NONE; -} - -//_wrap_obj2obj(LLVMInlineFunction, LLVMValueRef, int) - -/* Expose the void* inside a PyCObject as a PyLong. This allows us to - * use it as a unique ID. */ -static PyObject * -_wPyCObjectVoidPtrToPyLong(PyObject *self, PyObject *args) -{ - void *p; - - if (!(p = get_object_arg(args))) - return NULL; - - return PyLong_FromVoidPtr(p); -} - - -/*===----------------------------------------------------------------------===*/ -/* Python member method table */ -/*===----------------------------------------------------------------------===*/ - -#ifdef LLVM_PY_USE_PYCAPSULE - -#define _method( func ) { # func , ( PyCFunction )_w ## func , METH_VARARGS , NULL }, -#define _pass( P ) _method( LLVMAdd ## P ## Pass ) - -#else - -#define _method( func ) { # func , _w ## func , METH_VARARGS }, -#define _pass( P ) _method( LLVMAdd ## P ## Pass ) - -#endif - -static PyMethodDef core_methods[] = { - - /* Modules */ - _method( LLVMModuleCreateWithName ) - _method( LLVMGetDataLayout ) - _method( LLVMSetDataLayout ) - _method( LLVMGetTarget ) - _method( LLVMSetTarget ) - _method( LLVMModuleAddLibrary ) - _method( LLVMGetTypeByName ) - _method( LLVMDumpModule ) - _method( LLVMDisposeModule ) - _method( LLVMDumpModuleToString ) - _method( LLVMVerifyModule ) - _method( LLVMGetModuleFromAssembly ) - _method( LLVMGetModuleFromBitcode ) - _method( LLVMGetBitcodeFromModule ) - _method( LLVMModuleGetPointerSize ) - _method( LLVMModuleGetOrInsertFunction ) - _method( LLVMLinkModules ) - - /* Types */ - - /* General */ - _method( LLVMGetTypeKind ) - _method( LLVMDumpTypeToString ) - - /* Integer types */ - _method( LLVMInt1Type ) - _method( LLVMInt8Type ) - _method( LLVMInt16Type ) - _method( LLVMInt32Type ) - _method( LLVMInt64Type ) - _method( LLVMIntType ) - _method( LLVMGetIntTypeWidth ) - - /* Floating-point types */ - _method( LLVMFloatType ) - _method( LLVMDoubleType ) - _method( LLVMX86FP80Type ) - _method( LLVMFP128Type ) - _method( LLVMPPCFP128Type ) - - /* Function types */ - _method( LLVMFunctionType ) - _method( LLVMIsFunctionVarArg ) - _method( LLVMGetReturnType ) - _method( LLVMCountParamTypes ) - _method( LLVMGetFunctionTypeParams ) - - /* Struct types */ - _method( LLVMStructType ) - _method( LLVMCountStructElementTypes ) - //_method( LLVMGetStructElementTypes ) - _method( LLVMIsPackedStruct ) - - /* Array types */ - _method( LLVMArrayType ) - _method( LLVMGetElementType ) - _method( LLVMGetArrayLength ) - - /* Pointer types */ - _method( LLVMPointerType ) - _method( LLVMGetPointerAddressSpace ) - - /* Vector type */ - _method( LLVMVectorType ) - _method( LLVMGetVectorSize ) - - /* Other types */ - _method( LLVMVoidType ) - _method( LLVMLabelType ) - - /* Type handles */ - /* - _method( LLVMResolveTypeHandle ) - _method( LLVMDisposeTypeHandle ) - */ - - /* Values */ - - /* Operations on all values */ - _method( LLVMTypeOf ) - _method( LLVMGetValueName ) - _method( LLVMSetValueName ) - _method( LLVMDumpValue ) - _method( LLVMDumpValueToString ) - _method( LLVMValueGetID ) - _method( LLVMValueGetNumUses ) - _method( LLVMValueGetUses ) - - /* Users */ - - _method( LLVMUserGetNumOperands ) - _method( LLVMUserGetOperand ) - - /* Constant Values */ - - /* Operations on constants of any type */ - _method( LLVMConstNull ) - _method( LLVMConstAllOnes ) - _method( LLVMGetUndef ) - _method( LLVMIsConstant ) - _method( LLVMIsNull ) - _method( LLVMIsUndef ) - - /* Operations on scalar constants */ - _method( LLVMConstInt ) - _method( LLVMConstReal ) - _method( LLVMConstRealOfString ) - - /* Operations on composite constants */ - _method( LLVMConstString ) - _method( LLVMConstArray ) - _method( LLVMConstStruct ) - _method( LLVMConstVector ) - - /* Constant expressions */ - _method( LLVMSizeOf ) - _method( LLVMConstNeg ) - _method( LLVMConstNot ) - _method( LLVMConstAdd ) - _method( LLVMConstFAdd ) - _method( LLVMConstSub ) - _method( LLVMConstFSub ) - _method( LLVMConstMul ) - _method( LLVMConstFMul ) - _method( LLVMConstUDiv ) - _method( LLVMConstSDiv ) - _method( LLVMConstFDiv ) - _method( LLVMConstURem ) - _method( LLVMConstSRem ) - _method( LLVMConstFRem ) - _method( LLVMConstAnd ) - _method( LLVMConstOr ) - _method( LLVMConstXor ) - _method( LLVMConstICmp ) - _method( LLVMConstFCmp ) - _method( LLVMConstShl ) - _method( LLVMConstLShr ) - _method( LLVMConstAShr ) - _method( LLVMConstGEP ) - _method( LLVMConstTrunc ) - _method( LLVMConstSExt ) - _method( LLVMConstZExt ) - _method( LLVMConstFPTrunc ) - _method( LLVMConstFPExt ) - _method( LLVMConstUIToFP ) - _method( LLVMConstSIToFP ) - _method( LLVMConstFPToUI ) - _method( LLVMConstFPToSI ) - _method( LLVMConstPtrToInt ) - _method( LLVMConstIntToPtr ) - _method( LLVMConstBitCast ) - _method( LLVMConstSelect ) - _method( LLVMConstExtractElement ) - _method( LLVMConstInsertElement ) - _method( LLVMConstShuffleVector ) - - /* Globals */ - - /* Globals (general) */ - _method( LLVMGetGlobalParent ) - _method( LLVMIsDeclaration ) - _method( LLVMGetLinkage ) - _method( LLVMSetLinkage ) - _method( LLVMGetSection ) - _method( LLVMSetSection ) - _method( LLVMGetVisibility ) - _method( LLVMSetVisibility ) - _method( LLVMGetAlignment ) - _method( LLVMSetAlignment ) - - /* Global Variables */ - _method( LLVMAddGlobal ) - _method( LLVMGetNamedGlobal ) - _method( LLVMGetFirstGlobal ) - _method( LLVMGetNextGlobal ) - _method( LLVMDeleteGlobal ) - _method( LLVMHasInitializer ) - _method( LLVMGetInitializer ) - _method( LLVMSetInitializer ) - _method( LLVMSetThreadLocal ) - _method( LLVMSetGlobalConstant ) - _method( LLVMIsThreadLocal ) - _method( LLVMIsGlobalConstant ) - - /* Functions */ - _method( LLVMAddFunction ) - _method( LLVMGetNamedFunction ) - _method( LLVMGetFirstFunction ) - _method( LLVMGetNextFunction ) - _method( LLVMDeleteFunction ) - _method( LLVMGetIntrinsicID ) - _method( LLVMGetFunctionCallConv ) - _method( LLVMSetFunctionCallConv ) - _method( LLVMGetGC ) - _method( LLVMSetGC ) - _method( LLVMGetDoesNotThrow ) - _method( LLVMSetDoesNotThrow ) - _method( LLVMVerifyFunction ) - _method( LLVMViewFunctionCFG ) - _method( LLVMViewFunctionCFGOnly ) - _method( LLVMAddFunctionAttr ) - _method( LLVMRemoveFunctionAttr ) - - /* Arguments */ - _method( LLVMCountParams ) - _method( LLVMGetFirstParam ) - _method( LLVMGetNextParam ) - _method( LLVMGetParamParent ) - _method( LLVMAddAttribute ) - _method( LLVMRemoveAttribute ) - _method( LLVMSetParamAlignment ) - _method( LLVMGetParamAlignment ) - - /* Basic Blocks */ - _method( LLVMGetBasicBlockParent ) - _method( LLVMCountBasicBlocks ) - _method( LLVMGetFirstBasicBlock ) - _method( LLVMGetNextBasicBlock ) - _method( LLVMGetEntryBasicBlock ) - _method( LLVMAppendBasicBlock ) - _method( LLVMInsertBasicBlock ) - _method( LLVMDeleteBasicBlock ) - - /* Instructions */ - _method( LLVMGetInstructionParent ) - _method( LLVMGetFirstInstruction ) - _method( LLVMGetNextInstruction ) - _method( LLVMInstIsTerminator ) - _method( LLVMInstIsBinaryOp ) - _method( LLVMInstIsShift ) - _method( LLVMInstIsCast ) - _method( LLVMInstIsLogicalShift ) - _method( LLVMInstIsArithmeticShift ) - _method( LLVMInstIsAssociative ) - _method( LLVMInstIsCommutative ) - _method( LLVMInstIsVolatile ) - _method( LLVMInstGetOpcode ) - _method( LLVMInstGetOpcodeName ) - - /* Call Sites (Call or Invoke) */ - _method( LLVMSetInstructionCallConv ) - _method( LLVMGetInstructionCallConv ) - _method( LLVMIsTailCall ) - _method( LLVMSetTailCall ) - _method( LLVMAddInstrAttribute ) - _method( LLVMRemoveInstrAttribute ) - _method( LLVMSetInstrParamAlignment ) - - /* PHI Nodes */ - _method( LLVMAddIncoming1 ) - _method( LLVMCountIncoming ) - _method( LLVMGetIncomingValue ) - _method( LLVMGetIncomingBlock ) - - /* Comparison Instructions */ - _method( LLVMCmpInstGetPredicate ) - - /* Instruction builders */ - _method( LLVMCreateBuilder ) - _method( LLVMPositionBuilderBefore ) - _method( LLVMPositionBuilderAtEnd ) - _method( LLVMGetInsertBlock ) - _method( LLVMDisposeBuilder ) - - /* Terminators */ - _method( LLVMBuildRetVoid ) - _method( LLVMBuildRet ) - _method( LLVMBuildRetMultiple ) - _method( LLVMBuildBr ) - _method( LLVMBuildCondBr ) - _method( LLVMBuildSwitch ) - _method( LLVMBuildInvoke ) - _method( LLVMBuildUnreachable ) - - /* Add a case to the switch instruction */ - _method( LLVMAddCase ) - - /* Arithmetic */ - _method( LLVMBuildAdd ) - _method( LLVMBuildFAdd) - _method( LLVMBuildSub ) - _method( LLVMBuildFSub) - _method( LLVMBuildMul ) - _method( LLVMBuildFMul) - _method( LLVMBuildUDiv ) - _method( LLVMBuildSDiv ) - _method( LLVMBuildFDiv ) - _method( LLVMBuildURem ) - _method( LLVMBuildSRem ) - _method( LLVMBuildFRem ) - _method( LLVMBuildShl ) - _method( LLVMBuildLShr ) - _method( LLVMBuildAShr ) - _method( LLVMBuildAnd ) - _method( LLVMBuildOr ) - _method( LLVMBuildXor ) - _method( LLVMBuildNeg ) - _method( LLVMBuildNot ) - - /* Memory */ - _method( LLVMBuildMalloc ) - _method( LLVMBuildArrayMalloc ) - _method( LLVMBuildAlloca ) - _method( LLVMBuildArrayAlloca ) - _method( LLVMBuildFree ) - _method( LLVMBuildLoad ) - _method( LLVMBuildStore ) - _method( LLVMBuildGEP ) - - /* Casts */ - _method( LLVMBuildTrunc ) - _method( LLVMBuildZExt ) - _method( LLVMBuildSExt ) - _method( LLVMBuildFPToUI ) - _method( LLVMBuildFPToSI ) - _method( LLVMBuildUIToFP ) - _method( LLVMBuildSIToFP ) - _method( LLVMBuildFPTrunc ) - _method( LLVMBuildFPExt ) - _method( LLVMBuildPtrToInt ) - _method( LLVMBuildIntToPtr ) - _method( LLVMBuildBitCast ) - - /* Comparisons */ - _method( LLVMBuildICmp ) - _method( LLVMBuildFCmp ) - - /* Miscellaneous instructions */ - _method( LLVMBuildGetResult ) - _method( LLVMBuildPhi ) - _method( LLVMBuildCall ) - _method( LLVMBuildSelect ) - _method( LLVMBuildVAArg ) - _method( LLVMBuildExtractElement ) - _method( LLVMBuildInsertElement ) - _method( LLVMBuildShuffleVector ) - - /* Memory Buffer */ - _method( LLVMCreateMemoryBufferWithContentsOfFile ) - _method( LLVMCreateMemoryBufferWithSTDIN ) - _method( LLVMDisposeMemoryBuffer ) - - /* Pass Manager */ - _method( LLVMCreatePassManager ) - _method( LLVMCreateFunctionPassManagerForModule ) - _method( LLVMRunPassManager ) - _method( LLVMInitializeFunctionPassManager ) - _method( LLVMRunFunctionPassManager ) - _method( LLVMFinalizeFunctionPassManager ) - _method( LLVMDisposePassManager ) - - /* Passes */ - _pass( AAEval ) - _pass( AggressiveDCE ) - _pass( AliasAnalysisCounter ) - _pass( AlwaysInliner ) - _pass( ArgumentPromotion ) - _pass( BasicAliasAnalysis ) - _pass( BlockPlacement ) - _pass( BreakCriticalEdges ) - _pass( CFGSimplification ) - _pass( CodeGenPrepare ) - _pass( ConstantMerge ) - _pass( ConstantPropagation ) - _pass( DbgInfoPrinter ) - _pass( DeadArgElimination ) - _pass( DeadCodeElimination ) - _pass( DeadInstElimination ) - _pass( DeadStoreElimination ) - _pass( DemoteRegisterToMemory ) - _pass( DomOnlyPrinter ) - _pass( DomOnlyViewer ) - _pass( DomPrinter ) - _pass( DomViewer ) - _pass( EdgeProfiler ) - _pass( FunctionAttrs ) - _pass( FunctionInlining ) - //_pass( GEPSplitter ) - _pass( GlobalDCE ) - _pass( GlobalOptimizer ) - _pass( GlobalsModRef ) - _pass( GVN ) - _pass( IndVarSimplify ) - _pass( InstCount ) - _pass( InstructionCombining ) - _pass( InstructionNamer ) - _pass( IPConstantPropagation ) - _pass( IPSCCP ) - _pass( JumpThreading ) - _pass( LazyValueInfo ) - _pass( LCSSA ) - _pass( LICM ) - //_pass( LiveValues ) - _pass( LoopDeletion ) - _pass( LoopDependenceAnalysis ) - _pass( LoopExtractor ) - //_pass( LoopIndexSplit ) - _pass( LoopRotate ) - _pass( LoopSimplify ) - _pass( LoopStrengthReduce ) - _pass( LoopUnroll ) - _pass( LoopUnswitch ) - _pass( LowerInvoke ) - _pass( LowerSwitch ) - _pass( MemCpyOpt ) - _pass( MergeFunctions ) - _pass( NoAA ) - _pass( NoProfileInfo ) - _pass( OptimalEdgeProfiler ) - _pass( PartialInlining ) - //_pass( PartialSpecialization ) - _pass( PostDomOnlyPrinter ) - _pass( PostDomOnlyViewer ) - _pass( PostDomPrinter ) - _pass( PostDomViewer ) - _pass( ProfileEstimator ) - _pass( ProfileLoader ) - _pass( ProfileVerifier ) - _pass( PromoteMemoryToRegister ) - _pass( PruneEH ) - _pass( Reassociate ) - _pass( ScalarEvolutionAliasAnalysis ) - _pass( ScalarReplAggregates ) - _pass( SCCP ) - //_pass( SimplifyHalfPowrLibCalls ) - _pass( SimplifyLibCalls ) - _pass( SingleLoopExtractor ) - _pass( StripDeadPrototypes ) - _pass( StripNonDebugSymbols ) - _pass( StripSymbols ) - //_pass( StructRetPromotion ) - _pass( TailCallElimination ) - //_pass( TailDuplication ) - _pass( UnifyFunctionExitNodes ) - - _pass( Internalize2 ) - - /* Target Data */ - _method( LLVMCreateTargetData ) - _method( LLVMDisposeTargetData ) - _method( LLVMTargetDataAsString ) - _method( LLVMAddTargetData ) - _method( LLVMByteOrder ) - _method( LLVMPointerSize ) - _method( LLVMIntPtrType ) - _method( LLVMSizeOfTypeInBits ) - _method( LLVMStoreSizeOfType ) - _method( LLVMABISizeOfType ) - _method( LLVMABIAlignmentOfType ) - _method( LLVMCallFrameAlignmentOfType ) - _method( LLVMPreferredAlignmentOfType ) - _method( LLVMPreferredAlignmentOfGlobal ) - _method( LLVMElementAtOffset ) - _method( LLVMOffsetOfElement ) - - /* Execution Engine */ - _method( LLVMCreateExecutionEngine ) - _method( LLVMDisposeExecutionEngine ) - _method( LLVMRunFunction2 ) - _method( LLVMGetPointerToFunction ) - _method( LLVMGetExecutionEngineTargetData ) - _method( LLVMRunStaticConstructors ) - _method( LLVMRunStaticDestructors ) - _method( LLVMFreeMachineCodeForFunction ) - _method( LLVMAddModule ) - _method( LLVMRemoveModule2 ) - - /* Generic Value */ - _method( LLVMCreateGenericValueOfInt ) - _method( LLVMCreateGenericValueOfFloat ) - _method( LLVMCreateGenericValueOfPointer ) - _method( LLVMGenericValueToInt ) - _method( LLVMGenericValueToFloat ) - _method( LLVMGenericValueToPointer ) - _method( LLVMDisposeGenericValue ) - - /* Misc */ - _method( LLVMGetIntrinsic ) - _method( LLVMLoadLibraryPermanently ) - //_method( LLVMInlineFunction ) - _method( PyCObjectVoidPtrToPyLong ) - { NULL } -}; - - - -// Module main function, hairy because of py3k port - -#if (PY_MAJOR_VERSION >= 3) -struct PyModuleDef module_def = { - PyModuleDef_HEAD_INIT, - "_core", - NULL, - -1, - core_methods, - NULL, NULL, NULL, NULL -}; -#define INITERROR return NULL -PyObject * -PyInit__core(void) -#else -#define INITERROR return -PyMODINIT_FUNC -init_core(void) -#endif -{ - LLVMLinkInJIT(); - LLVMLinkInInterpreter(); - LLVMInitializeNativeTarget(); -#if PY_MAJOR_VERSION >= 3 - PyObject *module = PyModule_Create( &module_def ); -#else - PyObject *module = Py_InitModule("_core", core_methods); -#endif - if (module == NULL) - INITERROR; -#if PY_MAJOR_VERSION >= 3 - - return module; -#endif -} diff --git a/llvm/_intrinsic_ids.py b/llvm/_intrinsic_ids.py deleted file mode 100644 index c2e0ae5..0000000 --- a/llvm/_intrinsic_ids.py +++ /dev/null @@ -1,1942 +0,0 @@ -# -# Copyright (c) 2008-10, Mahadevan R All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of this software, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -"""Intrinsic IDs. - -Intended to be imported into the llvm.core namespace. Not for public use.""" -# Generate these using the ../tools/intrgen.py file - -INTR_ADJUST_TRAMPOLINE = 1 -INTR_ANNOTATION = 2 -INTR_ARM_CDP = 3 -INTR_ARM_CDP2 = 4 -INTR_ARM_GET_FPSCR = 5 -INTR_ARM_LDREXD = 6 -INTR_ARM_MCR = 7 -INTR_ARM_MCR2 = 8 -INTR_ARM_MCRR = 9 -INTR_ARM_MCRR2 = 10 -INTR_ARM_MRC = 11 -INTR_ARM_MRC2 = 12 -INTR_ARM_NEON_VABDS = 13 -INTR_ARM_NEON_VABDU = 14 -INTR_ARM_NEON_VABS = 15 -INTR_ARM_NEON_VACGED = 16 -INTR_ARM_NEON_VACGEQ = 17 -INTR_ARM_NEON_VACGTD = 18 -INTR_ARM_NEON_VACGTQ = 19 -INTR_ARM_NEON_VADDHN = 20 -INTR_ARM_NEON_VCLS = 21 -INTR_ARM_NEON_VCLZ = 22 -INTR_ARM_NEON_VCNT = 23 -INTR_ARM_NEON_VCVTFP2FXS = 24 -INTR_ARM_NEON_VCVTFP2FXU = 25 -INTR_ARM_NEON_VCVTFP2HF = 26 -INTR_ARM_NEON_VCVTFXS2FP = 27 -INTR_ARM_NEON_VCVTFXU2FP = 28 -INTR_ARM_NEON_VCVTHF2FP = 29 -INTR_ARM_NEON_VHADDS = 30 -INTR_ARM_NEON_VHADDU = 31 -INTR_ARM_NEON_VHSUBS = 32 -INTR_ARM_NEON_VHSUBU = 33 -INTR_ARM_NEON_VLD1 = 34 -INTR_ARM_NEON_VLD2 = 35 -INTR_ARM_NEON_VLD2LANE = 36 -INTR_ARM_NEON_VLD3 = 37 -INTR_ARM_NEON_VLD3LANE = 38 -INTR_ARM_NEON_VLD4 = 39 -INTR_ARM_NEON_VLD4LANE = 40 -INTR_ARM_NEON_VMAXS = 41 -INTR_ARM_NEON_VMAXU = 42 -INTR_ARM_NEON_VMINS = 43 -INTR_ARM_NEON_VMINU = 44 -INTR_ARM_NEON_VMULLP = 45 -INTR_ARM_NEON_VMULLS = 46 -INTR_ARM_NEON_VMULLU = 47 -INTR_ARM_NEON_VMULP = 48 -INTR_ARM_NEON_VPADALS = 49 -INTR_ARM_NEON_VPADALU = 50 -INTR_ARM_NEON_VPADD = 51 -INTR_ARM_NEON_VPADDLS = 52 -INTR_ARM_NEON_VPADDLU = 53 -INTR_ARM_NEON_VPMAXS = 54 -INTR_ARM_NEON_VPMAXU = 55 -INTR_ARM_NEON_VPMINS = 56 -INTR_ARM_NEON_VPMINU = 57 -INTR_ARM_NEON_VQABS = 58 -INTR_ARM_NEON_VQADDS = 59 -INTR_ARM_NEON_VQADDU = 60 -INTR_ARM_NEON_VQDMLAL = 61 -INTR_ARM_NEON_VQDMLSL = 62 -INTR_ARM_NEON_VQDMULH = 63 -INTR_ARM_NEON_VQDMULL = 64 -INTR_ARM_NEON_VQMOVNS = 65 -INTR_ARM_NEON_VQMOVNSU = 66 -INTR_ARM_NEON_VQMOVNU = 67 -INTR_ARM_NEON_VQNEG = 68 -INTR_ARM_NEON_VQRDMULH = 69 -INTR_ARM_NEON_VQRSHIFTNS = 70 -INTR_ARM_NEON_VQRSHIFTNSU = 71 -INTR_ARM_NEON_VQRSHIFTNU = 72 -INTR_ARM_NEON_VQRSHIFTS = 73 -INTR_ARM_NEON_VQRSHIFTU = 74 -INTR_ARM_NEON_VQSHIFTNS = 75 -INTR_ARM_NEON_VQSHIFTNSU = 76 -INTR_ARM_NEON_VQSHIFTNU = 77 -INTR_ARM_NEON_VQSHIFTS = 78 -INTR_ARM_NEON_VQSHIFTSU = 79 -INTR_ARM_NEON_VQSHIFTU = 80 -INTR_ARM_NEON_VQSUBS = 81 -INTR_ARM_NEON_VQSUBU = 82 -INTR_ARM_NEON_VRADDHN = 83 -INTR_ARM_NEON_VRECPE = 84 -INTR_ARM_NEON_VRECPS = 85 -INTR_ARM_NEON_VRHADDS = 86 -INTR_ARM_NEON_VRHADDU = 87 -INTR_ARM_NEON_VRSHIFTN = 88 -INTR_ARM_NEON_VRSHIFTS = 89 -INTR_ARM_NEON_VRSHIFTU = 90 -INTR_ARM_NEON_VRSQRTE = 91 -INTR_ARM_NEON_VRSQRTS = 92 -INTR_ARM_NEON_VRSUBHN = 93 -INTR_ARM_NEON_VSHIFTINS = 94 -INTR_ARM_NEON_VSHIFTLS = 95 -INTR_ARM_NEON_VSHIFTLU = 96 -INTR_ARM_NEON_VSHIFTN = 97 -INTR_ARM_NEON_VSHIFTS = 98 -INTR_ARM_NEON_VSHIFTU = 99 -INTR_ARM_NEON_VST1 = 100 -INTR_ARM_NEON_VST2 = 101 -INTR_ARM_NEON_VST2LANE = 102 -INTR_ARM_NEON_VST3 = 103 -INTR_ARM_NEON_VST3LANE = 104 -INTR_ARM_NEON_VST4 = 105 -INTR_ARM_NEON_VST4LANE = 106 -INTR_ARM_NEON_VSUBHN = 107 -INTR_ARM_NEON_VTBL1 = 108 -INTR_ARM_NEON_VTBL2 = 109 -INTR_ARM_NEON_VTBL3 = 110 -INTR_ARM_NEON_VTBL4 = 111 -INTR_ARM_NEON_VTBX1 = 112 -INTR_ARM_NEON_VTBX2 = 113 -INTR_ARM_NEON_VTBX3 = 114 -INTR_ARM_NEON_VTBX4 = 115 -INTR_ARM_QADD = 116 -INTR_ARM_QSUB = 117 -INTR_ARM_SET_FPSCR = 118 -INTR_ARM_SSAT = 119 -INTR_ARM_STREXD = 120 -INTR_ARM_THREAD_POINTER = 121 -INTR_ARM_USAT = 122 -INTR_ARM_VCVTR = 123 -INTR_ARM_VCVTRU = 124 -INTR_BSWAP = 125 -INTR_CONVERT_FROM_FP16 = 126 -INTR_CONVERT_TO_FP16 = 127 -INTR_CONVERTFF = 128 -INTR_CONVERTFSI = 129 -INTR_CONVERTFUI = 130 -INTR_CONVERTSIF = 131 -INTR_CONVERTSS = 132 -INTR_CONVERTSU = 133 -INTR_CONVERTUIF = 134 -INTR_CONVERTUS = 135 -INTR_CONVERTUU = 136 -INTR_COS = 137 -INTR_CTLZ = 138 -INTR_CTPOP = 139 -INTR_CTTZ = 140 -INTR_DBG_DECLARE = 141 -INTR_DBG_VALUE = 142 -INTR_EH_DWARF_CFA = 143 -INTR_EH_RETURN_I32 = 144 -INTR_EH_RETURN_I64 = 145 -INTR_EH_SJLJ_CALLSITE = 146 -INTR_EH_SJLJ_FUNCTIONCONTEXT = 147 -INTR_EH_SJLJ_LONGJMP = 148 -INTR_EH_SJLJ_LSDA = 149 -INTR_EH_SJLJ_SETJMP = 150 -INTR_EH_TYPEID_FOR = 151 -INTR_EH_UNWIND_INIT = 152 -INTR_EXP = 153 -INTR_EXP2 = 154 -INTR_EXPECT = 155 -INTR_FLT_ROUNDS = 156 -INTR_FMA = 157 -INTR_FRAMEADDRESS = 158 -INTR_GCREAD = 159 -INTR_GCROOT = 160 -INTR_GCWRITE = 161 -INTR_HEXAGON_A2_ABS = 162 -INTR_HEXAGON_A2_ABSP = 163 -INTR_HEXAGON_A2_ABSSAT = 164 -INTR_HEXAGON_A2_ADD = 165 -INTR_HEXAGON_A2_ADDH_H16_HH = 166 -INTR_HEXAGON_A2_ADDH_H16_HL = 167 -INTR_HEXAGON_A2_ADDH_H16_LH = 168 -INTR_HEXAGON_A2_ADDH_H16_LL = 169 -INTR_HEXAGON_A2_ADDH_H16_SAT_HH = 170 -INTR_HEXAGON_A2_ADDH_H16_SAT_HL = 171 -INTR_HEXAGON_A2_ADDH_H16_SAT_LH = 172 -INTR_HEXAGON_A2_ADDH_H16_SAT_LL = 173 -INTR_HEXAGON_A2_ADDH_L16_HH = 174 -INTR_HEXAGON_A2_ADDH_L16_HL = 175 -INTR_HEXAGON_A2_ADDH_L16_LH = 176 -INTR_HEXAGON_A2_ADDH_L16_LL = 177 -INTR_HEXAGON_A2_ADDH_L16_SAT_HH = 178 -INTR_HEXAGON_A2_ADDH_L16_SAT_HL = 179 -INTR_HEXAGON_A2_ADDH_L16_SAT_LH = 180 -INTR_HEXAGON_A2_ADDH_L16_SAT_LL = 181 -INTR_HEXAGON_A2_ADDI = 182 -INTR_HEXAGON_A2_ADDP = 183 -INTR_HEXAGON_A2_ADDPSAT = 184 -INTR_HEXAGON_A2_ADDSAT = 185 -INTR_HEXAGON_A2_ADDSP = 186 -INTR_HEXAGON_A2_AND = 187 -INTR_HEXAGON_A2_ANDIR = 188 -INTR_HEXAGON_A2_ANDP = 189 -INTR_HEXAGON_A2_ASLH = 190 -INTR_HEXAGON_A2_ASRH = 191 -INTR_HEXAGON_A2_COMBINE_HH = 192 -INTR_HEXAGON_A2_COMBINE_HL = 193 -INTR_HEXAGON_A2_COMBINE_LH = 194 -INTR_HEXAGON_A2_COMBINE_LL = 195 -INTR_HEXAGON_A2_COMBINEII = 196 -INTR_HEXAGON_A2_COMBINEW = 197 -INTR_HEXAGON_A2_MAX = 198 -INTR_HEXAGON_A2_MAXP = 199 -INTR_HEXAGON_A2_MAXU = 200 -INTR_HEXAGON_A2_MAXUP = 201 -INTR_HEXAGON_A2_MIN = 202 -INTR_HEXAGON_A2_MINP = 203 -INTR_HEXAGON_A2_MINU = 204 -INTR_HEXAGON_A2_MINUP = 205 -INTR_HEXAGON_A2_NEG = 206 -INTR_HEXAGON_A2_NEGP = 207 -INTR_HEXAGON_A2_NEGSAT = 208 -INTR_HEXAGON_A2_NOT = 209 -INTR_HEXAGON_A2_NOTP = 210 -INTR_HEXAGON_A2_OR = 211 -INTR_HEXAGON_A2_ORIR = 212 -INTR_HEXAGON_A2_ORP = 213 -INTR_HEXAGON_A2_SAT = 214 -INTR_HEXAGON_A2_SATB = 215 -INTR_HEXAGON_A2_SATH = 216 -INTR_HEXAGON_A2_SATUB = 217 -INTR_HEXAGON_A2_SATUH = 218 -INTR_HEXAGON_A2_SUB = 219 -INTR_HEXAGON_A2_SUBH_H16_HH = 220 -INTR_HEXAGON_A2_SUBH_H16_HL = 221 -INTR_HEXAGON_A2_SUBH_H16_LH = 222 -INTR_HEXAGON_A2_SUBH_H16_LL = 223 -INTR_HEXAGON_A2_SUBH_H16_SAT_HH = 224 -INTR_HEXAGON_A2_SUBH_H16_SAT_HL = 225 -INTR_HEXAGON_A2_SUBH_H16_SAT_LH = 226 -INTR_HEXAGON_A2_SUBH_H16_SAT_LL = 227 -INTR_HEXAGON_A2_SUBH_L16_HL = 228 -INTR_HEXAGON_A2_SUBH_L16_LL = 229 -INTR_HEXAGON_A2_SUBH_L16_SAT_HL = 230 -INTR_HEXAGON_A2_SUBH_L16_SAT_LL = 231 -INTR_HEXAGON_A2_SUBP = 232 -INTR_HEXAGON_A2_SUBRI = 233 -INTR_HEXAGON_A2_SUBSAT = 234 -INTR_HEXAGON_A2_SVADDH = 235 -INTR_HEXAGON_A2_SVADDHS = 236 -INTR_HEXAGON_A2_SVADDUHS = 237 -INTR_HEXAGON_A2_SVAVGH = 238 -INTR_HEXAGON_A2_SVAVGHS = 239 -INTR_HEXAGON_A2_SVNAVGH = 240 -INTR_HEXAGON_A2_SVSUBH = 241 -INTR_HEXAGON_A2_SVSUBHS = 242 -INTR_HEXAGON_A2_SVSUBUHS = 243 -INTR_HEXAGON_A2_SWIZ = 244 -INTR_HEXAGON_A2_SXTB = 245 -INTR_HEXAGON_A2_SXTH = 246 -INTR_HEXAGON_A2_SXTW = 247 -INTR_HEXAGON_A2_TFR = 248 -INTR_HEXAGON_A2_TFRIH = 249 -INTR_HEXAGON_A2_TFRIL = 250 -INTR_HEXAGON_A2_TFRP = 251 -INTR_HEXAGON_A2_TFRPI = 252 -INTR_HEXAGON_A2_TFRSI = 253 -INTR_HEXAGON_A2_VABSH = 254 -INTR_HEXAGON_A2_VABSHSAT = 255 -INTR_HEXAGON_A2_VABSW = 256 -INTR_HEXAGON_A2_VABSWSAT = 257 -INTR_HEXAGON_A2_VADDH = 258 -INTR_HEXAGON_A2_VADDHS = 259 -INTR_HEXAGON_A2_VADDUB = 260 -INTR_HEXAGON_A2_VADDUBS = 261 -INTR_HEXAGON_A2_VADDUHS = 262 -INTR_HEXAGON_A2_VADDW = 263 -INTR_HEXAGON_A2_VADDWS = 264 -INTR_HEXAGON_A2_VAVGH = 265 -INTR_HEXAGON_A2_VAVGHCR = 266 -INTR_HEXAGON_A2_VAVGHR = 267 -INTR_HEXAGON_A2_VAVGUB = 268 -INTR_HEXAGON_A2_VAVGUBR = 269 -INTR_HEXAGON_A2_VAVGUH = 270 -INTR_HEXAGON_A2_VAVGUHR = 271 -INTR_HEXAGON_A2_VAVGUW = 272 -INTR_HEXAGON_A2_VAVGUWR = 273 -INTR_HEXAGON_A2_VAVGW = 274 -INTR_HEXAGON_A2_VAVGWCR = 275 -INTR_HEXAGON_A2_VAVGWR = 276 -INTR_HEXAGON_A2_VCMPBEQ = 277 -INTR_HEXAGON_A2_VCMPBGTU = 278 -INTR_HEXAGON_A2_VCMPHEQ = 279 -INTR_HEXAGON_A2_VCMPHGT = 280 -INTR_HEXAGON_A2_VCMPHGTU = 281 -INTR_HEXAGON_A2_VCMPWEQ = 282 -INTR_HEXAGON_A2_VCMPWGT = 283 -INTR_HEXAGON_A2_VCMPWGTU = 284 -INTR_HEXAGON_A2_VCONJ = 285 -INTR_HEXAGON_A2_VMAXH = 286 -INTR_HEXAGON_A2_VMAXUB = 287 -INTR_HEXAGON_A2_VMAXUH = 288 -INTR_HEXAGON_A2_VMAXUW = 289 -INTR_HEXAGON_A2_VMAXW = 290 -INTR_HEXAGON_A2_VMINH = 291 -INTR_HEXAGON_A2_VMINUB = 292 -INTR_HEXAGON_A2_VMINUH = 293 -INTR_HEXAGON_A2_VMINUW = 294 -INTR_HEXAGON_A2_VMINW = 295 -INTR_HEXAGON_A2_VNAVGH = 296 -INTR_HEXAGON_A2_VNAVGHCR = 297 -INTR_HEXAGON_A2_VNAVGHR = 298 -INTR_HEXAGON_A2_VNAVGW = 299 -INTR_HEXAGON_A2_VNAVGWCR = 300 -INTR_HEXAGON_A2_VNAVGWR = 301 -INTR_HEXAGON_A2_VRADDUB = 302 -INTR_HEXAGON_A2_VRADDUB_ACC = 303 -INTR_HEXAGON_A2_VRSADUB = 304 -INTR_HEXAGON_A2_VRSADUB_ACC = 305 -INTR_HEXAGON_A2_VSUBH = 306 -INTR_HEXAGON_A2_VSUBHS = 307 -INTR_HEXAGON_A2_VSUBUB = 308 -INTR_HEXAGON_A2_VSUBUBS = 309 -INTR_HEXAGON_A2_VSUBUHS = 310 -INTR_HEXAGON_A2_VSUBW = 311 -INTR_HEXAGON_A2_VSUBWS = 312 -INTR_HEXAGON_A2_XOR = 313 -INTR_HEXAGON_A2_XORP = 314 -INTR_HEXAGON_A2_ZXTB = 315 -INTR_HEXAGON_A2_ZXTH = 316 -INTR_HEXAGON_A4_ANDN = 317 -INTR_HEXAGON_A4_ANDNP = 318 -INTR_HEXAGON_A4_COMBINEIR = 319 -INTR_HEXAGON_A4_COMBINERI = 320 -INTR_HEXAGON_A4_CROUND_RI = 321 -INTR_HEXAGON_A4_CROUND_RR = 322 -INTR_HEXAGON_A4_MODWRAPU = 323 -INTR_HEXAGON_A4_ORN = 324 -INTR_HEXAGON_A4_ORNP = 325 -INTR_HEXAGON_A4_RCMPEQ = 326 -INTR_HEXAGON_A4_RCMPEQI = 327 -INTR_HEXAGON_A4_RCMPNEQ = 328 -INTR_HEXAGON_A4_RCMPNEQI = 329 -INTR_HEXAGON_A4_ROUND_RI = 330 -INTR_HEXAGON_A4_ROUND_RI_SAT = 331 -INTR_HEXAGON_A4_ROUND_RR = 332 -INTR_HEXAGON_A4_ROUND_RR_SAT = 333 -INTR_HEXAGON_C2_ALL8 = 334 -INTR_HEXAGON_C2_AND = 335 -INTR_HEXAGON_C2_ANDN = 336 -INTR_HEXAGON_C2_ANY8 = 337 -INTR_HEXAGON_C2_BITSCLR = 338 -INTR_HEXAGON_C2_BITSCLRI = 339 -INTR_HEXAGON_C2_BITSSET = 340 -INTR_HEXAGON_C2_CMPEQ = 341 -INTR_HEXAGON_C2_CMPEQI = 342 -INTR_HEXAGON_C2_CMPEQP = 343 -INTR_HEXAGON_C2_CMPGEI = 344 -INTR_HEXAGON_C2_CMPGEUI = 345 -INTR_HEXAGON_C2_CMPGT = 346 -INTR_HEXAGON_C2_CMPGTI = 347 -INTR_HEXAGON_C2_CMPGTP = 348 -INTR_HEXAGON_C2_CMPGTU = 349 -INTR_HEXAGON_C2_CMPGTUI = 350 -INTR_HEXAGON_C2_CMPGTUP = 351 -INTR_HEXAGON_C2_CMPLT = 352 -INTR_HEXAGON_C2_CMPLTU = 353 -INTR_HEXAGON_C2_MASK = 354 -INTR_HEXAGON_C2_MUX = 355 -INTR_HEXAGON_C2_MUXII = 356 -INTR_HEXAGON_C2_MUXIR = 357 -INTR_HEXAGON_C2_MUXRI = 358 -INTR_HEXAGON_C2_NOT = 359 -INTR_HEXAGON_C2_OR = 360 -INTR_HEXAGON_C2_ORN = 361 -INTR_HEXAGON_C2_PXFER_MAP = 362 -INTR_HEXAGON_C2_TFRPR = 363 -INTR_HEXAGON_C2_TFRRP = 364 -INTR_HEXAGON_C2_VITPACK = 365 -INTR_HEXAGON_C2_VMUX = 366 -INTR_HEXAGON_C2_XOR = 367 -INTR_HEXAGON_C4_AND_AND = 368 -INTR_HEXAGON_C4_AND_ANDN = 369 -INTR_HEXAGON_C4_AND_OR = 370 -INTR_HEXAGON_C4_AND_ORN = 371 -INTR_HEXAGON_C4_CMPLTE = 372 -INTR_HEXAGON_C4_CMPLTEI = 373 -INTR_HEXAGON_C4_CMPLTEU = 374 -INTR_HEXAGON_C4_CMPLTEUI = 375 -INTR_HEXAGON_C4_CMPNEQ = 376 -INTR_HEXAGON_C4_CMPNEQI = 377 -INTR_HEXAGON_C4_FASTCORNER9 = 378 -INTR_HEXAGON_C4_FASTCORNER9_NOT = 379 -INTR_HEXAGON_C4_OR_AND = 380 -INTR_HEXAGON_C4_OR_ANDN = 381 -INTR_HEXAGON_C4_OR_OR = 382 -INTR_HEXAGON_C4_OR_ORN = 383 -INTR_HEXAGON_M2_ACCI = 384 -INTR_HEXAGON_M2_ACCII = 385 -INTR_HEXAGON_M2_CMACI_S0 = 386 -INTR_HEXAGON_M2_CMACR_S0 = 387 -INTR_HEXAGON_M2_CMACS_S0 = 388 -INTR_HEXAGON_M2_CMACS_S1 = 389 -INTR_HEXAGON_M2_CMACSC_S0 = 390 -INTR_HEXAGON_M2_CMACSC_S1 = 391 -INTR_HEXAGON_M2_CMPYI_S0 = 392 -INTR_HEXAGON_M2_CMPYR_S0 = 393 -INTR_HEXAGON_M2_CMPYRS_S0 = 394 -INTR_HEXAGON_M2_CMPYRS_S1 = 395 -INTR_HEXAGON_M2_CMPYRSC_S0 = 396 -INTR_HEXAGON_M2_CMPYRSC_S1 = 397 -INTR_HEXAGON_M2_CMPYS_S0 = 398 -INTR_HEXAGON_M2_CMPYS_S1 = 399 -INTR_HEXAGON_M2_CMPYSC_S0 = 400 -INTR_HEXAGON_M2_CMPYSC_S1 = 401 -INTR_HEXAGON_M2_CNACS_S0 = 402 -INTR_HEXAGON_M2_CNACS_S1 = 403 -INTR_HEXAGON_M2_CNACSC_S0 = 404 -INTR_HEXAGON_M2_CNACSC_S1 = 405 -INTR_HEXAGON_M2_DPMPYSS_ACC_S0 = 406 -INTR_HEXAGON_M2_DPMPYSS_NAC_S0 = 407 -INTR_HEXAGON_M2_DPMPYSS_RND_S0 = 408 -INTR_HEXAGON_M2_DPMPYSS_S0 = 409 -INTR_HEXAGON_M2_DPMPYUU_ACC_S0 = 410 -INTR_HEXAGON_M2_DPMPYUU_NAC_S0 = 411 -INTR_HEXAGON_M2_DPMPYUU_S0 = 412 -INTR_HEXAGON_M2_HMMPYH_RS1 = 413 -INTR_HEXAGON_M2_HMMPYL_RS1 = 414 -INTR_HEXAGON_M2_MACI = 415 -INTR_HEXAGON_M2_MACSIN = 416 -INTR_HEXAGON_M2_MACSIP = 417 -INTR_HEXAGON_M2_MMACHS_RS0 = 418 -INTR_HEXAGON_M2_MMACHS_RS1 = 419 -INTR_HEXAGON_M2_MMACHS_S0 = 420 -INTR_HEXAGON_M2_MMACHS_S1 = 421 -INTR_HEXAGON_M2_MMACLS_RS0 = 422 -INTR_HEXAGON_M2_MMACLS_RS1 = 423 -INTR_HEXAGON_M2_MMACLS_S0 = 424 -INTR_HEXAGON_M2_MMACLS_S1 = 425 -INTR_HEXAGON_M2_MMACUHS_RS0 = 426 -INTR_HEXAGON_M2_MMACUHS_RS1 = 427 -INTR_HEXAGON_M2_MMACUHS_S0 = 428 -INTR_HEXAGON_M2_MMACUHS_S1 = 429 -INTR_HEXAGON_M2_MMACULS_RS0 = 430 -INTR_HEXAGON_M2_MMACULS_RS1 = 431 -INTR_HEXAGON_M2_MMACULS_S0 = 432 -INTR_HEXAGON_M2_MMACULS_S1 = 433 -INTR_HEXAGON_M2_MMPYH_RS0 = 434 -INTR_HEXAGON_M2_MMPYH_RS1 = 435 -INTR_HEXAGON_M2_MMPYH_S0 = 436 -INTR_HEXAGON_M2_MMPYH_S1 = 437 -INTR_HEXAGON_M2_MMPYL_RS0 = 438 -INTR_HEXAGON_M2_MMPYL_RS1 = 439 -INTR_HEXAGON_M2_MMPYL_S0 = 440 -INTR_HEXAGON_M2_MMPYL_S1 = 441 -INTR_HEXAGON_M2_MMPYUH_RS0 = 442 -INTR_HEXAGON_M2_MMPYUH_RS1 = 443 -INTR_HEXAGON_M2_MMPYUH_S0 = 444 -INTR_HEXAGON_M2_MMPYUH_S1 = 445 -INTR_HEXAGON_M2_MMPYUL_RS0 = 446 -INTR_HEXAGON_M2_MMPYUL_RS1 = 447 -INTR_HEXAGON_M2_MMPYUL_S0 = 448 -INTR_HEXAGON_M2_MMPYUL_S1 = 449 -INTR_HEXAGON_M2_MPY_ACC_HH_S0 = 450 -INTR_HEXAGON_M2_MPY_ACC_HH_S1 = 451 -INTR_HEXAGON_M2_MPY_ACC_HL_S0 = 452 -INTR_HEXAGON_M2_MPY_ACC_HL_S1 = 453 -INTR_HEXAGON_M2_MPY_ACC_LH_S0 = 454 -INTR_HEXAGON_M2_MPY_ACC_LH_S1 = 455 -INTR_HEXAGON_M2_MPY_ACC_LL_S0 = 456 -INTR_HEXAGON_M2_MPY_ACC_LL_S1 = 457 -INTR_HEXAGON_M2_MPY_ACC_SAT_HH_S0 = 458 -INTR_HEXAGON_M2_MPY_ACC_SAT_HH_S1 = 459 -INTR_HEXAGON_M2_MPY_ACC_SAT_HL_S0 = 460 -INTR_HEXAGON_M2_MPY_ACC_SAT_HL_S1 = 461 -INTR_HEXAGON_M2_MPY_ACC_SAT_LH_S0 = 462 -INTR_HEXAGON_M2_MPY_ACC_SAT_LH_S1 = 463 -INTR_HEXAGON_M2_MPY_ACC_SAT_LL_S0 = 464 -INTR_HEXAGON_M2_MPY_ACC_SAT_LL_S1 = 465 -INTR_HEXAGON_M2_MPY_HH_S0 = 466 -INTR_HEXAGON_M2_MPY_HH_S1 = 467 -INTR_HEXAGON_M2_MPY_HL_S0 = 468 -INTR_HEXAGON_M2_MPY_HL_S1 = 469 -INTR_HEXAGON_M2_MPY_LH_S0 = 470 -INTR_HEXAGON_M2_MPY_LH_S1 = 471 -INTR_HEXAGON_M2_MPY_LL_S0 = 472 -INTR_HEXAGON_M2_MPY_LL_S1 = 473 -INTR_HEXAGON_M2_MPY_NAC_HH_S0 = 474 -INTR_HEXAGON_M2_MPY_NAC_HH_S1 = 475 -INTR_HEXAGON_M2_MPY_NAC_HL_S0 = 476 -INTR_HEXAGON_M2_MPY_NAC_HL_S1 = 477 -INTR_HEXAGON_M2_MPY_NAC_LH_S0 = 478 -INTR_HEXAGON_M2_MPY_NAC_LH_S1 = 479 -INTR_HEXAGON_M2_MPY_NAC_LL_S0 = 480 -INTR_HEXAGON_M2_MPY_NAC_LL_S1 = 481 -INTR_HEXAGON_M2_MPY_NAC_SAT_HH_S0 = 482 -INTR_HEXAGON_M2_MPY_NAC_SAT_HH_S1 = 483 -INTR_HEXAGON_M2_MPY_NAC_SAT_HL_S0 = 484 -INTR_HEXAGON_M2_MPY_NAC_SAT_HL_S1 = 485 -INTR_HEXAGON_M2_MPY_NAC_SAT_LH_S0 = 486 -INTR_HEXAGON_M2_MPY_NAC_SAT_LH_S1 = 487 -INTR_HEXAGON_M2_MPY_NAC_SAT_LL_S0 = 488 -INTR_HEXAGON_M2_MPY_NAC_SAT_LL_S1 = 489 -INTR_HEXAGON_M2_MPY_RND_HH_S0 = 490 -INTR_HEXAGON_M2_MPY_RND_HH_S1 = 491 -INTR_HEXAGON_M2_MPY_RND_HL_S0 = 492 -INTR_HEXAGON_M2_MPY_RND_HL_S1 = 493 -INTR_HEXAGON_M2_MPY_RND_LH_S0 = 494 -INTR_HEXAGON_M2_MPY_RND_LH_S1 = 495 -INTR_HEXAGON_M2_MPY_RND_LL_S0 = 496 -INTR_HEXAGON_M2_MPY_RND_LL_S1 = 497 -INTR_HEXAGON_M2_MPY_SAT_HH_S0 = 498 -INTR_HEXAGON_M2_MPY_SAT_HH_S1 = 499 -INTR_HEXAGON_M2_MPY_SAT_HL_S0 = 500 -INTR_HEXAGON_M2_MPY_SAT_HL_S1 = 501 -INTR_HEXAGON_M2_MPY_SAT_LH_S0 = 502 -INTR_HEXAGON_M2_MPY_SAT_LH_S1 = 503 -INTR_HEXAGON_M2_MPY_SAT_LL_S0 = 504 -INTR_HEXAGON_M2_MPY_SAT_LL_S1 = 505 -INTR_HEXAGON_M2_MPY_SAT_RND_HH_S0 = 506 -INTR_HEXAGON_M2_MPY_SAT_RND_HH_S1 = 507 -INTR_HEXAGON_M2_MPY_SAT_RND_HL_S0 = 508 -INTR_HEXAGON_M2_MPY_SAT_RND_HL_S1 = 509 -INTR_HEXAGON_M2_MPY_SAT_RND_LH_S0 = 510 -INTR_HEXAGON_M2_MPY_SAT_RND_LH_S1 = 511 -INTR_HEXAGON_M2_MPY_SAT_RND_LL_S0 = 512 -INTR_HEXAGON_M2_MPY_SAT_RND_LL_S1 = 513 -INTR_HEXAGON_M2_MPY_UP = 514 -INTR_HEXAGON_M2_MPYD_ACC_HH_S0 = 515 -INTR_HEXAGON_M2_MPYD_ACC_HH_S1 = 516 -INTR_HEXAGON_M2_MPYD_ACC_HL_S0 = 517 -INTR_HEXAGON_M2_MPYD_ACC_HL_S1 = 518 -INTR_HEXAGON_M2_MPYD_ACC_LH_S0 = 519 -INTR_HEXAGON_M2_MPYD_ACC_LH_S1 = 520 -INTR_HEXAGON_M2_MPYD_ACC_LL_S0 = 521 -INTR_HEXAGON_M2_MPYD_ACC_LL_S1 = 522 -INTR_HEXAGON_M2_MPYD_HH_S0 = 523 -INTR_HEXAGON_M2_MPYD_HH_S1 = 524 -INTR_HEXAGON_M2_MPYD_HL_S0 = 525 -INTR_HEXAGON_M2_MPYD_HL_S1 = 526 -INTR_HEXAGON_M2_MPYD_LH_S0 = 527 -INTR_HEXAGON_M2_MPYD_LH_S1 = 528 -INTR_HEXAGON_M2_MPYD_LL_S0 = 529 -INTR_HEXAGON_M2_MPYD_LL_S1 = 530 -INTR_HEXAGON_M2_MPYD_NAC_HH_S0 = 531 -INTR_HEXAGON_M2_MPYD_NAC_HH_S1 = 532 -INTR_HEXAGON_M2_MPYD_NAC_HL_S0 = 533 -INTR_HEXAGON_M2_MPYD_NAC_HL_S1 = 534 -INTR_HEXAGON_M2_MPYD_NAC_LH_S0 = 535 -INTR_HEXAGON_M2_MPYD_NAC_LH_S1 = 536 -INTR_HEXAGON_M2_MPYD_NAC_LL_S0 = 537 -INTR_HEXAGON_M2_MPYD_NAC_LL_S1 = 538 -INTR_HEXAGON_M2_MPYD_RND_HH_S0 = 539 -INTR_HEXAGON_M2_MPYD_RND_HH_S1 = 540 -INTR_HEXAGON_M2_MPYD_RND_HL_S0 = 541 -INTR_HEXAGON_M2_MPYD_RND_HL_S1 = 542 -INTR_HEXAGON_M2_MPYD_RND_LH_S0 = 543 -INTR_HEXAGON_M2_MPYD_RND_LH_S1 = 544 -INTR_HEXAGON_M2_MPYD_RND_LL_S0 = 545 -INTR_HEXAGON_M2_MPYD_RND_LL_S1 = 546 -INTR_HEXAGON_M2_MPYI = 547 -INTR_HEXAGON_M2_MPYSMI = 548 -INTR_HEXAGON_M2_MPYU_ACC_HH_S0 = 549 -INTR_HEXAGON_M2_MPYU_ACC_HH_S1 = 550 -INTR_HEXAGON_M2_MPYU_ACC_HL_S0 = 551 -INTR_HEXAGON_M2_MPYU_ACC_HL_S1 = 552 -INTR_HEXAGON_M2_MPYU_ACC_LH_S0 = 553 -INTR_HEXAGON_M2_MPYU_ACC_LH_S1 = 554 -INTR_HEXAGON_M2_MPYU_ACC_LL_S0 = 555 -INTR_HEXAGON_M2_MPYU_ACC_LL_S1 = 556 -INTR_HEXAGON_M2_MPYU_HH_S0 = 557 -INTR_HEXAGON_M2_MPYU_HH_S1 = 558 -INTR_HEXAGON_M2_MPYU_HL_S0 = 559 -INTR_HEXAGON_M2_MPYU_HL_S1 = 560 -INTR_HEXAGON_M2_MPYU_LH_S0 = 561 -INTR_HEXAGON_M2_MPYU_LH_S1 = 562 -INTR_HEXAGON_M2_MPYU_LL_S0 = 563 -INTR_HEXAGON_M2_MPYU_LL_S1 = 564 -INTR_HEXAGON_M2_MPYU_NAC_HH_S0 = 565 -INTR_HEXAGON_M2_MPYU_NAC_HH_S1 = 566 -INTR_HEXAGON_M2_MPYU_NAC_HL_S0 = 567 -INTR_HEXAGON_M2_MPYU_NAC_HL_S1 = 568 -INTR_HEXAGON_M2_MPYU_NAC_LH_S0 = 569 -INTR_HEXAGON_M2_MPYU_NAC_LH_S1 = 570 -INTR_HEXAGON_M2_MPYU_NAC_LL_S0 = 571 -INTR_HEXAGON_M2_MPYU_NAC_LL_S1 = 572 -INTR_HEXAGON_M2_MPYU_UP = 573 -INTR_HEXAGON_M2_MPYUD_ACC_HH_S0 = 574 -INTR_HEXAGON_M2_MPYUD_ACC_HH_S1 = 575 -INTR_HEXAGON_M2_MPYUD_ACC_HL_S0 = 576 -INTR_HEXAGON_M2_MPYUD_ACC_HL_S1 = 577 -INTR_HEXAGON_M2_MPYUD_ACC_LH_S0 = 578 -INTR_HEXAGON_M2_MPYUD_ACC_LH_S1 = 579 -INTR_HEXAGON_M2_MPYUD_ACC_LL_S0 = 580 -INTR_HEXAGON_M2_MPYUD_ACC_LL_S1 = 581 -INTR_HEXAGON_M2_MPYUD_HH_S0 = 582 -INTR_HEXAGON_M2_MPYUD_HH_S1 = 583 -INTR_HEXAGON_M2_MPYUD_HL_S0 = 584 -INTR_HEXAGON_M2_MPYUD_HL_S1 = 585 -INTR_HEXAGON_M2_MPYUD_LH_S0 = 586 -INTR_HEXAGON_M2_MPYUD_LH_S1 = 587 -INTR_HEXAGON_M2_MPYUD_LL_S0 = 588 -INTR_HEXAGON_M2_MPYUD_LL_S1 = 589 -INTR_HEXAGON_M2_MPYUD_NAC_HH_S0 = 590 -INTR_HEXAGON_M2_MPYUD_NAC_HH_S1 = 591 -INTR_HEXAGON_M2_MPYUD_NAC_HL_S0 = 592 -INTR_HEXAGON_M2_MPYUD_NAC_HL_S1 = 593 -INTR_HEXAGON_M2_MPYUD_NAC_LH_S0 = 594 -INTR_HEXAGON_M2_MPYUD_NAC_LH_S1 = 595 -INTR_HEXAGON_M2_MPYUD_NAC_LL_S0 = 596 -INTR_HEXAGON_M2_MPYUD_NAC_LL_S1 = 597 -INTR_HEXAGON_M2_MPYUI = 598 -INTR_HEXAGON_M2_NACCI = 599 -INTR_HEXAGON_M2_NACCII = 600 -INTR_HEXAGON_M2_SUBACC = 601 -INTR_HEXAGON_M2_VABSDIFFH = 602 -INTR_HEXAGON_M2_VABSDIFFW = 603 -INTR_HEXAGON_M2_VCMAC_S0_SAT_I = 604 -INTR_HEXAGON_M2_VCMAC_S0_SAT_R = 605 -INTR_HEXAGON_M2_VCMPY_S0_SAT_I = 606 -INTR_HEXAGON_M2_VCMPY_S0_SAT_R = 607 -INTR_HEXAGON_M2_VCMPY_S1_SAT_I = 608 -INTR_HEXAGON_M2_VCMPY_S1_SAT_R = 609 -INTR_HEXAGON_M2_VDMACS_S0 = 610 -INTR_HEXAGON_M2_VDMACS_S1 = 611 -INTR_HEXAGON_M2_VDMPYRS_S0 = 612 -INTR_HEXAGON_M2_VDMPYRS_S1 = 613 -INTR_HEXAGON_M2_VDMPYS_S0 = 614 -INTR_HEXAGON_M2_VDMPYS_S1 = 615 -INTR_HEXAGON_M2_VMAC2 = 616 -INTR_HEXAGON_M2_VMAC2ES = 617 -INTR_HEXAGON_M2_VMAC2ES_S0 = 618 -INTR_HEXAGON_M2_VMAC2ES_S1 = 619 -INTR_HEXAGON_M2_VMAC2S_S0 = 620 -INTR_HEXAGON_M2_VMAC2S_S1 = 621 -INTR_HEXAGON_M2_VMPY2ES_S0 = 622 -INTR_HEXAGON_M2_VMPY2ES_S1 = 623 -INTR_HEXAGON_M2_VMPY2S_S0 = 624 -INTR_HEXAGON_M2_VMPY2S_S0PACK = 625 -INTR_HEXAGON_M2_VMPY2S_S1 = 626 -INTR_HEXAGON_M2_VMPY2S_S1PACK = 627 -INTR_HEXAGON_M2_VRADDUH = 628 -INTR_HEXAGON_M2_VRCMACI_S0 = 629 -INTR_HEXAGON_M2_VRCMACI_S0C = 630 -INTR_HEXAGON_M2_VRCMACR_S0 = 631 -INTR_HEXAGON_M2_VRCMACR_S0C = 632 -INTR_HEXAGON_M2_VRCMPYI_S0 = 633 -INTR_HEXAGON_M2_VRCMPYI_S0C = 634 -INTR_HEXAGON_M2_VRCMPYR_S0 = 635 -INTR_HEXAGON_M2_VRCMPYR_S0C = 636 -INTR_HEXAGON_M2_VRCMPYS_ACC_S1 = 637 -INTR_HEXAGON_M2_VRCMPYS_S1 = 638 -INTR_HEXAGON_M2_VRCMPYS_S1RP = 639 -INTR_HEXAGON_M2_VRMAC_S0 = 640 -INTR_HEXAGON_M2_VRMPY_S0 = 641 -INTR_HEXAGON_M2_XOR_XACC = 642 -INTR_HEXAGON_M4_AND_AND = 643 -INTR_HEXAGON_M4_AND_ANDN = 644 -INTR_HEXAGON_M4_AND_OR = 645 -INTR_HEXAGON_M4_AND_XOR = 646 -INTR_HEXAGON_M4_OR_AND = 647 -INTR_HEXAGON_M4_OR_ANDN = 648 -INTR_HEXAGON_M4_OR_OR = 649 -INTR_HEXAGON_M4_OR_XOR = 650 -INTR_HEXAGON_M4_XOR_AND = 651 -INTR_HEXAGON_M4_XOR_ANDN = 652 -INTR_HEXAGON_M4_XOR_OR = 653 -INTR_HEXAGON_M4_XOR_XACC = 654 -INTR_HEXAGON_S2_ADDASL_RRRI = 655 -INTR_HEXAGON_S2_ASL_I_P = 656 -INTR_HEXAGON_S2_ASL_I_P_ACC = 657 -INTR_HEXAGON_S2_ASL_I_P_AND = 658 -INTR_HEXAGON_S2_ASL_I_P_NAC = 659 -INTR_HEXAGON_S2_ASL_I_P_OR = 660 -INTR_HEXAGON_S2_ASL_I_P_XACC = 661 -INTR_HEXAGON_S2_ASL_I_R = 662 -INTR_HEXAGON_S2_ASL_I_R_ACC = 663 -INTR_HEXAGON_S2_ASL_I_R_AND = 664 -INTR_HEXAGON_S2_ASL_I_R_NAC = 665 -INTR_HEXAGON_S2_ASL_I_R_OR = 666 -INTR_HEXAGON_S2_ASL_I_R_SAT = 667 -INTR_HEXAGON_S2_ASL_I_R_XACC = 668 -INTR_HEXAGON_S2_ASL_I_VH = 669 -INTR_HEXAGON_S2_ASL_I_VW = 670 -INTR_HEXAGON_S2_ASL_R_P = 671 -INTR_HEXAGON_S2_ASL_R_P_ACC = 672 -INTR_HEXAGON_S2_ASL_R_P_AND = 673 -INTR_HEXAGON_S2_ASL_R_P_NAC = 674 -INTR_HEXAGON_S2_ASL_R_P_OR = 675 -INTR_HEXAGON_S2_ASL_R_R = 676 -INTR_HEXAGON_S2_ASL_R_R_ACC = 677 -INTR_HEXAGON_S2_ASL_R_R_AND = 678 -INTR_HEXAGON_S2_ASL_R_R_NAC = 679 -INTR_HEXAGON_S2_ASL_R_R_OR = 680 -INTR_HEXAGON_S2_ASL_R_R_SAT = 681 -INTR_HEXAGON_S2_ASL_R_VH = 682 -INTR_HEXAGON_S2_ASL_R_VW = 683 -INTR_HEXAGON_S2_ASR_I_P = 684 -INTR_HEXAGON_S2_ASR_I_P_ACC = 685 -INTR_HEXAGON_S2_ASR_I_P_AND = 686 -INTR_HEXAGON_S2_ASR_I_P_NAC = 687 -INTR_HEXAGON_S2_ASR_I_P_OR = 688 -INTR_HEXAGON_S2_ASR_I_R = 689 -INTR_HEXAGON_S2_ASR_I_R_ACC = 690 -INTR_HEXAGON_S2_ASR_I_R_AND = 691 -INTR_HEXAGON_S2_ASR_I_R_NAC = 692 -INTR_HEXAGON_S2_ASR_I_R_OR = 693 -INTR_HEXAGON_S2_ASR_I_R_RND = 694 -INTR_HEXAGON_S2_ASR_I_R_RND_GOODSYNTAX = 695 -INTR_HEXAGON_S2_ASR_I_SVW_TRUN = 696 -INTR_HEXAGON_S2_ASR_I_VH = 697 -INTR_HEXAGON_S2_ASR_I_VW = 698 -INTR_HEXAGON_S2_ASR_R_P = 699 -INTR_HEXAGON_S2_ASR_R_P_ACC = 700 -INTR_HEXAGON_S2_ASR_R_P_AND = 701 -INTR_HEXAGON_S2_ASR_R_P_NAC = 702 -INTR_HEXAGON_S2_ASR_R_P_OR = 703 -INTR_HEXAGON_S2_ASR_R_R = 704 -INTR_HEXAGON_S2_ASR_R_R_ACC = 705 -INTR_HEXAGON_S2_ASR_R_R_AND = 706 -INTR_HEXAGON_S2_ASR_R_R_NAC = 707 -INTR_HEXAGON_S2_ASR_R_R_OR = 708 -INTR_HEXAGON_S2_ASR_R_R_SAT = 709 -INTR_HEXAGON_S2_ASR_R_SVW_TRUN = 710 -INTR_HEXAGON_S2_ASR_R_VH = 711 -INTR_HEXAGON_S2_ASR_R_VW = 712 -INTR_HEXAGON_S2_BREV = 713 -INTR_HEXAGON_S2_CL0 = 714 -INTR_HEXAGON_S2_CL0P = 715 -INTR_HEXAGON_S2_CL1 = 716 -INTR_HEXAGON_S2_CL1P = 717 -INTR_HEXAGON_S2_CLB = 718 -INTR_HEXAGON_S2_CLBNORM = 719 -INTR_HEXAGON_S2_CLBP = 720 -INTR_HEXAGON_S2_CLRBIT_I = 721 -INTR_HEXAGON_S2_CLRBIT_R = 722 -INTR_HEXAGON_S2_CT0 = 723 -INTR_HEXAGON_S2_CT1 = 724 -INTR_HEXAGON_S2_DEINTERLEAVE = 725 -INTR_HEXAGON_S2_EXTRACTU = 726 -INTR_HEXAGON_S2_EXTRACTU_RP = 727 -INTR_HEXAGON_S2_EXTRACTUP = 728 -INTR_HEXAGON_S2_EXTRACTUP_RP = 729 -INTR_HEXAGON_S2_INSERT = 730 -INTR_HEXAGON_S2_INSERT_RP = 731 -INTR_HEXAGON_S2_INSERTP = 732 -INTR_HEXAGON_S2_INSERTP_RP = 733 -INTR_HEXAGON_S2_INTERLEAVE = 734 -INTR_HEXAGON_S2_LFSP = 735 -INTR_HEXAGON_S2_LSL_R_P = 736 -INTR_HEXAGON_S2_LSL_R_P_ACC = 737 -INTR_HEXAGON_S2_LSL_R_P_AND = 738 -INTR_HEXAGON_S2_LSL_R_P_NAC = 739 -INTR_HEXAGON_S2_LSL_R_P_OR = 740 -INTR_HEXAGON_S2_LSL_R_R = 741 -INTR_HEXAGON_S2_LSL_R_R_ACC = 742 -INTR_HEXAGON_S2_LSL_R_R_AND = 743 -INTR_HEXAGON_S2_LSL_R_R_NAC = 744 -INTR_HEXAGON_S2_LSL_R_R_OR = 745 -INTR_HEXAGON_S2_LSL_R_VH = 746 -INTR_HEXAGON_S2_LSL_R_VW = 747 -INTR_HEXAGON_S2_LSR_I_P = 748 -INTR_HEXAGON_S2_LSR_I_P_ACC = 749 -INTR_HEXAGON_S2_LSR_I_P_AND = 750 -INTR_HEXAGON_S2_LSR_I_P_NAC = 751 -INTR_HEXAGON_S2_LSR_I_P_OR = 752 -INTR_HEXAGON_S2_LSR_I_P_XACC = 753 -INTR_HEXAGON_S2_LSR_I_R = 754 -INTR_HEXAGON_S2_LSR_I_R_ACC = 755 -INTR_HEXAGON_S2_LSR_I_R_AND = 756 -INTR_HEXAGON_S2_LSR_I_R_NAC = 757 -INTR_HEXAGON_S2_LSR_I_R_OR = 758 -INTR_HEXAGON_S2_LSR_I_R_XACC = 759 -INTR_HEXAGON_S2_LSR_I_VH = 760 -INTR_HEXAGON_S2_LSR_I_VW = 761 -INTR_HEXAGON_S2_LSR_R_P = 762 -INTR_HEXAGON_S2_LSR_R_P_ACC = 763 -INTR_HEXAGON_S2_LSR_R_P_AND = 764 -INTR_HEXAGON_S2_LSR_R_P_NAC = 765 -INTR_HEXAGON_S2_LSR_R_P_OR = 766 -INTR_HEXAGON_S2_LSR_R_R = 767 -INTR_HEXAGON_S2_LSR_R_R_ACC = 768 -INTR_HEXAGON_S2_LSR_R_R_AND = 769 -INTR_HEXAGON_S2_LSR_R_R_NAC = 770 -INTR_HEXAGON_S2_LSR_R_R_OR = 771 -INTR_HEXAGON_S2_LSR_R_VH = 772 -INTR_HEXAGON_S2_LSR_R_VW = 773 -INTR_HEXAGON_S2_PACKHL = 774 -INTR_HEXAGON_S2_PARITYP = 775 -INTR_HEXAGON_S2_SETBIT_I = 776 -INTR_HEXAGON_S2_SETBIT_R = 777 -INTR_HEXAGON_S2_SHUFFEB = 778 -INTR_HEXAGON_S2_SHUFFEH = 779 -INTR_HEXAGON_S2_SHUFFOB = 780 -INTR_HEXAGON_S2_SHUFFOH = 781 -INTR_HEXAGON_S2_SVSATHB = 782 -INTR_HEXAGON_S2_SVSATHUB = 783 -INTR_HEXAGON_S2_TABLEIDXB_GOODSYNTAX = 784 -INTR_HEXAGON_S2_TABLEIDXD_GOODSYNTAX = 785 -INTR_HEXAGON_S2_TABLEIDXH_GOODSYNTAX = 786 -INTR_HEXAGON_S2_TABLEIDXW_GOODSYNTAX = 787 -INTR_HEXAGON_S2_TOGGLEBIT_I = 788 -INTR_HEXAGON_S2_TOGGLEBIT_R = 789 -INTR_HEXAGON_S2_TSTBIT_I = 790 -INTR_HEXAGON_S2_TSTBIT_R = 791 -INTR_HEXAGON_S2_VALIGNIB = 792 -INTR_HEXAGON_S2_VALIGNRB = 793 -INTR_HEXAGON_S2_VCROTATE = 794 -INTR_HEXAGON_S2_VRNDPACKWH = 795 -INTR_HEXAGON_S2_VRNDPACKWHS = 796 -INTR_HEXAGON_S2_VSATHB = 797 -INTR_HEXAGON_S2_VSATHB_NOPACK = 798 -INTR_HEXAGON_S2_VSATHUB = 799 -INTR_HEXAGON_S2_VSATHUB_NOPACK = 800 -INTR_HEXAGON_S2_VSATWH = 801 -INTR_HEXAGON_S2_VSATWH_NOPACK = 802 -INTR_HEXAGON_S2_VSATWUH = 803 -INTR_HEXAGON_S2_VSATWUH_NOPACK = 804 -INTR_HEXAGON_S2_VSPLATRB = 805 -INTR_HEXAGON_S2_VSPLATRH = 806 -INTR_HEXAGON_S2_VSPLICEIB = 807 -INTR_HEXAGON_S2_VSPLICERB = 808 -INTR_HEXAGON_S2_VSXTBH = 809 -INTR_HEXAGON_S2_VSXTHW = 810 -INTR_HEXAGON_S2_VTRUNEHB = 811 -INTR_HEXAGON_S2_VTRUNEWH = 812 -INTR_HEXAGON_S2_VTRUNOHB = 813 -INTR_HEXAGON_S2_VTRUNOWH = 814 -INTR_HEXAGON_S2_VZXTBH = 815 -INTR_HEXAGON_S2_VZXTHW = 816 -INTR_HEXAGON_S4_ADDADDI = 817 -INTR_HEXAGON_S4_ANDNP = 818 -INTR_HEXAGON_S4_OR_ANDI = 819 -INTR_HEXAGON_S4_OR_ANDIX = 820 -INTR_HEXAGON_S4_OR_ORI = 821 -INTR_HEXAGON_S4_ORNP = 822 -INTR_HEXAGON_S4_SUBADDI = 823 -INTR_HEXAGON_SI_TO_SXTHI_ASRH = 824 -INTR_INIT_TRAMPOLINE = 825 -INTR_INVARIANT_END = 826 -INTR_INVARIANT_START = 827 -INTR_LIFETIME_END = 828 -INTR_LIFETIME_START = 829 -INTR_LOG = 830 -INTR_LOG10 = 831 -INTR_LOG2 = 832 -INTR_LONGJMP = 833 -INTR_MEMCPY = 834 -INTR_MEMMOVE = 835 -INTR_MEMSET = 836 -INTR_OBJECTSIZE = 837 -INTR_PCMARKER = 838 -INTR_POW = 839 -INTR_POWI = 840 -INTR_PPC_ALTIVEC_DSS = 841 -INTR_PPC_ALTIVEC_DSSALL = 842 -INTR_PPC_ALTIVEC_DST = 843 -INTR_PPC_ALTIVEC_DSTST = 844 -INTR_PPC_ALTIVEC_DSTSTT = 845 -INTR_PPC_ALTIVEC_DSTT = 846 -INTR_PPC_ALTIVEC_LVEBX = 847 -INTR_PPC_ALTIVEC_LVEHX = 848 -INTR_PPC_ALTIVEC_LVEWX = 849 -INTR_PPC_ALTIVEC_LVSL = 850 -INTR_PPC_ALTIVEC_LVSR = 851 -INTR_PPC_ALTIVEC_LVX = 852 -INTR_PPC_ALTIVEC_LVXL = 853 -INTR_PPC_ALTIVEC_MFVSCR = 854 -INTR_PPC_ALTIVEC_MTVSCR = 855 -INTR_PPC_ALTIVEC_STVEBX = 856 -INTR_PPC_ALTIVEC_STVEHX = 857 -INTR_PPC_ALTIVEC_STVEWX = 858 -INTR_PPC_ALTIVEC_STVX = 859 -INTR_PPC_ALTIVEC_STVXL = 860 -INTR_PPC_ALTIVEC_VADDCUW = 861 -INTR_PPC_ALTIVEC_VADDSBS = 862 -INTR_PPC_ALTIVEC_VADDSHS = 863 -INTR_PPC_ALTIVEC_VADDSWS = 864 -INTR_PPC_ALTIVEC_VADDUBS = 865 -INTR_PPC_ALTIVEC_VADDUHS = 866 -INTR_PPC_ALTIVEC_VADDUWS = 867 -INTR_PPC_ALTIVEC_VAVGSB = 868 -INTR_PPC_ALTIVEC_VAVGSH = 869 -INTR_PPC_ALTIVEC_VAVGSW = 870 -INTR_PPC_ALTIVEC_VAVGUB = 871 -INTR_PPC_ALTIVEC_VAVGUH = 872 -INTR_PPC_ALTIVEC_VAVGUW = 873 -INTR_PPC_ALTIVEC_VCFSX = 874 -INTR_PPC_ALTIVEC_VCFUX = 875 -INTR_PPC_ALTIVEC_VCMPBFP = 876 -INTR_PPC_ALTIVEC_VCMPBFP_P = 877 -INTR_PPC_ALTIVEC_VCMPEQFP = 878 -INTR_PPC_ALTIVEC_VCMPEQFP_P = 879 -INTR_PPC_ALTIVEC_VCMPEQUB = 880 -INTR_PPC_ALTIVEC_VCMPEQUB_P = 881 -INTR_PPC_ALTIVEC_VCMPEQUH = 882 -INTR_PPC_ALTIVEC_VCMPEQUH_P = 883 -INTR_PPC_ALTIVEC_VCMPEQUW = 884 -INTR_PPC_ALTIVEC_VCMPEQUW_P = 885 -INTR_PPC_ALTIVEC_VCMPGEFP = 886 -INTR_PPC_ALTIVEC_VCMPGEFP_P = 887 -INTR_PPC_ALTIVEC_VCMPGTFP = 888 -INTR_PPC_ALTIVEC_VCMPGTFP_P = 889 -INTR_PPC_ALTIVEC_VCMPGTSB = 890 -INTR_PPC_ALTIVEC_VCMPGTSB_P = 891 -INTR_PPC_ALTIVEC_VCMPGTSH = 892 -INTR_PPC_ALTIVEC_VCMPGTSH_P = 893 -INTR_PPC_ALTIVEC_VCMPGTSW = 894 -INTR_PPC_ALTIVEC_VCMPGTSW_P = 895 -INTR_PPC_ALTIVEC_VCMPGTUB = 896 -INTR_PPC_ALTIVEC_VCMPGTUB_P = 897 -INTR_PPC_ALTIVEC_VCMPGTUH = 898 -INTR_PPC_ALTIVEC_VCMPGTUH_P = 899 -INTR_PPC_ALTIVEC_VCMPGTUW = 900 -INTR_PPC_ALTIVEC_VCMPGTUW_P = 901 -INTR_PPC_ALTIVEC_VCTSXS = 902 -INTR_PPC_ALTIVEC_VCTUXS = 903 -INTR_PPC_ALTIVEC_VEXPTEFP = 904 -INTR_PPC_ALTIVEC_VLOGEFP = 905 -INTR_PPC_ALTIVEC_VMADDFP = 906 -INTR_PPC_ALTIVEC_VMAXFP = 907 -INTR_PPC_ALTIVEC_VMAXSB = 908 -INTR_PPC_ALTIVEC_VMAXSH = 909 -INTR_PPC_ALTIVEC_VMAXSW = 910 -INTR_PPC_ALTIVEC_VMAXUB = 911 -INTR_PPC_ALTIVEC_VMAXUH = 912 -INTR_PPC_ALTIVEC_VMAXUW = 913 -INTR_PPC_ALTIVEC_VMHADDSHS = 914 -INTR_PPC_ALTIVEC_VMHRADDSHS = 915 -INTR_PPC_ALTIVEC_VMINFP = 916 -INTR_PPC_ALTIVEC_VMINSB = 917 -INTR_PPC_ALTIVEC_VMINSH = 918 -INTR_PPC_ALTIVEC_VMINSW = 919 -INTR_PPC_ALTIVEC_VMINUB = 920 -INTR_PPC_ALTIVEC_VMINUH = 921 -INTR_PPC_ALTIVEC_VMINUW = 922 -INTR_PPC_ALTIVEC_VMLADDUHM = 923 -INTR_PPC_ALTIVEC_VMSUMMBM = 924 -INTR_PPC_ALTIVEC_VMSUMSHM = 925 -INTR_PPC_ALTIVEC_VMSUMSHS = 926 -INTR_PPC_ALTIVEC_VMSUMUBM = 927 -INTR_PPC_ALTIVEC_VMSUMUHM = 928 -INTR_PPC_ALTIVEC_VMSUMUHS = 929 -INTR_PPC_ALTIVEC_VMULESB = 930 -INTR_PPC_ALTIVEC_VMULESH = 931 -INTR_PPC_ALTIVEC_VMULEUB = 932 -INTR_PPC_ALTIVEC_VMULEUH = 933 -INTR_PPC_ALTIVEC_VMULOSB = 934 -INTR_PPC_ALTIVEC_VMULOSH = 935 -INTR_PPC_ALTIVEC_VMULOUB = 936 -INTR_PPC_ALTIVEC_VMULOUH = 937 -INTR_PPC_ALTIVEC_VNMSUBFP = 938 -INTR_PPC_ALTIVEC_VPERM = 939 -INTR_PPC_ALTIVEC_VPKPX = 940 -INTR_PPC_ALTIVEC_VPKSHSS = 941 -INTR_PPC_ALTIVEC_VPKSHUS = 942 -INTR_PPC_ALTIVEC_VPKSWSS = 943 -INTR_PPC_ALTIVEC_VPKSWUS = 944 -INTR_PPC_ALTIVEC_VPKUHUS = 945 -INTR_PPC_ALTIVEC_VPKUWUS = 946 -INTR_PPC_ALTIVEC_VREFP = 947 -INTR_PPC_ALTIVEC_VRFIM = 948 -INTR_PPC_ALTIVEC_VRFIN = 949 -INTR_PPC_ALTIVEC_VRFIP = 950 -INTR_PPC_ALTIVEC_VRFIZ = 951 -INTR_PPC_ALTIVEC_VRLB = 952 -INTR_PPC_ALTIVEC_VRLH = 953 -INTR_PPC_ALTIVEC_VRLW = 954 -INTR_PPC_ALTIVEC_VRSQRTEFP = 955 -INTR_PPC_ALTIVEC_VSEL = 956 -INTR_PPC_ALTIVEC_VSL = 957 -INTR_PPC_ALTIVEC_VSLB = 958 -INTR_PPC_ALTIVEC_VSLH = 959 -INTR_PPC_ALTIVEC_VSLO = 960 -INTR_PPC_ALTIVEC_VSLW = 961 -INTR_PPC_ALTIVEC_VSR = 962 -INTR_PPC_ALTIVEC_VSRAB = 963 -INTR_PPC_ALTIVEC_VSRAH = 964 -INTR_PPC_ALTIVEC_VSRAW = 965 -INTR_PPC_ALTIVEC_VSRB = 966 -INTR_PPC_ALTIVEC_VSRH = 967 -INTR_PPC_ALTIVEC_VSRO = 968 -INTR_PPC_ALTIVEC_VSRW = 969 -INTR_PPC_ALTIVEC_VSUBCUW = 970 -INTR_PPC_ALTIVEC_VSUBSBS = 971 -INTR_PPC_ALTIVEC_VSUBSHS = 972 -INTR_PPC_ALTIVEC_VSUBSWS = 973 -INTR_PPC_ALTIVEC_VSUBUBS = 974 -INTR_PPC_ALTIVEC_VSUBUHS = 975 -INTR_PPC_ALTIVEC_VSUBUWS = 976 -INTR_PPC_ALTIVEC_VSUM2SWS = 977 -INTR_PPC_ALTIVEC_VSUM4SBS = 978 -INTR_PPC_ALTIVEC_VSUM4SHS = 979 -INTR_PPC_ALTIVEC_VSUM4UBS = 980 -INTR_PPC_ALTIVEC_VSUMSWS = 981 -INTR_PPC_ALTIVEC_VUPKHPX = 982 -INTR_PPC_ALTIVEC_VUPKHSB = 983 -INTR_PPC_ALTIVEC_VUPKHSH = 984 -INTR_PPC_ALTIVEC_VUPKLPX = 985 -INTR_PPC_ALTIVEC_VUPKLSB = 986 -INTR_PPC_ALTIVEC_VUPKLSH = 987 -INTR_PPC_DCBA = 988 -INTR_PPC_DCBF = 989 -INTR_PPC_DCBI = 990 -INTR_PPC_DCBST = 991 -INTR_PPC_DCBT = 992 -INTR_PPC_DCBTST = 993 -INTR_PPC_DCBZ = 994 -INTR_PPC_DCBZL = 995 -INTR_PPC_SYNC = 996 -INTR_PREFETCH = 997 -INTR_PTR_ANNOTATION = 998 -INTR_PTX_BAR_SYNC = 999 -INTR_PTX_READ_CLOCK = 1000 -INTR_PTX_READ_CLOCK64 = 1001 -INTR_PTX_READ_CTAID_W = 1002 -INTR_PTX_READ_CTAID_X = 1003 -INTR_PTX_READ_CTAID_Y = 1004 -INTR_PTX_READ_CTAID_Z = 1005 -INTR_PTX_READ_GRIDID = 1006 -INTR_PTX_READ_LANEID = 1007 -INTR_PTX_READ_LANEMASK_EQ = 1008 -INTR_PTX_READ_LANEMASK_GE = 1009 -INTR_PTX_READ_LANEMASK_GT = 1010 -INTR_PTX_READ_LANEMASK_LE = 1011 -INTR_PTX_READ_LANEMASK_LT = 1012 -INTR_PTX_READ_NCTAID_W = 1013 -INTR_PTX_READ_NCTAID_X = 1014 -INTR_PTX_READ_NCTAID_Y = 1015 -INTR_PTX_READ_NCTAID_Z = 1016 -INTR_PTX_READ_NSMID = 1017 -INTR_PTX_READ_NTID_W = 1018 -INTR_PTX_READ_NTID_X = 1019 -INTR_PTX_READ_NTID_Y = 1020 -INTR_PTX_READ_NTID_Z = 1021 -INTR_PTX_READ_NWARPID = 1022 -INTR_PTX_READ_PM0 = 1023 -INTR_PTX_READ_PM1 = 1024 -INTR_PTX_READ_PM2 = 1025 -INTR_PTX_READ_PM3 = 1026 -INTR_PTX_READ_SMID = 1027 -INTR_PTX_READ_TID_W = 1028 -INTR_PTX_READ_TID_X = 1029 -INTR_PTX_READ_TID_Y = 1030 -INTR_PTX_READ_TID_Z = 1031 -INTR_PTX_READ_WARPID = 1032 -INTR_READCYCLECOUNTER = 1033 -INTR_RETURNADDRESS = 1034 -INTR_SADD_WITH_OVERFLOW = 1035 -INTR_SETJMP = 1036 -INTR_SIGLONGJMP = 1037 -INTR_SIGSETJMP = 1038 -INTR_SIN = 1039 -INTR_SMUL_WITH_OVERFLOW = 1040 -INTR_SPU_SI_A = 1041 -INTR_SPU_SI_ADDX = 1042 -INTR_SPU_SI_AH = 1043 -INTR_SPU_SI_AHI = 1044 -INTR_SPU_SI_AI = 1045 -INTR_SPU_SI_AND = 1046 -INTR_SPU_SI_ANDBI = 1047 -INTR_SPU_SI_ANDC = 1048 -INTR_SPU_SI_ANDHI = 1049 -INTR_SPU_SI_ANDI = 1050 -INTR_SPU_SI_BG = 1051 -INTR_SPU_SI_BGX = 1052 -INTR_SPU_SI_CEQ = 1053 -INTR_SPU_SI_CEQB = 1054 -INTR_SPU_SI_CEQBI = 1055 -INTR_SPU_SI_CEQH = 1056 -INTR_SPU_SI_CEQHI = 1057 -INTR_SPU_SI_CEQI = 1058 -INTR_SPU_SI_CG = 1059 -INTR_SPU_SI_CGT = 1060 -INTR_SPU_SI_CGTB = 1061 -INTR_SPU_SI_CGTBI = 1062 -INTR_SPU_SI_CGTH = 1063 -INTR_SPU_SI_CGTHI = 1064 -INTR_SPU_SI_CGTI = 1065 -INTR_SPU_SI_CGX = 1066 -INTR_SPU_SI_CLGT = 1067 -INTR_SPU_SI_CLGTB = 1068 -INTR_SPU_SI_CLGTBI = 1069 -INTR_SPU_SI_CLGTH = 1070 -INTR_SPU_SI_CLGTHI = 1071 -INTR_SPU_SI_CLGTI = 1072 -INTR_SPU_SI_DFA = 1073 -INTR_SPU_SI_DFM = 1074 -INTR_SPU_SI_DFMA = 1075 -INTR_SPU_SI_DFMS = 1076 -INTR_SPU_SI_DFNMA = 1077 -INTR_SPU_SI_DFNMS = 1078 -INTR_SPU_SI_DFS = 1079 -INTR_SPU_SI_FA = 1080 -INTR_SPU_SI_FCEQ = 1081 -INTR_SPU_SI_FCGT = 1082 -INTR_SPU_SI_FCMEQ = 1083 -INTR_SPU_SI_FCMGT = 1084 -INTR_SPU_SI_FM = 1085 -INTR_SPU_SI_FMA = 1086 -INTR_SPU_SI_FMS = 1087 -INTR_SPU_SI_FNMS = 1088 -INTR_SPU_SI_FS = 1089 -INTR_SPU_SI_FSMBI = 1090 -INTR_SPU_SI_MPY = 1091 -INTR_SPU_SI_MPYA = 1092 -INTR_SPU_SI_MPYH = 1093 -INTR_SPU_SI_MPYHH = 1094 -INTR_SPU_SI_MPYHHA = 1095 -INTR_SPU_SI_MPYHHAU = 1096 -INTR_SPU_SI_MPYHHU = 1097 -INTR_SPU_SI_MPYI = 1098 -INTR_SPU_SI_MPYS = 1099 -INTR_SPU_SI_MPYU = 1100 -INTR_SPU_SI_MPYUI = 1101 -INTR_SPU_SI_NAND = 1102 -INTR_SPU_SI_NOR = 1103 -INTR_SPU_SI_OR = 1104 -INTR_SPU_SI_ORBI = 1105 -INTR_SPU_SI_ORC = 1106 -INTR_SPU_SI_ORHI = 1107 -INTR_SPU_SI_ORI = 1108 -INTR_SPU_SI_SF = 1109 -INTR_SPU_SI_SFH = 1110 -INTR_SPU_SI_SFHI = 1111 -INTR_SPU_SI_SFI = 1112 -INTR_SPU_SI_SFX = 1113 -INTR_SPU_SI_SHLI = 1114 -INTR_SPU_SI_SHLQBI = 1115 -INTR_SPU_SI_SHLQBII = 1116 -INTR_SPU_SI_SHLQBY = 1117 -INTR_SPU_SI_SHLQBYI = 1118 -INTR_SPU_SI_XOR = 1119 -INTR_SPU_SI_XORBI = 1120 -INTR_SPU_SI_XORHI = 1121 -INTR_SPU_SI_XORI = 1122 -INTR_SQRT = 1123 -INTR_SSUB_WITH_OVERFLOW = 1124 -INTR_STACKPROTECTOR = 1125 -INTR_STACKRESTORE = 1126 -INTR_STACKSAVE = 1127 -INTR_TRAP = 1128 -INTR_UADD_WITH_OVERFLOW = 1129 -INTR_UMUL_WITH_OVERFLOW = 1130 -INTR_USUB_WITH_OVERFLOW = 1131 -INTR_VACOPY = 1132 -INTR_VAEND = 1133 -INTR_VAR_ANNOTATION = 1134 -INTR_VASTART = 1135 -INTR_X86_3DNOW_PAVGUSB = 1136 -INTR_X86_3DNOW_PF2ID = 1137 -INTR_X86_3DNOW_PFACC = 1138 -INTR_X86_3DNOW_PFADD = 1139 -INTR_X86_3DNOW_PFCMPEQ = 1140 -INTR_X86_3DNOW_PFCMPGE = 1141 -INTR_X86_3DNOW_PFCMPGT = 1142 -INTR_X86_3DNOW_PFMAX = 1143 -INTR_X86_3DNOW_PFMIN = 1144 -INTR_X86_3DNOW_PFMUL = 1145 -INTR_X86_3DNOW_PFRCP = 1146 -INTR_X86_3DNOW_PFRCPIT1 = 1147 -INTR_X86_3DNOW_PFRCPIT2 = 1148 -INTR_X86_3DNOW_PFRSQIT1 = 1149 -INTR_X86_3DNOW_PFRSQRT = 1150 -INTR_X86_3DNOW_PFSUB = 1151 -INTR_X86_3DNOW_PFSUBR = 1152 -INTR_X86_3DNOW_PI2FD = 1153 -INTR_X86_3DNOW_PMULHRW = 1154 -INTR_X86_3DNOWA_PF2IW = 1155 -INTR_X86_3DNOWA_PFNACC = 1156 -INTR_X86_3DNOWA_PFPNACC = 1157 -INTR_X86_3DNOWA_PI2FW = 1158 -INTR_X86_3DNOWA_PSWAPD = 1159 -INTR_X86_AESNI_AESDEC = 1160 -INTR_X86_AESNI_AESDECLAST = 1161 -INTR_X86_AESNI_AESENC = 1162 -INTR_X86_AESNI_AESENCLAST = 1163 -INTR_X86_AESNI_AESIMC = 1164 -INTR_X86_AESNI_AESKEYGENASSIST = 1165 -INTR_X86_AVX2_MASKLOAD_D = 1166 -INTR_X86_AVX2_MASKLOAD_D_256 = 1167 -INTR_X86_AVX2_MASKLOAD_Q = 1168 -INTR_X86_AVX2_MASKLOAD_Q_256 = 1169 -INTR_X86_AVX2_MASKSTORE_D = 1170 -INTR_X86_AVX2_MASKSTORE_D_256 = 1171 -INTR_X86_AVX2_MASKSTORE_Q = 1172 -INTR_X86_AVX2_MASKSTORE_Q_256 = 1173 -INTR_X86_AVX2_MOVNTDQA = 1174 -INTR_X86_AVX2_MPSADBW = 1175 -INTR_X86_AVX2_PABS_B = 1176 -INTR_X86_AVX2_PABS_D = 1177 -INTR_X86_AVX2_PABS_W = 1178 -INTR_X86_AVX2_PACKSSDW = 1179 -INTR_X86_AVX2_PACKSSWB = 1180 -INTR_X86_AVX2_PACKUSDW = 1181 -INTR_X86_AVX2_PACKUSWB = 1182 -INTR_X86_AVX2_PADDS_B = 1183 -INTR_X86_AVX2_PADDS_W = 1184 -INTR_X86_AVX2_PADDUS_B = 1185 -INTR_X86_AVX2_PADDUS_W = 1186 -INTR_X86_AVX2_PAVG_B = 1187 -INTR_X86_AVX2_PAVG_W = 1188 -INTR_X86_AVX2_PBLENDD_128 = 1189 -INTR_X86_AVX2_PBLENDD_256 = 1190 -INTR_X86_AVX2_PBLENDVB = 1191 -INTR_X86_AVX2_PBLENDW = 1192 -INTR_X86_AVX2_PBROADCASTB_128 = 1193 -INTR_X86_AVX2_PBROADCASTB_256 = 1194 -INTR_X86_AVX2_PBROADCASTD_128 = 1195 -INTR_X86_AVX2_PBROADCASTD_256 = 1196 -INTR_X86_AVX2_PBROADCASTQ_128 = 1197 -INTR_X86_AVX2_PBROADCASTQ_256 = 1198 -INTR_X86_AVX2_PBROADCASTW_128 = 1199 -INTR_X86_AVX2_PBROADCASTW_256 = 1200 -INTR_X86_AVX2_PERMD = 1201 -INTR_X86_AVX2_PERMPD = 1202 -INTR_X86_AVX2_PERMPS = 1203 -INTR_X86_AVX2_PERMQ = 1204 -INTR_X86_AVX2_PHADD_D = 1205 -INTR_X86_AVX2_PHADD_SW = 1206 -INTR_X86_AVX2_PHADD_W = 1207 -INTR_X86_AVX2_PHSUB_D = 1208 -INTR_X86_AVX2_PHSUB_SW = 1209 -INTR_X86_AVX2_PHSUB_W = 1210 -INTR_X86_AVX2_PMADD_UB_SW = 1211 -INTR_X86_AVX2_PMADD_WD = 1212 -INTR_X86_AVX2_PMAXS_B = 1213 -INTR_X86_AVX2_PMAXS_D = 1214 -INTR_X86_AVX2_PMAXS_W = 1215 -INTR_X86_AVX2_PMAXU_B = 1216 -INTR_X86_AVX2_PMAXU_D = 1217 -INTR_X86_AVX2_PMAXU_W = 1218 -INTR_X86_AVX2_PMINS_B = 1219 -INTR_X86_AVX2_PMINS_D = 1220 -INTR_X86_AVX2_PMINS_W = 1221 -INTR_X86_AVX2_PMINU_B = 1222 -INTR_X86_AVX2_PMINU_D = 1223 -INTR_X86_AVX2_PMINU_W = 1224 -INTR_X86_AVX2_PMOVMSKB = 1225 -INTR_X86_AVX2_PMOVSXBD = 1226 -INTR_X86_AVX2_PMOVSXBQ = 1227 -INTR_X86_AVX2_PMOVSXBW = 1228 -INTR_X86_AVX2_PMOVSXDQ = 1229 -INTR_X86_AVX2_PMOVSXWD = 1230 -INTR_X86_AVX2_PMOVSXWQ = 1231 -INTR_X86_AVX2_PMOVZXBD = 1232 -INTR_X86_AVX2_PMOVZXBQ = 1233 -INTR_X86_AVX2_PMOVZXBW = 1234 -INTR_X86_AVX2_PMOVZXDQ = 1235 -INTR_X86_AVX2_PMOVZXWD = 1236 -INTR_X86_AVX2_PMOVZXWQ = 1237 -INTR_X86_AVX2_PMUL_DQ = 1238 -INTR_X86_AVX2_PMUL_HR_SW = 1239 -INTR_X86_AVX2_PMULH_W = 1240 -INTR_X86_AVX2_PMULHU_W = 1241 -INTR_X86_AVX2_PMULU_DQ = 1242 -INTR_X86_AVX2_PSAD_BW = 1243 -INTR_X86_AVX2_PSHUF_B = 1244 -INTR_X86_AVX2_PSIGN_B = 1245 -INTR_X86_AVX2_PSIGN_D = 1246 -INTR_X86_AVX2_PSIGN_W = 1247 -INTR_X86_AVX2_PSLL_D = 1248 -INTR_X86_AVX2_PSLL_DQ = 1249 -INTR_X86_AVX2_PSLL_DQ_BS = 1250 -INTR_X86_AVX2_PSLL_Q = 1251 -INTR_X86_AVX2_PSLL_W = 1252 -INTR_X86_AVX2_PSLLI_D = 1253 -INTR_X86_AVX2_PSLLI_Q = 1254 -INTR_X86_AVX2_PSLLI_W = 1255 -INTR_X86_AVX2_PSLLV_D = 1256 -INTR_X86_AVX2_PSLLV_D_256 = 1257 -INTR_X86_AVX2_PSLLV_Q = 1258 -INTR_X86_AVX2_PSLLV_Q_256 = 1259 -INTR_X86_AVX2_PSRA_D = 1260 -INTR_X86_AVX2_PSRA_W = 1261 -INTR_X86_AVX2_PSRAI_D = 1262 -INTR_X86_AVX2_PSRAI_W = 1263 -INTR_X86_AVX2_PSRAV_D = 1264 -INTR_X86_AVX2_PSRAV_D_256 = 1265 -INTR_X86_AVX2_PSRL_D = 1266 -INTR_X86_AVX2_PSRL_DQ = 1267 -INTR_X86_AVX2_PSRL_DQ_BS = 1268 -INTR_X86_AVX2_PSRL_Q = 1269 -INTR_X86_AVX2_PSRL_W = 1270 -INTR_X86_AVX2_PSRLI_D = 1271 -INTR_X86_AVX2_PSRLI_Q = 1272 -INTR_X86_AVX2_PSRLI_W = 1273 -INTR_X86_AVX2_PSRLV_D = 1274 -INTR_X86_AVX2_PSRLV_D_256 = 1275 -INTR_X86_AVX2_PSRLV_Q = 1276 -INTR_X86_AVX2_PSRLV_Q_256 = 1277 -INTR_X86_AVX2_PSUBS_B = 1278 -INTR_X86_AVX2_PSUBS_W = 1279 -INTR_X86_AVX2_PSUBUS_B = 1280 -INTR_X86_AVX2_PSUBUS_W = 1281 -INTR_X86_AVX2_VBROADCAST_SD_PD_256 = 1282 -INTR_X86_AVX2_VBROADCAST_SS_PS = 1283 -INTR_X86_AVX2_VBROADCAST_SS_PS_256 = 1284 -INTR_X86_AVX2_VBROADCASTI128 = 1285 -INTR_X86_AVX2_VEXTRACTI128 = 1286 -INTR_X86_AVX2_VINSERTI128 = 1287 -INTR_X86_AVX2_VPERM2I128 = 1288 -INTR_X86_AVX_ADDSUB_PD_256 = 1289 -INTR_X86_AVX_ADDSUB_PS_256 = 1290 -INTR_X86_AVX_BLEND_PD_256 = 1291 -INTR_X86_AVX_BLEND_PS_256 = 1292 -INTR_X86_AVX_BLENDV_PD_256 = 1293 -INTR_X86_AVX_BLENDV_PS_256 = 1294 -INTR_X86_AVX_CMP_PD_256 = 1295 -INTR_X86_AVX_CMP_PS_256 = 1296 -INTR_X86_AVX_CVT_PD2_PS_256 = 1297 -INTR_X86_AVX_CVT_PD2DQ_256 = 1298 -INTR_X86_AVX_CVT_PS2_PD_256 = 1299 -INTR_X86_AVX_CVT_PS2DQ_256 = 1300 -INTR_X86_AVX_CVTDQ2_PD_256 = 1301 -INTR_X86_AVX_CVTDQ2_PS_256 = 1302 -INTR_X86_AVX_CVTT_PD2DQ_256 = 1303 -INTR_X86_AVX_CVTT_PS2DQ_256 = 1304 -INTR_X86_AVX_DP_PS_256 = 1305 -INTR_X86_AVX_HADD_PD_256 = 1306 -INTR_X86_AVX_HADD_PS_256 = 1307 -INTR_X86_AVX_HSUB_PD_256 = 1308 -INTR_X86_AVX_HSUB_PS_256 = 1309 -INTR_X86_AVX_LDU_DQ_256 = 1310 -INTR_X86_AVX_MASKLOAD_PD = 1311 -INTR_X86_AVX_MASKLOAD_PD_256 = 1312 -INTR_X86_AVX_MASKLOAD_PS = 1313 -INTR_X86_AVX_MASKLOAD_PS_256 = 1314 -INTR_X86_AVX_MASKSTORE_PD = 1315 -INTR_X86_AVX_MASKSTORE_PD_256 = 1316 -INTR_X86_AVX_MASKSTORE_PS = 1317 -INTR_X86_AVX_MASKSTORE_PS_256 = 1318 -INTR_X86_AVX_MAX_PD_256 = 1319 -INTR_X86_AVX_MAX_PS_256 = 1320 -INTR_X86_AVX_MIN_PD_256 = 1321 -INTR_X86_AVX_MIN_PS_256 = 1322 -INTR_X86_AVX_MOVMSK_PD_256 = 1323 -INTR_X86_AVX_MOVMSK_PS_256 = 1324 -INTR_X86_AVX_MOVNT_DQ_256 = 1325 -INTR_X86_AVX_MOVNT_PD_256 = 1326 -INTR_X86_AVX_MOVNT_PS_256 = 1327 -INTR_X86_AVX_PTESTC_256 = 1328 -INTR_X86_AVX_PTESTNZC_256 = 1329 -INTR_X86_AVX_PTESTZ_256 = 1330 -INTR_X86_AVX_RCP_PS_256 = 1331 -INTR_X86_AVX_ROUND_PD_256 = 1332 -INTR_X86_AVX_ROUND_PS_256 = 1333 -INTR_X86_AVX_RSQRT_PS_256 = 1334 -INTR_X86_AVX_SQRT_PD_256 = 1335 -INTR_X86_AVX_SQRT_PS_256 = 1336 -INTR_X86_AVX_STOREU_DQ_256 = 1337 -INTR_X86_AVX_STOREU_PD_256 = 1338 -INTR_X86_AVX_STOREU_PS_256 = 1339 -INTR_X86_AVX_VBROADCAST_SD_256 = 1340 -INTR_X86_AVX_VBROADCAST_SS = 1341 -INTR_X86_AVX_VBROADCAST_SS_256 = 1342 -INTR_X86_AVX_VBROADCASTF128_PD_256 = 1343 -INTR_X86_AVX_VBROADCASTF128_PS_256 = 1344 -INTR_X86_AVX_VEXTRACTF128_PD_256 = 1345 -INTR_X86_AVX_VEXTRACTF128_PS_256 = 1346 -INTR_X86_AVX_VEXTRACTF128_SI_256 = 1347 -INTR_X86_AVX_VINSERTF128_PD_256 = 1348 -INTR_X86_AVX_VINSERTF128_PS_256 = 1349 -INTR_X86_AVX_VINSERTF128_SI_256 = 1350 -INTR_X86_AVX_VPERM2F128_PD_256 = 1351 -INTR_X86_AVX_VPERM2F128_PS_256 = 1352 -INTR_X86_AVX_VPERM2F128_SI_256 = 1353 -INTR_X86_AVX_VPERMIL_PD = 1354 -INTR_X86_AVX_VPERMIL_PD_256 = 1355 -INTR_X86_AVX_VPERMIL_PS = 1356 -INTR_X86_AVX_VPERMIL_PS_256 = 1357 -INTR_X86_AVX_VPERMILVAR_PD = 1358 -INTR_X86_AVX_VPERMILVAR_PD_256 = 1359 -INTR_X86_AVX_VPERMILVAR_PS = 1360 -INTR_X86_AVX_VPERMILVAR_PS_256 = 1361 -INTR_X86_AVX_VTESTC_PD = 1362 -INTR_X86_AVX_VTESTC_PD_256 = 1363 -INTR_X86_AVX_VTESTC_PS = 1364 -INTR_X86_AVX_VTESTC_PS_256 = 1365 -INTR_X86_AVX_VTESTNZC_PD = 1366 -INTR_X86_AVX_VTESTNZC_PD_256 = 1367 -INTR_X86_AVX_VTESTNZC_PS = 1368 -INTR_X86_AVX_VTESTNZC_PS_256 = 1369 -INTR_X86_AVX_VTESTZ_PD = 1370 -INTR_X86_AVX_VTESTZ_PD_256 = 1371 -INTR_X86_AVX_VTESTZ_PS = 1372 -INTR_X86_AVX_VTESTZ_PS_256 = 1373 -INTR_X86_AVX_VZEROALL = 1374 -INTR_X86_AVX_VZEROUPPER = 1375 -INTR_X86_BMI_BEXTR_32 = 1376 -INTR_X86_BMI_BEXTR_64 = 1377 -INTR_X86_BMI_BZHI_32 = 1378 -INTR_X86_BMI_BZHI_64 = 1379 -INTR_X86_BMI_PDEP_32 = 1380 -INTR_X86_BMI_PDEP_64 = 1381 -INTR_X86_BMI_PEXT_32 = 1382 -INTR_X86_BMI_PEXT_64 = 1383 -INTR_X86_FMA4_VFMADD_PD = 1384 -INTR_X86_FMA4_VFMADD_PD_256 = 1385 -INTR_X86_FMA4_VFMADD_PS = 1386 -INTR_X86_FMA4_VFMADD_PS_256 = 1387 -INTR_X86_FMA4_VFMADD_SD = 1388 -INTR_X86_FMA4_VFMADD_SS = 1389 -INTR_X86_FMA4_VFMADDSUB_PD = 1390 -INTR_X86_FMA4_VFMADDSUB_PD_256 = 1391 -INTR_X86_FMA4_VFMADDSUB_PS = 1392 -INTR_X86_FMA4_VFMADDSUB_PS_256 = 1393 -INTR_X86_FMA4_VFMSUB_PD = 1394 -INTR_X86_FMA4_VFMSUB_PD_256 = 1395 -INTR_X86_FMA4_VFMSUB_PS = 1396 -INTR_X86_FMA4_VFMSUB_PS_256 = 1397 -INTR_X86_FMA4_VFMSUB_SD = 1398 -INTR_X86_FMA4_VFMSUB_SS = 1399 -INTR_X86_FMA4_VFMSUBADD_PD = 1400 -INTR_X86_FMA4_VFMSUBADD_PD_256 = 1401 -INTR_X86_FMA4_VFMSUBADD_PS = 1402 -INTR_X86_FMA4_VFMSUBADD_PS_256 = 1403 -INTR_X86_FMA4_VFNMADD_PD = 1404 -INTR_X86_FMA4_VFNMADD_PD_256 = 1405 -INTR_X86_FMA4_VFNMADD_PS = 1406 -INTR_X86_FMA4_VFNMADD_PS_256 = 1407 -INTR_X86_FMA4_VFNMADD_SD = 1408 -INTR_X86_FMA4_VFNMADD_SS = 1409 -INTR_X86_FMA4_VFNMSUB_PD = 1410 -INTR_X86_FMA4_VFNMSUB_PD_256 = 1411 -INTR_X86_FMA4_VFNMSUB_PS = 1412 -INTR_X86_FMA4_VFNMSUB_PS_256 = 1413 -INTR_X86_FMA4_VFNMSUB_SD = 1414 -INTR_X86_FMA4_VFNMSUB_SS = 1415 -INTR_X86_INT = 1416 -INTR_X86_MMX_EMMS = 1417 -INTR_X86_MMX_FEMMS = 1418 -INTR_X86_MMX_MASKMOVQ = 1419 -INTR_X86_MMX_MOVNT_DQ = 1420 -INTR_X86_MMX_PACKSSDW = 1421 -INTR_X86_MMX_PACKSSWB = 1422 -INTR_X86_MMX_PACKUSWB = 1423 -INTR_X86_MMX_PADD_B = 1424 -INTR_X86_MMX_PADD_D = 1425 -INTR_X86_MMX_PADD_Q = 1426 -INTR_X86_MMX_PADD_W = 1427 -INTR_X86_MMX_PADDS_B = 1428 -INTR_X86_MMX_PADDS_W = 1429 -INTR_X86_MMX_PADDUS_B = 1430 -INTR_X86_MMX_PADDUS_W = 1431 -INTR_X86_MMX_PALIGNR_B = 1432 -INTR_X86_MMX_PAND = 1433 -INTR_X86_MMX_PANDN = 1434 -INTR_X86_MMX_PAVG_B = 1435 -INTR_X86_MMX_PAVG_W = 1436 -INTR_X86_MMX_PCMPEQ_B = 1437 -INTR_X86_MMX_PCMPEQ_D = 1438 -INTR_X86_MMX_PCMPEQ_W = 1439 -INTR_X86_MMX_PCMPGT_B = 1440 -INTR_X86_MMX_PCMPGT_D = 1441 -INTR_X86_MMX_PCMPGT_W = 1442 -INTR_X86_MMX_PEXTR_W = 1443 -INTR_X86_MMX_PINSR_W = 1444 -INTR_X86_MMX_PMADD_WD = 1445 -INTR_X86_MMX_PMAXS_W = 1446 -INTR_X86_MMX_PMAXU_B = 1447 -INTR_X86_MMX_PMINS_W = 1448 -INTR_X86_MMX_PMINU_B = 1449 -INTR_X86_MMX_PMOVMSKB = 1450 -INTR_X86_MMX_PMULH_W = 1451 -INTR_X86_MMX_PMULHU_W = 1452 -INTR_X86_MMX_PMULL_W = 1453 -INTR_X86_MMX_PMULU_DQ = 1454 -INTR_X86_MMX_POR = 1455 -INTR_X86_MMX_PSAD_BW = 1456 -INTR_X86_MMX_PSLL_D = 1457 -INTR_X86_MMX_PSLL_Q = 1458 -INTR_X86_MMX_PSLL_W = 1459 -INTR_X86_MMX_PSLLI_D = 1460 -INTR_X86_MMX_PSLLI_Q = 1461 -INTR_X86_MMX_PSLLI_W = 1462 -INTR_X86_MMX_PSRA_D = 1463 -INTR_X86_MMX_PSRA_W = 1464 -INTR_X86_MMX_PSRAI_D = 1465 -INTR_X86_MMX_PSRAI_W = 1466 -INTR_X86_MMX_PSRL_D = 1467 -INTR_X86_MMX_PSRL_Q = 1468 -INTR_X86_MMX_PSRL_W = 1469 -INTR_X86_MMX_PSRLI_D = 1470 -INTR_X86_MMX_PSRLI_Q = 1471 -INTR_X86_MMX_PSRLI_W = 1472 -INTR_X86_MMX_PSUB_B = 1473 -INTR_X86_MMX_PSUB_D = 1474 -INTR_X86_MMX_PSUB_Q = 1475 -INTR_X86_MMX_PSUB_W = 1476 -INTR_X86_MMX_PSUBS_B = 1477 -INTR_X86_MMX_PSUBS_W = 1478 -INTR_X86_MMX_PSUBUS_B = 1479 -INTR_X86_MMX_PSUBUS_W = 1480 -INTR_X86_MMX_PUNPCKHBW = 1481 -INTR_X86_MMX_PUNPCKHDQ = 1482 -INTR_X86_MMX_PUNPCKHWD = 1483 -INTR_X86_MMX_PUNPCKLBW = 1484 -INTR_X86_MMX_PUNPCKLDQ = 1485 -INTR_X86_MMX_PUNPCKLWD = 1486 -INTR_X86_MMX_PXOR = 1487 -INTR_X86_RDFSBASE_32 = 1488 -INTR_X86_RDFSBASE_64 = 1489 -INTR_X86_RDGSBASE_32 = 1490 -INTR_X86_RDGSBASE_64 = 1491 -INTR_X86_SSE2_ADD_SD = 1492 -INTR_X86_SSE2_CLFLUSH = 1493 -INTR_X86_SSE2_CMP_PD = 1494 -INTR_X86_SSE2_CMP_SD = 1495 -INTR_X86_SSE2_COMIEQ_SD = 1496 -INTR_X86_SSE2_COMIGE_SD = 1497 -INTR_X86_SSE2_COMIGT_SD = 1498 -INTR_X86_SSE2_COMILE_SD = 1499 -INTR_X86_SSE2_COMILT_SD = 1500 -INTR_X86_SSE2_COMINEQ_SD = 1501 -INTR_X86_SSE2_CVTDQ2PD = 1502 -INTR_X86_SSE2_CVTDQ2PS = 1503 -INTR_X86_SSE2_CVTPD2DQ = 1504 -INTR_X86_SSE2_CVTPD2PS = 1505 -INTR_X86_SSE2_CVTPS2DQ = 1506 -INTR_X86_SSE2_CVTPS2PD = 1507 -INTR_X86_SSE2_CVTSD2SI = 1508 -INTR_X86_SSE2_CVTSD2SI64 = 1509 -INTR_X86_SSE2_CVTSD2SS = 1510 -INTR_X86_SSE2_CVTSI2SD = 1511 -INTR_X86_SSE2_CVTSI642SD = 1512 -INTR_X86_SSE2_CVTSS2SD = 1513 -INTR_X86_SSE2_CVTTPD2DQ = 1514 -INTR_X86_SSE2_CVTTPS2DQ = 1515 -INTR_X86_SSE2_CVTTSD2SI = 1516 -INTR_X86_SSE2_CVTTSD2SI64 = 1517 -INTR_X86_SSE2_DIV_SD = 1518 -INTR_X86_SSE2_LFENCE = 1519 -INTR_X86_SSE2_MASKMOV_DQU = 1520 -INTR_X86_SSE2_MAX_PD = 1521 -INTR_X86_SSE2_MAX_SD = 1522 -INTR_X86_SSE2_MFENCE = 1523 -INTR_X86_SSE2_MIN_PD = 1524 -INTR_X86_SSE2_MIN_SD = 1525 -INTR_X86_SSE2_MOVMSK_PD = 1526 -INTR_X86_SSE2_MUL_SD = 1527 -INTR_X86_SSE2_PACKSSDW_128 = 1528 -INTR_X86_SSE2_PACKSSWB_128 = 1529 -INTR_X86_SSE2_PACKUSWB_128 = 1530 -INTR_X86_SSE2_PADDS_B = 1531 -INTR_X86_SSE2_PADDS_W = 1532 -INTR_X86_SSE2_PADDUS_B = 1533 -INTR_X86_SSE2_PADDUS_W = 1534 -INTR_X86_SSE2_PAVG_B = 1535 -INTR_X86_SSE2_PAVG_W = 1536 -INTR_X86_SSE2_PMADD_WD = 1537 -INTR_X86_SSE2_PMAXS_W = 1538 -INTR_X86_SSE2_PMAXU_B = 1539 -INTR_X86_SSE2_PMINS_W = 1540 -INTR_X86_SSE2_PMINU_B = 1541 -INTR_X86_SSE2_PMOVMSKB_128 = 1542 -INTR_X86_SSE2_PMULH_W = 1543 -INTR_X86_SSE2_PMULHU_W = 1544 -INTR_X86_SSE2_PMULU_DQ = 1545 -INTR_X86_SSE2_PSAD_BW = 1546 -INTR_X86_SSE2_PSLL_D = 1547 -INTR_X86_SSE2_PSLL_DQ = 1548 -INTR_X86_SSE2_PSLL_DQ_BS = 1549 -INTR_X86_SSE2_PSLL_Q = 1550 -INTR_X86_SSE2_PSLL_W = 1551 -INTR_X86_SSE2_PSLLI_D = 1552 -INTR_X86_SSE2_PSLLI_Q = 1553 -INTR_X86_SSE2_PSLLI_W = 1554 -INTR_X86_SSE2_PSRA_D = 1555 -INTR_X86_SSE2_PSRA_W = 1556 -INTR_X86_SSE2_PSRAI_D = 1557 -INTR_X86_SSE2_PSRAI_W = 1558 -INTR_X86_SSE2_PSRL_D = 1559 -INTR_X86_SSE2_PSRL_DQ = 1560 -INTR_X86_SSE2_PSRL_DQ_BS = 1561 -INTR_X86_SSE2_PSRL_Q = 1562 -INTR_X86_SSE2_PSRL_W = 1563 -INTR_X86_SSE2_PSRLI_D = 1564 -INTR_X86_SSE2_PSRLI_Q = 1565 -INTR_X86_SSE2_PSRLI_W = 1566 -INTR_X86_SSE2_PSUBS_B = 1567 -INTR_X86_SSE2_PSUBS_W = 1568 -INTR_X86_SSE2_PSUBUS_B = 1569 -INTR_X86_SSE2_PSUBUS_W = 1570 -INTR_X86_SSE2_SQRT_PD = 1571 -INTR_X86_SSE2_SQRT_SD = 1572 -INTR_X86_SSE2_STOREL_DQ = 1573 -INTR_X86_SSE2_STOREU_DQ = 1574 -INTR_X86_SSE2_STOREU_PD = 1575 -INTR_X86_SSE2_SUB_SD = 1576 -INTR_X86_SSE2_UCOMIEQ_SD = 1577 -INTR_X86_SSE2_UCOMIGE_SD = 1578 -INTR_X86_SSE2_UCOMIGT_SD = 1579 -INTR_X86_SSE2_UCOMILE_SD = 1580 -INTR_X86_SSE2_UCOMILT_SD = 1581 -INTR_X86_SSE2_UCOMINEQ_SD = 1582 -INTR_X86_SSE3_ADDSUB_PD = 1583 -INTR_X86_SSE3_ADDSUB_PS = 1584 -INTR_X86_SSE3_HADD_PD = 1585 -INTR_X86_SSE3_HADD_PS = 1586 -INTR_X86_SSE3_HSUB_PD = 1587 -INTR_X86_SSE3_HSUB_PS = 1588 -INTR_X86_SSE3_LDU_DQ = 1589 -INTR_X86_SSE3_MONITOR = 1590 -INTR_X86_SSE3_MWAIT = 1591 -INTR_X86_SSE41_BLENDPD = 1592 -INTR_X86_SSE41_BLENDPS = 1593 -INTR_X86_SSE41_BLENDVPD = 1594 -INTR_X86_SSE41_BLENDVPS = 1595 -INTR_X86_SSE41_DPPD = 1596 -INTR_X86_SSE41_DPPS = 1597 -INTR_X86_SSE41_EXTRACTPS = 1598 -INTR_X86_SSE41_INSERTPS = 1599 -INTR_X86_SSE41_MOVNTDQA = 1600 -INTR_X86_SSE41_MPSADBW = 1601 -INTR_X86_SSE41_PACKUSDW = 1602 -INTR_X86_SSE41_PBLENDVB = 1603 -INTR_X86_SSE41_PBLENDW = 1604 -INTR_X86_SSE41_PEXTRB = 1605 -INTR_X86_SSE41_PEXTRD = 1606 -INTR_X86_SSE41_PEXTRQ = 1607 -INTR_X86_SSE41_PHMINPOSUW = 1608 -INTR_X86_SSE41_PMAXSB = 1609 -INTR_X86_SSE41_PMAXSD = 1610 -INTR_X86_SSE41_PMAXUD = 1611 -INTR_X86_SSE41_PMAXUW = 1612 -INTR_X86_SSE41_PMINSB = 1613 -INTR_X86_SSE41_PMINSD = 1614 -INTR_X86_SSE41_PMINUD = 1615 -INTR_X86_SSE41_PMINUW = 1616 -INTR_X86_SSE41_PMOVSXBD = 1617 -INTR_X86_SSE41_PMOVSXBQ = 1618 -INTR_X86_SSE41_PMOVSXBW = 1619 -INTR_X86_SSE41_PMOVSXDQ = 1620 -INTR_X86_SSE41_PMOVSXWD = 1621 -INTR_X86_SSE41_PMOVSXWQ = 1622 -INTR_X86_SSE41_PMOVZXBD = 1623 -INTR_X86_SSE41_PMOVZXBQ = 1624 -INTR_X86_SSE41_PMOVZXBW = 1625 -INTR_X86_SSE41_PMOVZXDQ = 1626 -INTR_X86_SSE41_PMOVZXWD = 1627 -INTR_X86_SSE41_PMOVZXWQ = 1628 -INTR_X86_SSE41_PMULDQ = 1629 -INTR_X86_SSE41_PTESTC = 1630 -INTR_X86_SSE41_PTESTNZC = 1631 -INTR_X86_SSE41_PTESTZ = 1632 -INTR_X86_SSE41_ROUND_PD = 1633 -INTR_X86_SSE41_ROUND_PS = 1634 -INTR_X86_SSE41_ROUND_SD = 1635 -INTR_X86_SSE41_ROUND_SS = 1636 -INTR_X86_SSE42_CRC32_32_16 = 1637 -INTR_X86_SSE42_CRC32_32_32 = 1638 -INTR_X86_SSE42_CRC32_32_8 = 1639 -INTR_X86_SSE42_CRC32_64_64 = 1640 -INTR_X86_SSE42_CRC32_64_8 = 1641 -INTR_X86_SSE42_PCMPESTRI128 = 1642 -INTR_X86_SSE42_PCMPESTRIA128 = 1643 -INTR_X86_SSE42_PCMPESTRIC128 = 1644 -INTR_X86_SSE42_PCMPESTRIO128 = 1645 -INTR_X86_SSE42_PCMPESTRIS128 = 1646 -INTR_X86_SSE42_PCMPESTRIZ128 = 1647 -INTR_X86_SSE42_PCMPESTRM128 = 1648 -INTR_X86_SSE42_PCMPISTRI128 = 1649 -INTR_X86_SSE42_PCMPISTRIA128 = 1650 -INTR_X86_SSE42_PCMPISTRIC128 = 1651 -INTR_X86_SSE42_PCMPISTRIO128 = 1652 -INTR_X86_SSE42_PCMPISTRIS128 = 1653 -INTR_X86_SSE42_PCMPISTRIZ128 = 1654 -INTR_X86_SSE42_PCMPISTRM128 = 1655 -INTR_X86_SSE_ADD_SS = 1656 -INTR_X86_SSE_CMP_PS = 1657 -INTR_X86_SSE_CMP_SS = 1658 -INTR_X86_SSE_COMIEQ_SS = 1659 -INTR_X86_SSE_COMIGE_SS = 1660 -INTR_X86_SSE_COMIGT_SS = 1661 -INTR_X86_SSE_COMILE_SS = 1662 -INTR_X86_SSE_COMILT_SS = 1663 -INTR_X86_SSE_COMINEQ_SS = 1664 -INTR_X86_SSE_CVTPD2PI = 1665 -INTR_X86_SSE_CVTPI2PD = 1666 -INTR_X86_SSE_CVTPI2PS = 1667 -INTR_X86_SSE_CVTPS2PI = 1668 -INTR_X86_SSE_CVTSI2SS = 1669 -INTR_X86_SSE_CVTSI642SS = 1670 -INTR_X86_SSE_CVTSS2SI = 1671 -INTR_X86_SSE_CVTSS2SI64 = 1672 -INTR_X86_SSE_CVTTPD2PI = 1673 -INTR_X86_SSE_CVTTPS2PI = 1674 -INTR_X86_SSE_CVTTSS2SI = 1675 -INTR_X86_SSE_CVTTSS2SI64 = 1676 -INTR_X86_SSE_DIV_SS = 1677 -INTR_X86_SSE_LDMXCSR = 1678 -INTR_X86_SSE_MAX_PS = 1679 -INTR_X86_SSE_MAX_SS = 1680 -INTR_X86_SSE_MIN_PS = 1681 -INTR_X86_SSE_MIN_SS = 1682 -INTR_X86_SSE_MOVMSK_PS = 1683 -INTR_X86_SSE_MUL_SS = 1684 -INTR_X86_SSE_PSHUF_W = 1685 -INTR_X86_SSE_RCP_PS = 1686 -INTR_X86_SSE_RCP_SS = 1687 -INTR_X86_SSE_RSQRT_PS = 1688 -INTR_X86_SSE_RSQRT_SS = 1689 -INTR_X86_SSE_SFENCE = 1690 -INTR_X86_SSE_SQRT_PS = 1691 -INTR_X86_SSE_SQRT_SS = 1692 -INTR_X86_SSE_STMXCSR = 1693 -INTR_X86_SSE_STOREU_PS = 1694 -INTR_X86_SSE_SUB_SS = 1695 -INTR_X86_SSE_UCOMIEQ_SS = 1696 -INTR_X86_SSE_UCOMIGE_SS = 1697 -INTR_X86_SSE_UCOMIGT_SS = 1698 -INTR_X86_SSE_UCOMILE_SS = 1699 -INTR_X86_SSE_UCOMILT_SS = 1700 -INTR_X86_SSE_UCOMINEQ_SS = 1701 -INTR_X86_SSSE3_PABS_B = 1702 -INTR_X86_SSSE3_PABS_B_128 = 1703 -INTR_X86_SSSE3_PABS_D = 1704 -INTR_X86_SSSE3_PABS_D_128 = 1705 -INTR_X86_SSSE3_PABS_W = 1706 -INTR_X86_SSSE3_PABS_W_128 = 1707 -INTR_X86_SSSE3_PHADD_D = 1708 -INTR_X86_SSSE3_PHADD_D_128 = 1709 -INTR_X86_SSSE3_PHADD_SW = 1710 -INTR_X86_SSSE3_PHADD_SW_128 = 1711 -INTR_X86_SSSE3_PHADD_W = 1712 -INTR_X86_SSSE3_PHADD_W_128 = 1713 -INTR_X86_SSSE3_PHSUB_D = 1714 -INTR_X86_SSSE3_PHSUB_D_128 = 1715 -INTR_X86_SSSE3_PHSUB_SW = 1716 -INTR_X86_SSSE3_PHSUB_SW_128 = 1717 -INTR_X86_SSSE3_PHSUB_W = 1718 -INTR_X86_SSSE3_PHSUB_W_128 = 1719 -INTR_X86_SSSE3_PMADD_UB_SW = 1720 -INTR_X86_SSSE3_PMADD_UB_SW_128 = 1721 -INTR_X86_SSSE3_PMUL_HR_SW = 1722 -INTR_X86_SSSE3_PMUL_HR_SW_128 = 1723 -INTR_X86_SSSE3_PSHUF_B = 1724 -INTR_X86_SSSE3_PSHUF_B_128 = 1725 -INTR_X86_SSSE3_PSIGN_B = 1726 -INTR_X86_SSSE3_PSIGN_B_128 = 1727 -INTR_X86_SSSE3_PSIGN_D = 1728 -INTR_X86_SSSE3_PSIGN_D_128 = 1729 -INTR_X86_SSSE3_PSIGN_W = 1730 -INTR_X86_SSSE3_PSIGN_W_128 = 1731 -INTR_X86_VCVTPH2PS_128 = 1732 -INTR_X86_VCVTPH2PS_256 = 1733 -INTR_X86_VCVTPS2PH_128 = 1734 -INTR_X86_VCVTPS2PH_256 = 1735 -INTR_X86_WRFSBASE_32 = 1736 -INTR_X86_WRFSBASE_64 = 1737 -INTR_X86_WRGSBASE_32 = 1738 -INTR_X86_WRGSBASE_64 = 1739 -INTR_X86_XOP_VFRCZ_PD = 1740 -INTR_X86_XOP_VFRCZ_PD_256 = 1741 -INTR_X86_XOP_VFRCZ_PS = 1742 -INTR_X86_XOP_VFRCZ_PS_256 = 1743 -INTR_X86_XOP_VFRCZ_SD = 1744 -INTR_X86_XOP_VFRCZ_SS = 1745 -INTR_X86_XOP_VPCMOV = 1746 -INTR_X86_XOP_VPCMOV_256 = 1747 -INTR_X86_XOP_VPCOMEQB = 1748 -INTR_X86_XOP_VPCOMEQD = 1749 -INTR_X86_XOP_VPCOMEQQ = 1750 -INTR_X86_XOP_VPCOMEQUB = 1751 -INTR_X86_XOP_VPCOMEQUD = 1752 -INTR_X86_XOP_VPCOMEQUQ = 1753 -INTR_X86_XOP_VPCOMEQUW = 1754 -INTR_X86_XOP_VPCOMEQW = 1755 -INTR_X86_XOP_VPCOMFALSEB = 1756 -INTR_X86_XOP_VPCOMFALSED = 1757 -INTR_X86_XOP_VPCOMFALSEQ = 1758 -INTR_X86_XOP_VPCOMFALSEUB = 1759 -INTR_X86_XOP_VPCOMFALSEUD = 1760 -INTR_X86_XOP_VPCOMFALSEUQ = 1761 -INTR_X86_XOP_VPCOMFALSEUW = 1762 -INTR_X86_XOP_VPCOMFALSEW = 1763 -INTR_X86_XOP_VPCOMGEB = 1764 -INTR_X86_XOP_VPCOMGED = 1765 -INTR_X86_XOP_VPCOMGEQ = 1766 -INTR_X86_XOP_VPCOMGEUB = 1767 -INTR_X86_XOP_VPCOMGEUD = 1768 -INTR_X86_XOP_VPCOMGEUQ = 1769 -INTR_X86_XOP_VPCOMGEUW = 1770 -INTR_X86_XOP_VPCOMGEW = 1771 -INTR_X86_XOP_VPCOMGTB = 1772 -INTR_X86_XOP_VPCOMGTD = 1773 -INTR_X86_XOP_VPCOMGTQ = 1774 -INTR_X86_XOP_VPCOMGTUB = 1775 -INTR_X86_XOP_VPCOMGTUD = 1776 -INTR_X86_XOP_VPCOMGTUQ = 1777 -INTR_X86_XOP_VPCOMGTUW = 1778 -INTR_X86_XOP_VPCOMGTW = 1779 -INTR_X86_XOP_VPCOMLEB = 1780 -INTR_X86_XOP_VPCOMLED = 1781 -INTR_X86_XOP_VPCOMLEQ = 1782 -INTR_X86_XOP_VPCOMLEUB = 1783 -INTR_X86_XOP_VPCOMLEUD = 1784 -INTR_X86_XOP_VPCOMLEUQ = 1785 -INTR_X86_XOP_VPCOMLEUW = 1786 -INTR_X86_XOP_VPCOMLEW = 1787 -INTR_X86_XOP_VPCOMLTB = 1788 -INTR_X86_XOP_VPCOMLTD = 1789 -INTR_X86_XOP_VPCOMLTQ = 1790 -INTR_X86_XOP_VPCOMLTUB = 1791 -INTR_X86_XOP_VPCOMLTUD = 1792 -INTR_X86_XOP_VPCOMLTUQ = 1793 -INTR_X86_XOP_VPCOMLTUW = 1794 -INTR_X86_XOP_VPCOMLTW = 1795 -INTR_X86_XOP_VPCOMNEB = 1796 -INTR_X86_XOP_VPCOMNED = 1797 -INTR_X86_XOP_VPCOMNEQ = 1798 -INTR_X86_XOP_VPCOMNEUB = 1799 -INTR_X86_XOP_VPCOMNEUD = 1800 -INTR_X86_XOP_VPCOMNEUQ = 1801 -INTR_X86_XOP_VPCOMNEUW = 1802 -INTR_X86_XOP_VPCOMNEW = 1803 -INTR_X86_XOP_VPCOMTRUEB = 1804 -INTR_X86_XOP_VPCOMTRUED = 1805 -INTR_X86_XOP_VPCOMTRUEQ = 1806 -INTR_X86_XOP_VPCOMTRUEUB = 1807 -INTR_X86_XOP_VPCOMTRUEUD = 1808 -INTR_X86_XOP_VPCOMTRUEUQ = 1809 -INTR_X86_XOP_VPCOMTRUEUW = 1810 -INTR_X86_XOP_VPCOMTRUEW = 1811 -INTR_X86_XOP_VPERMIL2PD = 1812 -INTR_X86_XOP_VPERMIL2PD_256 = 1813 -INTR_X86_XOP_VPERMIL2PS = 1814 -INTR_X86_XOP_VPERMIL2PS_256 = 1815 -INTR_X86_XOP_VPHADDBD = 1816 -INTR_X86_XOP_VPHADDBQ = 1817 -INTR_X86_XOP_VPHADDBW = 1818 -INTR_X86_XOP_VPHADDDQ = 1819 -INTR_X86_XOP_VPHADDUBD = 1820 -INTR_X86_XOP_VPHADDUBQ = 1821 -INTR_X86_XOP_VPHADDUBW = 1822 -INTR_X86_XOP_VPHADDUDQ = 1823 -INTR_X86_XOP_VPHADDUWD = 1824 -INTR_X86_XOP_VPHADDUWQ = 1825 -INTR_X86_XOP_VPHADDWD = 1826 -INTR_X86_XOP_VPHADDWQ = 1827 -INTR_X86_XOP_VPHSUBBW = 1828 -INTR_X86_XOP_VPHSUBDQ = 1829 -INTR_X86_XOP_VPHSUBWD = 1830 -INTR_X86_XOP_VPMACSDD = 1831 -INTR_X86_XOP_VPMACSDQH = 1832 -INTR_X86_XOP_VPMACSDQL = 1833 -INTR_X86_XOP_VPMACSSDD = 1834 -INTR_X86_XOP_VPMACSSDQH = 1835 -INTR_X86_XOP_VPMACSSDQL = 1836 -INTR_X86_XOP_VPMACSSWD = 1837 -INTR_X86_XOP_VPMACSSWW = 1838 -INTR_X86_XOP_VPMACSWD = 1839 -INTR_X86_XOP_VPMACSWW = 1840 -INTR_X86_XOP_VPMADCSSWD = 1841 -INTR_X86_XOP_VPMADCSWD = 1842 -INTR_X86_XOP_VPPERM = 1843 -INTR_X86_XOP_VPROTB = 1844 -INTR_X86_XOP_VPROTD = 1845 -INTR_X86_XOP_VPROTQ = 1846 -INTR_X86_XOP_VPROTW = 1847 -INTR_X86_XOP_VPSHAB = 1848 -INTR_X86_XOP_VPSHAD = 1849 -INTR_X86_XOP_VPSHAQ = 1850 -INTR_X86_XOP_VPSHAW = 1851 -INTR_X86_XOP_VPSHLB = 1852 -INTR_X86_XOP_VPSHLD = 1853 -INTR_X86_XOP_VPSHLQ = 1854 -INTR_X86_XOP_VPSHLW = 1855 -INTR_XCORE_BITREV = 1856 -INTR_XCORE_CHECKEVENT = 1857 -INTR_XCORE_CHKCT = 1858 -INTR_XCORE_CLRE = 1859 -INTR_XCORE_CLRSR = 1860 -INTR_XCORE_CRC32 = 1861 -INTR_XCORE_CRC8 = 1862 -INTR_XCORE_EEU = 1863 -INTR_XCORE_ENDIN = 1864 -INTR_XCORE_FREER = 1865 -INTR_XCORE_GETED = 1866 -INTR_XCORE_GETET = 1867 -INTR_XCORE_GETID = 1868 -INTR_XCORE_GETPS = 1869 -INTR_XCORE_GETR = 1870 -INTR_XCORE_GETST = 1871 -INTR_XCORE_GETTS = 1872 -INTR_XCORE_IN = 1873 -INTR_XCORE_INCT = 1874 -INTR_XCORE_INITCP = 1875 -INTR_XCORE_INITDP = 1876 -INTR_XCORE_INITLR = 1877 -INTR_XCORE_INITPC = 1878 -INTR_XCORE_INITSP = 1879 -INTR_XCORE_INSHR = 1880 -INTR_XCORE_INT = 1881 -INTR_XCORE_MJOIN = 1882 -INTR_XCORE_MSYNC = 1883 -INTR_XCORE_OUT = 1884 -INTR_XCORE_OUTCT = 1885 -INTR_XCORE_OUTSHR = 1886 -INTR_XCORE_OUTT = 1887 -INTR_XCORE_PEEK = 1888 -INTR_XCORE_SETC = 1889 -INTR_XCORE_SETCLK = 1890 -INTR_XCORE_SETD = 1891 -INTR_XCORE_SETEV = 1892 -INTR_XCORE_SETPS = 1893 -INTR_XCORE_SETPSC = 1894 -INTR_XCORE_SETPT = 1895 -INTR_XCORE_SETRDY = 1896 -INTR_XCORE_SETSR = 1897 -INTR_XCORE_SETTW = 1898 -INTR_XCORE_SETV = 1899 -INTR_XCORE_SEXT = 1900 -INTR_XCORE_SSYNC = 1901 -INTR_XCORE_SYNCR = 1902 -INTR_XCORE_TESTCT = 1903 -INTR_XCORE_TESTWCT = 1904 -INTR_XCORE_WAITEVENT = 1905 -INTR_XCORE_ZEXT = 1906 - diff --git a/llvm/_util.py b/llvm/_util.py deleted file mode 100644 index 1ff4cc9..0000000 --- a/llvm/_util.py +++ /dev/null @@ -1,79 +0,0 @@ -# -# Copyright (c) 2008-10, Mahadevan R All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of this software, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -"""Utility functions and classes. - -Used only in other modules, not for public use.""" - -import llvm -import llvm._core as _core # for PyCObjectVoidPtrToPyLong - - -#===----------------------------------------------------------------------=== -# A set of helpers to check various things. Raises exceptions on -# failures. -#===----------------------------------------------------------------------=== - -def check_gen(obj, typ): - if not isinstance(obj, typ): - typ_str = typ.__name__ - msg = "argument not an instance of llvm.core.%s" % typ_str - raise TypeError(msg) - -def check_is_unowned(ownable): - if ownable.owner: - raise llvm.LLVMException("object is already owned") - - -#===----------------------------------------------------------------------=== -# A set of helpers to unpack a list of Python wrapper objects -# into a list of PyCObject wrapped objects, checking types along -# the way. -#===----------------------------------------------------------------------=== - -def unpack_gen(objlist, check_fn): - for obj in objlist: check_fn(obj) - return [ obj.ptr for obj in objlist ] - - -#===----------------------------------------------------------------------=== -# Helper to wrap over iterables (LLVMFirstXXX, LLVMNextXXX). This used -# to be a generator, but that loses subscriptability of the result, so -# we now return a list. -#===----------------------------------------------------------------------=== - -def wrapiter(first, next, container, wrapper): - ret = [] - ptr = first(container) - while ptr: - ret.append(wrapper(ptr)) - ptr = next(ptr) - return ret - diff --git a/llvm/_version.py b/llvm/_version.py new file mode 100644 index 0000000..a90c5b8 --- /dev/null +++ b/llvm/_version.py @@ -0,0 +1,193 @@ + +IN_LONG_VERSION_PY = True +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by github's download-from-tag +# feature). Distribution tarballs (build by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.7+ (https://github.com/warner/python-versioneer) + +# these strings will be replaced by git during git-archive +git_refnames = "$Format:%d$" +git_full = "$Format:%H$" +GIT = "git" + +import subprocess +import sys + +def run_command(args, cwd=None, verbose=False): + try: + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) + except EnvironmentError: + e = sys.exc_info()[1] + if verbose: + print("unable to run %s" % args[0]) + print(e) + return None + stdout = p.communicate()[0].strip() + if sys.version >= '3': + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % args[0]) + return None + return stdout + + +import sys +import re +import os.path + +def get_expanded_variables(versionfile_source): + # the code embedded in _version.py can just fetch the value of these + # variables. When used from setup.py, we don't want to import + # _version.py, so we do it with a regexp instead. This function is not + # used from _version.py. + variables = {} + try: + for line in open(versionfile_source,"r").readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["full"] = mo.group(1) + except EnvironmentError: + pass + return variables + +def versions_from_expanded_variables(variables, tag_prefix, verbose=False): + refnames = variables["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("variables are unexpanded, not using") + return {} # unexpanded, so not in an unpacked git-archive tarball + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + for ref in list(refs): + if not re.search(r'\d', ref): + if verbose: + print("discarding '%s', no digits" % ref) + refs.discard(ref) + # Assume all version tags have a digit. git's %d expansion + # behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us + # distinguish between branches and tags. By ignoring refnames + # without digits, we filter out many common branch names like + # "release" and "stabilization", as well as "HEAD" and "master". + if verbose: + print("remaining refs: %s" % ",".join(sorted(refs))) + for ref in sorted(refs): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return { "version": r, + "full": variables["full"].strip() } + # no suitable tags, so we use the full revision id + if verbose: + print("no suitable tags, using full revision id") + return { "version": variables["full"].strip(), + "full": variables["full"].strip() } + +def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): + # this runs 'git' from the root of the source tree. That either means + # someone ran a setup.py command (and this code is in versioneer.py, so + # IN_LONG_VERSION_PY=False, thus the containing directory is the root of + # the source tree), or someone ran a project-specific entry point (and + # this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the + # containing directory is somewhere deeper in the source tree). This only + # gets called if the git-archive 'subst' variables were *not* expanded, + # and _version.py hasn't already been rewritten with a short version + # string, meaning we're inside a checked out source tree. + + try: + here = os.path.abspath(__file__) + except NameError: + # some py2exe/bbfreeze/non-CPython implementations don't do __file__ + return {} # not always correct + + # versionfile_source is the relative path from the top of the source tree + # (where the .git directory might live) to this file. Invert this to find + # the root from __file__. + root = here + if IN_LONG_VERSION_PY: + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + root = os.path.dirname(here) + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %s" % root) + return {} + + stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], + cwd=root) + if stdout is None: + return {} + if not stdout.startswith(tag_prefix): + if verbose: + print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix)) + return {} + tag = stdout[len(tag_prefix):] + stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + if tag.endswith("-dirty"): + full += "-dirty" + return {"version": tag, "full": full} + + +def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): + if IN_LONG_VERSION_PY: + # We're running from _version.py. If it's from a source tree + # (execute-in-place), we can work upwards to find the root of the + # tree, and then check the parent directory for a version string. If + # it's in an installed application, there's no hope. + try: + here = os.path.abspath(__file__) + except NameError: + # py2exe/bbfreeze/non-CPython don't have __file__ + return {} # without __file__, we have no hope + # versionfile_source is the relative path from the top of the source + # tree to _version.py. Invert this to find the root from __file__. + root = here + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + # we're running from versioneer.py, which means we're running from + # the setup.py in a source tree. sys.argv[0] is setup.py in the root. + here = os.path.abspath(sys.argv[0]) + root = os.path.dirname(here) + + # Source tarballs conventionally unpack into a directory that includes + # both the project name and a version string. + dirname = os.path.basename(root) + if not dirname.startswith(parentdir_prefix): + if verbose: + print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" % + (root, dirname, parentdir_prefix)) + return None + return {"version": dirname[len(parentdir_prefix):], "full": ""} + +tag_prefix = "" +parentdir_prefix = "llvmpy-" +versionfile_source = "llvm/_version.py" + +def get_versions(default={"version": "unknown", "full": ""}, verbose=False): + variables = { "refnames": git_refnames, "full": git_full } + ver = versions_from_expanded_variables(variables, tag_prefix, verbose) + if not ver: + ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) + if not ver: + ver = versions_from_parentdir(parentdir_prefix, versionfile_source, + verbose) + if not ver: + ver = default + return ver diff --git a/llvm/core.py b/llvm/core.py index 0992dde..4db8135 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -28,156 +28,216 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -"""Core classes of LLVM. +from io import BytesIO +try: + from StringIO import StringIO +except ImportError: + try: + from cStringIO import StringIO + except ImportError: + from io import StringIO -The llvm.core module contains classes and constants required to build the -in-memory intermediate representation (IR) data structures.""" - - -import llvm # top-level, for common stuff -import llvm._core as _core # C wrappers -import llvm._util as _util # utility functions +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) -# type kinds (LLVMTypeKind enum) -TYPE_VOID = 0 -TYPE_HALF = 1 -TYPE_FLOAT = 2 -TYPE_DOUBLE = 3 -TYPE_X86_FP80 = 4 -TYPE_FP128 = 5 -TYPE_PPC_FP128 = 6 -TYPE_LABEL = 7 -TYPE_INTEGER = 8 -TYPE_FUNCTION = 9 -TYPE_STRUCT = 10 -TYPE_ARRAY = 11 -TYPE_POINTER = 12 -TYPE_VECTOR = 13 -TYPE_METADATA = 14 -TYPE_X86_MMX = 15 + @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) +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) -VALUE_ARGUMENT = 0 -VALUE_BASIC_BLOCK = 1 -VALUE_FUNCTION = 2 -VALUE_GLOBAL_ALIAS = 3 -VALUE_GLOBAL_VARIABLE = 4 -VALUE_UNDEF_VALUE = 5 -VALUE_BLOCK_ADDRESS = 6 -VALUE_CONSTANT_EXPR = 7 -VALUE_CONSTANT_AGGREGATE_ZERO = 8 -VALUE_CONSTANT_DATA_ARRAY = 9 -VALUE_CONSTANT_DATA_VECTOR = 10 -VALUE_CONSTANT_INT = 11 -VALUE_CONSTANT_FP = 12 -VALUE_CONSTANT_ARRAY = 13 -VALUE_CONSTANT_STRUCT = 14 -VALUE_CONSTANT_VECTOR = 15 -VALUE_CONSTANT_POINTER_NULL = 16 -VALUE_MD_NODE = 17 -VALUE_MD_STRING = 18 -VALUE_INLINE_ASM = 19 -VALUE_PSEUDO_SOURCE_VALUE = 20 -VALUE_FIXED_STACK_PSEUDO_SOURCE_VALUE = 21 -VALUE_INSTRUCTION = 22 +# According to the doxygen docs, it is not a good idea to use these enums. +# There are more values than those declared. +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 = 0 -CC_FASTCALL = 8 -CC_COLDCALL = 9 -CC_GHC = 10 -CC_X86_STDCALL = 64 -CC_X86_FASTCALL = 65 -CC_ARM_APCS = 66 -CC_ARM_AAPCS = 67 -CC_ARM_AAPCS_VFP = 68 -CC_MSP430_INTR = 69 -CC_X86_THISCALL = 70 -CC_PTX_KERNEL = 71 -CC_PTX_DEVICE = 72 -CC_MBLAZE_INTR = 73 -CC_MBLAZE_SVOL = 74 +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 = 32 -ICMP_NE = 33 -ICMP_UGT = 34 -ICMP_UGE = 35 -ICMP_ULT = 36 -ICMP_ULE = 37 -ICMP_SGT = 38 -ICMP_SGE = 39 -ICMP_SLT = 40 -ICMP_SLE = 41 +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 @@ -190,24 +250,33 @@ IPRED_SLT = ICMP_SLT IPRED_SLE = ICMP_SLE # real predicates -FCMP_FALSE = 0 -FCMP_OEQ = 1 -FCMP_OGT = 2 -FCMP_OGE = 3 -FCMP_OLT = 4 -FCMP_OLE = 5 -FCMP_ONE = 6 -FCMP_ORD = 7 -FCMP_UNO = 8 -FCMP_UEQ = 9 -FCMP_UGT = 10 -FCMP_UGE = 11 -FCMP_ULT = 12 -FCMP_ULE = 13 -FCMP_UNE = 14 -FCMP_TRUE = 15 + +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 @@ -225,98 +294,78 @@ RPRED_ULE = FCMP_ULE RPRED_UNE = FCMP_UNE RPRED_TRUE = FCMP_TRUE -# linkages (see llvm-c/Core.h) -LINKAGE_EXTERNAL = 0 -LINKAGE_AVAILABLE_EXTERNALLY = 1 -LINKAGE_LINKONCE_ANY = 2 -LINKAGE_LINKONCE_ODR = 3 -LINKAGE_WEAK_ANY = 4 -LINKAGE_WEAK_ODR = 5 -LINKAGE_APPENDING = 6 -LINKAGE_INTERNAL = 7 -LINKAGE_PRIVATE = 8 -LINKAGE_DLLIMPORT = 9 -LINKAGE_DLLEXPORT = 10 -LINKAGE_EXTERNAL_WEAK = 11 -LINKAGE_GHOST = 12 -LINKAGE_COMMON = 13 -LINKAGE_LINKER_PRIVATE = 14 -LINKAGE_LINKER_PRIVATE_WEAK = 15 -LINKAGE_LINKER_PRIVATE_WEAK_DEF_AUTO = 16 +# linkages (see llvm::GlobalValue::LinkageTypes) +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 = 0 -VISIBILITY_HIDDEN = 1 -VISIBILITY_PROTECTED = 2 +class VisibilityEnum(Enum): + prefix = 'VISIBILITY_' -# parameter attributes (see llvm/Attributes.h) -ATTR_NONE = 0 -ATTR_ZEXT = 1 -ATTR_SEXT = 2 -ATTR_NO_RETURN = 4 -ATTR_IN_REG = 8 -ATTR_STRUCT_RET = 16 -ATTR_NO_UNWIND = 32 -ATTR_NO_ALIAS = 64 -ATTR_BY_VAL = 128 -ATTR_NEST = 256 -ATTR_READ_NONE = 512 -ATTR_READONLY = 1024 -ATTR_NO_INLINE = 1<<11 -ATTR_ALWAYS_INLINE = 1<<12 -ATTR_OPTIMIZE_FOR_SIZE = 1<<13 -ATTR_STACK_PROTECT = 1<<14 -ATTR_STACK_PROTECT_REQ = 1<<15 -ATTR_ALIGNMENT = 1<<16 -ATTR_NO_CAPTURE = 1<<21 -ATTR_NO_REDZONE = 1<<22 -ATTR_NO_IMPLICIT_FLOAT = 1<<23 -ATTR_NAKED = 1<<24 -ATTR_INLINE_HINT = 1<<25 -ATTR_STACK_ALIGNMENT = 7<<26 -ATTR_HOTPATCH = 1<<29 + VISIBILITY_DEFAULT = api.llvm.GlobalValue.VisibilityTypes.DefaultVisibility + VISIBILITY_HIDDEN = api.llvm.GlobalValue.VisibilityTypes.HiddenVisibility + VISIBILITY_PROTECTED = api.llvm.GlobalValue.VisibilityTypes.ProtectedVisibility -# intrinsic IDs -from llvm._intrinsic_ids import * +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_' -#===----------------------------------------------------------------------=== -# Helpers (for internal use) -#===----------------------------------------------------------------------=== - -def check_is_type(obj): _util.check_gen(obj, Type) -def check_is_type_struct(obj): _util.check_gen(obj, StructType) -def check_is_value(obj): _util.check_gen(obj, Value) -def check_is_constant(obj): _util.check_gen(obj, Constant) -def check_is_function(obj): _util.check_gen(obj, Function) -def check_is_basic_block(obj): _util.check_gen(obj, BasicBlock) -def check_is_module(obj): _util.check_gen(obj, Module) - -def unpack_types(objlst): return _util.unpack_gen(objlst, check_is_type) -def unpack_values(objlst): return _util.unpack_gen(objlst, check_is_value) -def unpack_constants(objlst): return _util.unpack_gen(objlst, check_is_constant) - -def check_is_callable(obj): - if isinstance(obj, Function): - return - typ = obj.type - if isinstance(typ, PointerType) and \ - isinstance(typ.pointee, FunctionType): - return - raise TypeError("argument is neither a function nor a function pointer") - -def _to_int(v): - if v: - return 1 + if llvm.version >= (3, 3): + AttrVal = api.llvm.Attribute.AttrKind else: - return 0 + 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 -#===----------------------------------------------------------------------=== -# Module -#===----------------------------------------------------------------------=== +AttrEnum.declare() -class Module(llvm.Ownable, llvm.Cacheable): +class Module(llvm.Wrapper): """A Module instance stores all the information related to an LLVM module. Modules are the top level container of all other LLVM Intermediate @@ -330,6 +379,16 @@ class Module(llvm.Ownable, llvm.Cacheable): module_obj = Module.new('my_module') """ + __slots__ = '__weakref__' + __cache = weakref.WeakValueDictionary() + + def __new__(cls, ptr): + cached = cls.__cache.get(ptr) + if cached: + return cached + obj = object.__new__(cls) + cls.__cache[ptr] = obj + return obj @staticmethod def new(id): @@ -337,96 +396,102 @@ class Module(llvm.Ownable, llvm.Cacheable): Creates an instance of Module, having the id `id'. """ - return Module(_core.LLVMModuleCreateWithName(id)) + context = api.llvm.getGlobalContext() + m = api.llvm.Module.new(id, context) + return Module(m) @staticmethod - def from_bitcode(fileobj): + def from_bitcode(fileobj_or_str): """Create a Module instance from the contents of a bitcode - file.""" + file. - data = fileobj.read() - ret = _core.LLVMGetModuleFromBitcode(data) - if not ret: - raise llvm.LLVMException("Unable to create module from bitcode") - elif isinstance(ret, str): - raise llvm.LLVMException(ret) + fileobj_or_str -- takes a file-like object or string that contains + a module represented in bitcode. + """ + if isinstance(fileobj_or_str, str): + bc = fileobj_or_str else: - return Module(ret) + bc = fileobj_or_str.read() + errbuf = BytesIO() + context = api.llvm.getGlobalContext() + m = api.llvm.ParseBitCodeFile(bc, context, errbuf) + if not m: + raise Exception(errbuf.getvalue()) + errbuf.close() + return Module(m) + @staticmethod - def from_assembly(fileobj): + def from_assembly(fileobj_or_str): """Create a Module instance from the contents of an LLVM - assembly (.ll) file.""" + assembly (.ll) file. - data = fileobj.read() - ret = _core.LLVMGetModuleFromAssembly(data) - if not ret: - raise llvm.LLVMException("Unable to create module from assembly") - elif isinstance(ret, str): - raise llvm.LLVMException(ret) - else: - return Module(ret) - def __init__(self, ptr): - """DO NOT CALL DIRECTLY. - - Use the static method `Module.new' instead. + fileobj_or_str -- takes a file-like object or string that contains + a module represented in llvm-ir assembly. """ - llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeModule) + if isinstance(fileobj_or_str, str): + ir = fileobj_or_str + else: + ir = fileobj_or_str.read() + errbuf = BytesIO() + context = api.llvm.getGlobalContext() + m = api.llvm.ParseAssemblyString(ir, None, api.llvm.SMDiagnostic.new(), + context) + errbuf.close() + return Module(m) def __str__(self): """Text representation of a module. - Returns the textual representation (`llvm assembly') of the - module. Use it like this: + Returns the textual representation (`llvm assembly') of the + module. Use it like this: - ll = str(module_obj) - print module_obj # same as `print ll' - """ - return _core.LLVMDumpModuleToString(self.ptr) + ll = str(module_obj) + print module_obj # same as `print ll' + """ + return str(self._ptr) + + def __hash__(self): + return id(self._ptr) def __eq__(self, 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 + return not (self == rhs) + def _get_target(self): - return _core.LLVMGetTarget(self.ptr) + return self._ptr.getTargetTriple() def _set_target(self, value): - return _core.LLVMSetTarget(self.ptr, value) + return self._ptr.setTargetTriple(value) target = property(_get_target, _set_target, - """The target triple string describing the target host.""" - ) + doc="The target triple string describing the target host.") + def _get_data_layout(self): - return _core.LLVMGetDataLayout(self.ptr) + return self._ptr.getDataLayout() def _set_data_layout(self, value): - _core.LLVMSetDataLayout(self.ptr, value) + return self._ptr.setDataLayout(value) data_layout = property(_get_data_layout, _set_data_layout, - """The data layout string for the module's target platform. + doc = """The data layout string for the module's target platform. - The data layout strings is an encoded representation of - the type sizes and alignments expected by this module. - """ - ) + The data layout strings is an encoded representation of + the type sizes and alignments expected by this module. + """ + ) @property def pointer_size(self): - """Pointer size of target platform. + return self._ptr.getPointerSize() - Can be 0, 32 or 64. Zero represents - llvm::Module::AnyPointerSize.""" - return _core.LLVMModuleGetPointerSize(self.ptr) - - def link_in(self, other): + def link_in(self, other, preserve=False): """Link the `other' module into this one. The `other' module is linked into this one such that types, @@ -438,130 +503,246 @@ class Module(llvm.Ownable, llvm.Cacheable): In the future, this API might be replaced with a full-fledged Linker class. """ - check_is_module(other) - other.forget() # remove it from object cache - ret = _core.LLVMLinkModules(self.ptr, other.ptr) - if isinstance(ret, str): - raise llvm.LLVMException(ret) - # Do not try to destroy the other module's llvm::Module*. - other._own(llvm.DummyOwner()) + assert isinstance(other, Module) + enum_mode = api.llvm.Linker.LinkerMode + mode = enum_mode.PreserveSource if preserve else enum_mode.DestroySource + + with contextlib.closing(BytesIO()) as errmsg: + failed = api.llvm.Linker.LinkModules(self._ptr, + other._ptr, + mode, + errmsg) + if failed: + raise llvm.LLVMException(errmsg.getvalue()) def get_type_named(self, name): - """Return a Type object with the given name.""" - ptr = _core.LLVMGetTypeByName(self.ptr, name) - if ptr: - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) - return None + typ = self._ptr.getTypeByName(name) + if typ: + return StructType(typ) - def add_global_variable(self, ty, name): + def add_global_variable(self, ty, name, addrspace=0): """Add a global variable of given type with given name.""" - return GlobalVariable.new(self, ty, name) + external = api.llvm.GlobalVariable.LinkageTypes.ExternalLinkage + notthreadlocal = api.llvm.GlobalVariable.ThreadLocalMode.NotThreadLocal + init = None + insertbefore = None + ptr = api.llvm.GlobalVariable.new(self._ptr, + ty._ptr, + False, + external, + init, + name, + insertbefore, + notthreadlocal, + addrspace) + return _make_value(ptr) def get_global_variable_named(self, name): """Return a GlobalVariable object for the given name.""" - return GlobalVariable.get(self, name) + ptr = self._ptr.getNamedGlobal(name) + if ptr is None: + raise llvm.LLVMException("No global named: %s" % name) + return _make_value(ptr) @property def global_variables(self): - """All global variables in this module.""" - return _util.wrapiter(_core.LLVMGetFirstGlobal, - _core.LLVMGetNextGlobal, self.ptr, _make_value) + return list(map(_make_value, self._ptr.list_globals())) def add_function(self, ty, name): """Add a function of given type with given name.""" return Function.new(self, ty, name) +# fn = self.get_function_named(name) +# if fn is not None: +# raise llvm.LLVMException("Duplicated function %s" % name) +# return self.get_or_insert_function(ty, name) def get_function_named(self, name): """Return a Function object representing function with given name.""" return Function.get(self, name) +# fn = self._ptr.getFunction(name) +# if fn is not None: +# return _make_value(fn) def get_or_insert_function(self, ty, name): """Like get_function_named(), but does add_function() first, if - function is not present.""" + function is not present.""" return Function.get_or_insert(self, ty, name) +# constant = self._ptr.getOrInsertFunction(name, ty._ptr) +# try: +# fn = constant._downcast(api.llvm.Function) +# except ValueError: +# # bitcasted to function type +# return _make_value(constant) +# else: +# return _make_value(fn) @property def functions(self): """All functions in this module.""" - return _util.wrapiter(_core.LLVMGetFirstFunction, - _core.LLVMGetNextFunction, self.ptr, _make_value) + return list(map(_make_value, self._ptr.list_functions())) def verify(self): """Verify module. - Checks module for errors. Raises `llvm.LLVMException' on any - error.""" - ret = _core.LLVMVerifyModule(self.ptr) - if ret != "": - raise llvm.LLVMException(ret) + Checks module for errors. Raises `llvm.LLVMException' on any + error.""" + action = api.llvm.VerifierFailureAction.ReturnStatusAction + errio = BytesIO() + broken = api.llvm.verifyModule(self._ptr, action, errio) + if broken: + raise llvm.LLVMException(errio.getvalue()) - def to_bitcode(self, fileobj): + def to_bitcode(self, fileobj=None): """Write bitcode representation of module to given file-like - object.""" + object. - data = _core.LLVMGetBitcodeFromModule(self.ptr) - if not data: - raise llvm.LLVMException("Unable to create bitcode") - fileobj.write(data) + fileobj -- A file-like object to where the bitcode is written. + If it is None, the bitcode is returned. - def add_library(self, name): - return _core.LLVMModuleAddLibrary(self.ptr, name) + Return value -- Returns None if fileobj is not None. + Otherwise, return the bitcode as a bytestring. + """ + ret = False + if fileobj is None: + ret = True + fileobj = BytesIO() + api.llvm.WriteBitcodeToFile(self._ptr, fileobj) + if ret: + return fileobj.getvalue() + + def _get_id(self): + return self._ptr.getModuleIdentifier() + + def _set_id(self, string): + self._ptr.setModuleIdentifier(string) + + id = property(_get_id, _set_id) + + def _to_native_something(self, fileobj, cgft): + + cgft = api.llvm.TargetMachine.CodeGenFileType.CGFT_AssemblyFile + cgft = api.llvm.TargetMachine.CodeGenFileType.CGFT_ObjectFile + + from llvm.ee import TargetMachine + from llvm.passes import PassManager + from llvmpy import extra + tm = TargetMachine.new()._ptr + pm = PassManager.new()._ptr + formatted + failed = tm.addPassesToEmitFile(pm, fileobj, cgft, False) + + if failed: + raise llvm.LLVMException("Failed to write native object file") + if ret: + return fileobj.getvalue() -#===----------------------------------------------------------------------=== -# Types -#===----------------------------------------------------------------------=== + def to_native_object(self, fileobj=None): + '''Outputs the byte string of the module as native object code -class Type(object): + If a fileobj is given, the output is written to it; + Otherwise, the output is returned + ''' + ret = False + if fileobj is None: + ret = True + fileobj = BytesIO() + from llvm.ee import TargetMachine + tm = TargetMachine.new() + fileobj.write(tm.emit_object(self)) + if ret: + return fileobj.getvalue() + + + def to_native_assembly(self, fileobj=None): + '''Outputs the byte string of the module as native assembly code + + If a fileobj is given, the output is written to it; + Otherwise, the output is returned + ''' + ret = False + if fileobj is None: + ret = True + fileobj = StringIO() + from llvm.ee import TargetMachine + tm = TargetMachine.new() + asm = tm.emit_assembly(self) + fileobj.write(asm) + if ret: + return fileobj.getvalue() + + + def get_or_insert_named_metadata(self, name): + return NamedMetaData(self._ptr.getOrInsertNamedMetadata(name)) + + def get_named_metadata(self, name): + md = self._ptr.getNamedMetadata(name) + if md: + return NamedMetaData(md) + + def clone(self): + return Module(api.llvm.CloneModule(self._ptr)) + +class Type(llvm.Wrapper): """Represents a type, like a 32-bit integer or an 80-bit x86 float. Use one of the static methods to create an instance. Example: - ty = Type.double() + ty = Type.double() """ + __slots__ = '__name__' + _type_ = api.llvm.Type + + def __init__(self, ptr): + ptr = ptr._downcast(type(self)._type_) + super(Type, self).__init__(ptr) + + @property + def kind(self): + return self._ptr.getTypeID() @staticmethod def int(bits=32): """Create an integer type having the given bit width.""" - if bits == 1: - return _make_type(_core.LLVMInt1Type(), TYPE_INTEGER) - elif bits == 8: - return _make_type(_core.LLVMInt8Type(), TYPE_INTEGER) - elif bits == 16: - return _make_type(_core.LLVMInt16Type(), TYPE_INTEGER) - elif bits == 32: - return _make_type(_core.LLVMInt32Type(), TYPE_INTEGER) - elif bits == 64: - return _make_type(_core.LLVMInt64Type(), TYPE_INTEGER) - else: - bits = int(bits) # bits must be an int - return _make_type(_core.LLVMIntType(bits), TYPE_INTEGER) + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getIntNTy(context, bits) + return Type(ptr) @staticmethod def float(): """Create a 32-bit floating point type.""" - return _make_type(_core.LLVMFloatType(), TYPE_FLOAT) + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getFloatTy(context) + return Type(ptr) @staticmethod def double(): """Create a 64-bit floating point type.""" - return _make_type(_core.LLVMDoubleType(), TYPE_DOUBLE) + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getDoubleTy(context) + return Type(ptr) @staticmethod def x86_fp80(): """Create a 80-bit x86 floating point type.""" - return _make_type(_core.LLVMX86FP80Type(), TYPE_X86_FP80) + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getX86_FP80Ty(context) + return Type(ptr) @staticmethod def fp128(): """Create a 128-bit floating point type (with 112-bit - mantissa).""" - return _make_type(_core.LLVMFP128Type(), TYPE_FP128) + mantissa).""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getFP128Ty(context) + return Type(ptr) @staticmethod def ppc_fp128(): """Create a 128-bit floating point type (two 64-bits).""" - return _make_type(_core.LLVMPPCFP128Type(), TYPE_PPC_FP128) + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getPPC_FP128Ty(context) + return Type(ptr) + @staticmethod def function(return_ty, param_tys, var_arg=False): @@ -571,31 +752,58 @@ class Type(object): `return_ty', takes arguments of types as given in the iterable `param_tys'. Set `var_arg' to True (default is False) for a variadic function.""" - check_is_type(return_ty) - var_arg = _to_int(var_arg) # ensure int - params = unpack_types(param_tys) - return _make_type(_core.LLVMFunctionType(return_ty.ptr, params, - var_arg), TYPE_FUNCTION) + ptr = api.llvm.FunctionType.get(return_ty._ptr, + llvm._extract_ptrs(param_tys), + var_arg) + return FunctionType(ptr) @staticmethod - def struct(element_tys): # not packed + def opaque(name): + """Create a opaque StructType""" + context = api.llvm.getGlobalContext() + if not name: + raise llvm.LLVMException("Opaque type must have a non-empty name") + ptr = api.llvm.StructType.create(context, name) + return StructType(ptr) + + @staticmethod + def struct(element_tys, name=''): # not packed """Create a (unpacked) structure type. Creates a structure type with elements of types as given in the iterable `element_tys'. This method creates a unpacked - structure. For a packed one, use the packed_struct() method.""" - elems = unpack_types(element_tys) - return _make_type(_core.LLVMStructType(elems, 0), TYPE_STRUCT) + structure. For a packed one, use the packed_struct() method. + + If name is not '', creates a identified type; + otherwise, creates a literal type.""" + context = api.llvm.getGlobalContext() + is_packed = False + if name: + ptr = api.llvm.StructType.create(context, name) + ptr.setBody(llvm._extract_ptrs(element_tys), is_packed) + else: + ptr = api.llvm.StructType.get(context, + llvm._extract_ptrs(element_tys), + is_packed) + + + return StructType(ptr) @staticmethod - def packed_struct(element_tys): + def packed_struct(element_tys, name=''): """Create a (packed) structure type. Creates a structure type with elements of types as given in the iterable `element_tys'. This method creates a packed - structure. For an unpacked one, use the struct() method.""" - elems = unpack_types(element_tys) - return _make_type(_core.LLVMStructType(elems, 1), TYPE_STRUCT) + structure. For an unpacked one, use the struct() method. + + If name is not '', creates a identified type; + otherwise, creates a literal type.""" + context = api.llvm.getGlobalContext() + is_packed = True + ptr = api.llvm.StructType.create(context, name) + ptr.setBody(llvm._extract_ptrs(element_tys), is_packed) + return StructType(ptr) @staticmethod def array(element_ty, count): @@ -603,10 +811,8 @@ class Type(object): Creates a type for an array of elements of type `element_ty', having 'count' elements.""" - check_is_type(element_ty) - count = int(count) # must be an int - return _make_type(_core.LLVMArrayType(element_ty.ptr, count), - TYPE_ARRAY) + ptr = api.llvm.ArrayType.get(element_ty._ptr, count) + return ArrayType(ptr) @staticmethod def pointer(pointee_ty, addr_space=0): @@ -614,10 +820,8 @@ class Type(object): Creates a pointer type, which can point to values of type `pointee_ty', in the address space `addr_space'.""" - check_is_type(pointee_ty) - addr_space = int(addr_space) # must be an int - return _make_type(_core.LLVMPointerType(pointee_ty.ptr, - addr_space), TYPE_POINTER) + ptr = api.llvm.PointerType.get(pointee_ty._ptr, addr_space) + return PointerType(ptr) @staticmethod def vector(element_ty, count): @@ -625,186 +829,227 @@ class Type(object): Creates a type for a vector of elements of type `element_ty', having `count' elements.""" - check_is_type(element_ty) - count = int(count) # must be an int - return _make_type(_core.LLVMVectorType(element_ty.ptr, count), - TYPE_VECTOR) + ptr = api.llvm.VectorType.get(element_ty._ptr, count) + return VectorType(ptr) @staticmethod def void(): """Create a void type. Represents the `void' type.""" - return _make_type(_core.LLVMVoidType(), TYPE_VOID) + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getVoidTy(context) + return Type(ptr) @staticmethod def label(): """Create a label type.""" - return _make_type(_core.LLVMLabelType(), TYPE_LABEL) + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getLabelTy(context) + return Type(ptr) - def __init__(self, ptr, kind): - """DO NOT CALL DIRECTLY. + def __new__(cls, ptr): + tyid = ptr.getTypeID() - Use one of the static methods instead.""" - self.ptr = ptr - self.kind = kind - """An enum (int) value denoting which type this is. + idmap = { + TYPE_HALF: IntegerType, + TYPE_INTEGER: IntegerType, + TYPE_FUNCTION: FunctionType, + TYPE_STRUCT: StructType, + TYPE_ARRAY: ArrayType, + TYPE_POINTER: PointerType, + TYPE_VECTOR: VectorType, + } - Use the symbolic constants TYPE_* defined in llvm.core - module.""" + try: + newcls = idmap[tyid] + except KeyError: + newcls = Type + obj = llvm.Wrapper.__new__(newcls) + return obj def __str__(self): - """Text representation of a type. + return str(self._ptr) - Returns the textual representation (`llvm assembly') of the type.""" - return _core.LLVMDumpTypeToString(self.ptr) + def __hash__(self): + return hash(self._ptr) def __eq__(self, rhs): - if isinstance(rhs, Type): - return str(self) == str(rhs) - else: - return False + return self._ptr is rhs._ptr def __ne__(self, rhs): - return not self == rhs - + return not (self == rhs) class IntegerType(Type): """Represents an integer type.""" + __slots__ = () + _type_ = api.llvm.IntegerType @property def width(self): """The width of the integer type, in bits.""" - return _core.LLVMGetIntTypeWidth(self.ptr) - + return self._ptr.getIntegerBitWidth() class FunctionType(Type): """Represents a function type.""" + __slots__ = () + _type_ = api.llvm.FunctionType @property def return_type(self): """The type of the value returned by this function.""" - ptr = _core.LLVMGetReturnType(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) + return Type(self._ptr.getReturnType()) @property def vararg(self): """True if this function is variadic.""" - return _core.LLVMIsFunctionVarArg(self.ptr) != 0 + return self._ptr.isVarArg() @property def args(self): """An iterable that yields Type objects, representing the types of the - arguments accepted by this function, in order.""" - pp = _core.LLVMGetFunctionTypeParams(self.ptr) - return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ] + arguments accepted by this function, in order.""" + return [Type(self._ptr.getParamType(i)) for i in range(self.arg_count)] @property def arg_count(self): """Number of arguments accepted by this function. - Same as len(obj.args), but faster.""" - return _core.LLVMCountParamTypes(self.ptr) + Same as len(obj.args), but faster.""" + return self._ptr.getNumParams() class StructType(Type): """Represents a structure type.""" + _type_ = api.llvm.StructType + __slots__ = () @property def element_count(self): """Number of elements (members) in the structure. - Same as len(obj.elements), but faster.""" - return _core.LLVMCountStructElementTypes(self.ptr) + Same as len(obj.elements), but faster.""" + return self._ptr.getNumElements() - #@property - #def elements(self): - # """An iterable that yieldsd Type objects, representing the types of the - # elements (members) of the structure, in order.""" - # pp = _core.LLVMGetStructElementTypes(self.ptr) - # return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ] + @property + def elements(self): + """An iterable that yields Type objects, representing the types of the + elements (members) of the structure, in order.""" + return [Type(self._ptr.getElementType(i)) + for i in range(self._ptr.getNumElements())] + + def set_body(self, elems, packed=False): + """Filled the body of a opaque type. + """ + # check + if not self.is_opaque: + raise llvm.LLVMException("Body is already defined.") + + self._ptr.setBody(llvm._extract_ptrs(elems), packed) @property def packed(self): """True if the structure is packed, False otherwise.""" - return _core.LLVMIsPackedStruct(self.ptr) != 0 + return self._ptr.isPacked() + def _set_name(self, name): + self._ptr.setName(name) + + def _get_name(self): + if self._ptr.isLiteral(): + return "" + else: + return self._ptr.getName() + + name = property(_get_name, _set_name) + + @property + def is_literal(self): + return self._ptr.isLiteral() + + @property + def is_identified(self): + return not self.is_literal + + @property + 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): - ptr = _core.LLVMGetElementType(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) + return Type(self._ptr.getArrayElementType()) @property def count(self): - return _core.LLVMGetArrayLength(self.ptr) - + return self._ptr.getNumElements() class PointerType(Type): + _type_ = api.llvm.PointerType + __slots__ = () @property def pointee(self): - ptr = _core.LLVMGetElementType(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) + return Type(self._ptr.getPointerElementType()) @property def address_space(self): - return _core.LLVMGetPointerAddressSpace(self.ptr) - + return self._ptr.getAddressSpace() class VectorType(Type): + _type_ = api.llvm.VectorType + __slots__ = () @property def element(self): - ptr = _core.LLVMGetElementType(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) + return Type(self._ptr.getVectorElementType()) @property def count(self): - return _core.LLVMGetVectorSize(self.ptr) + return self._ptr.getNumElements() +class Value(llvm.Wrapper): + _type_ = api.llvm.Value + __slots__ = '__weakref__' -#===----------------------------------------------------------------------=== -# Type factory method -#===----------------------------------------------------------------------=== + def __init__(self, builder, ptr): + assert builder is _ValueFactory -# type ID -> class map -__class_for_typeid = { - TYPE_INTEGER : IntegerType, - TYPE_FUNCTION : FunctionType, - TYPE_STRUCT : StructType, - TYPE_ARRAY : ArrayType, - TYPE_POINTER : PointerType, - TYPE_VECTOR : VectorType, -} - -def _make_type(ptr, kind): - class_obj = __class_for_typeid.get(kind) - if class_obj: - return class_obj(ptr, kind) - else: - # "generic" type - return Type(ptr, kind) - - -#===----------------------------------------------------------------------=== -# Values -#===----------------------------------------------------------------------=== - -class Value(llvm.Cacheable): - - def __init__(self, ptr): - self.ptr = ptr + if type(self._type_) is type: + if isinstance(ptr, self._type_): # is not downcast + casted = ptr + else: + casted = ptr._downcast(self._type_) + else: + try: + for ty in self._type_: + if isinstance(ptr, ty): # is not downcast + casted = ptr + else: + try: + casted = ptr._downcast(ty) + except ValueError: + pass + else: + break + else: + casted = ptr + except TypeError: + casted = ptr + super(Value, self).__init__(casted) def __str__(self): - return _core.LLVMDumpValueToString(self.ptr) + return str(self._ptr) + + def __hash__(self): + return hash(self._ptr) def __eq__(self, rhs): if isinstance(rhs, Value): @@ -816,1142 +1061,1466 @@ class Value(llvm.Cacheable): return not self == rhs def _get_name(self): - return _core.LLVMGetValueName(self.ptr) + return self._ptr.getName() def _set_name(self, value): - return _core.LLVMSetValueName(self.ptr, value) + return self._ptr.setName(value) name = property(_get_name, _set_name) @property def value_id(self): - return _core.LLVMValueGetID(self.ptr) + return self._ptr.getValueID() @property def type(self): - ptr = _core.LLVMTypeOf(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) + return Type(self._ptr.getType()) @property def use_count(self): - return _core.LLVMValueGetNumUses(self.ptr) + return self._ptr.getNumUses() @property def uses(self): - return [ _make_value(v) for v in _core.LLVMValueGetUses(self.ptr) ] - + return list(map(_make_value, self._ptr.list_use())) class User(Value): + _type_ = api.llvm.User + __slots__ = () @property def operand_count(self): - return _core.LLVMUserGetNumOperands(self.ptr) + return self._ptr.getNumOperands() @property def operands(self): """Yields operands of this instruction.""" - return [self._get_operand(i) for i in range(self.operand_count)] - - def _get_operand(self, i): - return _make_value(_core.LLVMUserGetOperand(self.ptr, i)) + return [_make_value(self._ptr.getOperand(i)) + for i in range(self.operand_count)] class Constant(User): + _type_ = api.llvm.Constant + __slots__ = () @staticmethod def null(ty): - check_is_type(ty) - return _make_value(_core.LLVMConstNull(ty.ptr)) + return _make_value(api.llvm.Constant.getNullValue(ty._ptr)) @staticmethod def all_ones(ty): - check_is_type(ty) - return _make_value(_core.LLVMConstAllOnes(ty.ptr)) + return _make_value(api.llvm.Constant.getAllOnesValue(ty._ptr)) @staticmethod def undef(ty): - check_is_type(ty) - return _make_value(_core.LLVMGetUndef(ty.ptr)) + return _make_value(api.llvm.UndefValue.get(ty._ptr)) @staticmethod def int(ty, value): - check_is_type(ty) - return _make_value(_core.LLVMConstInt(ty.ptr, value, 0)) + return _make_value(api.llvm.ConstantInt.get(ty._ptr, int(value), False)) @staticmethod def int_signextend(ty, value): - check_is_type(ty) - return _make_value(_core.LLVMConstInt(ty.ptr, value, 1)) + return _make_value(api.llvm.ConstantInt.get(ty._ptr, int(value), True)) @staticmethod def real(ty, value): - check_is_type(ty) - if isinstance(value, str): - return _make_value(_core.LLVMConstRealOfString(ty.ptr, value)) - else: - return _make_value(_core.LLVMConstReal(ty.ptr, value)) + return _make_value(api.llvm.ConstantFP.get(ty._ptr, float(value))) @staticmethod def string(strval): # dont_null_terminate=True - return _make_value(_core.LLVMConstString(strval, 1)) + cxt = api.llvm.getGlobalContext() + return _make_value(api.llvm.ConstantDataArray.getString(cxt, strval, False)) @staticmethod def stringz(strval): # dont_null_terminate=False - return _make_value(_core.LLVMConstString(strval, 0)) + cxt = api.llvm.getGlobalContext() + return _make_value(api.llvm.ConstantDataArray.getString(cxt, strval, True)) @staticmethod def array(ty, consts): - check_is_type(ty) - const_ptrs = unpack_constants(consts) - return _make_value(_core.LLVMConstArray(ty.ptr, const_ptrs)) + aryty = Type.array(ty, len(consts)) + return _make_value(api.llvm.ConstantArray.get(aryty._ptr, + llvm._extract_ptrs(consts))) @staticmethod def struct(consts): # not packed - const_ptrs = unpack_constants(consts) - return _make_value(_core.LLVMConstStruct(const_ptrs, 0)) + return _make_value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), + False)) @staticmethod def packed_struct(consts): - const_ptrs = unpack_constants(consts) - return _make_value(_core.LLVMConstStruct(const_ptrs, 1)) + return _make_value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), + False)) @staticmethod def vector(consts): - const_ptrs = unpack_constants(consts) - return _make_value(_core.LLVMConstVector(const_ptrs)) + return _make_value(api.llvm.ConstantVector.get(llvm._extract_ptrs(consts))) @staticmethod def sizeof(ty): - check_is_type(ty) - return _make_value(_core.LLVMSizeOf(ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getSizeOf(ty._ptr)) def neg(self): - return _make_value(_core.LLVMConstNeg(self.ptr)) + return _make_value(api.llvm.ConstantExpr.getNeg(self._ptr)) def not_(self): - return _make_value(_core.LLVMConstNot(self.ptr)) + return _make_value(api.llvm.ConstantExpr.getNot(self._ptr)) def add(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstAdd(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getAdd(self._ptr, rhs._ptr)) def fadd(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFAdd(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getFAdd(self._ptr, rhs._ptr)) def sub(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstSub(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getSub(self._ptr, rhs._ptr)) def fsub(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFSub(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getFSub(self._ptr, rhs._ptr)) def mul(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstMul(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getMul(self._ptr, rhs._ptr)) def fmul(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFMul(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getFMul(self._ptr, rhs._ptr)) def udiv(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstUDiv(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getUDiv(self._ptr, rhs._ptr)) def sdiv(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstSDiv(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getSDiv(self._ptr, rhs._ptr)) def fdiv(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFDiv(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getFDiv(self._ptr, rhs._ptr)) def urem(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstURem(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getURem(self._ptr, rhs._ptr)) def srem(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstSRem(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getSRem(self._ptr, rhs._ptr)) def frem(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFRem(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getFRem(self._ptr, rhs._ptr)) def and_(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstAnd(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getAnd(self._ptr, rhs._ptr)) def or_(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstOr(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getOr(self._ptr, rhs._ptr)) def xor(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstXor(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getXor(self._ptr, rhs._ptr)) def icmp(self, int_pred, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstICmp(int_pred, self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getICmp(int_pred, self._ptr, rhs._ptr)) def fcmp(self, real_pred, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFCmp(real_pred, self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getFCmp(real_pred, self._ptr, rhs._ptr)) def shl(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstShl(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getShl(self._ptr, rhs._ptr)) def lshr(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstLShr(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getLShr(self._ptr, rhs._ptr)) def ashr(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstAShr(self.ptr, rhs.ptr)) + return _make_value(api.llvm.ConstantExpr.getAShr(self._ptr, rhs._ptr)) def gep(self, indices): - index_ptrs = unpack_constants(indices) - return _make_value(_core.LLVMConstGEP(self.ptr, index_ptrs)) + indices = llvm._extract_ptrs(indices) + return _make_value(api.llvm.ConstantExpr.getGetElementPtr(self._ptr, indices)) def trunc(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstTrunc(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getTrunc(self._ptr, ty._ptr)) def sext(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstSExt(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getSExt(self._ptr, ty._ptr)) def zext(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstZExt(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getZExt(self._ptr, ty._ptr)) def fptrunc(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstFPTrunc(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getFPTrunc(self._ptr, ty._ptr)) def fpext(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstFPExt(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getFPExtend(self._ptr, ty._ptr)) def uitofp(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstUIToFP(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getUIToFP(self._ptr, ty._ptr)) def sitofp(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstSIToFP(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getSIToFP(self._ptr, ty._ptr)) def fptoui(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstFPToUI(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getFPToUI(self._ptr, ty._ptr)) def fptosi(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstFPToSI(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getFPToSI(self._ptr, ty._ptr)) def ptrtoint(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstPtrToInt(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getPtrToInt(self._ptr, ty._ptr)) def inttoptr(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstIntToPtr(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getIntToPtr(self._ptr, ty._ptr)) def bitcast(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstBitCast(self.ptr, ty.ptr)) + return _make_value(api.llvm.ConstantExpr.getBitCast(self._ptr, ty._ptr)) def select(self, true_const, false_const): - check_is_constant(true_const) - check_is_constant(false_const) - return _make_value( - _core.LLVMConstSelect(self.ptr, true_const.ptr, false_const.ptr)) + return _make_value(api.llvm.ConstantExpr.getSelect(self._ptr, + true_const._ptr, + false_const._ptr)) def extract_element(self, index): # note: self must be a _vector_ constant - check_is_constant(index) - return _make_value( - _core.LLVMConstExtractElement(self.ptr, index.ptr)) + return _make_value(api.llvm.ConstantExpr.getExtractElement(self._ptr, index._ptr)) def insert_element(self, value, index): - # note: self must be a _vector_ constant - check_is_constant(value) - check_is_constant(index) - return _make_value( - _core.LLVMConstInsertElement(self.ptr, value.ptr, index.ptr)) + return _make_value(api.llvm.ConstantExpr.getExtractElement(self._ptr, + value._ptr, + index._ptr)) def shuffle_vector(self, vector_b, mask): - # note: self must be a _vector_ constant - check_is_constant(vector_b) - # note: vector_b must be a _vector_ constant - check_is_constant(mask) - return _make_value( - _core.LLVMConstShuffleVector(self.ptr, vector_b.ptr, mask.ptr)) - + return _make_value(api.llvm.ConstantExpr.getShuffleVector(self._ptr, + vector_b._ptr, + mask._ptr)) class ConstantExpr(Constant): - pass + _type_ = api.llvm.ConstantExpr + __slots__ = () + @property + def opcode(self): + return self._ptr.getOpcode() + + @property + def opcode_name(self): + return self._ptr.getOpcodeName() class ConstantAggregateZero(Constant): - pass + __slots__ = () class ConstantDataArray(Constant): - pass + __slots__ = () class ConstantDataVector(Constant): - pass + __slots__ = () + class ConstantInt(Constant): - pass + _type_ = api.llvm.ConstantInt + __slots__ = () + + @property + def z_ext_value(self): + '''Obtain the zero extended value for an integer constant value.''' + # Warning: assertion failure when value does not fit in 64 bits + return self._ptr.getZExtValue() + + @property + def s_ext_value(self): + '''Obtain the sign extended value for an integer constant value.''' + # Warning: assertion failure when value does not fit in 64 bits + return self._ptr.getSExtValue() 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): - - def __init__(self, ptr): - Constant.__init__(self, ptr) - # Hang on to the module, don't let it die before we do. - # It is nice to have just a map of functions without - # retaining a ref to the owning module. - self._module_obj = self.module - - def _delete(self): - # Called in subclass delete() methods. - self._module_obj = None + _type_ = api.llvm.GlobalValue + __slots__ = () def _get_linkage(self): - return _core.LLVMGetLinkage(self.ptr) + return self._ptr.getLinkage() + def _set_linkage(self, value): - _core.LLVMSetLinkage(self.ptr, value) + self._ptr.setLinkage(value) + linkage = property(_get_linkage, _set_linkage) def _get_section(self): - return _core.LLVMGetSection(self.ptr) + return self._ptr.getSection() + def _set_section(self, value): - return _core.LLVMSetSection(self.ptr, value) + return self._ptr.setSection(value) + section = property(_get_section, _set_section) def _get_visibility(self): - return _core.LLVMGetVisibility(self.ptr) + return self._ptr.getVisibility() + def _set_visibility(self, value): - return _core.LLVMSetVisibility(self.ptr, value) + return self._ptr.setVisibility(value) + visibility = property(_get_visibility, _set_visibility) def _get_alignment(self): - return _core.LLVMGetAlignment(self.ptr) + return self._ptr.getAlignment() + def _set_alignment(self, value): - return _core.LLVMSetAlignment(self.ptr, value) + return self._ptr.setAlignment(value) + alignment = property(_get_alignment, _set_alignment) @property def is_declaration(self): - return _core.LLVMIsDeclaration(self.ptr) != 0 + return self._ptr.isDeclaration() @property def module(self): - return Module(_core.LLVMGetGlobalParent(self.ptr)) + return Module(self._ptr.getParent()) + class GlobalVariable(GlobalValue): + _type_ = api.llvm.GlobalVariable + __slots__ = () @staticmethod - def new(module, ty, name): - check_is_module(module) - check_is_type(ty) - return _make_value(_core.LLVMAddGlobal(module.ptr, ty.ptr, name)) + def new(module, ty, name, addrspace=0): + linkage = api.llvm.GlobalValue.LinkageTypes + external_linkage = linkage.ExternalLinkage + tlmode = api.llvm.GlobalVariable.ThreadLocalMode + not_threadlocal = tlmode.NotThreadLocal + gv = api.llvm.GlobalVariable.new(module._ptr, + ty._ptr, + False, # is constant + external_linkage, + None, # initializer + name, + None, # insert before + not_threadlocal, + addrspace) + return _make_value(gv) @staticmethod def get(module, name): - check_is_module(module) - ptr = _core.LLVMGetNamedGlobal(module.ptr, name) - if not ptr: - raise llvm.LLVMException("no global named `%s`" % name) - return _make_value(ptr) + gv = _make_value(module._ptr.getNamedGlobal(name)) + if not gv: + llvm.LLVMException("no global named `%s`" % name) + return gv def delete(self): - self._delete() - _core.LLVMDeleteGlobal(self.ptr) - self.forget() - self.ptr = None + _ValueFactory.delete(self._ptr) + self._ptr.eraseFromParent() def _get_initializer(self): - if _core.LLVMHasInitializer(self.ptr): - return _make_value(_core.LLVMGetInitializer(self.ptr)) - else: + if not self._ptr.hasInitializer(): return None + return _make_value(self._ptr.getInitializer()) def _set_initializer(self, const): - check_is_constant(const) - _core.LLVMSetInitializer(self.ptr, const.ptr) + self._ptr.setInitializer(const._ptr) + + def _del_initializer(self): + self._ptr.setInitializer(None) initializer = property(_get_initializer, _set_initializer) def _get_is_global_constant(self): - return _core.LLVMIsGlobalConstant(self.ptr) + return self._ptr.isConstant() def _set_is_global_constant(self, value): - value = _to_int(value) - _core.LLVMSetGlobalConstant(self.ptr, value) + self._ptr.setConstant(value) - global_constant = \ - property(_get_is_global_constant, _set_is_global_constant) + global_constant = property(_get_is_global_constant, + _set_is_global_constant) + def _get_thread_local(self): + return self._ptr.isThreadLocal() + + def _set_thread_local(self, value): + return self._ptr.setThreadLocal(value) + + 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): - _core.LLVMAddAttribute(self.ptr, attr) + 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): - _core.LLVMRemoveAttribute(self.ptr, attr) + if attr not in self: + raise ValueError("Attribute %r is not valid for arg %s" % + (attr, self)) - def _set_alignment(self, align): - _core.LLVMSetParamAlignment(self.ptr, align) + 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 _core.LLVMGetParamAlignment(self.ptr) + return self._ptr.getParamAlignment() - alignment = \ - property(_get_alignment, _set_alignment) + 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 def new(module, func_ty, name): - check_is_module(module) - check_is_type(func_ty) - return _make_value(_core.LLVMAddFunction(module.ptr, name, - func_ty.ptr)) + try: + fn = Function.get(module, name) + except llvm.LLVMException: + return Function.get_or_insert(module, func_ty, name) + else: + raise llvm.LLVMException("Duplicated function %s" % name) + @staticmethod def get_or_insert(module, func_ty, name): - check_is_module(module) - check_is_type(func_ty) - return _make_value(_core.LLVMModuleGetOrInsertFunction(module.ptr, - name, func_ty.ptr)) + constant = module._ptr.getOrInsertFunction(name, func_ty._ptr) + try: + fn = constant._downcast(api.llvm.Function) + except ValueError: + # bitcasted to function type + return _make_value(constant) + else: + return _make_value(fn) @staticmethod def get(module, name): - check_is_module(module) - ptr = _core.LLVMGetNamedFunction(module.ptr, name) - if not ptr: + fn = module._ptr.getFunction(name) + if fn is None: raise llvm.LLVMException("no function named `%s`" % name) - return _make_value(ptr) + else: + return _make_value(fn) @staticmethod def intrinsic(module, intrinsic_id, types): - check_is_module(module) - ptrs = unpack_types(types) - return _make_value( - _core.LLVMGetIntrinsic(module.ptr, intrinsic_id, ptrs)) + fn = api.llvm.Intrinsic.getDeclaration(module._ptr, + intrinsic_id, + llvm._extract_ptrs(types)) + return _make_value(fn) def delete(self): - self._delete() - _core.LLVMDeleteFunction(self.ptr) - self.forget() - self.ptr = None + _ValueFactory.delete(self._ptr) + self._ptr.eraseFromParent() @property def intrinsic_id(self): - return _core.LLVMGetIntrinsicID(self.ptr) + self._ptr.getIntrinsicID() + + def _get_cc(self): + return self._ptr.getCallingConv() + + def _set_cc(self, value): + self._ptr.setCallingConv(value) - def _get_cc(self): return _core.LLVMGetFunctionCallConv(self.ptr) - def _set_cc(self, value): _core.LLVMSetFunctionCallConv(self.ptr, value) calling_convention = property(_get_cc, _set_cc) - def _get_coll(self): return _core.LLVMGetGC(self.ptr) - def _set_coll(self, value): _core.LLVMSetGC(self.ptr, value) + def _get_coll(self): + return self._ptr.getGC() + + def _set_coll(self, value): + return self._ptr.setGC(value) + collector = property(_get_coll, _set_coll) # the nounwind attribute: - def _get_does_not_throw(self): return _core.LLVMGetDoesNotThrow(self.ptr) - def _set_does_not_throw(self,value): _core.LLVMSetDoesNotThrow(self.ptr, value) + def _get_does_not_throw(self): + return self._ptr.doesNotThrow() + + def _set_does_not_throw(self,value): + assert value + self._ptr.setDoesNotThrow() + does_not_throw = property(_get_does_not_throw, _set_does_not_throw) @property def args(self): - return _util.wrapiter(_core.LLVMGetFirstParam, - _core.LLVMGetNextParam, self.ptr, _make_value) + args = self._ptr.getArgumentList() + return list(map(_make_value, args)) @property def basic_block_count(self): - return _core.LLVMCountBasicBlocks(self.ptr) + return len(self.basic_blocks) @property def entry_basic_block(self): - if self.basic_block_count == 0: - return None - return _make_value(_core.LLVMGetEntryBasicBlock(self.ptr)) + assert self.basic_block_count + return _make_value(self._ptr.getEntryBlock()) def get_entry_basic_block(self): - """Deprecated, use entry_basic_block property.""" + "Deprecated. Use entry_basic_block instead" return self.entry_basic_block def append_basic_block(self, name): - return _make_value(_core.LLVMAppendBasicBlock(self.ptr, name)) + context = api.llvm.getGlobalContext() + bb = api.llvm.BasicBlock.Create(context, name, self._ptr, None) + return _make_value(bb) @property def basic_blocks(self): - return _util.wrapiter(_core.LLVMGetFirstBasicBlock, - _core.LLVMGetNextBasicBlock, self.ptr, _make_value) + return list(map(_make_value, self._ptr.getBasicBlockList())) def viewCFG(self): - return _core.LLVMViewFunctionCFG(self.ptr) + return self._ptr.viewCFG() def add_attribute(self, attr): - _core.LLVMAddFunctionAttr(self.ptr, attr) + self._ptr.addFnAttr(attr) def remove_attribute(self, attr): - _core.LLVMRemoveFunctionAttr(self.ptr, attr) + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + 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): - return _core.LLVMViewFunctionCFGOnly(self.ptr) + return self._ptr.viewCFGOnly() def verify(self): # Although we're just asking LLVM to return the success or # failure, it appears to print result to stderr and abort. - return _core.LLVMVerifyFunction(self.ptr) != 0 + + # Note: LLVM has a bug in preverifier that will always abort + # the process upon failure. + actions = api.llvm.VerifierFailureAction + broken = api.llvm.verifyFunction(self._ptr, + actions.ReturnStatusAction) + if broken: + # If broken, then re-run to print the message + api.llvm.verifyFunction(self._ptr, actions.PrintMessageAction) + raise llvm.LLVMException("Function %s failed verification" % + self.name) + +#===----------------------------------------------------------------------=== +# InlineAsm +#===----------------------------------------------------------------------=== + +class InlineAsm(Value): + __slots__ = () + _type_ = api.llvm.InlineAsm + + @staticmethod + def get(functype, asm, constrains, side_effect=False, + align_stack=False, dialect=api.llvm.InlineAsm.AsmDialect.AD_ATT): + ilasm = api.llvm.InlineAsm.get(functype._ptr, asm, constrains, + side_effect, align_stack, dialect) + return _make_value(ilasm) + +#===----------------------------------------------------------------------=== +# MetaData +#===----------------------------------------------------------------------=== + +class MetaData(Value): + __slots__ = () + _type_ = api.llvm.MDNode + + @staticmethod + def get(module, values): + ''' + values -- must be an iterable of Constant or None. None is treated as "null". + ''' + context = api.llvm.getGlobalContext() + ptr = api.llvm.MDNode.get(context, llvm._extract_ptrs(values)) + return _make_value(ptr) + + @staticmethod + def get_named_operands(module, name): + namedmd = module.get_named_metadata(name) + if not namedmd: + return [] + return [_make_value(namedmd._ptr.getOperand(i)) + for i in range(namedmd._ptr.getNumOperands())] + + @staticmethod + def add_named_operand(module, name, operand): + namedmd = module.get_or_insert_named_metadata(name)._ptr + namedmd.addOperand(operand._ptr) + + @property + def operand_count(self): + return self._ptr.getNumOperands() + + @property + def operands(self): + """Yields operands of this metadata.""" + res = [] + for i in range(self.operand_count): + op = self._ptr.getOperand(i) + if op is None: + res.append(None) + else: + res.append(_make_value(op)) + return res + +class MetaDataString(Value): + _type_ = api.llvm.MDString + + @staticmethod + def get(module, s): + context = api.llvm.getGlobalContext() + ptr = api.llvm.MDString.get(context, s) + return _make_value(ptr) + + @property + def string(self): + '''Same as MDString::getString''' + return self._ptr.getString() + + +class NamedMetaData(llvm.Wrapper): + __slots__ = () + + @staticmethod + def get_or_insert(mod, name): + return mod.get_or_insert_named_metadata(name) + + @staticmethod + def get(mod, name): + return mod.get_named_metadata(name) + + def delete(self): + _ValueFactory.delete(self._ptr) + self._ptr.eraseFromParent() + + @property + def name(self): + return self._ptr.getName() + + def __str__(self): + return str(self._ptr) + + def add(self, operand): + self._ptr.addOperand(operand._ptr) + #===----------------------------------------------------------------------=== # Instruction #===----------------------------------------------------------------------=== class Instruction(User): + __slots__ = () + _type_ = api.llvm.Instruction @property def basic_block(self): - return _make_value(_core.LLVMGetInstructionParent(self.ptr)) + return _make_value(self._ptr.getParent()) @property def is_terminator(self): - return _core.LLVMInstIsTerminator(self.ptr) != 0 + return self._ptr.isTerminator() @property def is_binary_op(self): - return _core.LLVMInstIsBinaryOp(self.ptr) != 0 + return self._ptr.isBinaryOp() @property def is_shift(self): - return _core.LLVMInstIsShift(self.ptr) != 0 + return self._ptr.isShift() @property def is_cast(self): - return _core.LLVMInstIsCast(self.ptr) != 0 + return self._ptr.isCast() @property def is_logical_shift(self): - return _core.LLVMInstIsLogicalShift(self.ptr) != 0 + return self._ptr.isLogicalShift() @property def is_arithmetic_shift(self): - return _core.LLVMInstIsArithmeticShift(self.ptr) != 0 + return self._ptr.isArithmeticShift() @property def is_associative(self): - return _core.LLVMInstIsAssociative(self.ptr) != 0 + return self._ptr.isAssociative() @property def is_commutative(self): - return _core.LLVMInstIsCommutative(self.ptr) != 0 + return self._ptr.isCommutative() @property def is_volatile(self): """True if this is a volatile load or store.""" - return _core.LLVMInstIsVolatile(self.ptr) != 0 + if api.llvm.LoadInst.classof(self._ptr): + return self._ptr._downcast(api.llvm.LoadInst).isVolatile() + elif api.llvm.StoreInst.classof(self._ptr): + return self._ptr._downcast(api.llvm.StoreInst).isVolatile() + else: + return False + + def set_volatile(self, flag): + if api.llvm.LoadInst.classof(self._ptr): + return self._ptr._downcast(api.llvm.LoadInst).setVolatile(flag) + elif api.llvm.StoreInst.classof(self._ptr): + return self._ptr._downcast(api.llvm.StoreInst).setVolatile(flag) + else: + return False + + 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 _core.LLVMInstGetOpcode(self.ptr) + return self._ptr.getOpcode() @property def opcode_name(self): - return _core.LLVMInstGetOpcodeName(self.ptr) + return self._ptr.getOpcodeName() + + 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): + return self._ptr.getCallingConv() + + def _set_cc(self, value): + return self._ptr.setCallingConv(value) - def _get_cc(self): return _core.LLVMGetInstructionCallConv(self.ptr) - def _set_cc(self, value): _core.LLVMSetInstructionCallConv(self.ptr, value) calling_convention = property(_get_cc, _set_cc) def add_parameter_attribute(self, idx, attr): - _core.LLVMAddInstrAttribute(self.ptr, idx, attr) + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + 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): - _core.LLVMRemoveInstrAttribute(self.ptr, idx, attr) + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + 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): - _core.LLVMSetInstrParamAlignment(self.ptr, idx, align) + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAlignmentAttr(align) + if llvm.version >= (3, 3): + attrs = api.llvm.Attribute.get(context, attrbldr) + else: + attrs = api.llvm.Attributes.get(context, attrbldr) - # tail call is valid only for 'call', not 'invoke' - # disabled for now - #def _get_tc(self): return _core.LLVMIsTailCall(self.ptr) - #def _set_tc(self, value): _core.LLVMSetTailCall(self.ptr, value) - #tail_call = property(_get_tc, _set_tc) + self._ptr.addAttribute(idx, attrs) + + def _get_called_function(self): + function = self._ptr.getCalledFunction() + if function: # Return value can be None on indirect call/invoke + return _make_value(function) + + def _set_called_function(self, function): + self._ptr.setCalledFunction(function._ptr) + + called_function = property(_get_called_function, _set_called_function) class PHINode(Instruction): + __slots__ = () + _type_ = api.llvm.PHINode @property def incoming_count(self): - return _core.LLVMCountIncoming(self.ptr) + return self._ptr.getNumIncomingValues() def add_incoming(self, value, block): - check_is_value(value) - check_is_basic_block(block) - _core.LLVMAddIncoming1(self.ptr, value.ptr, block.ptr) + self._ptr.addIncoming(value._ptr, block._ptr) def get_incoming_value(self, idx): - return _make_value(_core.LLVMGetIncomingValue(self.ptr, idx)) + return _make_value(self._ptr.getIncomingValue(idx)) def get_incoming_block(self, idx): - return _make_value(_core.LLVMGetIncomingBlock(self.ptr, idx)) + return _make_value(self._ptr.getIncomingBlock(idx)) class SwitchInstruction(Instruction): + __slots__ = () + _type_ = api.llvm.SwitchInst def add_case(self, const, bblk): - check_is_constant(const) # and has to be an int too - check_is_basic_block(bblk) - _core.LLVMAddCase(self.ptr, const.ptr, bblk.ptr) + self._ptr.addCase(const._ptr, bblk._ptr) class CompareInstruction(Instruction): + __slots__ = () + _type_ = api.llvm.CmpInst @property def predicate(self): - return _core.LLVMCmpInstGetPredicate(self.ptr) + 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): - return _make_value(_core.LLVMInsertBasicBlock(self.ptr, name)) + context = api.llvm.getGlobalContext() + ptr = api.llvm.BasicBlock.Create(context, name, self.function._ptr, + self._ptr) + return _make_value(ptr) def delete(self): - _core.LLVMDeleteBasicBlock(self.ptr) - self.forget() - self.ptr = None + _ValueFactory.delete(self._ptr) + self._ptr.eraseFromParent() @property def function(self): - func_ptr = _core.LLVMGetBasicBlockParent(self.ptr) - return _make_value(func_ptr) + return _make_value(self._ptr.getParent()) @property def instructions(self): - return _util.wrapiter(_core.LLVMGetFirstInstruction, - _core.LLVMGetNextInstruction, self.ptr, _make_value) - + return list(map(_make_value, self._ptr.getInstList())) #===----------------------------------------------------------------------=== # Value factory method #===----------------------------------------------------------------------=== -# value ID -> class map -__class_for_valueid = { - VALUE_ARGUMENT : Argument, - VALUE_BASIC_BLOCK : BasicBlock, - VALUE_FUNCTION : Function, - VALUE_GLOBAL_ALIAS : GlobalValue, - VALUE_GLOBAL_VARIABLE : GlobalVariable, - VALUE_UNDEF_VALUE : UndefValue, - VALUE_CONSTANT_EXPR : ConstantExpr, - VALUE_CONSTANT_AGGREGATE_ZERO : ConstantAggregateZero, - VALUE_CONSTANT_DATA_ARRAY : ConstantDataArray, - VALUE_CONSTANT_DATA_VECTOR : ConstantDataVector, - VALUE_CONSTANT_INT : ConstantInt, - VALUE_CONSTANT_FP : ConstantFP, - VALUE_CONSTANT_ARRAY : ConstantArray, - VALUE_CONSTANT_STRUCT : ConstantStruct, - VALUE_CONSTANT_VECTOR : ConstantVector, - VALUE_CONSTANT_POINTER_NULL : ConstantPointerNull, - VALUE_INSTRUCTION + OPCODE_PHI : PHINode, - VALUE_INSTRUCTION + OPCODE_CALL : CallOrInvokeInstruction, - VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction, - VALUE_INSTRUCTION + OPCODE_SWITCH : SwitchInstruction, - VALUE_INSTRUCTION + OPCODE_ICMP : CompareInstruction, - VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction -} + +class _ValueFactory(object): + __slots__ = () + cache = weakref.WeakValueDictionary() + + # value ID -> class map + class_for_valueid = { + VALUE_ARGUMENT : Argument, + VALUE_BASIC_BLOCK : BasicBlock, + VALUE_FUNCTION : Function, + VALUE_GLOBAL_ALIAS : GlobalValue, + VALUE_GLOBAL_VARIABLE : GlobalVariable, + VALUE_UNDEF_VALUE : UndefValue, + VALUE_CONSTANT_EXPR : ConstantExpr, + VALUE_CONSTANT_AGGREGATE_ZERO : ConstantAggregateZero, + VALUE_CONSTANT_DATA_ARRAY : ConstantDataArray, + VALUE_CONSTANT_DATA_VECTOR : ConstantDataVector, + VALUE_CONSTANT_INT : ConstantInt, + VALUE_CONSTANT_FP : ConstantFP, + VALUE_CONSTANT_ARRAY : ConstantArray, + VALUE_CONSTANT_STRUCT : ConstantStruct, + VALUE_CONSTANT_VECTOR : ConstantVector, + VALUE_CONSTANT_POINTER_NULL : ConstantPointerNull, + VALUE_MD_NODE : MetaData, + VALUE_MD_STRING : MetaDataString, + VALUE_INLINE_ASM : InlineAsm, + VALUE_INSTRUCTION + OPCODE_PHI : PHINode, + VALUE_INSTRUCTION + OPCODE_CALL : CallOrInvokeInstruction, + VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction, + VALUE_INSTRUCTION + OPCODE_SWITCH : SwitchInstruction, + VALUE_INSTRUCTION + OPCODE_ICMP : CompareInstruction, + VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction, + VALUE_INSTRUCTION + OPCODE_ALLOCA : AllocaInstruction, + } + + @classmethod + def build(cls, ptr): + # try to look in the cache + addr = ptr._capsule.pointer + id = ptr.getValueID() + key = id, addr + try: + obj = cls.cache[key] + return obj + except KeyError: + pass + # find class by value id + ctorcls = cls.class_for_valueid.get(id) + if not ctorcls: + if id > VALUE_INSTRUCTION: # "generic" instruction + ctorcls = Instruction + else: # "generic" value + ctorcls = Value + # cache the obj + obj = ctorcls(_ValueFactory, ptr) + cls.cache[key] = obj + return obj + + @classmethod + def delete(cls, ptr): + del cls.cache[(ptr.getValueID(), ptr._capsule.pointer)] def _make_value(ptr): - kind = _core.LLVMValueGetID(ptr) - # based on kind, create one of the Value subclasses - class_obj = __class_for_valueid.get(kind) - if class_obj: - return class_obj(ptr) - elif kind > VALUE_INSTRUCTION: - # "generic" instruction - return Instruction(ptr) - else: - # "generic" value - return Value(ptr) - + return _ValueFactory.build(ptr) #===----------------------------------------------------------------------=== # Builder #===----------------------------------------------------------------------=== -class Builder(object): +_atomic_orderings = { + 'unordered' : api.llvm.AtomicOrdering.Unordered, + 'monotonic' : api.llvm.AtomicOrdering.Monotonic, + 'acquire' : api.llvm.AtomicOrdering.Acquire, + 'release' : api.llvm.AtomicOrdering.Release, + 'acq_rel' : api.llvm.AtomicOrdering.AcquireRelease, + 'seq_cst' : api.llvm.AtomicOrdering.SequentiallyConsistent +} + +class Builder(llvm.Wrapper): + __slots__ = () @staticmethod def new(basic_block): - check_is_basic_block(basic_block) - b = Builder(_core.LLVMCreateBuilder()) - b.position_at_end(basic_block) - return b - - def __init__(self, ptr): - self.ptr = ptr - - def __del__(self): - _core.LLVMDisposeBuilder(self.ptr) + context = api.llvm.getGlobalContext() + ptr = api.llvm.IRBuilder.new(context) + ptr.SetInsertPoint(basic_block._ptr) + return Builder(ptr) def position_at_beginning(self, bblk): """Position the builder at the beginning of the given block. Next instruction inserted will be first one in the block.""" - check_is_basic_block(bblk) - # Avoids using "blk.instructions", which will fetch all the - # instructions into a list. Don't try this at home, though. - inst_ptr = _core.LLVMGetFirstInstruction(bblk.ptr) - if inst_ptr: - # Issue #10: inst_ptr can be None if b/b has no insts. - inst = _make_value(inst_ptr) - self.position_before(inst) + + # Instruction list won't be long anyway, + # Does not matter much to build a list of all instructions + instrs = bblk.instructions + if instrs: + self.position_before(instrs[0]) + else: + self.position_at_end(bblk) def position_at_end(self, bblk): """Position the builder at the end of the given block. Next instruction inserted will be last one in the block.""" - _core.LLVMPositionBuilderAtEnd(self.ptr, bblk.ptr) + + self._ptr.SetInsertPoint(bblk._ptr) def position_before(self, instr): """Position the builder before the given instruction. - The instruction can belong to a basic block other than the - current one.""" - _core.LLVMPositionBuilderBefore(self.ptr, instr.ptr) - - @property - def block(self): - """Deprecated, use basic_block property instead.""" - return _make_value(_core.LLVMGetInsertBlock(self.ptr)) + The instruction can belong to a basic block other than the + current one.""" + self._ptr.SetInsertPoint(instr._ptr) @property def basic_block(self): """The basic block where the builder is positioned.""" - return _make_value(_core.LLVMGetInsertBlock(self.ptr)) + return _make_value(self._ptr.GetInsertBlock()) # terminator instructions + def _guard_terminators(self): + if __debug__: + import warnings + for instr in self.basic_block.instructions: + if instr.is_terminator: + warnings.warn("BasicBlock can only have one terminator") def ret_void(self): - return _make_value(_core.LLVMBuildRetVoid(self.ptr)) + self._guard_terminators() + return _make_value(self._ptr.CreateRetVoid()) def ret(self, value): - check_is_value(value) - return _make_value(_core.LLVMBuildRet(self.ptr, value.ptr)) + self._guard_terminators() + return _make_value(self._ptr.CreateRet(value._ptr)) def ret_many(self, values): - vs = unpack_values(values) - return _make_value(_core.LLVMBuildRetMultiple(self.ptr, vs)) + self._guard_terminators() + values = llvm._extract_ptrs(values) + return _make_value(self._ptr.CreateAggregateRet(values, len(values))) def branch(self, bblk): - check_is_basic_block(bblk) - return _make_value(_core.LLVMBuildBr(self.ptr, bblk.ptr)) + self._guard_terminators() + return _make_value(self._ptr.CreateBr(bblk._ptr)) def cbranch(self, if_value, then_blk, else_blk): - check_is_value(if_value) - check_is_basic_block(then_blk) - check_is_basic_block(else_blk) - return _make_value( - _core.LLVMBuildCondBr(self.ptr, - if_value.ptr, then_blk.ptr, else_blk.ptr)) + self._guard_terminators() + return _make_value(self._ptr.CreateCondBr(if_value._ptr, + then_blk._ptr, + else_blk._ptr)) def switch(self, value, else_blk, n=10): - check_is_value(value) # value has to be of any 'int' type - check_is_basic_block(else_blk) - return _make_value( - _core.LLVMBuildSwitch(self.ptr, value.ptr, else_blk.ptr, n)) + self._guard_terminators() + return _make_value(self._ptr.CreateSwitch(value._ptr, + else_blk._ptr, + n)) def invoke(self, func, args, then_blk, catch_blk, name=""): - check_is_callable(func) - check_is_basic_block(then_blk) - check_is_basic_block(catch_blk) - args2 = unpack_values(args) - return _make_value( - _core.LLVMBuildInvoke(self.ptr, func.ptr, args2, - then_blk.ptr, catch_blk.ptr, name)) + self._guard_terminators() + return _make_value(self._ptr.CreateInvoke(func._ptr, + then_blk._ptr, + catch_blk._ptr, + llvm._extract_ptrs(args))) def unreachable(self): - return _make_value(_core.LLVMBuildUnreachable(self.ptr)) + self._guard_terminators() + return _make_value(self._ptr.CreateUnreachable()) # arithmethic, bitwise and logical - def add(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildAdd(self.ptr, 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=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildFAdd(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateFAdd(lhs._ptr, rhs._ptr, name)) - def sub(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildSub(self.ptr, 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=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildFSub(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateFSub(lhs._ptr, rhs._ptr, name)) - def mul(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildMul(self.ptr, 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=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildFMul(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) - def udiv(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildUDiv(self.ptr, 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=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildSDiv(self.ptr, 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=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildFDiv(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateFDiv(lhs._ptr, rhs._ptr, name)) def urem(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildURem(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateURem(lhs._ptr, rhs._ptr, name)) def srem(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildSRem(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateSRem(lhs._ptr, rhs._ptr, name)) def frem(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildFRem(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateFRem(lhs._ptr, rhs._ptr, name)) - def shl(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildShl(self.ptr, 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=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildLShr(self.ptr, 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=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildAShr(self.ptr, 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=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildAnd(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateAnd(lhs._ptr, rhs._ptr, name)) def or_(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildOr(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateOr(lhs._ptr, rhs._ptr, name)) def xor(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildXor(self.ptr, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateXor(lhs._ptr, rhs._ptr, name)) - def neg(self, val, name=""): - check_is_value(val) - return _make_value(_core.LLVMBuildNeg(self.ptr, 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=""): - check_is_value(val) - return _make_value(_core.LLVMBuildNot(self.ptr, val.ptr, name)) + return _make_value(self._ptr.CreateNot(val._ptr, name)) # memory def malloc(self, ty, name=""): - check_is_type(ty) - return _make_value(_core.LLVMBuildMalloc(self.ptr, ty.ptr, name)) + allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) + ity = allocsz.getType() + malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, + ity, + ty._ptr, + allocsz, + None, + None, + "") + inst = self._ptr.Insert(malloc, name) + return _make_value(inst) def malloc_array(self, ty, size, name=""): - check_is_type(ty) - check_is_value(size) - return _make_value( - _core.LLVMBuildArrayMalloc(self.ptr, ty.ptr, size.ptr, name)) + allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) + ity = allocsz.getType() + malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, + ity, + ty._ptr, + allocsz, + size._ptr, + None, + "") + inst = self._ptr.Insert(malloc, name) + return _make_value(inst) - def alloca(self, ty, name=""): - check_is_type(ty) - return _make_value(_core.LLVMBuildAlloca(self.ptr, ty.ptr, 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=""): - check_is_type(ty) - check_is_value(size) - return _make_value( - _core.LLVMBuildArrayAlloca(self.ptr, ty.ptr, size.ptr, name)) + return self.alloca(ty, size, name=name) def free(self, ptr): - check_is_value(ptr) - return _make_value(_core.LLVMBuildFree(self.ptr, ptr.ptr)) + free = api.llvm.CallInst.CreateFree(ptr._ptr, self.basic_block._ptr) + inst = self._ptr.Insert(free) + return _make_value(inst) - def load(self, ptr, name=""): - check_is_value(ptr) - return _make_value(_core.LLVMBuildLoad(self.ptr, ptr.ptr, name)) + def load(self, ptr, name="", align=0, volatile=False, invariant=False): + inst = _make_value(self._ptr.CreateLoad(ptr._ptr, name)) + if align: + inst._ptr.setAlignment(align) + if volatile: + inst.set_volatile(volatile) + if invariant: + mod = self.basic_block.function.module + md = MetaData.get(mod, []) # empty metadata node + inst.set_metadata('invariant.load', md) + return inst - def store(self, value, ptr): - check_is_value(value) - check_is_value(ptr) - return _make_value(_core.LLVMBuildStore(self.ptr, value.ptr, ptr.ptr)) + def store(self, value, ptr, align=0, volatile=False): + inst = _make_value(self._ptr.CreateStore(value._ptr, ptr._ptr)) + if align: + inst._ptr.setAlignment(align) + if volatile: + inst.set_volatile(volatile) + return inst - def gep(self, ptr, indices, name=""): - check_is_value(ptr) - index_ptrs = unpack_values(indices) - return _make_value( - _core.LLVMBuildGEP(self.ptr, ptr.ptr, index_ptrs, name)) + def gep(self, ptr, indices, name="", inbounds=False): + if inbounds: + ret = self._ptr.CreateInBoundsGEP(ptr._ptr, + llvm._extract_ptrs(indices), + name) + else: + ret = self._ptr.CreateGEP(ptr._ptr, + llvm._extract_ptrs(indices), + name) + return _make_value(ret) # casts and extensions def trunc(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildTrunc(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateTrunc(value._ptr, dest_ty._ptr, name)) def zext(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildZExt(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateZExt(value._ptr, dest_ty._ptr, name)) def sext(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildSExt(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateSExt(value._ptr, dest_ty._ptr, name)) def fptoui(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildFPToUI(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateFPToUI(value._ptr, dest_ty._ptr, name)) def fptosi(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildFPToSI(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateFPToSI(value._ptr, dest_ty._ptr, name)) def uitofp(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildUIToFP(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateUIToFP(value._ptr, dest_ty._ptr, name)) def sitofp(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildSIToFP(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateSIToFP(value._ptr, dest_ty._ptr, name)) def fptrunc(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildFPTrunc(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateFPTrunc(value._ptr, dest_ty._ptr, name)) def fpext(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildFPExt(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateFPExt(value._ptr, dest_ty._ptr, name)) def ptrtoint(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildPtrToInt(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreatePtrToInt(value._ptr, dest_ty._ptr, name)) def inttoptr(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildIntToPtr(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateIntToPtr(value._ptr, dest_ty._ptr, name)) def bitcast(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildBitCast(self.ptr, value.ptr, dest_ty.ptr, name)) + return _make_value(self._ptr.CreateBitCast(value._ptr, dest_ty._ptr, name)) # comparisons def icmp(self, ipred, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildICmp(self.ptr, ipred, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateICmp(ipred, lhs._ptr, rhs._ptr, name)) def fcmp(self, rpred, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildFCmp(self.ptr, rpred, lhs.ptr, rhs.ptr, name)) + return _make_value(self._ptr.CreateFCmp(rpred, lhs._ptr, rhs._ptr, name)) # misc def extract_value(self, retval, idx, name=""): - check_is_value(retval) - return _make_value( - _core.LLVMBuildGetResult(self.ptr, 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, + name)) + def phi(self, ty, name=""): - check_is_type(ty) - return _make_value(_core.LLVMBuildPhi(self.ptr, ty.ptr, name)) + return _make_value(self._ptr.CreatePHI(ty._ptr, 2, name)) def call(self, fn, args, name=""): - check_is_callable(fn) - arg_ptrs = unpack_values(args) - return _make_value( - _core.LLVMBuildCall(self.ptr, fn.ptr, arg_ptrs, name)) + err_template = 'Argument type mismatch: expected %s but got %s' + + for i, (t, v) in enumerate(zip(fn.type.pointee.args, args)): + if t != v.type: + raise TypeError(err_template % (t, v.type)) + arg_ptrs = llvm._extract_ptrs(args) + return _make_value(self._ptr.CreateCall(fn._ptr, arg_ptrs, name)) def select(self, cond, then_value, else_value, name=""): - check_is_value(cond) - check_is_value(then_value) - check_is_value(else_value) - return _make_value( - _core.LLVMBuildSelect(self.ptr, cond.ptr, - then_value.ptr, else_value.ptr, name)) + return _make_value(self._ptr.CreateSelect(cond._ptr, then_value._ptr, + else_value._ptr, name)) def vaarg(self, list_val, ty, name=""): - check_is_value(list_val) - check_is_type(ty) - return _make_value( - _core.LLVMBuildVAArg(self.ptr, list_val.ptr, ty.ptr, name)) + return _make_value(self._ptr.CreateVAArg(list_val._ptr, ty._ptr, name)) def extract_element(self, vec_val, idx_val, name=""): - check_is_value(vec_val) - check_is_value(idx_val) - return _make_value( - _core.LLVMBuildExtractElement(self.ptr, vec_val.ptr, - idx_val.ptr, name)) + return _make_value(self._ptr.CreateExtractElement(vec_val._ptr, + idx_val._ptr, + name)) + def insert_element(self, vec_val, elt_val, idx_val, name=""): - check_is_value(vec_val) - check_is_value(elt_val) - check_is_value(idx_val) - return _make_value( - _core.LLVMBuildInsertElement(self.ptr, vec_val.ptr, - elt_val.ptr, idx_val.ptr, name)) + return _make_value(self._ptr.CreateInsertElement(vec_val._ptr, + elt_val._ptr, + idx_val._ptr, + name)) def shuffle_vector(self, vecA, vecB, mask, name=""): - check_is_value(vecA) - check_is_value(vecB) - check_is_value(mask) - return _make_value( - _core.LLVMBuildShuffleVector(self.ptr, - vecA.ptr, vecB.ptr, mask.ptr, name)) + return _make_value(self._ptr.CreateShuffleVector(vecA._ptr, + vecB._ptr, + mask._ptr, + name)) + # atomics + + def atomic_cmpxchg(self, ptr, old, new, ordering, crossthread=True): + return _make_value(self._ptr.CreateAtomicCmpXchg(ptr._ptr, + old._ptr, + new._ptr, + _atomic_orderings[ordering], + _sync_scope(crossthread))) + + def atomic_rmw(self, op, ptr, val, ordering, crossthread=True): + op_dict = dict((k.lower(), v) + for k, v in vars(api.llvm.AtomicRMWInst.BinOp).items()) + op = op_dict[op] + return _make_value(self._ptr.CreateAtomicRMW(op, ptr._ptr, val._ptr, + _atomic_orderings[ordering], + _sync_scope(crossthread))) + + def atomic_xchg(self, *args, **kwargs): + return self.atomic_rmw('xchg', *args, **kwargs) + + def atomic_add(self, *args, **kwargs): + return self.atomic_rmw('add', *args, **kwargs) + + def atomic_sub(self, *args, **kwargs): + return self.atomic_rmw('sub', *args, **kwargs) + + def atomic_and(self, *args, **kwargs): + return self.atomic_rmw('and', *args, **kwargs) + + def atomic_nand(self, *args, **kwargs): + return self.atomic_rmw('nand', *args, **kwargs) + + def atomic_or(self, *args, **kwargs): + return self.atomic_rmw('or', *args, **kwargs) + + def atomic_xor(self, *args, **kwargs): + return self.atomic_rmw('xor', *args, **kwargs) + + def atomic_max(self, *args, **kwargs): + return self.atomic_rmw('max', *args, **kwargs) + + def atomic_min(self, *args, **kwargs): + return self.atomic_rmw('min', *args, **kwargs) + + def atomic_umax(self, *args, **kwargs): + return self.atomic_rmw('umax', *args, **kwargs) + + def atomic_umin(self, *args, **kwargs): + return self.atomic_rmw('umin', *args, **kwargs) + + def atomic_load(self, ptr, ordering, align=1, crossthread=True, + volatile=False, name=""): + inst = self.load(ptr, align=align, volatile=volatile, name=name) + inst._ptr.setAtomic(_atomic_orderings[ordering], + _sync_scope(crossthread)) + return inst + + def atomic_store(self, value, ptr, ordering, align=1, crossthread=True, + volatile=False): + inst = self.store(value, ptr, align=align, volatile=volatile) + inst._ptr.setAtomic(_atomic_orderings[ordering], + _sync_scope(crossthread)) + return inst -#===----------------------------------------------------------------------=== -# Memory buffer -#===----------------------------------------------------------------------=== + def fence(self, ordering, crossthread=True): + return _make_value(self._ptr.CreateFence(_atomic_orderings[ordering], + _sync_scope(crossthread))) -class MemoryBuffer(object): - - @staticmethod - def from_file(fname): - ret = _core.LLVMCreateMemoryBufferWithContentsOfFile(fname) - if isinstance(ret, str): - return (None, ret) - else: - obj = MemoryBuffer(ret) - return (obj, "") - - @staticmethod - def from_stdin(): - ret = _core.LLVMCreateMemoryBufferWithSTDIN() - if isinstance(ret, str): - return (None, ret) - else: - obj = MemoryBuffer(ret) - return (obj, "") - - def __init__(self, ptr): - self.ptr = ptr - - def __del__(self): - _core.LLVMDisposeMemoryBuffer(self.ptr) - - -#===----------------------------------------------------------------------=== -# Misc -#===----------------------------------------------------------------------=== +def _sync_scope(crossthread): + if crossthread: + scope = api.llvm.SynchronizationScope.CrossThread + else: + scope = api.llvm.SynchronizationScope.SingleThread + return scope def load_library_permanently(filename): """Load a shared library. @@ -1959,12 +2528,27 @@ def load_library_permanently(filename): Load the given shared library (filename argument specifies the full path of the .so file) using LLVM. Symbols from these are available from the execution engine thereafter.""" - - ret = _core.LLVMLoadLibraryPermanently(filename) - if isinstance(ret, str): - raise llvm.LLVMException(ret) + with contextlib.closing(BytesIO()) as errmsg: + failed = api.llvm.sys.DynamicLibrary.LoadPermanentLibrary(filename, + errmsg) + if failed: + raise llvm.LLVMException(errmsg.getvalue()) def inline_function(call): - check_is_value(call) - return _core.LLVMInlineFunction(call.ptr) + info = api.llvm.InlineFunctionInfo.new() + return api.llvm.InlineFunction(call._ptr, info) +def parse_environment_options(progname, envname): + api.llvm.cl.ParseEnvironmentOptions(progname, envname) + +if api.llvm.InitializeNativeTarget(): + raise llvm.LLVMException("No native target!?") +if api.llvm.InitializeNativeTargetAsmPrinter(): + # should this be an optional feature? + # should user trigger the initialization? + raise llvm.LLVMException("No native asm printer!?") +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 a54698d..f615b61 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -28,209 +28,237 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -"""Execution Engine and related classes. +"Execution Engine and related classes." -""" - -import llvm # top-level, for common stuff -import llvm.core as core # module, function etc. -import llvm._core as _core # C wrappers -import llvm._util as _util # utility functions +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 #===----------------------------------------------------------------------=== - -BO_BIG_ENDIAN = 0 -BO_LITTLE_ENDIAN = 1 - - -#===----------------------------------------------------------------------=== -# Target data -#===----------------------------------------------------------------------=== - -class TargetData(llvm.Ownable): - - @staticmethod - def new(strrep): - return TargetData(_core.LLVMCreateTargetData(strrep)) - - def __init__(self, ptr): - llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeTargetData) - - def __str__(self): - return _core.LLVMTargetDataAsString(self.ptr) - - @property - def byte_order(self): - return _core.LLVMByteOrder(self.ptr) - - @property - def pointer_size(self): - return _core.LLVMPointerSize(self.ptr) - - @property - def target_integer_type(self): - ptr = _core.LLVMIntPtrType(self.ptr); - return core.IntegerType(ptr, core.TYPE_INTEGER) - - def size(self, ty): - core.check_is_type(ty) - return _core.LLVMSizeOfTypeInBits(self.ptr, ty.ptr) - - def store_size(self, ty): - core.check_is_type(ty) - return _core.LLVMStoreSizeOfType(self.ptr, ty.ptr) - - def abi_size(self, ty): - core.check_is_type(ty) - return _core.LLVMABISizeOfType(self.ptr, ty.ptr) - - def abi_alignment(self, ty): - core.check_is_type(ty) - return _core.LLVMABIAlignmentOfType(self.ptr, ty.ptr) - - def callframe_alignment(self, ty): - core.check_is_type(ty) - return _core.LLVMCallFrameAlignmentOfType(self.ptr, ty.ptr) - - def preferred_alignment(self, ty_or_gv): - if isinstance(ty_or_gv, core.Type): - return _core.LLVMPreferredAlignmentOfType(self.ptr, - ty_or_gv.ptr) - elif isinstance(ty_or_gv, core.GlobalVariable): - return _core.LLVMPreferredAlignmentOfGlobal(self.ptr, - ty_or_gv.ptr) - else: - raise core.LLVMException("argument is neither a type nor a global variable") - - def element_at_offset(self, ty, ofs): - core.check_is_type_struct(ty) - ofs = int(ofs) # ofs is unsigned long long - return _core.LLVMElementAtOffset(self.ptr, ty.ptr, ofs) - - def offset_of_element(self, ty, el): - core.check_is_type_struct(ty) - el = int(el) # el should be an int - return _core.LLVMOffsetOfElement(self.ptr, ty.ptr, el) +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) #===----------------------------------------------------------------------=== # Generic value #===----------------------------------------------------------------------=== -class GenericValue(object): +class GenericValue(llvm.Wrapper): @staticmethod def int(ty, intval): - core.check_is_type(ty) - ptr = _core.LLVMCreateGenericValueOfInt(ty.ptr, intval, 0) + ptr = api.llvm.GenericValue.CreateInt(ty._ptr, int(intval), False) return GenericValue(ptr) @staticmethod def int_signed(ty, intval): - core.check_is_type(ty) - ptr = _core.LLVMCreateGenericValueOfInt(ty.ptr, intval, 1) + ptr = api.llvm.GenericValue.CreateInt(ty._ptr, int(intval), True) return GenericValue(ptr) @staticmethod def real(ty, floatval): - core.check_is_type(ty) # only float or double - ptr = _core.LLVMCreateGenericValueOfFloat(ty.ptr, floatval) + if str(ty) == 'float': + ptr = api.llvm.GenericValue.CreateFloat(float(floatval)) + elif str(ty) == 'double': + ptr = api.llvm.GenericValue.CreateDouble(float(floatval)) + else: + raise Exception('Unreachable') return GenericValue(ptr) @staticmethod - def pointer(ty, intval): - core.check_is_type(ty) - ptr = _core.LLVMCreateGenericValueOfPointer(ty.ptr, intval) - return GenericValue(ptr) - - def __init__(self, ptr): - self.ptr = ptr + def pointer(addr): + ''' + One argument version takes (addr). + Two argument version takes (ty, addr). [Deprecated] - def __del__(self): - _core.LLVMDisposeGenericValue(self.ptr) + `ty` is unused. + `addr` is an integer representing an address. + + ''' + ptr = api.llvm.GenericValue.CreatePointer(int(addr)) + return GenericValue(ptr) def as_int(self): - return _core.LLVMGenericValueToInt(self.ptr, 0) + return self._ptr.toUnsignedInt() def as_int_signed(self): - return _core.LLVMGenericValueToInt(self.ptr, 1) + return self._ptr.toSignedInt() def as_real(self, ty): - core.check_is_type(ty) # only float or double - return _core.LLVMGenericValueToFloat(ty.ptr, self.ptr) + return self._ptr.toFloat(ty._ptr) def as_pointer(self): - return _core.LLVMGenericValueToPointer(self.ptr) + return self._ptr.toPointer() +#===----------------------------------------------------------------------=== +# Engine builder +#===----------------------------------------------------------------------=== -# helper functions for generic value objects -def check_is_generic_value(obj): _util.check_gen(obj, GenericValue) -def _unpack_generic_values(objlist): - return _util.unpack_gen(objlist, check_is_generic_value) +class EngineBuilder(llvm.Wrapper): + @staticmethod + def new(module): + ptr = api.llvm.EngineBuilder.new(module._ptr) + return EngineBuilder(ptr) + def force_jit(self): + self._ptr.setEngineKind(api.llvm.EngineKind.Kind.JIT) + return self + + def force_interpreter(self): + self._ptr.setEngineKind(api.llvm.EngineKind.Kind.Interpreter) + return self + + def opt(self, level): + ''' + level valid [0, 1, 2, 3] -- [None, Less, Default, Aggressive] + ''' + assert 0 <= level <= 3 + self._ptr.setOptLevel(level) + return self + + def mattrs(self, string): + '''set machine attributes as a comma/space separated string + + e.g: +sse,-3dnow + ''' + self._ptr.setMAttrs(string.split(',')) + return self + + def create(self, tm=None): + ''' + tm --- Optional. Provide a TargetMachine. Ownership is transfered + to the returned execution engine. + ''' + 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() + ee = ExecutionEngine(engine) + ee.finalize_object() # no effect for legacy JIT + return ee + + def select_target(self, *args): + '''get the corresponding target machine + + Accept no arguments or (triple, march, mcpu, mattrs) + ''' + if args: + triple, march, mcpu, mattrs = args + ptr = self._ptr.selectTarget(triple, march, mcpu, + mattrs.split(',')) + else: + 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 #===----------------------------------------------------------------------=== -class ExecutionEngine(object): +class ExecutionEngine(llvm.Wrapper): @staticmethod def new(module, force_interpreter=False): - core.check_is_module(module) - _util.check_is_unowned(module) - ret = _core.LLVMCreateExecutionEngine(module.ptr, int(force_interpreter)) - if isinstance(ret, str): - raise llvm.LLVMException(ret) - return ExecutionEngine(ret, module) + eb = EngineBuilder.new(module) + if force_interpreter: + eb.force_interpreter() + return eb.create() - def __init__(self, ptr, module): - self.ptr = ptr - module._own(self) - - def __del__(self): - _core.LLVMDisposeExecutionEngine(self.ptr) + def disable_lazy_compilation(self, disabled=True): + self._ptr.DisableLazyCompilation(disabled) def run_function(self, fn, args): - core.check_is_function(fn) - ptrs = _unpack_generic_values(args) - gvptr = _core.LLVMRunFunction2(self.ptr, fn.ptr, ptrs) - return GenericValue(gvptr) + 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): - core.check_is_function(fn) - return _core.LLVMGetPointerToFunction(self.ptr,fn.ptr) + return self._ptr.getPointerToFunction(fn._ptr) + + def get_pointer_to_global(self, val): + return self._ptr.getPointerToGlobal(val._ptr) + + def add_global_mapping(self, gvar, addr): + assert addr >= 0, "Address cannot not be negative" + self._ptr.addGlobalMapping(gvar._ptr, addr) def run_static_ctors(self): - _core.LLVMRunStaticConstructors(self.ptr) + self._ptr.runStaticConstructorsDestructors(False) def run_static_dtors(self): - _core.LLVMRunStaticDestructors(self.ptr) + self._ptr.runStaticConstructorsDestructors(True) def free_machine_code_for(self, fn): - core.check_is_function(fn) - _core.LLVMFreeMachineCodeForFunction(self.ptr, fn.ptr) + self._ptr.freeMachineCodeForFunction(fn._ptr) def add_module(self, module): - core.check_is_module(module) - _core.LLVMAddModule(self.ptr, module.ptr) - module._own(self) + self._ptr.addModule(module._ptr) def remove_module(self, module): - core.check_is_module(module) - if module.owner != self: - raise llvm.LLVMException("module is not owned by self") - ret = _core.LLVMRemoveModule2(self.ptr, module.ptr) - if isinstance(ret, str): - raise llvm.LLVMException(ret) - return core.Module(ret) + return self._ptr.removeModule(module._ptr) + + def finalize_object(self): + return self._ptr.finalizeObject() @property def target_data(self): - td = TargetData(_core.LLVMGetExecutionEngineTargetData(self.ptr)) - td._own(self) - return td + ptr = self._ptr.getDataLayout() + return TargetData(ptr) + +#===----------------------------------------------------------------------=== +# Dynamic Library +#===----------------------------------------------------------------------=== + +def dylib_add_symbol(name, ptr): + api.llvm.sys.DynamicLibrary.AddSymbol(name, ptr) + +def dylib_address_of_symbol(name): + return api.llvm.sys.DynamicLibrary.SearchForAddressOfSymbol(name) + +def dylib_import_library(filename): + """Permanently import a dynamic library. + + Returns a DynamicLibrary object + + Raises RuntimeError + """ + return DynamicLibrary(filename) + + +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/extra.cpp b/llvm/extra.cpp deleted file mode 100644 index d7b33e5..0000000 --- a/llvm/extra.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Copyright (c) 2008-10, Mahadevan R All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of this software, nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * These are some "extra" functions not available in the standard LLVM-C - * bindings, but are required / good-to-have inorder to implement the - * Python bindings. - */ - -// standard includes -#include -#include -#include -#include -#include - -// LLVM includes -#include "llvm/LLVMContext.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Casting.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/GlobalVariable.h" -//#include "llvm/TypeSymbolTable.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/CallSite.h" -#include "llvm/IntrinsicInst.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Assembly/Parser.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/PassManager.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/Analysis/LoopPass.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/DomPrinter.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h" -#include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Linker.h" -#include "llvm/Support/SourceMgr.h" - -// LLVM-C includes -#include "llvm-c/Core.h" -#include "llvm-c/ExecutionEngine.h" - -// our includes -#include "extra.h" - -//using namespace llvm; - -/* Helper method for LLVMDumpXXXToString() methods. */ -template -char *do_print(W obj) -{ - std::string s; - llvm::raw_string_ostream buf(s); - UW *p = llvm::unwrap(obj); - assert(p); - p->print(buf); - return strdup(buf.str().c_str()); -} - -char *LLVMDumpModuleToString(LLVMModuleRef module) -{ - std::string s; - llvm::raw_string_ostream buf(s); - llvm::Module *p = llvm::unwrap(module); - assert(p); - p->print(buf, NULL); - return strdup(buf.str().c_str()); -} - -void LLVMModuleAddLibrary(LLVMModuleRef module, const char *name) -{ - llvm::Module *M = llvm::unwrap(module); - llvm::StringRef namestr = llvm::StringRef(name); - M->addLibrary(namestr); - return; -} - -char *LLVMDumpTypeToString(LLVMTypeRef type) -{ - return do_print(type); -} - -char *LLVMDumpValueToString(LLVMValueRef value) -{ - return do_print(value); -} - -unsigned LLVMModuleGetPointerSize(LLVMModuleRef module) -{ - llvm::Module *modulep = llvm::unwrap(module); - assert(modulep); - - llvm::Module::PointerSize p = modulep->getPointerSize(); - if (p == llvm::Module::Pointer32) - return 32; - else if (p == llvm::Module::Pointer64) - return 64; - return 0; -} - -LLVMValueRef LLVMModuleGetOrInsertFunction(LLVMModuleRef module, - const char *name, LLVMTypeRef function_type) -{ - assert(name); - - llvm::Module *modulep = llvm::unwrap(module); - assert(modulep); - - llvm::FunctionType *ftp = llvm::unwrap(function_type); - assert(ftp); - - llvm::Constant *f = modulep->getOrInsertFunction(name, ftp); - return wrap(f); -} - -int LLVMHasInitializer(LLVMValueRef global_var) -{ - llvm::GlobalVariable *gvp = llvm::unwrap(global_var); - assert(gvp); - - return gvp->hasInitializer(); -} - -#define inst_checkfn(ourfn, llvmfn) \ -unsigned ourfn (LLVMValueRef v) { \ - llvm::Instruction *ip = llvm::unwrap(v); \ - assert(ip); \ - return ip-> llvmfn () ? 1 : 0; \ -} - -inst_checkfn(LLVMInstIsTerminator, isTerminator) -inst_checkfn(LLVMInstIsBinaryOp, isBinaryOp) -inst_checkfn(LLVMInstIsShift, isShift) -inst_checkfn(LLVMInstIsCast, isCast) -inst_checkfn(LLVMInstIsLogicalShift, isLogicalShift) -inst_checkfn(LLVMInstIsArithmeticShift, isArithmeticShift) -inst_checkfn(LLVMInstIsAssociative, isAssociative) -inst_checkfn(LLVMInstIsCommutative, isCommutative) - -unsigned LLVMInstIsVolatile(LLVMValueRef v) -{ - using namespace llvm; - Instruction *ip = unwrap(v); - assert(ip); - return ((isa(*ip) && cast(*ip).isVolatile()) || - (isa(*ip) && cast(*ip).isVolatile()) ); -} - -const char *LLVMInstGetOpcodeName(LLVMValueRef inst) -{ - llvm::Instruction *instp = llvm::unwrap(inst); - assert(instp); - return instp->getOpcodeName(); -} - -unsigned LLVMInstGetOpcode(LLVMValueRef inst) -{ - llvm::Instruction *instp = llvm::unwrap(inst); - assert(instp); - return instp->getOpcode(); -} - -unsigned LLVMCmpInstGetPredicate(LLVMValueRef cmpinst) -{ - llvm::CmpInst *instp = llvm::unwrap(cmpinst); - assert(instp); - return instp->getPredicate(); -} - -/* llvm::unwrap a set of `n' wrapped objects starting at `values', - * into a vector of pointers to llvm::unwrapped objects `out'. */ -template -void unwrap_vec(W *values, unsigned n, std::vector& out) -{ - out.clear(); - - while (n--) { - UW *p = llvm::unwrap(*values); - assert(p); - out.push_back(p); - ++values; - } -} - -/* Same as llvm::unwrap_vec, but use a vector of const pointers. */ -template -void unwrap_cvec(W *values, unsigned n, std::vector& out) -{ - out.clear(); - - while (n--) { - UW *p = llvm::unwrap(*values); - assert(p); - out.push_back(p); - ++values; - } -} - -LLVMValueRef LLVMBuildRetMultiple(LLVMBuilderRef builder, - LLVMValueRef *values, unsigned n_values) -{ - assert(values); - - std::vector values_vec; - unwrap_vec(values, n_values, values_vec); - - llvm::IRBuilder<> *builderp = llvm::unwrap(builder); - assert(builderp); - - return llvm::wrap(builderp->CreateAggregateRet(&values_vec[0], values_vec.size())); -} - -LLVMValueRef LLVMBuildGetResult(LLVMBuilderRef builder, - LLVMValueRef value, unsigned index, const char *name) -{ - assert(name); - - llvm::IRBuilder<> *builderp = llvm::unwrap(builder); - assert(builderp); - - return llvm::wrap(builderp->CreateExtractValue(llvm::unwrap(value), index, name)); -} - -unsigned LLVMValueGetID(LLVMValueRef value) -{ - llvm::Value *valuep = llvm::unwrap(value); - assert(valuep); - - return valuep->getValueID(); -} - - -unsigned LLVMValueGetNumUses(LLVMValueRef value) -{ - llvm::Value *valuep = llvm::unwrap(value); - assert(valuep); - - return valuep->getNumUses(); -} - - -unsigned LLVMValueGetUses(LLVMValueRef value, LLVMValueRef **refs) -{ - llvm::Value *valuep = llvm::unwrap(value); - assert(valuep); - - unsigned n = valuep->getNumUses(); - if (n == 0) - return 0; - - assert(refs); - LLVMValueRef *out = (LLVMValueRef *)malloc(sizeof(LLVMValueRef) * n); - if (!out) - return 0; - *refs = out; - - memset(out, 0, sizeof(LLVMValueRef) * n); - llvm::Value::use_iterator it = valuep->use_begin(); - while (it != valuep->use_end()) { - *out++ = llvm::wrap(*it); - ++it; - } - - return n; -} - -void LLVMDisposeValueRefArray(LLVMValueRef *refs) -{ - assert(refs); - free(refs); -} - -unsigned LLVMUserGetNumOperands(LLVMValueRef user) -{ - llvm::User *userp = llvm::unwrap(user); - assert(userp); - return userp->getNumOperands(); -} - -LLVMValueRef LLVMUserGetOperand(LLVMValueRef user, unsigned idx) -{ - llvm::User *userp = llvm::unwrap(user); - assert(userp); - llvm::Value *operand = userp->getOperand(idx); - return llvm::wrap(operand); -} - -unsigned LLVMGetDoesNotThrow(LLVMValueRef fn) -{ - llvm::Function *fnp = llvm::unwrap(fn); - assert(fnp); - - return fnp->doesNotThrow(); -} - -void LLVMSetDoesNotThrow(LLVMValueRef fn, int DoesNotThrow) -{ - llvm::Function *fnp = llvm::unwrap(fn); - assert(fnp); - - return fnp->setDoesNotThrow((bool)DoesNotThrow); -} - - -LLVMValueRef LLVMGetIntrinsic(LLVMModuleRef module, int id, - LLVMTypeRef *types, unsigned n_types) -{ - assert(types); - - std::vector< llvm::Type* > types_vec; - unwrap_vec(types, n_types, types_vec); - - llvm::Module *modulep = llvm::unwrap(module); - assert(modulep); - - llvm::Function *intfunc = llvm::Intrinsic::getDeclaration(modulep, - llvm::Intrinsic::ID(id), types_vec[0]); - - return wrap(intfunc); -} - -LLVMModuleRef LLVMGetModuleFromAssembly(const char *asmtext, unsigned txtlen, - char **out) -{ - assert(asmtext); - assert(out); - - llvm::Module *modulep; - llvm::SMDiagnostic error; - if (!(modulep = llvm::ParseAssemblyString(asmtext, NULL, error, - llvm::getGlobalContext()))) { - std::string s; - llvm::raw_string_ostream buf(s); - error.print("llvm-py", buf); - *out = strdup(buf.str().c_str()); - return NULL; - } - - return wrap(modulep); -} - -LLVMModuleRef LLVMGetModuleFromBitcode(const char *bitcode, unsigned bclen, - char **out) -{ - assert(bitcode); - assert(out); - - llvm::StringRef as_str(bitcode, bclen); - - llvm::MemoryBuffer *mbp; - if (!(mbp = llvm::MemoryBuffer::getMemBufferCopy(as_str))) - return NULL; - - std::string msg; - llvm::Module *modulep; - if (!(modulep = llvm::ParseBitcodeFile(mbp, llvm::getGlobalContext(), - &msg))) - *out = strdup(msg.c_str()); - - delete mbp; - return wrap(modulep); -} - -unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, unsigned int mode, - char **out) -{ - llvm::Module *sourcep = llvm::unwrap(src); - assert(sourcep); - llvm::Module *destinationp = llvm::unwrap(dest); - assert(destinationp); - - std::string msg; - if (llvm::Linker::LinkModules(destinationp, sourcep, mode, &msg)) { - *out = strdup(msg.c_str()); - return 0; - } - - return 1; -} - -unsigned char *LLVMGetBitcodeFromModule(LLVMModuleRef module, unsigned *lenp) -{ - assert(lenp); - - llvm::Module *modulep = llvm::unwrap(module); - assert(modulep); - - /* get bc into a string */ - std::string s; - llvm::raw_string_ostream buf(s); - llvm::WriteBitcodeToFile(modulep, buf); - const std::string& bc = buf.str(); - - /* and then into a malloc()-ed block */ - size_t bclen = bc.size(); - unsigned char *bytes = (unsigned char *)malloc(bclen); - if (!bytes) - return NULL; - memcpy(bytes, bc.data(), bclen); - - /* return */ - *lenp = bclen; - return bytes; -} - -/* Return 0 on failure (with errmsg filled in), 1 on success. */ -unsigned LLVMLoadLibraryPermanently(const char* filename, char **errmsg) -{ - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1"); - assert(filename); - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@2"); - assert(errmsg); - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3"); - - /* Note: the LLVM API returns true on failure. Don't ask why. */ - std::string msg; - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4"); - if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(filename, &msg)) { - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@5"); - *errmsg = strdup(msg.c_str()); - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@6"); - return 0; - } - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7"); - return 1; -} - -void *LLVMGetPointerToFunction(LLVMExecutionEngineRef ee, LLVMValueRef fn) -{ - llvm::ExecutionEngine *eep = llvm::unwrap(ee); - assert(eep); - - llvm::Function *fnp = llvm::unwrap(fn); - assert(fnp); - - return eep->getPointerToFunction(fnp); -} - - -int LLVMInlineFunction(LLVMValueRef call) -{ - llvm::Value *callp = llvm::unwrap(call); - assert(callp); - -// llvm::CallSite cs = llvm::CallSite::get(callp); - llvm::CallSite cs; - llvm::Instruction *II = llvm::dyn_cast(callp); - if (II->getOpcode() == llvm::Instruction::Call) - cs = llvm::CallSite(static_cast(II)); - else if (II->getOpcode() == llvm::Instruction::Invoke) - cs = llvm::CallSite(static_cast(II)); - - llvm::InlineFunctionInfo unused; - return llvm::InlineFunction(cs, unused); -} - -unsigned LLVMGetParamAlignment(LLVMValueRef arg) -{ - llvm::Argument *argp = llvm::unwrap(arg); - assert(argp); - - unsigned argno = argp->getArgNo(); - - return argp->getParent()->getParamAlignment(argno + 1); -} - -/* Passes. A few passes (listed below) are used directly from LLVM-C, - * rest are defined here. - */ - -#define define_pass(P) \ -void LLVMAdd ## P ## Pass (LLVMPassManagerRef passmgr) { \ - using namespace llvm; \ - llvm::PassManagerBase *pmp = llvm::unwrap(passmgr); \ - assert(pmp); \ - pmp->add( create ## P ## Pass ()); \ -} - -define_pass( AAEval ) -define_pass( AliasAnalysisCounter ) -//define_pass( AlwaysInliner ) -//define_pass( BasicAliasAnalysis ) -define_pass( BlockPlacement ) -define_pass( BreakCriticalEdges ) -define_pass( CodeGenPrepare ) -define_pass( DbgInfoPrinter ) -define_pass( DeadCodeElimination ) -define_pass( DeadInstElimination ) -define_pass( DemoteRegisterToMemory ) -define_pass( DomOnlyPrinter ) -define_pass( DomOnlyViewer ) -define_pass( DomPrinter ) -define_pass( DomViewer ) -define_pass( EdgeProfiler ) -//define_pass( GEPSplitter ) -define_pass( GlobalsModRef ) -define_pass( InstCount ) -define_pass( InstructionNamer ) -define_pass( LazyValueInfo ) -define_pass( LCSSA ) -//define_pass( LiveValues ) -define_pass( LoopDependenceAnalysis ) -define_pass( LoopExtractor ) -define_pass( LoopSimplify ) -define_pass( LoopStrengthReduce ) -define_pass( LowerInvoke ) -define_pass( LowerSwitch ) -define_pass( MergeFunctions ) -define_pass( NoAA ) -define_pass( NoProfileInfo ) -define_pass( OptimalEdgeProfiler ) -define_pass( PartialInlining ) -//define_pass( PartialSpecialization ) -define_pass( PostDomOnlyPrinter ) -define_pass( PostDomOnlyViewer ) -define_pass( PostDomPrinter ) -define_pass( PostDomViewer ) -define_pass( ProfileEstimator ) -define_pass( ProfileLoader ) -define_pass( ProfileVerifier ) -define_pass( ScalarEvolutionAliasAnalysis ) -//define_pass( SimplifyHalfPowrLibCalls ) -define_pass( SingleLoopExtractor ) -define_pass( StripNonDebugSymbols ) -//define_pass( StructRetPromotion ) -//define_pass( TailDuplication ) -define_pass( UnifyFunctionExitNodes ) - -/* we support only internalize(true) */ -llvm::ModulePass *createInternalize2Pass() { return llvm::createInternalizePass(true); } -define_pass( Internalize2 ) - diff --git a/llvm/extra.h b/llvm/extra.h deleted file mode 100644 index 3bdb070..0000000 --- a/llvm/extra.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2008-10, Mahadevan R All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of this software, nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * These are some "extra" functions not available in the standard LLVM-C - * bindings, but are required / good-to-have inorder to implement the - * Python bindings. - */ - -#ifndef LLVM_PY_EXTRA_H -#define LLVM_PY_EXTRA_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Notes: - * - Some returned strings must be disposed of by LLVMDisposeMessage. These are - * indicated in the comments. Where it is not indicated, DO NOT call dispose. - */ - -/* Wraps llvm::Module::print(). Dispose the returned string after use, via - * LLVMDisposeMessage(). */ -char *LLVMDumpModuleToString(LLVMModuleRef module); - -/* Wraps llvm::Module::addLibrary(name). */ -void LLVMModuleAddLibrary(LLVMModuleRef module, const char *name); - -/* Wraps llvm::Type::print(). Dispose the returned string after use, via - * LLVMDisposeMessage(). */ -char *LLVMDumpTypeToString(LLVMTypeRef type); - -/* Wraps llvm::Value::print(). Dispose the returned string after use, via - * LLVMDisposeMessage(). */ -char *LLVMDumpValueToString(LLVMValueRef Val); - -/* Wraps llvm::IRBuilder::CreateRet(). */ -LLVMValueRef LLVMBuildRetMultiple(LLVMBuilderRef bulder, LLVMValueRef *values, - unsigned n_values); - -/* Wraps llvm::IRBuilder::CreateGetResult(). */ -LLVMValueRef LLVMBuildGetResult(LLVMBuilderRef builder, LLVMValueRef value, - unsigned index, const char *name); - -/* Wraps llvm::Value::getValueID(). */ -unsigned LLVMValueGetID(LLVMValueRef value); - -/* Wraps llvm::Value::getNumUses(). */ -unsigned LLVMValueGetNumUses(LLVMValueRef value); - -/* Wraps llvm::Value::use_{begin,end}. Allocates LLVMValueRef's as - * required. Number of objects are returned as return value. If that is - * greater than zero, the pointer given out must be freed by a - * subsequent call to LLVMDisposeValueRefArray(). */ -unsigned LLVMValueGetUses(LLVMValueRef value, LLVMValueRef **refs); - -/* See above. */ -void LLVMDisposeValueRefArray(LLVMValueRef *refs); - -/* Wraps llvm:User::getNumOperands(). */ -unsigned LLVMUserGetNumOperands(LLVMValueRef user); - -/* Wraps llvm:User::getOperand(). */ -LLVMValueRef LLVMUserGetOperand(LLVMValueRef user, unsigned idx); - -/* Wraps llvm::ConstantExpr::getVICmp(). */ -LLVMValueRef LLVMConstVICmp(LLVMIntPredicate predicate, LLVMValueRef lhs, - LLVMValueRef rhs); - -/* Wraps llvm::ConstantExpr::getVFCmp(). */ -LLVMValueRef LLVMConstVFCmp(LLVMRealPredicate predicate, LLVMValueRef lhs, - LLVMValueRef rhs); - -/* Wraps llvm::IRBuilder::CreateVICmp(). */ -LLVMValueRef LLVMBuildVICmp(LLVMBuilderRef builder, LLVMIntPredicate predicate, - LLVMValueRef lhs, LLVMValueRef rhs, const char *name); - -/* Wraps llvm::IRBuilder::CreateVFCmp(). */ -LLVMValueRef LLVMBuildVFCmp(LLVMBuilderRef builder, LLVMRealPredicate predicate, - LLVMValueRef lhs, LLVMValueRef rhs, const char *name); - -/* Wraps llvm::Intrinsic::getDeclaration(). */ -LLVMValueRef LLVMGetIntrinsic(LLVMModuleRef builder, int id, - LLVMTypeRef *types, unsigned n_types); - -/* Wraps llvm::Function::doesNotThrow(). */ -unsigned LLVMGetDoesNotThrow(LLVMValueRef fn); - -/* Wraps llvm::Function::setDoesNotThrow(). */ -void LLVMSetDoesNotThrow(LLVMValueRef fn, int DoesNotThrow); - -/* Wraps llvm::Module::getPointerSize(). */ -unsigned LLVMModuleGetPointerSize(LLVMModuleRef module); - -/* Wraps llvm::Module::getOrInsertFunction(). */ -LLVMValueRef LLVMModuleGetOrInsertFunction(LLVMModuleRef module, - const char *name, LLVMTypeRef function_type); - -/* Wraps llvm::GlobalVariable::hasInitializer(). */ -int LLVMHasInitializer(LLVMValueRef global_var); - -/* The following functions wrap various llvm::Instruction::isXXX() functions. - * All of them take an instruction and return 0 (isXXX returned false) or 1 - * (isXXX returned false). */ -unsigned LLVMInstIsTerminator (LLVMValueRef inst); -unsigned LLVMInstIsBinaryOp (LLVMValueRef inst); -unsigned LLVMInstIsShift (LLVMValueRef inst); -unsigned LLVMInstIsCast (LLVMValueRef inst); -unsigned LLVMInstIsLogicalShift (LLVMValueRef inst); -unsigned LLVMInstIsArithmeticShift (LLVMValueRef inst); -unsigned LLVMInstIsAssociative (LLVMValueRef inst); -unsigned LLVMInstIsCommutative (LLVMValueRef inst); -unsigned LLVMInstIsTrapping (LLVMValueRef inst); - -/* As above, but these are wrap methods from subclasses of Instruction. */ -unsigned LLVMInstIsVolatile (LLVMValueRef inst); - -/* Wraps llvm::Instruction::getOpcodeName(). */ -const char *LLVMInstGetOpcodeName(LLVMValueRef inst); - -/* Wraps llvm::Instruction::getOpcode(). */ -unsigned LLVMInstGetOpcode(LLVMValueRef inst); - -/* Wraps llvm::CmpInst::getPredicate(). */ -unsigned LLVMCmpInstGetPredicate(LLVMValueRef cmpinst); - -/* Wraps llvm::ParseAssemblyString(). Returns a module reference or NULL (with - * `out' pointing to an error message). Dispose error message after use, via - * LLVMDisposeMessage(). */ -LLVMModuleRef LLVMGetModuleFromAssembly(const char *asmtxt, unsigned txten, - char **out); - -/* Wraps llvm::ParseBitcodeFile(). Returns a module reference or NULL (with - * `out' pointing to an error message). Dispose error message after use, via - * LLVMDisposeMessage(). */ -LLVMModuleRef LLVMGetModuleFromBitcode(const char *bc, unsigned bclen, - char **out); - -/* Wraps llvm::Linker::LinkModules(). Returns 0 on failure (with errmsg - * filled in) and 1 on success. Dispose error message after use with - * LLVMDisposeMessage(). */ -unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, - unsigned int, char **errmsg); - -/* Returns pointer to a heap-allocated block of `*len' bytes containing bit code - * for the given module. NULL on error. */ -unsigned char *LLVMGetBitcodeFromModule(LLVMModuleRef module, unsigned *len); - -/* Wraps llvm::sys::DynamicLibrary::LoadLibraryPermanently(). Returns 0 on - * failure (with errmsg filled in) and 1 on success. Dispose error message after - * use, via LLVMDisposeMessage(). */ -unsigned LLVMLoadLibraryPermanently(const char* filename, char **errmsg); - -/* Wraps llvm::ExecutionEngine::getPointerToFunction(). Returns a pointer - * to the JITted function. */ -void *LLVMGetPointerToFunction(LLVMExecutionEngineRef ee, LLVMValueRef fn); - -/* Wraps llvm::InlineFunction(). Inlines a function. C is the call - * instruction, created by LLVMBuildCall. Even if it fails, the Function - * containing the call is still in a proper state (not changed). */ -//int LLVMInlineFunction(LLVMValueRef call); - -/* Wraps llvm::getAlignmentFromAttrs from Attributes.h. Compliments the - * already available LLVMSetParamAlignment(). */ -unsigned LLVMGetParamAlignment(LLVMValueRef arg); - -/* Passes. Some passes are used directly from LLVM-C, rest are declared - * here. */ - -#define declare_pass(P) \ - void LLVMAdd ## P ## Pass (LLVMPassManagerRef PM); - -declare_pass( AAEval ) -declare_pass( AliasAnalysisCounter ) -declare_pass( AlwaysInliner ) -declare_pass( BasicAliasAnalysis ) -declare_pass( BlockPlacement ) -declare_pass( BreakCriticalEdges ) -declare_pass( CodeGenPrepare ) -declare_pass( DbgInfoPrinter ) -declare_pass( DeadCodeElimination ) -declare_pass( DeadInstElimination ) -declare_pass( DemoteRegisterToMemory ) -declare_pass( DomOnlyPrinter ) -declare_pass( DomOnlyViewer ) -declare_pass( DomPrinter ) -declare_pass( DomViewer ) -declare_pass( EdgeProfiler ) -//declare_pass( GEPSplitter ) -declare_pass( GlobalsModRef ) -declare_pass( InstCount ) -declare_pass( InstructionNamer ) -declare_pass( LazyValueInfo ) -declare_pass( LCSSA ) -//declare_pass( LiveValues ) -declare_pass( LoopDependenceAnalysis ) -declare_pass( LoopExtractor ) -declare_pass( LoopSimplify ) -declare_pass( LoopStrengthReduce ) -declare_pass( LowerInvoke ) -declare_pass( LowerSwitch ) -declare_pass( MergeFunctions ) -declare_pass( NoAA ) -declare_pass( NoProfileInfo ) -declare_pass( OptimalEdgeProfiler ) -declare_pass( PartialInlining ) -//declare_pass( PartialSpecialization ) -declare_pass( PostDomOnlyPrinter ) -declare_pass( PostDomOnlyViewer ) -declare_pass( PostDomPrinter ) -declare_pass( PostDomViewer ) -declare_pass( ProfileEstimator ) -declare_pass( ProfileLoader ) -declare_pass( ProfileVerifier ) -declare_pass( ScalarEvolutionAliasAnalysis ) -declare_pass( SimplifyHalfPowrLibCalls ) -declare_pass( SingleLoopExtractor ) -declare_pass( StripNonDebugSymbols ) -declare_pass( StructRetPromotion ) -declare_pass( TailDuplication ) -declare_pass( UnifyFunctionExitNodes ) - -declare_pass( Internalize2 ) - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* LLVM_PY_EXTRA_H */ - 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 + +;