diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 3a05aa8..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -llvm/_version.py export-subst diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6d6296f..0000000 --- a/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -*~ -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 deleted file mode 100644 index f4474f7..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -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 45d6a5f..396ce0e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,88 +1,14 @@ -2014-04-28 0.12.5: ---------------------- - * Fixes memory leaks (#92) - * Fixes tarball (#99) -2014-03-20 0.12.4: ---------------------- - * Add dylib_import_library and friends - * Fix BasicBlock downcast - * Module hashing - * Fix test script +0.7, in progress: -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). -2010-08-31 0.6: ------------------ +0.6, 31-Aug-2010: + * Add and remove function attributes (Krzysztof Goj) (Issue #21). * Wrap fadd,fsub,fmul (Aaron S Lav) (Issue #31). * Migrate to LLVM 2.7. @@ -101,16 +27,16 @@ in progress, 0.7: * Migrate to LLVM 2.5. -2008-11-22 0.5: ------------------ +0.5, 22-Nov-2008: + * Added vicmp, vfcmp instructions and constant expressions. * Builds on FreeBSD. * Updated documentation. * Migrate to LLVM 2.4. -2008-11-21 0.4: ------------------ +0.4, 21-Nov-2008: + * Code cleanup, added license headers. * Added llvm.core.load_library_permanently() (Issue #12). * Fix comparison using != (Issue #11). @@ -119,8 +45,8 @@ in progress, 0.7: * Added viewCFG methods to Function (Paulo Silva). -2008-09-08 0.3: ------------------ +0.3, 8-Sep-2008: + * Passes added. * Assembly support: create modules from .ll files. * Various bug fixes. @@ -132,13 +58,13 @@ in progress, 0.7: * Updated documentation. -2008-06-28 0.2.1: -------------------- +0.2.1, 18-Jun-2008: + * Build cleanly with LLVM 2.3 and 2.3svn. -2008-06-15 0.2: ------------------ +0.2, 15-Jun-2008: + * 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 @@ -153,6 +79,7 @@ in progress, 0.7: * Lots of cleanup. -2008-05-10 0.1: ------------------ - * Initial release +0.1, 10-May-2008: + + * Initial release. + diff --git a/LICENSE b/LICENSE index 8117ae1..579d556 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,4 @@ 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 25a211d..ec22b21 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,4 @@ -include CHANGELOG LICENSE README.rst setup.py MANIFEST.in versioneer.py +include CHANGELOG LICENSE README setup.py MANIFEST.in recursive-include llvm * -recursive-include llvmpy * recursive-include www * recursive-include test * -recursive-include tools * diff --git a/README.md b/README.md new file mode 100644 index 0000000..74194eb --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# 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 deleted file mode 100644 index a1abf84..0000000 --- a/README.rst +++ /dev/null @@ -1,67 +0,0 @@ -================================ -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 deleted file mode 100644 index da180c4..0000000 --- a/README_LLVM_CBUILDER.md +++ /dev/null @@ -1,144 +0,0 @@ -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 deleted file mode 100644 index e9177c5..0000000 --- a/buildscripts/condarecipe/bld.bat +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index 5c98fde..0000000 --- a/buildscripts/condarecipe/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/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 deleted file mode 100644 index 4612840..0000000 --- a/buildscripts/condarecipe/meta.yaml +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index 682b8d4..0000000 --- a/buildscripts/condarecipe/run_test.py +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 8e563cc..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,157 +0,0 @@ -# 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 deleted file mode 100755 index 3ee5d20..0000000 --- a/docs/gh-pages.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/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 deleted file mode 100644 index 701ef80..0000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,259 +0,0 @@ -# -*- 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 deleted file mode 100644 index 2f1b87b..0000000 --- a/docs/source/doc/comparision.rst +++ /dev/null @@ -1,147 +0,0 @@ -+--------------------------------+ -| 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 deleted file mode 100644 index a3b94b6..0000000 --- a/docs/source/doc/core.rst +++ /dev/null @@ -1,9 +0,0 @@ -******************************** -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 deleted file mode 100644 index 9e01700..0000000 --- a/docs/source/doc/examples.rst +++ /dev/null @@ -1,12 +0,0 @@ -******************************** -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 deleted file mode 100644 index 09f3c33..0000000 --- a/docs/source/doc/examples/JITTutorial1.rst +++ /dev/null @@ -1,36 +0,0 @@ -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 deleted file mode 100644 index 6e76150..0000000 --- a/docs/source/doc/examples/JITTutorial2.rst +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index 0cd3532..0000000 --- a/docs/source/doc/examples/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index 0f6a4d0..0000000 --- a/docs/source/doc/firstexample.rst +++ /dev/null @@ -1,125 +0,0 @@ -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 deleted file mode 100644 index 8922dd0..0000000 --- a/docs/source/doc/functions.rst +++ /dev/null @@ -1,149 +0,0 @@ -+--------------------+ -| 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 deleted file mode 100644 index 53c2982..0000000 --- a/docs/source/doc/getting_started.rst +++ /dev/null @@ -1,115 +0,0 @@ - -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 deleted file mode 100644 index ae4b80d..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst +++ /dev/null @@ -1,312 +0,0 @@ -************************************************* -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 deleted file mode 100644 index a375512..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst +++ /dev/null @@ -1,1079 +0,0 @@ -*************************************************** -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 deleted file mode 100644 index 15ec212..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst +++ /dev/null @@ -1,1087 +0,0 @@ -******************************************* -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 deleted file mode 100644 index 7ac3d97..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl4.rst +++ /dev/null @@ -1,936 +0,0 @@ -************************************************* -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 deleted file mode 100644 index 33edba2..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl5.rst +++ /dev/null @@ -1,1549 +0,0 @@ -***************************************************** -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 deleted file mode 100644 index 8ff31d4..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl6.rst +++ /dev/null @@ -1,1557 +0,0 @@ -********************************************************************** -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 deleted file mode 100644 index dee1c31..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst +++ /dev/null @@ -1,1835 +0,0 @@ -******************************************************************************* -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 deleted file mode 100644 index eb13dd0..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl8.rst +++ /dev/null @@ -1,275 +0,0 @@ -*************************************************** -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 deleted file mode 100644 index 6099fea..0000000 --- a/docs/source/doc/kaleidoscope/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index ff7669c..0000000 --- a/docs/source/doc/llpython/articles.rst +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index 53f63bf..0000000 --- a/docs/source/doc/llpython/ctmp_in_llpython.rst +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 43ea17a..0000000 --- a/docs/source/doc/llpython/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index 47c0c2a..0000000 --- a/docs/source/doc/llpython/intro_llpython.rst +++ /dev/null @@ -1,46 +0,0 @@ -==================== -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 deleted file mode 100644 index e851dac..0000000 --- a/docs/source/doc/llpython/llpython.byte_control.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -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 deleted file mode 100644 index 783a54b..0000000 --- a/docs/source/doc/llpython/llpython.byte_flow.rst +++ /dev/null @@ -1,6 +0,0 @@ -================== -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 deleted file mode 100644 index 2a5993c..0000000 --- a/docs/source/doc/llpython/llpython.byte_translator.rst +++ /dev/null @@ -1,6 +0,0 @@ -======================== -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 deleted file mode 100644 index 3479ff7..0000000 --- a/docs/source/doc/llpython/llpython.bytecode_visitor.rst +++ /dev/null @@ -1,6 +0,0 @@ -========================= -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 deleted file mode 100644 index 81efe83..0000000 --- a/docs/source/doc/llpython/llpython.bytetype.rst +++ /dev/null @@ -1,6 +0,0 @@ -================= -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 deleted file mode 100644 index c9aee7d..0000000 --- a/docs/source/doc/llpython/llpython.control_flow.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -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 deleted file mode 100644 index 2bc19db..0000000 --- a/docs/source/doc/llpython/llpython.gen_bytecode_visitor.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================= -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 deleted file mode 100644 index 59e052d..0000000 --- a/docs/source/doc/llpython/llpython.nobitey.rst +++ /dev/null @@ -1,6 +0,0 @@ -================ -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 deleted file mode 100644 index 0fa5387..0000000 --- a/docs/source/doc/llpython/llpython.opcode_util.rst +++ /dev/null @@ -1,6 +0,0 @@ -==================== -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 deleted file mode 100644 index 3db3863..0000000 --- a/docs/source/doc/llpython/llpython.phi_injector.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -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 deleted file mode 100644 index 39e0de7..0000000 --- a/docs/source/doc/llpython/llpython.pyaddfunc.rst +++ /dev/null @@ -1,6 +0,0 @@ -================== -llpython.pyaddfunc -================== - -.. automodule:: llpython.pyaddfunc - :members: diff --git a/docs/source/doc/llpython/llpython.rst b/docs/source/doc/llpython/llpython.rst deleted file mode 100644 index 87fd3d5..0000000 --- a/docs/source/doc/llpython/llpython.rst +++ /dev/null @@ -1,6 +0,0 @@ -======== -llpython -======== - -.. automodule:: llpython - :members: diff --git a/docs/source/doc/llpython/nobitey_dev.rst b/docs/source/doc/llpython/nobitey_dev.rst deleted file mode 100644 index be7b4d8..0000000 --- a/docs/source/doc/llpython/nobitey_dev.rst +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 7818100..0000000 --- a/docs/source/doc/llpython/reference.rst +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index a2ffbfa..0000000 --- a/docs/source/doc/llvm.core.Argument.rst +++ /dev/null @@ -1,65 +0,0 @@ -+-------------------------------+ -| 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 deleted file mode 100644 index 3a4e645..0000000 --- a/docs/source/doc/llvm.core.ArrayType.rst +++ /dev/null @@ -1,37 +0,0 @@ -+--------------------------------+ -| 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 deleted file mode 100644 index eb10be3..0000000 --- a/docs/source/doc/llvm.core.BasicBlock.rst +++ /dev/null @@ -1,51 +0,0 @@ -+---------------------------------+ -| 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 deleted file mode 100644 index 24b9361..0000000 --- a/docs/source/doc/llvm.core.Builder.rst +++ /dev/null @@ -1,418 +0,0 @@ -+------------------------------+ -| 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 deleted file mode 100644 index 3822046..0000000 --- a/docs/source/doc/llvm.core.Constant.rst +++ /dev/null @@ -1,363 +0,0 @@ -+-------------------------------+ -| 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 deleted file mode 100644 index cda101e..0000000 --- a/docs/source/doc/llvm.core.Function.rst +++ /dev/null @@ -1,158 +0,0 @@ -+-------------------------------+ -| 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 deleted file mode 100644 index 7b728a8..0000000 --- a/docs/source/doc/llvm.core.FunctionType.rst +++ /dev/null @@ -1,55 +0,0 @@ -+-----------------------------------+ -| 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 deleted file mode 100644 index a5c2383..0000000 --- a/docs/source/doc/llvm.core.GlobalValue.rst +++ /dev/null @@ -1,103 +0,0 @@ -+----------------------------------+ -| 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 deleted file mode 100644 index 1ba69d8..0000000 --- a/docs/source/doc/llvm.core.GlobalVariable.rst +++ /dev/null @@ -1,49 +0,0 @@ -+-------------------------------------+ -| 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 deleted file mode 100644 index 67c43f0..0000000 --- a/docs/source/doc/llvm.core.Instruction.rst +++ /dev/null @@ -1,249 +0,0 @@ -+----------------------------------+ -| 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 deleted file mode 100644 index 6f1e2b1..0000000 --- a/docs/source/doc/llvm.core.IntegerType.rst +++ /dev/null @@ -1,30 +0,0 @@ -+----------------------------------+ -| 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 deleted file mode 100644 index 75cc174..0000000 --- a/docs/source/doc/llvm.core.Module.rst +++ /dev/null @@ -1,29 +0,0 @@ -+-----------------------------+ -| 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 deleted file mode 100644 index cc65139..0000000 --- a/docs/source/doc/llvm.core.PointerType.rst +++ /dev/null @@ -1,38 +0,0 @@ -+----------------------------------+ -| 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 deleted file mode 100644 index f3b0786..0000000 --- a/docs/source/doc/llvm.core.StructType.rst +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index b1eb354..0000000 --- a/docs/source/doc/llvm.core.Type.rst +++ /dev/null @@ -1,135 +0,0 @@ -+---------------------------+ -| 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 deleted file mode 100644 index 12d40c5..0000000 --- a/docs/source/doc/llvm.core.User.rst +++ /dev/null @@ -1,46 +0,0 @@ -+---------------------------+ -| 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 deleted file mode 100644 index 081d328..0000000 --- a/docs/source/doc/llvm.core.Value.rst +++ /dev/null @@ -1,72 +0,0 @@ -+----------------------------+ -| 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 deleted file mode 100644 index a18f6ea..0000000 --- a/docs/source/doc/llvm.core.VectorType.rst +++ /dev/null @@ -1,38 +0,0 @@ -+---------------------------------+ -| 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 deleted file mode 100644 index e317acc..0000000 --- a/docs/source/doc/llvm.ee.EngineBuilder.rst +++ /dev/null @@ -1,56 +0,0 @@ -+----------------------------------+ -| 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 deleted file mode 100644 index 718358c..0000000 --- a/docs/source/doc/llvm.ee.ExecutionEngine.rst +++ /dev/null @@ -1,62 +0,0 @@ -+------------------------------------+ -| 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 deleted file mode 100644 index 8680093..0000000 --- a/docs/source/doc/llvm.ee.GenericValue.rst +++ /dev/null @@ -1,64 +0,0 @@ -+---------------------------------+ -| 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 deleted file mode 100644 index 5a774b8..0000000 --- a/docs/source/doc/llvm.ee.TargetData.rst +++ /dev/null @@ -1,70 +0,0 @@ -+-------------------------------+ -| 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 deleted file mode 100644 index 137cf74..0000000 --- a/docs/source/doc/llvm.passes.FunctionPassManager.rst +++ /dev/null @@ -1,42 +0,0 @@ -+--------------------------------------------+ -| 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 deleted file mode 100644 index e0a2536..0000000 --- a/docs/source/doc/llvm.passes.PassManager.rst +++ /dev/null @@ -1,29 +0,0 @@ -+------------------------------------+ -| 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 deleted file mode 100644 index 99e1935..0000000 --- a/docs/source/doc/llvm.passes.PassManagerBuilder.rst +++ /dev/null @@ -1,72 +0,0 @@ -+-------------------------------------------+ -| 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 deleted file mode 100644 index c8623c2..0000000 --- a/docs/source/doc/llvm_cbuilder.rst +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 8690e49..0000000 --- a/docs/source/doc/llvm_concepts.rst +++ /dev/null @@ -1,239 +0,0 @@ -******************** -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 deleted file mode 100644 index a3b94b6..0000000 --- a/docs/source/doc/llvmcore.rst +++ /dev/null @@ -1,9 +0,0 @@ -******************************** -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 deleted file mode 100644 index 2145502..0000000 --- a/docs/source/doc/llvmee.rst +++ /dev/null @@ -1,9 +0,0 @@ -******************************** -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 deleted file mode 100644 index 0931467..0000000 --- a/docs/source/doc/llvmpasses.rst +++ /dev/null @@ -1,9 +0,0 @@ -******************************** -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 deleted file mode 100644 index eac3814..0000000 --- a/docs/source/doc/llvmpy_package.rst +++ /dev/null @@ -1,89 +0,0 @@ -*********************** -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 deleted file mode 100644 index f3b9da2..0000000 --- a/docs/source/doc/types.rst +++ /dev/null @@ -1,123 +0,0 @@ -+----------------+ -| 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 deleted file mode 100644 index 1bb4b4f..0000000 --- a/docs/source/doc/userguide.rst +++ /dev/null @@ -1,17 +0,0 @@ -************ -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 deleted file mode 100644 index a999740..0000000 --- a/docs/source/doc/values.rst +++ /dev/null @@ -1,78 +0,0 @@ -+-----------------+ -| 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 deleted file mode 100644 index fbf5c8b..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. 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 deleted file mode 100644 index e49d06a..0000000 --- a/example/vector_instr.py +++ /dev/null @@ -1,152 +0,0 @@ -''' -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 deleted file mode 100644 index e69de29..0000000 diff --git a/llpython/byte_control.py b/llpython/byte_control.py deleted file mode 100644 index 8ca407e..0000000 --- a/llpython/byte_control.py +++ /dev/null @@ -1,125 +0,0 @@ -# ______________________________________________________________________ -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 deleted file mode 100644 index 197c839..0000000 --- a/llpython/byte_flow.py +++ /dev/null @@ -1,266 +0,0 @@ -# ______________________________________________________________________ -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 deleted file mode 100644 index a6e5864..0000000 --- a/llpython/byte_translator.py +++ /dev/null @@ -1,612 +0,0 @@ -# ______________________________________________________________________ -'''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 deleted file mode 100644 index 3fa3f48..0000000 --- a/llpython/bytecode_visitor.py +++ /dev/null @@ -1,360 +0,0 @@ -# ______________________________________________________________________ -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 deleted file mode 100644 index 484d09e..0000000 --- a/llpython/bytetype.py +++ /dev/null @@ -1,42 +0,0 @@ -# ______________________________________________________________________ - -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 deleted file mode 100644 index 8026aba..0000000 --- a/llpython/control_flow.py +++ /dev/null @@ -1,217 +0,0 @@ -# ______________________________________________________________________ - -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 deleted file mode 100644 index a60b345..0000000 --- a/llpython/gen_bytecode_visitor.py +++ /dev/null @@ -1,26 +0,0 @@ -# ______________________________________________________________________ -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 deleted file mode 100644 index 4236d29..0000000 --- a/llpython/nobitey.py +++ /dev/null @@ -1,367 +0,0 @@ -# ______________________________________________________________________ -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 deleted file mode 100644 index 7a1972b..0000000 --- a/llpython/opcode_util.py +++ /dev/null @@ -1,225 +0,0 @@ -# ______________________________________________________________________ - -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 deleted file mode 100644 index dfa1061..0000000 --- a/llpython/phi_injector.py +++ /dev/null @@ -1,153 +0,0 @@ -# ______________________________________________________________________ - -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 deleted file mode 100644 index d6a2945..0000000 --- a/llpython/pyaddfunc.py +++ /dev/null @@ -1,40 +0,0 @@ -# ______________________________________________________________________ - -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 deleted file mode 100644 index e69de29..0000000 diff --git a/llpython/tests/llfuncs.py b/llpython/tests/llfuncs.py deleted file mode 100644 index 8b5b1f3..0000000 --- a/llpython/tests/llfuncs.py +++ /dev/null @@ -1,41 +0,0 @@ -# ______________________________________________________________________ - -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 deleted file mode 100644 index 8335044..0000000 --- a/llpython/tests/llfunctys.py +++ /dev/null @@ -1,19 +0,0 @@ -# ______________________________________________________________________ - -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 deleted file mode 100644 index b15eac5..0000000 --- a/llrtc/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 539d9c3..0000000 --- a/llrtc/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# 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 deleted file mode 100644 index fbcf76a..0000000 --- a/llrtc/lib/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.o -*.run -*.out -*.ll diff --git a/llrtc/lib/Makefile b/llrtc/lib/Makefile deleted file mode 100644 index 9dbfb27..0000000 --- a/llrtc/lib/Makefile +++ /dev/null @@ -1,66 +0,0 @@ -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 deleted file mode 100644 index 8466965..0000000 --- a/llrtc/lib/div64.c +++ /dev/null @@ -1,11 +0,0 @@ -#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 deleted file mode 100644 index 4e9e348..0000000 --- a/llrtc/lib/llrt.h +++ /dev/null @@ -1,19 +0,0 @@ -#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 deleted file mode 100644 index 875f6b9..0000000 --- a/llrtc/lib/mod64.c +++ /dev/null @@ -1,15 +0,0 @@ -#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 deleted file mode 100644 index df294b3..0000000 --- a/llrtc/lib/sdivmod64.c +++ /dev/null @@ -1,40 +0,0 @@ -#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 deleted file mode 100644 index 1e804d6..0000000 --- a/llrtc/lib/test_sdivmod64.c +++ /dev/null @@ -1,21 +0,0 @@ -#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 deleted file mode 100644 index 4aa49a9..0000000 --- a/llrtc/lib/test_sdivmod64.py +++ /dev/null @@ -1,56 +0,0 @@ -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 deleted file mode 100644 index 70b44aa..0000000 --- a/llrtc/lib/test_udivmod64.c +++ /dev/null @@ -1,20 +0,0 @@ -#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 deleted file mode 100644 index da07ccb..0000000 --- a/llrtc/lib/test_udivmod64.py +++ /dev/null @@ -1,53 +0,0 @@ -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 deleted file mode 100644 index 5936f98..0000000 --- a/llrtc/lib/udivmod64.c +++ /dev/null @@ -1,84 +0,0 @@ -/* -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 deleted file mode 100644 index a20ba34..0000000 --- a/llrtc/tools/striptriple.py +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 3f756ee..0000000 --- a/llvm-config-win32.py +++ /dev/null @@ -1,88 +0,0 @@ -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 new file mode 100644 index 0000000..5572286 --- /dev/null +++ b/llvm/2.9_update.diff @@ -0,0 +1,2117 @@ +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 9b24112..9128c70 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -1,47 +1,149 @@ -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions +# +# 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 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] +#===----------------------------------------------------------------------=== +# Exceptions +#===----------------------------------------------------------------------=== 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 - Run self-test, and return the number of failures + errors - """ - from llvm.tests import run +#===----------------------------------------------------------------------=== +# 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. +#===----------------------------------------------------------------------=== - result = run(verbosity=verbosity, run_isolated=run_isolated) - errct = len(result.failures) + len(result.errors) +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) - return errct diff --git a/llvm/_core.c b/llvm/_core.c new file mode 100644 index 0000000..f9e76fe --- /dev/null +++ b/llvm/_core.c @@ -0,0 +1,1840 @@ +/* + * 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 new file mode 100644 index 0000000..c2e0ae5 --- /dev/null +++ b/llvm/_intrinsic_ids.py @@ -0,0 +1,1942 @@ +# +# 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 new file mode 100644 index 0000000..1ff4cc9 --- /dev/null +++ b/llvm/_util.py @@ -0,0 +1,79 @@ +# +# 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 deleted file mode 100644 index a90c5b8..0000000 --- a/llvm/_version.py +++ /dev/null @@ -1,193 +0,0 @@ - -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 4db8135..0992dde 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -28,216 +28,156 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -from io import BytesIO -try: - from StringIO import StringIO -except ImportError: - try: - from cStringIO import StringIO - except ImportError: - from io import StringIO +"""Core classes of LLVM. -import contextlib, weakref +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 llvm -from llvm._intrinsic_ids import * -from llvm.deprecated import deprecated -from llvmpy import api #===----------------------------------------------------------------------=== # Enumerations #===----------------------------------------------------------------------=== -class Enum(int): - '''Overload integer to print the name of the enum. - ''' - def __repr__(self): - return '%s(%d)' % (type(self).__name__, self) - @classmethod - def declare(cls): - declared = cls._declared_ = {} - scope = globals() - for name in filter(lambda s: s.startswith(cls.prefix), dir(cls)): - n = getattr(cls, name) - typ = type(name, (cls,), {}) - obj = typ(n) - declared[n] = obj - scope[name] = obj - - @classmethod - def get(cls, num): - return cls._declared_[num] - -# type id (llvm::Type::TypeID) -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() +# 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 # value IDs (llvm::Value::ValueTy enum) -# According to the doxygen docs, it is not a good idea to use these enums. -# There are more values than those declared. -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() +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 # instruction opcodes (from include/llvm/Instruction.def) -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() +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 # 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 -class ICMPEnum(Enum): - prefix = 'ICMP_' +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 - 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 @@ -250,33 +190,24 @@ IPRED_SLT = ICMP_SLT IPRED_SLE = ICMP_SLE # real predicates - -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() +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 # real predicates - RPRED_FALSE = FCMP_FALSE RPRED_OEQ = FCMP_OEQ RPRED_OGT = FCMP_OGT @@ -294,78 +225,98 @@ RPRED_ULE = FCMP_ULE RPRED_UNE = FCMP_UNE RPRED_TRUE = FCMP_TRUE -# 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() +# 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 # visibility (see llvm/GlobalValue.h) -class VisibilityEnum(Enum): - prefix = 'VISIBILITY_' +VISIBILITY_DEFAULT = 0 +VISIBILITY_HIDDEN = 1 +VISIBILITY_PROTECTED = 2 - VISIBILITY_DEFAULT = api.llvm.GlobalValue.VisibilityTypes.DefaultVisibility - VISIBILITY_HIDDEN = api.llvm.GlobalValue.VisibilityTypes.HiddenVisibility - VISIBILITY_PROTECTED = api.llvm.GlobalValue.VisibilityTypes.ProtectedVisibility +# 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 -VisibilityEnum.declare() +# intrinsic IDs +from llvm._intrinsic_ids import * -# parameter attributes -# LLVM 3.2 llvm::Attributes::AttrVal (see llvm/Attributes.h) -# LLVM 3.3 llvm::Attribute::AttrKind (see llvm/Attributes.h) -class AttrEnum(Enum): - prefix = 'ATTR_' - if llvm.version >= (3, 3): - AttrVal = api.llvm.Attribute.AttrKind +#===----------------------------------------------------------------------=== +# 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 else: - AttrVal = api.llvm.Attributes.AttrVal + return 0 - ATTR_NONE = AttrVal.None_ - ATTR_ZEXT = AttrVal.ZExt - ATTR_SEXT = AttrVal.SExt - ATTR_NO_RETURN = AttrVal.NoReturn - ATTR_IN_REG = AttrVal.InReg - ATTR_STRUCT_RET = AttrVal.StructRet - ATTR_NO_UNWIND = AttrVal.NoUnwind - ATTR_NO_ALIAS = AttrVal.NoAlias - ATTR_BY_VAL = AttrVal.ByVal - ATTR_NEST = AttrVal.Nest - ATTR_READ_NONE = AttrVal.ReadNone - ATTR_READONLY = AttrVal.ReadOnly - ATTR_NO_INLINE = AttrVal.NoInline - ATTR_ALWAYS_INLINE = AttrVal.AlwaysInline - ATTR_OPTIMIZE_FOR_SIZE = AttrVal.OptimizeForSize - ATTR_STACK_PROTECT = AttrVal.StackProtect - ATTR_STACK_PROTECT_REQ = AttrVal.StackProtectReq - ATTR_ALIGNMENT = AttrVal.Alignment - ATTR_NO_CAPTURE = AttrVal.NoCapture - ATTR_NO_REDZONE = AttrVal.NoRedZone - ATTR_NO_IMPLICIT_FLOAT = AttrVal.NoImplicitFloat - ATTR_NAKED = AttrVal.Naked - ATTR_INLINE_HINT = AttrVal.InlineHint - ATTR_STACK_ALIGNMENT = AttrVal.StackAlignment -AttrEnum.declare() +#===----------------------------------------------------------------------=== +# Module +#===----------------------------------------------------------------------=== -class Module(llvm.Wrapper): +class Module(llvm.Ownable, llvm.Cacheable): """A Module instance stores all the information related to an LLVM module. Modules are the top level container of all other LLVM Intermediate @@ -379,16 +330,6 @@ class Module(llvm.Wrapper): 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): @@ -396,102 +337,96 @@ class Module(llvm.Wrapper): Creates an instance of Module, having the id `id'. """ - context = api.llvm.getGlobalContext() - m = api.llvm.Module.new(id, context) - return Module(m) + return Module(_core.LLVMModuleCreateWithName(id)) @staticmethod - def from_bitcode(fileobj_or_str): + def from_bitcode(fileobj): """Create a Module instance from the contents of a bitcode - file. + file.""" - 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 + 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) else: - 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) - + return Module(ret) @staticmethod - def from_assembly(fileobj_or_str): + def from_assembly(fileobj): """Create a Module instance from the contents of an LLVM - assembly (.ll) file. + assembly (.ll) file.""" - - fileobj_or_str -- takes a file-like object or string that contains - a module represented in llvm-ir assembly. - """ - if isinstance(fileobj_or_str, str): - ir = fileobj_or_str + 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: - 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) + return Module(ret) + + def __init__(self, ptr): + """DO NOT CALL DIRECTLY. + + Use the static method `Module.new' instead. + """ + llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeModule) 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 str(self._ptr) - - def __hash__(self): - return id(self._ptr) + ll = str(module_obj) + print module_obj # same as `print ll' + """ + return _core.LLVMDumpModuleToString(self.ptr) def __eq__(self, rhs): if isinstance(rhs, Module): - return self._ptr == rhs._ptr + return str(self) == str(rhs) + else: + return False def __ne__(self, rhs): - return not (self == rhs) - + return not self == rhs def _get_target(self): - return self._ptr.getTargetTriple() + return _core.LLVMGetTarget(self.ptr) def _set_target(self, value): - return self._ptr.setTargetTriple(value) + return _core.LLVMSetTarget(self.ptr, value) target = property(_get_target, _set_target, - doc="The target triple string describing the target host.") - + """The target triple string describing the target host.""" + ) def _get_data_layout(self): - return self._ptr.getDataLayout() + return _core.LLVMGetDataLayout(self.ptr) def _set_data_layout(self, value): - return self._ptr.setDataLayout(value) + _core.LLVMSetDataLayout(self.ptr, value) data_layout = property(_get_data_layout, _set_data_layout, - doc = """The data layout string for the module's target platform. + """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): - return self._ptr.getPointerSize() + """Pointer size of target platform. - def link_in(self, other, preserve=False): + Can be 0, 32 or 64. Zero represents + llvm::Module::AnyPointerSize.""" + return _core.LLVMModuleGetPointerSize(self.ptr) + + def link_in(self, other): """Link the `other' module into this one. The `other' module is linked into this one such that types, @@ -503,246 +438,130 @@ class Module(llvm.Wrapper): In the future, this API might be replaced with a full-fledged Linker class. """ - 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()) + 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()) def get_type_named(self, name): - typ = self._ptr.getTypeByName(name) - if typ: - return StructType(typ) + """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 - def add_global_variable(self, ty, name, addrspace=0): + def add_global_variable(self, ty, name): """Add a global variable of given type with given 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) + return GlobalVariable.new(self, ty, name) def get_global_variable_named(self, name): """Return a GlobalVariable object for the given name.""" - ptr = self._ptr.getNamedGlobal(name) - if ptr is None: - raise llvm.LLVMException("No global named: %s" % name) - return _make_value(ptr) + return GlobalVariable.get(self, name) @property def global_variables(self): - return list(map(_make_value, self._ptr.list_globals())) + """All global variables in this module.""" + return _util.wrapiter(_core.LLVMGetFirstGlobal, + _core.LLVMGetNextGlobal, self.ptr, _make_value) 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 list(map(_make_value, self._ptr.list_functions())) + return _util.wrapiter(_core.LLVMGetFirstFunction, + _core.LLVMGetNextFunction, self.ptr, _make_value) def verify(self): """Verify module. - 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()) + Checks module for errors. Raises `llvm.LLVMException' on any + error.""" + ret = _core.LLVMVerifyModule(self.ptr) + if ret != "": + raise llvm.LLVMException(ret) - def to_bitcode(self, fileobj=None): + def to_bitcode(self, fileobj): """Write bitcode representation of module to given file-like - object. + object.""" - fileobj -- A file-like object to where the bitcode is written. - If it is None, the bitcode is returned. + data = _core.LLVMGetBitcodeFromModule(self.ptr) + if not data: + raise llvm.LLVMException("Unable to create bitcode") + fileobj.write(data) - 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() + def add_library(self, name): + return _core.LLVMModuleAddLibrary(self.ptr, name) - def to_native_object(self, fileobj=None): - '''Outputs the byte string of the module as native object code +#===----------------------------------------------------------------------=== +# Types +#===----------------------------------------------------------------------=== - 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): +class Type(object): """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.""" - context = api.llvm.getGlobalContext() - ptr = api.llvm.Type.getIntNTy(context, bits) - return Type(ptr) + 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) @staticmethod def float(): """Create a 32-bit floating point type.""" - context = api.llvm.getGlobalContext() - ptr = api.llvm.Type.getFloatTy(context) - return Type(ptr) + return _make_type(_core.LLVMFloatType(), TYPE_FLOAT) @staticmethod def double(): """Create a 64-bit floating point type.""" - context = api.llvm.getGlobalContext() - ptr = api.llvm.Type.getDoubleTy(context) - return Type(ptr) + return _make_type(_core.LLVMDoubleType(), TYPE_DOUBLE) @staticmethod def x86_fp80(): """Create a 80-bit x86 floating point type.""" - context = api.llvm.getGlobalContext() - ptr = api.llvm.Type.getX86_FP80Ty(context) - return Type(ptr) + return _make_type(_core.LLVMX86FP80Type(), TYPE_X86_FP80) @staticmethod def fp128(): """Create a 128-bit floating point type (with 112-bit - mantissa).""" - context = api.llvm.getGlobalContext() - ptr = api.llvm.Type.getFP128Ty(context) - return Type(ptr) + mantissa).""" + return _make_type(_core.LLVMFP128Type(), TYPE_FP128) @staticmethod def ppc_fp128(): """Create a 128-bit floating point type (two 64-bits).""" - context = api.llvm.getGlobalContext() - ptr = api.llvm.Type.getPPC_FP128Ty(context) - return Type(ptr) - + return _make_type(_core.LLVMPPCFP128Type(), TYPE_PPC_FP128) @staticmethod def function(return_ty, param_tys, var_arg=False): @@ -752,58 +571,31 @@ class Type(llvm.Wrapper): `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.""" - ptr = api.llvm.FunctionType.get(return_ty._ptr, - llvm._extract_ptrs(param_tys), - var_arg) - return FunctionType(ptr) + 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) @staticmethod - 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 + def struct(element_tys): # 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. - - 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) + structure. For a packed one, use the packed_struct() method.""" + elems = unpack_types(element_tys) + return _make_type(_core.LLVMStructType(elems, 0), TYPE_STRUCT) @staticmethod - def packed_struct(element_tys, name=''): + def packed_struct(element_tys): """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. - - 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) + structure. For an unpacked one, use the struct() method.""" + elems = unpack_types(element_tys) + return _make_type(_core.LLVMStructType(elems, 1), TYPE_STRUCT) @staticmethod def array(element_ty, count): @@ -811,8 +603,10 @@ class Type(llvm.Wrapper): Creates a type for an array of elements of type `element_ty', having 'count' elements.""" - ptr = api.llvm.ArrayType.get(element_ty._ptr, count) - return ArrayType(ptr) + check_is_type(element_ty) + count = int(count) # must be an int + return _make_type(_core.LLVMArrayType(element_ty.ptr, count), + TYPE_ARRAY) @staticmethod def pointer(pointee_ty, addr_space=0): @@ -820,8 +614,10 @@ class Type(llvm.Wrapper): Creates a pointer type, which can point to values of type `pointee_ty', in the address space `addr_space'.""" - ptr = api.llvm.PointerType.get(pointee_ty._ptr, addr_space) - return PointerType(ptr) + 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) @staticmethod def vector(element_ty, count): @@ -829,227 +625,186 @@ class Type(llvm.Wrapper): Creates a type for a vector of elements of type `element_ty', having `count' elements.""" - ptr = api.llvm.VectorType.get(element_ty._ptr, count) - return VectorType(ptr) + check_is_type(element_ty) + count = int(count) # must be an int + return _make_type(_core.LLVMVectorType(element_ty.ptr, count), + TYPE_VECTOR) @staticmethod def void(): """Create a void type. Represents the `void' type.""" - context = api.llvm.getGlobalContext() - ptr = api.llvm.Type.getVoidTy(context) - return Type(ptr) + return _make_type(_core.LLVMVoidType(), TYPE_VOID) @staticmethod def label(): """Create a label type.""" - context = api.llvm.getGlobalContext() - ptr = api.llvm.Type.getLabelTy(context) - return Type(ptr) + return _make_type(_core.LLVMLabelType(), TYPE_LABEL) - def __new__(cls, ptr): - tyid = ptr.getTypeID() + def __init__(self, ptr, kind): + """DO NOT CALL DIRECTLY. - idmap = { - TYPE_HALF: IntegerType, - TYPE_INTEGER: IntegerType, - TYPE_FUNCTION: FunctionType, - TYPE_STRUCT: StructType, - TYPE_ARRAY: ArrayType, - TYPE_POINTER: PointerType, - TYPE_VECTOR: VectorType, - } + Use one of the static methods instead.""" + self.ptr = ptr + self.kind = kind + """An enum (int) value denoting which type this is. - try: - newcls = idmap[tyid] - except KeyError: - newcls = Type - obj = llvm.Wrapper.__new__(newcls) - return obj + Use the symbolic constants TYPE_* defined in llvm.core + module.""" def __str__(self): - return str(self._ptr) + """Text representation of a type. - def __hash__(self): - return hash(self._ptr) + Returns the textual representation (`llvm assembly') of the type.""" + return _core.LLVMDumpTypeToString(self.ptr) def __eq__(self, rhs): - return self._ptr is rhs._ptr + if isinstance(rhs, Type): + return str(self) == str(rhs) + else: + return False 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 self._ptr.getIntegerBitWidth() + return _core.LLVMGetIntTypeWidth(self.ptr) + 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.""" - return Type(self._ptr.getReturnType()) + ptr = _core.LLVMGetReturnType(self.ptr) + kind = _core.LLVMGetTypeKind(ptr) + return _make_type(ptr, kind) @property def vararg(self): """True if this function is variadic.""" - return self._ptr.isVarArg() + return _core.LLVMIsFunctionVarArg(self.ptr) != 0 @property def args(self): """An iterable that yields Type objects, representing the types of the - arguments accepted by this function, in order.""" - return [Type(self._ptr.getParamType(i)) for i in range(self.arg_count)] + arguments accepted by this function, in order.""" + pp = _core.LLVMGetFunctionTypeParams(self.ptr) + return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ] @property def arg_count(self): """Number of arguments accepted by this function. - Same as len(obj.args), but faster.""" - return self._ptr.getNumParams() + Same as len(obj.args), but faster.""" + return _core.LLVMCountParamTypes(self.ptr) 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 self._ptr.getNumElements() + Same as len(obj.elements), but faster.""" + return _core.LLVMCountStructElementTypes(self.ptr) - @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 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 packed(self): """True if the structure is packed, False otherwise.""" - return self._ptr.isPacked() + return _core.LLVMIsPackedStruct(self.ptr) != 0 - 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): - return Type(self._ptr.getArrayElementType()) + ptr = _core.LLVMGetElementType(self.ptr) + kind = _core.LLVMGetTypeKind(ptr) + return _make_type(ptr, kind) @property def count(self): - return self._ptr.getNumElements() + return _core.LLVMGetArrayLength(self.ptr) + class PointerType(Type): - _type_ = api.llvm.PointerType - __slots__ = () @property def pointee(self): - return Type(self._ptr.getPointerElementType()) + ptr = _core.LLVMGetElementType(self.ptr) + kind = _core.LLVMGetTypeKind(ptr) + return _make_type(ptr, kind) @property def address_space(self): - return self._ptr.getAddressSpace() + return _core.LLVMGetPointerAddressSpace(self.ptr) + class VectorType(Type): - _type_ = api.llvm.VectorType - __slots__ = () @property def element(self): - return Type(self._ptr.getVectorElementType()) + ptr = _core.LLVMGetElementType(self.ptr) + kind = _core.LLVMGetTypeKind(ptr) + return _make_type(ptr, kind) @property def count(self): - return self._ptr.getNumElements() + return _core.LLVMGetVectorSize(self.ptr) -class Value(llvm.Wrapper): - _type_ = api.llvm.Value - __slots__ = '__weakref__' - def __init__(self, builder, ptr): - assert builder is _ValueFactory +#===----------------------------------------------------------------------=== +# Type factory method +#===----------------------------------------------------------------------=== - 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) +# 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 def __str__(self): - return str(self._ptr) - - def __hash__(self): - return hash(self._ptr) + return _core.LLVMDumpValueToString(self.ptr) def __eq__(self, rhs): if isinstance(rhs, Value): @@ -1061,1466 +816,1142 @@ class Value(llvm.Wrapper): return not self == rhs def _get_name(self): - return self._ptr.getName() + return _core.LLVMGetValueName(self.ptr) def _set_name(self, value): - return self._ptr.setName(value) + return _core.LLVMSetValueName(self.ptr, value) name = property(_get_name, _set_name) @property def value_id(self): - return self._ptr.getValueID() + return _core.LLVMValueGetID(self.ptr) @property def type(self): - return Type(self._ptr.getType()) + ptr = _core.LLVMTypeOf(self.ptr) + kind = _core.LLVMGetTypeKind(ptr) + return _make_type(ptr, kind) @property def use_count(self): - return self._ptr.getNumUses() + return _core.LLVMValueGetNumUses(self.ptr) @property def uses(self): - return list(map(_make_value, self._ptr.list_use())) + return [ _make_value(v) for v in _core.LLVMValueGetUses(self.ptr) ] + class User(Value): - _type_ = api.llvm.User - __slots__ = () @property def operand_count(self): - return self._ptr.getNumOperands() + return _core.LLVMUserGetNumOperands(self.ptr) @property def operands(self): """Yields operands of this instruction.""" - return [_make_value(self._ptr.getOperand(i)) - for i in range(self.operand_count)] + 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)) class Constant(User): - _type_ = api.llvm.Constant - __slots__ = () @staticmethod def null(ty): - return _make_value(api.llvm.Constant.getNullValue(ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstNull(ty.ptr)) @staticmethod def all_ones(ty): - return _make_value(api.llvm.Constant.getAllOnesValue(ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstAllOnes(ty.ptr)) @staticmethod def undef(ty): - return _make_value(api.llvm.UndefValue.get(ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMGetUndef(ty.ptr)) @staticmethod def int(ty, value): - return _make_value(api.llvm.ConstantInt.get(ty._ptr, int(value), False)) + check_is_type(ty) + return _make_value(_core.LLVMConstInt(ty.ptr, value, 0)) @staticmethod def int_signextend(ty, value): - return _make_value(api.llvm.ConstantInt.get(ty._ptr, int(value), True)) + check_is_type(ty) + return _make_value(_core.LLVMConstInt(ty.ptr, value, 1)) @staticmethod def real(ty, value): - return _make_value(api.llvm.ConstantFP.get(ty._ptr, float(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)) @staticmethod def string(strval): # dont_null_terminate=True - cxt = api.llvm.getGlobalContext() - return _make_value(api.llvm.ConstantDataArray.getString(cxt, strval, False)) + return _make_value(_core.LLVMConstString(strval, 1)) @staticmethod def stringz(strval): # dont_null_terminate=False - cxt = api.llvm.getGlobalContext() - return _make_value(api.llvm.ConstantDataArray.getString(cxt, strval, True)) + return _make_value(_core.LLVMConstString(strval, 0)) @staticmethod def array(ty, consts): - aryty = Type.array(ty, len(consts)) - return _make_value(api.llvm.ConstantArray.get(aryty._ptr, - llvm._extract_ptrs(consts))) + check_is_type(ty) + const_ptrs = unpack_constants(consts) + return _make_value(_core.LLVMConstArray(ty.ptr, const_ptrs)) @staticmethod def struct(consts): # not packed - return _make_value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), - False)) + const_ptrs = unpack_constants(consts) + return _make_value(_core.LLVMConstStruct(const_ptrs, 0)) @staticmethod def packed_struct(consts): - return _make_value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), - False)) + const_ptrs = unpack_constants(consts) + return _make_value(_core.LLVMConstStruct(const_ptrs, 1)) @staticmethod def vector(consts): - return _make_value(api.llvm.ConstantVector.get(llvm._extract_ptrs(consts))) + const_ptrs = unpack_constants(consts) + return _make_value(_core.LLVMConstVector(const_ptrs)) @staticmethod def sizeof(ty): - return _make_value(api.llvm.ConstantExpr.getSizeOf(ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMSizeOf(ty.ptr)) def neg(self): - return _make_value(api.llvm.ConstantExpr.getNeg(self._ptr)) + return _make_value(_core.LLVMConstNeg(self.ptr)) def not_(self): - return _make_value(api.llvm.ConstantExpr.getNot(self._ptr)) + return _make_value(_core.LLVMConstNot(self.ptr)) def add(self, rhs): - return _make_value(api.llvm.ConstantExpr.getAdd(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstAdd(self.ptr, rhs.ptr)) def fadd(self, rhs): - return _make_value(api.llvm.ConstantExpr.getFAdd(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstFAdd(self.ptr, rhs.ptr)) def sub(self, rhs): - return _make_value(api.llvm.ConstantExpr.getSub(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstSub(self.ptr, rhs.ptr)) def fsub(self, rhs): - return _make_value(api.llvm.ConstantExpr.getFSub(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstFSub(self.ptr, rhs.ptr)) def mul(self, rhs): - return _make_value(api.llvm.ConstantExpr.getMul(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstMul(self.ptr, rhs.ptr)) def fmul(self, rhs): - return _make_value(api.llvm.ConstantExpr.getFMul(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstFMul(self.ptr, rhs.ptr)) def udiv(self, rhs): - return _make_value(api.llvm.ConstantExpr.getUDiv(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstUDiv(self.ptr, rhs.ptr)) def sdiv(self, rhs): - return _make_value(api.llvm.ConstantExpr.getSDiv(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstSDiv(self.ptr, rhs.ptr)) def fdiv(self, rhs): - return _make_value(api.llvm.ConstantExpr.getFDiv(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstFDiv(self.ptr, rhs.ptr)) def urem(self, rhs): - return _make_value(api.llvm.ConstantExpr.getURem(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstURem(self.ptr, rhs.ptr)) def srem(self, rhs): - return _make_value(api.llvm.ConstantExpr.getSRem(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstSRem(self.ptr, rhs.ptr)) def frem(self, rhs): - return _make_value(api.llvm.ConstantExpr.getFRem(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstFRem(self.ptr, rhs.ptr)) def and_(self, rhs): - return _make_value(api.llvm.ConstantExpr.getAnd(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstAnd(self.ptr, rhs.ptr)) def or_(self, rhs): - return _make_value(api.llvm.ConstantExpr.getOr(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstOr(self.ptr, rhs.ptr)) def xor(self, rhs): - return _make_value(api.llvm.ConstantExpr.getXor(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstXor(self.ptr, rhs.ptr)) def icmp(self, int_pred, rhs): - return _make_value(api.llvm.ConstantExpr.getICmp(int_pred, self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstICmp(int_pred, self.ptr, rhs.ptr)) def fcmp(self, real_pred, rhs): - return _make_value(api.llvm.ConstantExpr.getFCmp(real_pred, self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstFCmp(real_pred, self.ptr, rhs.ptr)) def shl(self, rhs): - return _make_value(api.llvm.ConstantExpr.getShl(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstShl(self.ptr, rhs.ptr)) def lshr(self, rhs): - return _make_value(api.llvm.ConstantExpr.getLShr(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstLShr(self.ptr, rhs.ptr)) def ashr(self, rhs): - return _make_value(api.llvm.ConstantExpr.getAShr(self._ptr, rhs._ptr)) + check_is_constant(rhs) + return _make_value(_core.LLVMConstAShr(self.ptr, rhs.ptr)) def gep(self, indices): - indices = llvm._extract_ptrs(indices) - return _make_value(api.llvm.ConstantExpr.getGetElementPtr(self._ptr, indices)) + index_ptrs = unpack_constants(indices) + return _make_value(_core.LLVMConstGEP(self.ptr, index_ptrs)) def trunc(self, ty): - return _make_value(api.llvm.ConstantExpr.getTrunc(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstTrunc(self.ptr, ty.ptr)) def sext(self, ty): - return _make_value(api.llvm.ConstantExpr.getSExt(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstSExt(self.ptr, ty.ptr)) def zext(self, ty): - return _make_value(api.llvm.ConstantExpr.getZExt(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstZExt(self.ptr, ty.ptr)) def fptrunc(self, ty): - return _make_value(api.llvm.ConstantExpr.getFPTrunc(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstFPTrunc(self.ptr, ty.ptr)) def fpext(self, ty): - return _make_value(api.llvm.ConstantExpr.getFPExtend(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstFPExt(self.ptr, ty.ptr)) def uitofp(self, ty): - return _make_value(api.llvm.ConstantExpr.getUIToFP(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstUIToFP(self.ptr, ty.ptr)) def sitofp(self, ty): - return _make_value(api.llvm.ConstantExpr.getSIToFP(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstSIToFP(self.ptr, ty.ptr)) def fptoui(self, ty): - return _make_value(api.llvm.ConstantExpr.getFPToUI(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstFPToUI(self.ptr, ty.ptr)) def fptosi(self, ty): - return _make_value(api.llvm.ConstantExpr.getFPToSI(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstFPToSI(self.ptr, ty.ptr)) def ptrtoint(self, ty): - return _make_value(api.llvm.ConstantExpr.getPtrToInt(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstPtrToInt(self.ptr, ty.ptr)) def inttoptr(self, ty): - return _make_value(api.llvm.ConstantExpr.getIntToPtr(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstIntToPtr(self.ptr, ty.ptr)) def bitcast(self, ty): - return _make_value(api.llvm.ConstantExpr.getBitCast(self._ptr, ty._ptr)) + check_is_type(ty) + return _make_value(_core.LLVMConstBitCast(self.ptr, ty.ptr)) def select(self, true_const, false_const): - return _make_value(api.llvm.ConstantExpr.getSelect(self._ptr, - true_const._ptr, - false_const._ptr)) + check_is_constant(true_const) + check_is_constant(false_const) + return _make_value( + _core.LLVMConstSelect(self.ptr, true_const.ptr, false_const.ptr)) def extract_element(self, index): # note: self must be a _vector_ constant - return _make_value(api.llvm.ConstantExpr.getExtractElement(self._ptr, index._ptr)) + check_is_constant(index) + return _make_value( + _core.LLVMConstExtractElement(self.ptr, index.ptr)) def insert_element(self, value, index): - return _make_value(api.llvm.ConstantExpr.getExtractElement(self._ptr, - value._ptr, - index._ptr)) + # 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)) def shuffle_vector(self, vector_b, mask): - return _make_value(api.llvm.ConstantExpr.getShuffleVector(self._ptr, - vector_b._ptr, - mask._ptr)) + # 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)) + class ConstantExpr(Constant): - _type_ = api.llvm.ConstantExpr - __slots__ = () + pass - @property - def opcode(self): - return self._ptr.getOpcode() - - @property - def opcode_name(self): - return self._ptr.getOpcodeName() class ConstantAggregateZero(Constant): - __slots__ = () + pass class ConstantDataArray(Constant): - __slots__ = () + pass class ConstantDataVector(Constant): - __slots__ = () - + pass class ConstantInt(Constant): - _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() + pass class ConstantFP(Constant): - __slots__ = () + pass class ConstantArray(Constant): - __slots__ = () + pass class ConstantStruct(Constant): - __slots__ = () + pass class ConstantVector(Constant): - __slots__ = () + pass class ConstantPointerNull(Constant): - __slots__ = () + pass class UndefValue(Constant): - __slots__ = () + pass class GlobalValue(Constant): - _type_ = api.llvm.GlobalValue - __slots__ = () + + 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 def _get_linkage(self): - return self._ptr.getLinkage() - + return _core.LLVMGetLinkage(self.ptr) def _set_linkage(self, value): - self._ptr.setLinkage(value) - + _core.LLVMSetLinkage(self.ptr, value) linkage = property(_get_linkage, _set_linkage) def _get_section(self): - return self._ptr.getSection() - + return _core.LLVMGetSection(self.ptr) def _set_section(self, value): - return self._ptr.setSection(value) - + return _core.LLVMSetSection(self.ptr, value) section = property(_get_section, _set_section) def _get_visibility(self): - return self._ptr.getVisibility() - + return _core.LLVMGetVisibility(self.ptr) def _set_visibility(self, value): - return self._ptr.setVisibility(value) - + return _core.LLVMSetVisibility(self.ptr, value) visibility = property(_get_visibility, _set_visibility) def _get_alignment(self): - return self._ptr.getAlignment() - + return _core.LLVMGetAlignment(self.ptr) def _set_alignment(self, value): - return self._ptr.setAlignment(value) - + return _core.LLVMSetAlignment(self.ptr, value) alignment = property(_get_alignment, _set_alignment) @property def is_declaration(self): - return self._ptr.isDeclaration() + return _core.LLVMIsDeclaration(self.ptr) != 0 @property def module(self): - return Module(self._ptr.getParent()) - + return Module(_core.LLVMGetGlobalParent(self.ptr)) class GlobalVariable(GlobalValue): - _type_ = api.llvm.GlobalVariable - __slots__ = () @staticmethod - 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) + def new(module, ty, name): + check_is_module(module) + check_is_type(ty) + return _make_value(_core.LLVMAddGlobal(module.ptr, ty.ptr, name)) @staticmethod def get(module, name): - gv = _make_value(module._ptr.getNamedGlobal(name)) - if not gv: - llvm.LLVMException("no global named `%s`" % name) - return gv + 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) def delete(self): - _ValueFactory.delete(self._ptr) - self._ptr.eraseFromParent() + self._delete() + _core.LLVMDeleteGlobal(self.ptr) + self.forget() + self.ptr = None def _get_initializer(self): - if not self._ptr.hasInitializer(): + if _core.LLVMHasInitializer(self.ptr): + return _make_value(_core.LLVMGetInitializer(self.ptr)) + else: return None - return _make_value(self._ptr.getInitializer()) def _set_initializer(self, const): - self._ptr.setInitializer(const._ptr) - - def _del_initializer(self): - self._ptr.setInitializer(None) + check_is_constant(const) + _core.LLVMSetInitializer(self.ptr, const.ptr) initializer = property(_get_initializer, _set_initializer) def _get_is_global_constant(self): - return self._ptr.isConstant() + return _core.LLVMIsGlobalConstant(self.ptr) def _set_is_global_constant(self, value): - self._ptr.setConstant(value) + value = _to_int(value) + _core.LLVMSetGlobalConstant(self.ptr, 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]) - 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 add_attribute(self, attr): + _core.LLVMAddAttribute(self.ptr, attr) - if attr not in self: - raise ValueError("Attribute %r is not valid for arg %s" % - (attr, self)) + def remove_attribute(self, attr): + _core.LLVMRemoveAttribute(self.ptr, attr) - 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 _set_alignment(self, align): + _core.LLVMSetParamAlignment(self.ptr, align) def _get_alignment(self): - return self._ptr.getParamAlignment() + return _core.LLVMGetParamAlignment(self.ptr) - 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): - 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) - + check_is_module(module) + check_is_type(func_ty) + return _make_value(_core.LLVMAddFunction(module.ptr, name, + func_ty.ptr)) @staticmethod def get_or_insert(module, func_ty, name): - 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) + check_is_module(module) + check_is_type(func_ty) + return _make_value(_core.LLVMModuleGetOrInsertFunction(module.ptr, + name, func_ty.ptr)) @staticmethod def get(module, name): - fn = module._ptr.getFunction(name) - if fn is None: + check_is_module(module) + ptr = _core.LLVMGetNamedFunction(module.ptr, name) + if not ptr: raise llvm.LLVMException("no function named `%s`" % name) - else: - return _make_value(fn) + return _make_value(ptr) @staticmethod def intrinsic(module, intrinsic_id, types): - fn = api.llvm.Intrinsic.getDeclaration(module._ptr, - intrinsic_id, - llvm._extract_ptrs(types)) - return _make_value(fn) + check_is_module(module) + ptrs = unpack_types(types) + return _make_value( + _core.LLVMGetIntrinsic(module.ptr, intrinsic_id, ptrs)) def delete(self): - _ValueFactory.delete(self._ptr) - self._ptr.eraseFromParent() + self._delete() + _core.LLVMDeleteFunction(self.ptr) + self.forget() + self.ptr = None @property def intrinsic_id(self): - self._ptr.getIntrinsicID() - - def _get_cc(self): - return self._ptr.getCallingConv() - - def _set_cc(self, value): - self._ptr.setCallingConv(value) + return _core.LLVMGetIntrinsicID(self.ptr) + 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 self._ptr.getGC() - - def _set_coll(self, value): - return self._ptr.setGC(value) - + def _get_coll(self): return _core.LLVMGetGC(self.ptr) + def _set_coll(self, value): _core.LLVMSetGC(self.ptr, value) collector = property(_get_coll, _set_coll) # the nounwind attribute: - def _get_does_not_throw(self): - return self._ptr.doesNotThrow() - - def _set_does_not_throw(self,value): - assert value - self._ptr.setDoesNotThrow() - + def _get_does_not_throw(self): return _core.LLVMGetDoesNotThrow(self.ptr) + def _set_does_not_throw(self,value): _core.LLVMSetDoesNotThrow(self.ptr, value) does_not_throw = property(_get_does_not_throw, _set_does_not_throw) @property def args(self): - args = self._ptr.getArgumentList() - return list(map(_make_value, args)) + return _util.wrapiter(_core.LLVMGetFirstParam, + _core.LLVMGetNextParam, self.ptr, _make_value) @property def basic_block_count(self): - return len(self.basic_blocks) + return _core.LLVMCountBasicBlocks(self.ptr) @property def entry_basic_block(self): - assert self.basic_block_count - return _make_value(self._ptr.getEntryBlock()) + if self.basic_block_count == 0: + return None + return _make_value(_core.LLVMGetEntryBasicBlock(self.ptr)) def get_entry_basic_block(self): - "Deprecated. Use entry_basic_block instead" + """Deprecated, use entry_basic_block property.""" return self.entry_basic_block def append_basic_block(self, name): - context = api.llvm.getGlobalContext() - bb = api.llvm.BasicBlock.Create(context, name, self._ptr, None) - return _make_value(bb) + return _make_value(_core.LLVMAppendBasicBlock(self.ptr, name)) @property def basic_blocks(self): - return list(map(_make_value, self._ptr.getBasicBlockList())) + return _util.wrapiter(_core.LLVMGetFirstBasicBlock, + _core.LLVMGetNextBasicBlock, self.ptr, _make_value) def viewCFG(self): - return self._ptr.viewCFG() + return _core.LLVMViewFunctionCFG(self.ptr) def add_attribute(self, attr): - self._ptr.addFnAttr(attr) + _core.LLVMAddFunctionAttr(self.ptr, attr) def remove_attribute(self, 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) + _core.LLVMRemoveFunctionAttr(self.ptr, attr) def viewCFGOnly(self): - return self._ptr.viewCFGOnly() + return _core.LLVMViewFunctionCFGOnly(self.ptr) def verify(self): # Although we're just asking LLVM to return the success or # failure, it appears to print result to stderr and abort. - - # 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) - + return _core.LLVMVerifyFunction(self.ptr) != 0 #===----------------------------------------------------------------------=== # Instruction #===----------------------------------------------------------------------=== class Instruction(User): - __slots__ = () - _type_ = api.llvm.Instruction @property def basic_block(self): - return _make_value(self._ptr.getParent()) + return _make_value(_core.LLVMGetInstructionParent(self.ptr)) @property def is_terminator(self): - return self._ptr.isTerminator() + return _core.LLVMInstIsTerminator(self.ptr) != 0 @property def is_binary_op(self): - return self._ptr.isBinaryOp() + return _core.LLVMInstIsBinaryOp(self.ptr) != 0 @property def is_shift(self): - return self._ptr.isShift() + return _core.LLVMInstIsShift(self.ptr) != 0 @property def is_cast(self): - return self._ptr.isCast() + return _core.LLVMInstIsCast(self.ptr) != 0 @property def is_logical_shift(self): - return self._ptr.isLogicalShift() + return _core.LLVMInstIsLogicalShift(self.ptr) != 0 @property def is_arithmetic_shift(self): - return self._ptr.isArithmeticShift() + return _core.LLVMInstIsArithmeticShift(self.ptr) != 0 @property def is_associative(self): - return self._ptr.isAssociative() + return _core.LLVMInstIsAssociative(self.ptr) != 0 @property def is_commutative(self): - return self._ptr.isCommutative() + return _core.LLVMInstIsCommutative(self.ptr) != 0 @property def is_volatile(self): """True if this is a volatile load or store.""" - 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) + return _core.LLVMInstIsVolatile(self.ptr) != 0 @property def opcode(self): - return self._ptr.getOpcode() + return _core.LLVMInstGetOpcode(self.ptr) @property def opcode_name(self): - return self._ptr.getOpcodeName() - - def erase_from_parent(self): - return self._ptr.eraseFromParent() - - def replace_all_uses_with(self, inst): - self._ptr.replaceAllUsesWith(inst) + return _core.LLVMInstGetOpcodeName(self.ptr) 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): - 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) + _core.LLVMAddInstrAttribute(self.ptr, idx, attr) def remove_parameter_attribute(self, 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) + _core.LLVMRemoveInstrAttribute(self.ptr, idx, attr) def set_parameter_alignment(self, 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) + _core.LLVMSetInstrParamAlignment(self.ptr, idx, align) - 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) + # 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) class PHINode(Instruction): - __slots__ = () - _type_ = api.llvm.PHINode @property def incoming_count(self): - return self._ptr.getNumIncomingValues() + return _core.LLVMCountIncoming(self.ptr) def add_incoming(self, value, block): - self._ptr.addIncoming(value._ptr, block._ptr) + check_is_value(value) + check_is_basic_block(block) + _core.LLVMAddIncoming1(self.ptr, value.ptr, block.ptr) def get_incoming_value(self, idx): - return _make_value(self._ptr.getIncomingValue(idx)) + return _make_value(_core.LLVMGetIncomingValue(self.ptr, idx)) def get_incoming_block(self, idx): - return _make_value(self._ptr.getIncomingBlock(idx)) + return _make_value(_core.LLVMGetIncomingBlock(self.ptr, idx)) class SwitchInstruction(Instruction): - __slots__ = () - _type_ = api.llvm.SwitchInst def add_case(self, const, bblk): - self._ptr.addCase(const._ptr, bblk._ptr) + check_is_constant(const) # and has to be an int too + check_is_basic_block(bblk) + _core.LLVMAddCase(self.ptr, const.ptr, bblk.ptr) class CompareInstruction(Instruction): - __slots__ = () - _type_ = api.llvm.CmpInst @property def predicate(self): - n = self._ptr.getPredicate() - try: - return ICMPEnum.get(n) - except KeyError: - return FCMPEnum.get(n) + return _core.LLVMCmpInstGetPredicate(self.ptr) -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): - context = api.llvm.getGlobalContext() - ptr = api.llvm.BasicBlock.Create(context, name, self.function._ptr, - self._ptr) - return _make_value(ptr) + return _make_value(_core.LLVMInsertBasicBlock(self.ptr, name)) def delete(self): - _ValueFactory.delete(self._ptr) - self._ptr.eraseFromParent() + _core.LLVMDeleteBasicBlock(self.ptr) + self.forget() + self.ptr = None @property def function(self): - return _make_value(self._ptr.getParent()) + func_ptr = _core.LLVMGetBasicBlockParent(self.ptr) + return _make_value(func_ptr) @property def instructions(self): - return list(map(_make_value, self._ptr.getInstList())) + return _util.wrapiter(_core.LLVMGetFirstInstruction, + _core.LLVMGetNextInstruction, self.ptr, _make_value) + #===----------------------------------------------------------------------=== # Value factory method #===----------------------------------------------------------------------=== - -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)] +# 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 +} def _make_value(ptr): - return _ValueFactory.build(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) + #===----------------------------------------------------------------------=== # Builder #===----------------------------------------------------------------------=== -_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__ = () +class Builder(object): @staticmethod def new(basic_block): - context = api.llvm.getGlobalContext() - ptr = api.llvm.IRBuilder.new(context) - ptr.SetInsertPoint(basic_block._ptr) - return Builder(ptr) + 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) 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.""" - - # 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) + 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) 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.""" - - self._ptr.SetInsertPoint(bblk._ptr) + _core.LLVMPositionBuilderAtEnd(self.ptr, 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.""" - self._ptr.SetInsertPoint(instr._ptr) + 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)) @property def basic_block(self): """The basic block where the builder is positioned.""" - return _make_value(self._ptr.GetInsertBlock()) + return _make_value(_core.LLVMGetInsertBlock(self.ptr)) # 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): - self._guard_terminators() - return _make_value(self._ptr.CreateRetVoid()) + return _make_value(_core.LLVMBuildRetVoid(self.ptr)) def ret(self, value): - self._guard_terminators() - return _make_value(self._ptr.CreateRet(value._ptr)) + check_is_value(value) + return _make_value(_core.LLVMBuildRet(self.ptr, value.ptr)) def ret_many(self, values): - self._guard_terminators() - values = llvm._extract_ptrs(values) - return _make_value(self._ptr.CreateAggregateRet(values, len(values))) + vs = unpack_values(values) + return _make_value(_core.LLVMBuildRetMultiple(self.ptr, vs)) def branch(self, bblk): - self._guard_terminators() - return _make_value(self._ptr.CreateBr(bblk._ptr)) + check_is_basic_block(bblk) + return _make_value(_core.LLVMBuildBr(self.ptr, bblk.ptr)) def cbranch(self, if_value, then_blk, else_blk): - self._guard_terminators() - return _make_value(self._ptr.CreateCondBr(if_value._ptr, - then_blk._ptr, - else_blk._ptr)) + 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)) def switch(self, value, else_blk, n=10): - self._guard_terminators() - return _make_value(self._ptr.CreateSwitch(value._ptr, - else_blk._ptr, - n)) + 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)) def invoke(self, func, args, then_blk, catch_blk, name=""): - self._guard_terminators() - return _make_value(self._ptr.CreateInvoke(func._ptr, - then_blk._ptr, - catch_blk._ptr, - llvm._extract_ptrs(args))) + 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)) def unreachable(self): - self._guard_terminators() - return _make_value(self._ptr.CreateUnreachable()) + return _make_value(_core.LLVMBuildUnreachable(self.ptr)) # arithmethic, bitwise and logical - def add(self, lhs, rhs, name="", nuw=False, nsw=False): - return _make_value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name, - nuw, nsw)) + 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 fadd(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateFAdd(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value(_core.LLVMBuildFAdd(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 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 fsub(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateFSub(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value(_core.LLVMBuildFSub(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 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 fmul(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value(_core.LLVMBuildFMul(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 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 sdiv(self, lhs, rhs, name="", exact=False): - return _make_value(self._ptr.CreateSDiv(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 fdiv(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateFDiv(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value( + _core.LLVMBuildFDiv(self.ptr, lhs.ptr, rhs.ptr, name)) def urem(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateURem(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value( + _core.LLVMBuildURem(self.ptr, lhs.ptr, rhs.ptr, name)) def srem(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateSRem(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value( + _core.LLVMBuildSRem(self.ptr, lhs.ptr, rhs.ptr, name)) def frem(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateFRem(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value( + _core.LLVMBuildFRem(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 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 lshr(self, lhs, rhs, name="", exact=False): - return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name, - exact)) + 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 ashr(self, lhs, rhs, name="", exact=False): - return _make_value(self._ptr.CreateAShr(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 and_(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateAnd(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value( + _core.LLVMBuildAnd(self.ptr, lhs.ptr, rhs.ptr, name)) def or_(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateOr(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value( + _core.LLVMBuildOr(self.ptr, lhs.ptr, rhs.ptr, name)) def xor(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateXor(lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value( + _core.LLVMBuildXor(self.ptr, lhs.ptr, rhs.ptr, name)) - def neg(self, val, name="", nuw=False, nsw=False): - return _make_value(self._ptr.CreateNeg(val._ptr, name, nuw, nsw)) + def neg(self, val, name=""): + check_is_value(val) + return _make_value(_core.LLVMBuildNeg(self.ptr, val.ptr, name)) def not_(self, val, name=""): - return _make_value(self._ptr.CreateNot(val._ptr, name)) + check_is_value(val) + return _make_value(_core.LLVMBuildNot(self.ptr, val.ptr, name)) # memory def malloc(self, ty, 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) + check_is_type(ty) + return _make_value(_core.LLVMBuildMalloc(self.ptr, ty.ptr, name)) def malloc_array(self, ty, size, 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) + check_is_type(ty) + check_is_value(size) + return _make_value( + _core.LLVMBuildArrayMalloc(self.ptr, ty.ptr, size.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)) + def alloca(self, ty, name=""): + check_is_type(ty) + return _make_value(_core.LLVMBuildAlloca(self.ptr, ty.ptr, name)) - @deprecated def alloca_array(self, ty, size, name=""): - return self.alloca(ty, size, name=name) + check_is_type(ty) + check_is_value(size) + return _make_value( + _core.LLVMBuildArrayAlloca(self.ptr, ty.ptr, size.ptr, name)) def free(self, ptr): - free = api.llvm.CallInst.CreateFree(ptr._ptr, self.basic_block._ptr) - inst = self._ptr.Insert(free) - return _make_value(inst) + check_is_value(ptr) + return _make_value(_core.LLVMBuildFree(self.ptr, ptr.ptr)) - 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 load(self, ptr, name=""): + check_is_value(ptr) + return _make_value(_core.LLVMBuildLoad(self.ptr, ptr.ptr, name)) - 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 store(self, value, ptr): + check_is_value(value) + check_is_value(ptr) + return _make_value(_core.LLVMBuildStore(self.ptr, value.ptr, ptr.ptr)) - 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) + 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)) # casts and extensions def trunc(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateTrunc(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildTrunc(self.ptr, value.ptr, dest_ty.ptr, name)) def zext(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateZExt(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildZExt(self.ptr, value.ptr, dest_ty.ptr, name)) def sext(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateSExt(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildSExt(self.ptr, value.ptr, dest_ty.ptr, name)) def fptoui(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateFPToUI(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildFPToUI(self.ptr, value.ptr, dest_ty.ptr, name)) def fptosi(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateFPToSI(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildFPToSI(self.ptr, value.ptr, dest_ty.ptr, name)) def uitofp(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateUIToFP(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildUIToFP(self.ptr, value.ptr, dest_ty.ptr, name)) def sitofp(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateSIToFP(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildSIToFP(self.ptr, value.ptr, dest_ty.ptr, name)) def fptrunc(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateFPTrunc(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildFPTrunc(self.ptr, value.ptr, dest_ty.ptr, name)) def fpext(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateFPExt(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildFPExt(self.ptr, value.ptr, dest_ty.ptr, name)) def ptrtoint(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreatePtrToInt(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildPtrToInt(self.ptr, value.ptr, dest_ty.ptr, name)) def inttoptr(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateIntToPtr(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildIntToPtr(self.ptr, value.ptr, dest_ty.ptr, name)) def bitcast(self, value, dest_ty, name=""): - return _make_value(self._ptr.CreateBitCast(value._ptr, dest_ty._ptr, name)) + check_is_value(value) + check_is_type(dest_ty) + return _make_value( + _core.LLVMBuildBitCast(self.ptr, value.ptr, dest_ty.ptr, name)) # comparisons def icmp(self, ipred, lhs, rhs, name=""): - return _make_value(self._ptr.CreateICmp(ipred, lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value( + _core.LLVMBuildICmp(self.ptr, ipred, lhs.ptr, rhs.ptr, name)) def fcmp(self, rpred, lhs, rhs, name=""): - return _make_value(self._ptr.CreateFCmp(rpred, lhs._ptr, rhs._ptr, name)) + check_is_value(lhs) + check_is_value(rhs) + return _make_value( + _core.LLVMBuildFCmp(self.ptr, rpred, lhs.ptr, rhs.ptr, name)) # misc def extract_value(self, retval, idx, name=""): - if not isinstance(idx, (tuple, list)): - idx = [idx] - return _make_value(self._ptr.CreateExtractValue(retval._ptr, idx, - name)) + check_is_value(retval) + return _make_value( + _core.LLVMBuildGetResult(self.ptr, 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=""): - return _make_value(self._ptr.CreatePHI(ty._ptr, 2, name)) + check_is_type(ty) + return _make_value(_core.LLVMBuildPhi(self.ptr, ty.ptr, name)) def call(self, fn, args, 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)) + check_is_callable(fn) + arg_ptrs = unpack_values(args) + return _make_value( + _core.LLVMBuildCall(self.ptr, fn.ptr, arg_ptrs, name)) def select(self, cond, then_value, else_value, name=""): - return _make_value(self._ptr.CreateSelect(cond._ptr, then_value._ptr, - else_value._ptr, 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)) def vaarg(self, list_val, ty, name=""): - return _make_value(self._ptr.CreateVAArg(list_val._ptr, ty._ptr, name)) + check_is_value(list_val) + check_is_type(ty) + return _make_value( + _core.LLVMBuildVAArg(self.ptr, list_val.ptr, ty.ptr, name)) def extract_element(self, vec_val, idx_val, name=""): - return _make_value(self._ptr.CreateExtractElement(vec_val._ptr, - idx_val._ptr, - 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)) def insert_element(self, vec_val, elt_val, idx_val, name=""): - return _make_value(self._ptr.CreateInsertElement(vec_val._ptr, - elt_val._ptr, - idx_val._ptr, - 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)) def shuffle_vector(self, vecA, vecB, mask, 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 + 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)) - def fence(self, ordering, crossthread=True): - return _make_value(self._ptr.CreateFence(_atomic_orderings[ordering], - _sync_scope(crossthread))) +#===----------------------------------------------------------------------=== +# Memory buffer +#===----------------------------------------------------------------------=== -def _sync_scope(crossthread): - if crossthread: - scope = api.llvm.SynchronizationScope.CrossThread - else: - scope = api.llvm.SynchronizationScope.SingleThread - return scope +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 load_library_permanently(filename): """Load a shared library. @@ -2528,27 +1959,12 @@ 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.""" - with contextlib.closing(BytesIO()) as errmsg: - failed = api.llvm.sys.DynamicLibrary.LoadPermanentLibrary(filename, - errmsg) - if failed: - raise llvm.LLVMException(errmsg.getvalue()) + + ret = _core.LLVMLoadLibraryPermanently(filename) + if isinstance(ret, str): + raise llvm.LLVMException(ret) def inline_function(call): - info = api.llvm.InlineFunctionInfo.new() - return api.llvm.InlineFunction(call._ptr, info) + check_is_value(call) + return _core.LLVMInlineFunction(call.ptr) -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 deleted file mode 100644 index 6db5fe7..0000000 --- a/llvm/deprecated.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -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 f615b61..a54698d 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -28,237 +28,209 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -"Execution Engine and related classes." +"""Execution Engine and related classes. -import sys +""" + +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 llvm -from llvm import core -from llvm.passes import TargetData, TargetTransformInfo -from llvmpy import api, extra #===----------------------------------------------------------------------=== -# import items which were moved to target module +# Enumerations #===----------------------------------------------------------------------=== -from llvm.target import (initialize_all, initialize_target, - print_registered_targets, get_host_cpu_name, get_default_triple, - TargetMachine, - BO_BIG_ENDIAN, BO_LITTLE_ENDIAN, - CM_DEFAULT, CM_JITDEFAULT, CM_SMALL, CM_KERNEL, CM_MEDIUM, CM_LARGE, - RELOC_DEFAULT, RELOC_STATIC, RELOC_PIC, RELOC_DYNAMIC_NO_PIC) + +BO_BIG_ENDIAN = 0 +BO_LITTLE_ENDIAN = 1 + + +#===----------------------------------------------------------------------=== +# 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) #===----------------------------------------------------------------------=== # Generic value #===----------------------------------------------------------------------=== -class GenericValue(llvm.Wrapper): +class GenericValue(object): @staticmethod def int(ty, intval): - ptr = api.llvm.GenericValue.CreateInt(ty._ptr, int(intval), False) + core.check_is_type(ty) + ptr = _core.LLVMCreateGenericValueOfInt(ty.ptr, intval, 0) return GenericValue(ptr) @staticmethod def int_signed(ty, intval): - ptr = api.llvm.GenericValue.CreateInt(ty._ptr, int(intval), True) + core.check_is_type(ty) + ptr = _core.LLVMCreateGenericValueOfInt(ty.ptr, intval, 1) return GenericValue(ptr) @staticmethod def real(ty, 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') + core.check_is_type(ty) # only float or double + ptr = _core.LLVMCreateGenericValueOfFloat(ty.ptr, floatval) return GenericValue(ptr) @staticmethod - def pointer(addr): - ''' - One argument version takes (addr). - Two argument version takes (ty, addr). [Deprecated] - - `ty` is unused. - `addr` is an integer representing an address. - - ''' - ptr = api.llvm.GenericValue.CreatePointer(int(addr)) + 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 __del__(self): + _core.LLVMDisposeGenericValue(self.ptr) def as_int(self): - return self._ptr.toUnsignedInt() + return _core.LLVMGenericValueToInt(self.ptr, 0) def as_int_signed(self): - return self._ptr.toSignedInt() + return _core.LLVMGenericValueToInt(self.ptr, 1) def as_real(self, ty): - return self._ptr.toFloat(ty._ptr) + core.check_is_type(ty) # only float or double + return _core.LLVMGenericValueToFloat(ty.ptr, self.ptr) def as_pointer(self): - return self._ptr.toPointer() + return _core.LLVMGenericValueToPointer(self.ptr) -#===----------------------------------------------------------------------=== -# Engine builder -#===----------------------------------------------------------------------=== -class EngineBuilder(llvm.Wrapper): - @staticmethod - def new(module): - ptr = api.llvm.EngineBuilder.new(module._ptr) - return EngineBuilder(ptr) +# 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) - 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(llvm.Wrapper): +class ExecutionEngine(object): @staticmethod def new(module, force_interpreter=False): - eb = EngineBuilder.new(module) - if force_interpreter: - eb.force_interpreter() - return eb.create() + 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) - def disable_lazy_compilation(self, disabled=True): - self._ptr.DisableLazyCompilation(disabled) + def __init__(self, ptr, module): + self.ptr = ptr + module._own(self) + + def __del__(self): + _core.LLVMDisposeExecutionEngine(self.ptr) def run_function(self, fn, args): - 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) + core.check_is_function(fn) + ptrs = _unpack_generic_values(args) + gvptr = _core.LLVMRunFunction2(self.ptr, fn.ptr, ptrs) + return GenericValue(gvptr) def get_pointer_to_function(self, fn): - 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) + core.check_is_function(fn) + return _core.LLVMGetPointerToFunction(self.ptr,fn.ptr) def run_static_ctors(self): - self._ptr.runStaticConstructorsDestructors(False) + _core.LLVMRunStaticConstructors(self.ptr) def run_static_dtors(self): - self._ptr.runStaticConstructorsDestructors(True) + _core.LLVMRunStaticDestructors(self.ptr) def free_machine_code_for(self, fn): - self._ptr.freeMachineCodeForFunction(fn._ptr) + core.check_is_function(fn) + _core.LLVMFreeMachineCodeForFunction(self.ptr, fn.ptr) def add_module(self, module): - self._ptr.addModule(module._ptr) + core.check_is_module(module) + _core.LLVMAddModule(self.ptr, module.ptr) + module._own(self) def remove_module(self, module): - return self._ptr.removeModule(module._ptr) - - def finalize_object(self): - return self._ptr.finalizeObject() + 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) @property def target_data(self): - ptr = self._ptr.getDataLayout() - return TargetData(ptr) + td = TargetData(_core.LLVMGetExecutionEngineTargetData(self.ptr)) + td._own(self) + return td - -#===----------------------------------------------------------------------=== -# 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 new file mode 100644 index 0000000..d7b33e5 --- /dev/null +++ b/llvm/extra.cpp @@ -0,0 +1,565 @@ +/* + * 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 new file mode 100644 index 0000000..3bdb070 --- /dev/null +++ b/llvm/extra.h @@ -0,0 +1,257 @@ +/* + * 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 deleted file mode 100644 index c704a66..0000000 --- a/llvm/llrt.py +++ /dev/null @@ -1,79 +0,0 @@ -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 deleted file mode 100644 index 5096214..0000000 --- a/llvm/llrt/llrt_x86.ll +++ /dev/null @@ -1,371 +0,0 @@ -; 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 - -;