Updated documentation, license and changelog.
git-svn-id: http://llvm-py.googlecode.com/svn/trunk@8 8d1e9007-1d4e-0410-b67e-1979fd6579aa
This commit is contained in:
parent
55a6a6ed79
commit
71e1ee072a
15 changed files with 868 additions and 373 deletions
28
CHANGELOG
28
CHANGELOG
|
|
@ -1,19 +1,21 @@
|
|||
|
||||
0.2, xx-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
|
||||
assembly representation
|
||||
* Modules and functions can be verified
|
||||
* MemoryBuffer and TypeHandle are available
|
||||
* ExecutionEngine, TargetData and passes are available
|
||||
* Unit tester added (but doesn't test much for now)
|
||||
* Python doc string documentation added (still incomplete)
|
||||
* Many minor style/cosmetic changes and bug fixes
|
||||
* Added documentation as on website into SVN
|
||||
|
||||
|
||||
0.1, 10-May-2008:
|
||||
|
||||
* Initial release.
|
||||
|
||||
|
||||
0.2, ongoing:
|
||||
|
||||
* Independent package, need not be unpacked into llvm/bindings
|
||||
* Modules can be dumped to a string
|
||||
* Modules can be verified
|
||||
* Module.global_variables, Module.functions, Function.args,
|
||||
Function.basic_blocks and BasicBlock.instructions are
|
||||
now proper iterators (generators in fact) than plain lists
|
||||
|
||||
* MemoryBuffer is done
|
||||
* TypeHandle is done
|
||||
* Unit tester added (but doesn't do much for now)
|
||||
|
||||
|
|
|
|||
6
LICENSE
6
LICENSE
|
|
@ -10,9 +10,9 @@ modification, are permitted provided that the following conditions are met:
|
|||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the Mahadevan R, llvm-py nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
About
|
||||
=====
|
||||
|
||||
[NOTE]
|
||||
._llvm-py_ Mission Statement
|
||||
=======================================================================
|
||||
Provide a simple, consistent and well-documented suite of APIs that
|
||||
exposes just enough of LLVM to write a compiler/VM in Python.
|
||||
=======================================================================
|
||||
|
||||
_llvm-py_ is developed by Mahadevan R, in his spare time, without being
|
||||
paid for it. He can be reached at _mdevan.foobar .at. gmail.com_, on the
|
||||
llvm-py is developed by Mahadevan R, in his spare time, without being
|
||||
paid for it. He can be reached at mdevan.foobar@gmail.com, on the
|
||||
llvm-dev mailing list and irc.oftc.net#llvm (mdevan).
|
||||
|
||||
These web pages were generated using the nifty tool
|
||||
http://www.methods.co.nz/asciidoc/[asciidoc].
|
||||
Many thanks to the guys over at LLVM for all the nifty software, and a
|
||||
helpful mailing list.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,23 @@
|
|||
Contribute
|
||||
==========
|
||||
|
||||
_llvm-py_ is just hatching. It needs your patches and suggestions to
|
||||
grow up. Please contribute! All patches are welcome.
|
||||
llvm-py is just hatching. It needs your patches and suggestions to
|
||||
grow up. Please contribute! All patches are welcome. Here are some links
|
||||
to start hacking away:
|
||||
|
||||
The _llvm-py_ code is hosted on a google code project by the same name,
|
||||
http://code.google.com/p/llvm-py/[here]. It provides the SVN repository
|
||||
and a http://code.google.com/p/llvm-py/issues/list[bug tracker]. The
|
||||
latest code can be checked out from SVN like so:
|
||||
`40`60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Google code hosting, http://code.google.com/p/llvm-py/[http://code.google.com/p/llvm-py/]
|
||||
Browse SVN, http://code.google.com/p/llvm-py/source/browse/[http://code.google.com/p/llvm-py/source/browse]
|
||||
Issues tracker, http://code.google.com/p/llvm-py/issues/list[http://code.google.com/p/llvm-py/issues/list]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
SVN HEAD can be checked out like so:
|
||||
|
||||
----
|
||||
$ svn checkout http://llvm-py.googlecode.com/svn/trunk/ llvm-py
|
||||
----
|
||||
|
||||
You can browse the source online at:
|
||||
http://code.google.com/p/llvm-py/source/browse[http://code.google.com/p/llvm-py/source/browse].
|
||||
Mahadevan R (mdevan.foobar@gmail.com) is available to answer your
|
||||
queries.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
Download and Setup
|
||||
==================
|
||||
Download
|
||||
========
|
||||
|
||||
The latest release is 0.2, released xx-Jun-2008 (full link:#changelog[Changelog]
|
||||
The latest release is 0.2, released xx-Jun-2008 (link:#changelog[Changelog]
|
||||
below).
|
||||
|
||||
Download it here:
|
||||
|
|
@ -15,81 +15,14 @@ Release,Date,Package,Mirror
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
Bleeding Edge
|
||||
-------------
|
||||
|
||||
The latest code can be checked out from SVN thusly:
|
||||
The latest code can be checked out from SVN like so:
|
||||
|
||||
----
|
||||
$ svn checkout http://llvm-py.googlecode.com/svn/trunk/ llvm-py
|
||||
----
|
||||
|
||||
Happy hacking, and please send in your patches.
|
||||
|
||||
|
||||
Setting Up
|
||||
----------
|
||||
|
||||
Follow these steps to get _llvm-py_ up and running:
|
||||
|
||||
* link:#uninstall[Uninstall] any previous version of _llvm-py_.
|
||||
* Get and build LLVM.
|
||||
* Optionally, install it.
|
||||
* Get the latest release (see above) of _llvm-py_ and untar it:
|
||||
----
|
||||
$ wget http://link/llvm-py-0.2.tar.bz2
|
||||
$ tar jxvf llvm-py-0.2.tar.bz2
|
||||
----
|
||||
* If you've installed LLVM, setup _llvm-py_ like this:
|
||||
----
|
||||
$ cd llvm-py-0.2
|
||||
$ sudo python setup.py install
|
||||
----
|
||||
* If you haven't installed LLVM, locate the executable +llvm-config+
|
||||
under your LLVM build directory (should be something like
|
||||
+/home/mdevan/llvm/Release/bin/llvm-config+) and pass this to setup.py:
|
||||
----
|
||||
$ cd llvm-py-0.2
|
||||
$ sudo python setup.py install --llvm-config=/path/to/llvm-config
|
||||
----
|
||||
|
||||
That's it!
|
||||
|
||||
.Notes:
|
||||
- _setup.py_ is a standard Python distutils script. See the Python
|
||||
documentation regarding
|
||||
http://docs.python.org/inst/inst.html[Installing Python Modules] and
|
||||
http://docs.python.org/dist/dist.html[Distributing Python Modules] for
|
||||
more information on such scripts.
|
||||
|
||||
- To build the debug version, build with the +-g+ flag and the debug
|
||||
version of llvm-config:
|
||||
+
|
||||
----
|
||||
$ python setup.py build -g --llvm-config=/path/to/Debug/bin/llvm-config
|
||||
$ sudo python setup.py install
|
||||
----
|
||||
|
||||
- Debug binaries are _huge_! (65 MB+)
|
||||
|
||||
- If +++--llvm-config+++ is not specified, +setup.py+ looks for
|
||||
+llvm-config+ in the +PATH+, which will succeed if LLVM is installed.
|
||||
|
||||
|
||||
[[uninstall]]
|
||||
Uninstall
|
||||
---------
|
||||
|
||||
To get rid of llvm-py completely, if you wish to do so:
|
||||
|
||||
----
|
||||
# rm -rf /usr/lib/python2.5/site-packages/llvm
|
||||
# rm -f /usr/lib/python2.5/site-packages/llvm_py-0.1.egg-info
|
||||
----
|
||||
|
||||
- You need to be root to do this.
|
||||
- Paths are for debian-based systems, in other distros it might be different.
|
||||
- Note that there is a version number in the egg file name.
|
||||
Follow the steps link:userguide.html#install[described here] to install the
|
||||
package.
|
||||
|
||||
|
||||
[[changelog]]
|
||||
|
|
|
|||
|
|
@ -1,19 +1,14 @@
|
|||
llvm-py: Python Bindings for LLVM
|
||||
===================================
|
||||
|
||||
_llvm-py_ provides http://www.python.org/[Python] bindings for
|
||||
http://llvm.org/[LLVM]. It currently provides APIs to build the in-memory IR
|
||||
(intermediate representation) and to dump it. Execution engine and related APIs
|
||||
should appear soon.
|
||||
llvm-py provides http://www.python.org/[Python] bindings for
|
||||
http://llvm.org/[LLVM]. It's goal is to expose enough of LLVM APIs to
|
||||
implement a compiler or VM in pure Python. Currently, llvm-py is
|
||||
available for LLVM 2.3 and Python 2.5, on Linux/x86. It is expected to
|
||||
be usable on various unices, as well as with Python 2.4, with minimal
|
||||
changes, if any. It should be stable enough for you to play with.
|
||||
|
||||
_llvm-py_ is a set of Python-based and C-based Python modules. It makes use of
|
||||
llvm-c, the C binding for LLVM. It is based on the latest SVN version of LLVM
|
||||
(and will not work on 2.2). It has been tested only with Python 2.5, although
|
||||
it should be usable with 2.4 also. I've built and tested it only on Linux/i386
|
||||
machines.
|
||||
|
||||
Download links, setup help and changelog are on the
|
||||
link:download.html[download] page.
|
||||
llvm-py is just hatching, and your contributions would be most welcome.
|
||||
|
||||
News
|
||||
----
|
||||
|
|
|
|||
|
|
@ -11,30 +11,5 @@ http://code.google.com/p/llvm-py/source/browse/trunk/LICENSE[LICENSE]
|
|||
file in the distribution, and is reproduced here:
|
||||
|
||||
----
|
||||
Copyright (c) 2008, 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 the Mahadevan R, llvm-py 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.
|
||||
include::../../LICENSE[]
|
||||
----
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
llvm-py User Guide
|
||||
===================
|
||||
|
||||
_llvm-py_ provides Python bindings for LLVM. This document explains how
|
||||
llvm-py 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.
|
||||
|
||||
|
|
@ -16,33 +16,33 @@ static and dynamic (JIT) backends for many platforms. See the website at
|
|||
http://www.llvm.org/[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 prove easier to create working
|
||||
with the LLVM APIs. It should also be easier to create working
|
||||
prototypes and experimental languages using this medium.
|
||||
|
||||
.License
|
||||
Both LLVM and _llvm-py_ are distributed under (different) permissive
|
||||
open source licenses. _llvm-py_ uses the
|
||||
Both LLVM and llvm-py are distributed under (different) permissive
|
||||
open source licenses. llvm-py uses the
|
||||
http://opensource.org/licenses/bsd-license.php[new BSD license]. More
|
||||
information is available link:license.html[here].
|
||||
|
||||
.Platforms
|
||||
Currently, _llvm-py_ has been built and tested only on Linux/x86. However,
|
||||
Currently, llvm-py has been built and tested only on Linux/x86. However,
|
||||
it should be trivial to build it on other unices. Windows is not
|
||||
supported, for a variety of reasons.
|
||||
|
||||
.Versions
|
||||
As of now, _llvm-py_ requires the latest SVN version of LLVM. It will
|
||||
not work with version 2.2 of LLVM. However, 2.3 should be release soon,
|
||||
and _llvm-py_ should work with stock 2.3 LLVM.
|
||||
llvm-py requires verion 2.3 of LLVM. It will not work with previous
|
||||
versions.
|
||||
|
||||
_llvm-py_ has been built and tested with Python 2.5. It should work with
|
||||
llvm-py has been built and tested with Python 2.5. It should work with
|
||||
Python 2.4, with minimal changes, if any.
|
||||
|
||||
|
||||
[[install]]
|
||||
Installation
|
||||
------------
|
||||
|
||||
_llvm-py_ is distributed as a source tarball. You'll need to build and
|
||||
llvm-py is distributed as a source tarball. You'll need to build and
|
||||
install it before it can be used. At least the following will be
|
||||
required for this:
|
||||
|
||||
|
|
@ -54,7 +54,10 @@ required for this:
|
|||
On debian-based systems, the first three can be installed with the
|
||||
command `sudo apt-get install gcc g++ python python-dev'. Note that
|
||||
ubuntu repository has an old version of llvm (1.8) which will not work
|
||||
with _llvm-py_.
|
||||
with llvm-py.
|
||||
|
||||
Tip: If LLVM 2.3 does not install cleanly, try installing 'ocamldoc'
|
||||
first.
|
||||
|
||||
|
||||
llvm-config
|
||||
|
|
@ -67,6 +70,10 @@ 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 llvm-py. 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
|
||||
~~~~~
|
||||
|
|
@ -201,8 +208,8 @@ 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. The LLVM
|
||||
instruction set therefore has an instruction called _phi_.
|
||||
PHI nodes have to be explicitly created in the LLVM IR. Accordingly the
|
||||
LLVM instruction set has an instruction called +phi+.
|
||||
|
||||
|
||||
LLVM Assembly Language
|
||||
|
|
@ -277,11 +284,12 @@ most suitable for the code in the module.
|
|||
There is a LLVM binary called http://www.llvm.org/cmds/opt.html[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 _llvm-py_ does not allow you to
|
||||
loaded and executed by +opt+. (Although llvm-py 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.)
|
||||
|
||||
Passes are run using a _pass manager_. For our purposes, there are two
|
||||
pass managers TODO
|
||||
|
||||
|
||||
Execution Engine
|
||||
|
|
@ -295,24 +303,246 @@ BitCode
|
|||
|
||||
TODO
|
||||
|
||||
|
||||
llvm-gcc
|
||||
~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
The _llvm-py_ Package
|
||||
|
||||
The llvm-py Package
|
||||
---------------------
|
||||
|
||||
modules overview: llvm, llvm.core, llvm.ee, llvm.passes
|
||||
The llvm-py 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.
|
||||
|
||||
importing modules
|
||||
Out of the 6 modules, one is an "extension" module (i.e., it's written
|
||||
in C), and another one is a private utility module, which leaves 4
|
||||
public modules. These are:
|
||||
|
||||
core:
|
||||
- +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
|
||||
|
||||
types
|
||||
The modules contain only classes and (integer) constants. Mostly simple
|
||||
Python constructs are used (deliberately) --
|
||||
http://docs.python.org/lib/built-in-funcs.html[property()] and
|
||||
http://wiki.python.org/moin/PythonDecoratorLibrary[property
|
||||
decorators] are probably the most exotic animals around. The APIs are
|
||||
designed to be navigable (and guessable!) once you know a few
|
||||
conventions. These conventions are highlighted in the sections below.
|
||||
|
||||
constants
|
||||
Here is a quick overview of the contents of each package:
|
||||
|
||||
values
|
||||
.llvm
|
||||
- LLVMException -- exception class (currently the only one)
|
||||
|
||||
.llvm.core
|
||||
- Module -- represents an LLVM Module
|
||||
- Type -- represents an LLVM Type
|
||||
- IntegerType, FunctionType, StructType, ArrayType, PointerType,
|
||||
VectorType -- derived classes of Type
|
||||
- TypeHandle -- used for constructing recursive (self-referencing) types
|
||||
(e.g. linked list nodes)
|
||||
- Value -- represents an LLVM Value
|
||||
- Constant, GlobalValue, GlobalVariable, Argument, Function,
|
||||
Instruction, CallOrInvokeInstruction, PHINode, SwitchInstruction --
|
||||
various derived classes of Value
|
||||
- BasicBlock -- another derived of Value, represents an LLVM basic block
|
||||
- Builder -- used for creating instructions, wraps LLVM IRBuilder helper
|
||||
class
|
||||
- ModuleProvider -- required to use modules in execution engine and pass
|
||||
manager
|
||||
- constants +TYPE_*+ that represents various types
|
||||
- constants +CC_*+ that represent calling conventions
|
||||
- constants +IPRED_*+ and +RPRED_*+ 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 'import'ing of these modules
|
||||
Pythonically, modules are imported with the statement +"import
|
||||
llvm.core"+ and not +"from llvm.core import *"+. However, you might find
|
||||
it more convenient to import llvm-py modules thus:
|
||||
|
||||
[python]
|
||||
source~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
from llvm import *
|
||||
from llvm.core import *
|
||||
from llvm.ee import *
|
||||
from llvm.passes import *
|
||||
source~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This avoids quite some typing. Both conventions work, however.
|
||||
|
||||
TIP: Python-style documentation strings (+__doc__+) are present in
|
||||
llvm-py. You can use the +help()+ of the interactive Python
|
||||
interpreter or the +object?+ of http://ipython.scipy.org/moin/[IPython]
|
||||
to get online help. (Note: not complete yet!)
|
||||
|
||||
|
||||
Module (llvm.core)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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+:
|
||||
|
||||
[python]
|
||||
source~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
#!/usr/bin/env python
|
||||
|
||||
from llvm import *
|
||||
from llvm.core import *
|
||||
|
||||
# create a module
|
||||
my_module = Module.new('my_module')
|
||||
source~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The constructor of the Module class should *not* be used to instantiate
|
||||
a Module object. This is a common feature for all llvm-py classes.
|
||||
|
||||
[TIP]
|
||||
.Convention
|
||||
=======================================================================
|
||||
*All* llvm-py objects are instantiated using static methods of
|
||||
corresponding classes. Constructors _should not_ be used.
|
||||
=======================================================================
|
||||
|
||||
The argument 'my_module' is a module identifier (a plain string).
|
||||
|
||||
|
||||
Types (llvm.core)
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Types are what you think they are. A instance of +llvm.core.Type+, or
|
||||
one of its derived classes, represent a type. llvm-py 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.
|
||||
|
||||
[frame="all",grid="all"]
|
||||
`50`30`20~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
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)+, +StructType+
|
||||
packed struct, +Type.packed_struct(eltys)+, +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+
|
||||
opaque, +Type.opaque()+, +Type+
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
Values (llvm.core)
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
Instructions (llvm.core)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
Basic Block (llvm.core)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
Builder (llvm.core)
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
Module Provider (llvm.core)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
Execution Engine (llvm.ee)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
Target Data (llvm.ee)
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
Pass Managers and Passes (llvm.passes)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
Annotated Examples
|
||||
------------------
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
About the llvm-py Project
|
||||
---------------------------
|
||||
|
||||
llvm-py lives at
|
||||
http://mdevan.nfshost.com/llvm-py/[http://mdevan.nfshost.com/llvm-py/].
|
||||
The code (subversion repository) and the issue tracker are hosted on google
|
||||
code, at
|
||||
http://code.google.com/p/llvm-py/[http://code.google.com/p/llvm-py/].
|
||||
llvm-py is distributed under the new BSD license, the full license
|
||||
text is in the file named
|
||||
http://code.google.com/p/llvm-py/source/browse/trunk/LICENSE[LICENSE]
|
||||
available in the source distribution.
|
||||
|
||||
The entire llvm-py website is generated from marked up text files
|
||||
using the tool http://www.methods.co.nz/asciidoc/[AsciiDoc]. These text
|
||||
files and the generated HTML pages are available in the source
|
||||
distribution.
|
||||
|
||||
llvm-py is an ongoing, live project. Your contributions in any form
|
||||
are most welcome. You can checkout the latest SVN HEAD from
|
||||
http://code.google.com/p/llvm-py/source/checkout[here].
|
||||
|
||||
Mahadevan R wrote llvm-py and works on it in his spare time. He can be
|
||||
reached at _mdevan.foobar@gmail.com_.
|
||||
|
||||
|
|
|
|||
|
|
@ -35,29 +35,17 @@
|
|||
</div>
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<div class="admonitionblock">
|
||||
<table><tr>
|
||||
<td class="icon">
|
||||
<img src="./images/icons/note.png" alt="Note" />
|
||||
</td>
|
||||
<td class="content">
|
||||
<div class="title"><em>llvm-py</em> Mission Statement</div>
|
||||
<p>Provide a simple, consistent and well-documented suite of APIs that
|
||||
exposes just enough of LLVM to write a compiler/VM in Python.</p>
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<p><em>llvm-py</em> is developed by Mahadevan R, in his spare time, without being
|
||||
paid for it. He can be reached at <em>mdevan.foobar .at. gmail.com</em>, on the
|
||||
<p>llvm-py is developed by Mahadevan R, in his spare time, without being
|
||||
paid for it. He can be reached at mdevan.foobar@gmail.com, on the
|
||||
llvm-dev mailing list and irc.oftc.net#llvm (mdevan).</p>
|
||||
<p>These web pages were generated using the nifty tool
|
||||
<a href="http://www.methods.co.nz/asciidoc/">asciidoc</a>.</p>
|
||||
<p>Many thanks to the guys over at LLVM for all the nifty software, and a
|
||||
helpful mailing list.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Web pages © Mahadevan R. Generated with <a href="http://www.methods.co.nz/asciidoc/">asciidoc</a>.
|
||||
Last updated 09-Jun-2008.
|
||||
Last updated 10-Jun-2008.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -35,24 +35,56 @@
|
|||
</div>
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<p><em>llvm-py</em> is just hatching. It needs your patches and suggestions to
|
||||
grow up. Please contribute! All patches are welcome.</p>
|
||||
<p>The <em>llvm-py</em> code is hosted on a google code project by the same name,
|
||||
<a href="http://code.google.com/p/llvm-py/">here</a>. It provides the SVN repository
|
||||
and a <a href="http://code.google.com/p/llvm-py/issues/list">bug tracker</a>. The
|
||||
latest code can be checked out from SVN like so:</p>
|
||||
<p>llvm-py is just hatching. It needs your patches and suggestions to
|
||||
grow up. Please contribute! All patches are welcome. Here are some links
|
||||
to start hacking away:</p>
|
||||
<div class="tableblock">
|
||||
<table rules="none"
|
||||
frame="hsides"
|
||||
cellspacing="0" cellpadding="4">
|
||||
<col width="320" />
|
||||
<col width="480" />
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<td align="left">
|
||||
Google code hosting
|
||||
</td>
|
||||
<td align="left">
|
||||
<a href="http://code.google.com/p/llvm-py/">http://code.google.com/p/llvm-py/</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
Browse SVN
|
||||
</td>
|
||||
<td align="left">
|
||||
<a href="http://code.google.com/p/llvm-py/source/browse/">http://code.google.com/p/llvm-py/source/browse</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
Issues tracker
|
||||
</td>
|
||||
<td align="left">
|
||||
<a href="http://code.google.com/p/llvm-py/issues/list">http://code.google.com/p/llvm-py/issues/list</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>SVN HEAD can be checked out like so:</p>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>$ svn checkout http://llvm-py.googlecode.com/svn/trunk/ llvm-py</tt></pre>
|
||||
</div></div>
|
||||
<p>You can browse the source online at:
|
||||
<a href="http://code.google.com/p/llvm-py/source/browse">http://code.google.com/p/llvm-py/source/browse</a>.</p>
|
||||
<p>Mahadevan R (mdevan.foobar@gmail.com) is available to answer your
|
||||
queries.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Web pages © Mahadevan R. Generated with <a href="http://www.methods.co.nz/asciidoc/">asciidoc</a>.
|
||||
Last updated 09-Jun-2008.
|
||||
Last updated 10-Jun-2008.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<link rel="stylesheet" href="style/xhtml11.css" type="text/css" />
|
||||
<link rel="stylesheet" href="style/xhtml11-quirks.css" type="text/css" />
|
||||
<link rel="stylesheet" href="style/layout.css" type="text/css" />
|
||||
<title>Download and Setup - llvm-py</title>
|
||||
<title>Download - llvm-py</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="layout-banner">
|
||||
|
|
@ -31,11 +31,11 @@
|
|||
<td>
|
||||
<div id="layout-content">
|
||||
<div id="header">
|
||||
<h1>Download and Setup</h1>
|
||||
<h1>Download</h1>
|
||||
</div>
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<p>The latest release is 0.2, released xx-Jun-2008 (full <a href="#changelog">Changelog</a>
|
||||
<p>The latest release is 0.2, released xx-Jun-2008 (<a href="#changelog">Changelog</a>
|
||||
below).</p>
|
||||
<p>Download it here:</p>
|
||||
<div class="tableblock">
|
||||
|
|
@ -94,162 +94,46 @@ cellspacing="0" cellpadding="4">
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Bleeding Edge</h2>
|
||||
<div class="sectionbody">
|
||||
<p>The latest code can be checked out from SVN thusly:</p>
|
||||
<p>The latest code can be checked out from SVN like so:</p>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>$ svn checkout http://llvm-py.googlecode.com/svn/trunk/ llvm-py</tt></pre>
|
||||
</div></div>
|
||||
<p>Happy hacking, and please send in your patches.</p>
|
||||
<p>Follow the steps <a href="userguide.html#install">described here</a> to install the
|
||||
package.</p>
|
||||
</div>
|
||||
<h2>Setting Up</h2>
|
||||
<div class="sectionbody">
|
||||
<p>Follow these steps to get <em>llvm-py</em> up and running:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>
|
||||
<a href="#uninstall">Uninstall</a> any previous version of <em>llvm-py</em>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Get and build LLVM.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Optionally, install it.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Get the latest release (see above) of <em>llvm-py</em> and untar it:
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>$ wget http://link/llvm-py-0.2.tar.bz2
|
||||
$ tar jxvf llvm-py-0.2.tar.bz2</tt></pre>
|
||||
</div></div>
|
||||
<ul>
|
||||
<li>
|
||||
<p>
|
||||
If you've installed LLVM, setup <em>llvm-py</em> like this:
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>$ cd llvm-py-0.2
|
||||
$ sudo python setup.py install</tt></pre>
|
||||
</div></div>
|
||||
<ul>
|
||||
<li>
|
||||
<p>
|
||||
If you haven't installed LLVM, locate the executable <tt>llvm-config</tt>
|
||||
under your LLVM build directory (should be something like
|
||||
<tt>/home/mdevan/llvm/Release/bin/llvm-config</tt>) and pass this to setup.py:
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>$ cd llvm-py-0.2
|
||||
$ sudo python setup.py install --llvm-config=/path/to/llvm-config</tt></pre>
|
||||
</div></div>
|
||||
<p>That's it!</p>
|
||||
<div class="title">Notes:</div><ul>
|
||||
<li>
|
||||
<p>
|
||||
<em>setup.py</em> is a standard Python distutils script. See the Python
|
||||
documentation regarding
|
||||
<a href="http://docs.python.org/inst/inst.html">Installing Python Modules</a> and
|
||||
<a href="http://docs.python.org/dist/dist.html">Distributing Python Modules</a> for
|
||||
more information on such scripts.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
To build the debug version, build with the <tt>-g</tt> flag and the debug
|
||||
version of llvm-config:
|
||||
</p>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>$ python setup.py build -g --llvm-config=/path/to/Debug/bin/llvm-config
|
||||
$ sudo python setup.py install</tt></pre>
|
||||
</div></div>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Debug binaries are <em>huge</em>! (65 MB+)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
If --llvm-config is not specified, <tt>setup.py</tt> looks for
|
||||
<tt>llvm-config</tt> in the <tt>PATH</tt>, which will succeed if LLVM is installed.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h2><a id="uninstall"></a>Uninstall</h2>
|
||||
<div class="sectionbody">
|
||||
<p>To get rid of llvm-py completely, if you wish to do so:</p>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt># rm -rf /usr/lib/python2.5/site-packages/llvm
|
||||
# rm -f /usr/lib/python2.5/site-packages/llvm_py-0.1.egg-info</tt></pre>
|
||||
</div></div>
|
||||
<ul>
|
||||
<li>
|
||||
<p>
|
||||
You need to be root to do this.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Paths are for debian-based systems, in other distros it might be different.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Note that there is a version number in the egg file name.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h2><a id="changelog"></a>Changelog</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>0.1, 10-May-2008:
|
||||
<pre><tt>0.2, ongoing:
|
||||
|
||||
* 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
|
||||
assembly representation
|
||||
* Modules and functions can be verified
|
||||
* MemoryBuffer and TypeHandle are available
|
||||
* ExecutionEngine, TargetData and passes are available
|
||||
* Unit tester added (but doesn't test much for now)
|
||||
* Python doc string documentation added (still incomplete)
|
||||
* Many minor style/cosmetic changes and bug fixes
|
||||
* Added documentation as on website into SVN
|
||||
|
||||
|
||||
0.1, 10-May-2008:
|
||||
|
||||
* Initial release.
|
||||
|
||||
|
||||
0.2, ongoing:
|
||||
|
||||
* Independent package, need not be unpacked into llvm/bindings
|
||||
* Modules can be dumped to a string
|
||||
* Modules can be verified
|
||||
* Module.global_variables, Module.functions, Function.args,
|
||||
Function.basic_blocks and BasicBlock.instructions are
|
||||
now proper iterators (generators in fact) than plain lists
|
||||
|
||||
* MemoryBuffer is done
|
||||
* TypeHandle is done
|
||||
* Unit tester added (but doesn't do much for now)
|
||||
</tt></pre>
|
||||
</div></div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Web pages © Mahadevan R. Generated with <a href="http://www.methods.co.nz/asciidoc/">asciidoc</a>.
|
||||
Last updated 09-Jun-2008.
|
||||
Last updated 10-Jun-2008.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ entry:
|
|||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Web pages © Mahadevan R. Generated with <a href="http://www.methods.co.nz/asciidoc/">asciidoc</a>.
|
||||
Last updated 09-Jun-2008.
|
||||
Last updated 10-Jun-2008.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -35,17 +35,13 @@
|
|||
</div>
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<p><em>llvm-py</em> provides <a href="http://www.python.org/">Python</a> bindings for
|
||||
<a href="http://llvm.org/">LLVM</a>. It currently provides APIs to build the in-memory IR
|
||||
(intermediate representation) and to dump it. Execution engine and related APIs
|
||||
should appear soon.</p>
|
||||
<p><em>llvm-py</em> is a set of Python-based and C-based Python modules. It makes use of
|
||||
llvm-c, the C binding for LLVM. It is based on the latest SVN version of LLVM
|
||||
(and will not work on 2.2). It has been tested only with Python 2.5, although
|
||||
it should be usable with 2.4 also. I've built and tested it only on Linux/i386
|
||||
machines.</p>
|
||||
<p>Download links, setup help and changelog are on the
|
||||
<a href="download.html">download</a> page.</p>
|
||||
<p>llvm-py provides <a href="http://www.python.org/">Python</a> bindings for
|
||||
<a href="http://llvm.org/">LLVM</a>. It's goal is to expose enough of LLVM APIs to
|
||||
implement a compiler or VM in pure Python. Currently, llvm-py is
|
||||
available for LLVM 2.3 and Python 2.5, on Linux/x86. It is expected to
|
||||
be usable on various unices, as well as with Python 2.4, with minimal
|
||||
changes, if any. It should be stable enough for you to play with.</p>
|
||||
<p>llvm-py is just hatching, and your contributions would be most welcome.</p>
|
||||
</div>
|
||||
</div>
|
||||
<h2>News</h2>
|
||||
|
|
@ -64,7 +60,7 @@ machines.</p>
|
|||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Web pages © Mahadevan R. Generated with <a href="http://www.methods.co.nz/asciidoc/">asciidoc</a>.
|
||||
Last updated 09-Jun-2008.
|
||||
Last updated 10-Jun-2008.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ modification, are permitted provided that the following conditions are met:
|
|||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the Mahadevan R, llvm-py nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
* 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
|
||||
|
|
@ -76,7 +76,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</tt></pre>
|
|||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Web pages © Mahadevan R. Generated with <a href="http://www.methods.co.nz/asciidoc/">asciidoc</a>.
|
||||
Last updated 09-Jun-2008.
|
||||
Last updated 10-Jun-2008.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
</div>
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<p><em>llvm-py</em> provides Python bindings for LLVM. This document explains how
|
||||
<p>llvm-py 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.</p>
|
||||
</div>
|
||||
|
|
@ -48,27 +48,26 @@ JIT-compiled language. It provides extensive optimization support, and
|
|||
static and dynamic (JIT) backends for many platforms. See the website at
|
||||
<a href="http://www.llvm.org/">http://www.llvm.org/</a> to discover more.</p>
|
||||
<p>Python bindings for LLVM provides a gentler learning curve for working
|
||||
with the LLVM APIs. It should also prove easier to create working
|
||||
with the LLVM APIs. It should also be easier to create working
|
||||
prototypes and experimental languages using this medium.</p>
|
||||
<div class="title">License</div>
|
||||
<p>Both LLVM and <em>llvm-py</em> are distributed under (different) permissive
|
||||
open source licenses. <em>llvm-py</em> uses the
|
||||
<p>Both LLVM and llvm-py are distributed under (different) permissive
|
||||
open source licenses. llvm-py uses the
|
||||
<a href="http://opensource.org/licenses/bsd-license.php">new BSD license</a>. More
|
||||
information is available <a href="license.html">here</a>.</p>
|
||||
<div class="title">Platforms</div>
|
||||
<p>Currently, <em>llvm-py</em> has been built and tested only on Linux/x86. However,
|
||||
<p>Currently, llvm-py has been built and tested only on Linux/x86. However,
|
||||
it should be trivial to build it on other unices. Windows is not
|
||||
supported, for a variety of reasons.</p>
|
||||
<div class="title">Versions</div>
|
||||
<p>As of now, <em>llvm-py</em> requires the latest SVN version of LLVM. It will
|
||||
not work with version 2.2 of LLVM. However, 2.3 should be release soon,
|
||||
and <em>llvm-py</em> should work with stock 2.3 LLVM.</p>
|
||||
<p><em>llvm-py</em> has been built and tested with Python 2.5. It should work with
|
||||
<p>llvm-py requires verion 2.3 of LLVM. It will not work with previous
|
||||
versions.</p>
|
||||
<p>llvm-py has been built and tested with Python 2.5. It should work with
|
||||
Python 2.4, with minimal changes, if any.</p>
|
||||
</div>
|
||||
<h2>Installation</h2>
|
||||
<h2><a id="install"></a>Installation</h2>
|
||||
<div class="sectionbody">
|
||||
<p><em>llvm-py</em> is distributed as a source tarball. You'll need to build and
|
||||
<p>llvm-py is distributed as a source tarball. You'll need to build and
|
||||
install it before it can be used. At least the following will be
|
||||
required for this:</p>
|
||||
<ul>
|
||||
|
|
@ -96,7 +95,9 @@ LLVM, either installed or built
|
|||
<p>On debian-based systems, the first three can be installed with the
|
||||
command `sudo apt-get install gcc g++ python python-dev'. Note that
|
||||
ubuntu repository has an old version of llvm (1.8) which will not work
|
||||
with <em>llvm-py</em>.</p>
|
||||
with llvm-py.</p>
|
||||
<p>Tip: If LLVM 2.3 does not install cleanly, try installing <em>ocamldoc</em>
|
||||
first.</p>
|
||||
<h3>llvm-config</h3>
|
||||
<p>Inorder to build llvm-py, it's build script needs to know from where to
|
||||
invoke the llvm helper program, <tt>llvm-config</tt>. If you've installed LLVM,
|
||||
|
|
@ -104,6 +105,9 @@ then this will be available in your <tt>PATH</tt>, and nothing further needs to
|
|||
be done. If you've built LLVM yourself, or for any reason <tt>llvm-config</tt>
|
||||
is not in your <tt>PATH</tt>, you'll need to pass the full path of
|
||||
<tt>llvm-config</tt> to the build script.</p>
|
||||
<p>You'll need to be <em>root</em> to install llvm-py. Remember that your <tt>PATH</tt>
|
||||
is different from that of <em>root</em>, so even if <tt>llvm-config</tt> is in your
|
||||
<tt>PATH</tt>, it may not be available when you do <tt>sudo</tt>.</p>
|
||||
<h3>Steps</h3>
|
||||
<p>The commands illustrated below assume that the LLVM source is available
|
||||
under <tt>/home/mdevan/llvm</tt>. If you've a previous version of llvm-py
|
||||
|
|
@ -252,8 +256,8 @@ b = PHI(a1, a2);</tt></pre>
|
|||
<p>The PHI node selects <tt>a1</tt> or <tt>a2</tt>, depending on where the control
|
||||
reached the PHI node. The argument <tt>a1</tt> of the PHI node is associated
|
||||
with the block <tt>"a1 = 1;"</tt> and <tt>a2</tt> with the block <tt>"a2 = 2;"</tt>.</p>
|
||||
<p>PHI nodes have to be explicitly created in the LLVM IR. The LLVM
|
||||
instruction set therefore has an instruction called <em>phi</em>.</p>
|
||||
<p>PHI nodes have to be explicitly created in the LLVM IR. Accordingly the
|
||||
LLVM instruction set has an instruction called <tt>phi</tt>.</p>
|
||||
<h3>LLVM Assembly Language</h3>
|
||||
<p>The LLVM IR can be represented offline in two formats
|
||||
- a textual, human-readable form, similar to assembly language, called
|
||||
|
|
@ -323,10 +327,11 @@ most suitable for the code in the module.</p>
|
|||
<p>There is a LLVM binary called <a href="http://www.llvm.org/cmds/opt.html">opt</a>,
|
||||
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 <tt>opt</tt>. (Although <em>llvm-py</em> does not allow you to
|
||||
loaded and executed by <tt>opt</tt>. (Although llvm-py 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.)</p>
|
||||
<p>Passes are run using a <em>pass manager</em>. For our purposes, there are two</p>
|
||||
<p>Passes are run using a <em>pass manager</em>. For our purposes, there are two
|
||||
pass managers TODO</p>
|
||||
<h3>Execution Engine</h3>
|
||||
<p>TODO</p>
|
||||
<h3>BitCode</h3>
|
||||
|
|
@ -334,19 +339,474 @@ any stage, and perform any transforms on it as you like.)</p>
|
|||
<h3>llvm-gcc</h3>
|
||||
<p>TODO</p>
|
||||
</div>
|
||||
<h2>The <em>llvm-py</em> Package</h2>
|
||||
<h2>The llvm-py Package</h2>
|
||||
<div class="sectionbody">
|
||||
<p>modules overview: llvm, llvm.core, llvm.ee, llvm.passes</p>
|
||||
<p>importing modules</p>
|
||||
<p>core:</p>
|
||||
<p>types</p>
|
||||
<p>constants</p>
|
||||
<p>values</p>
|
||||
<p>The llvm-py 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.</p>
|
||||
<p>Out of the 6 modules, one is an "extension" module (i.e., it's written
|
||||
in C), and another one is a private utility module, which leaves 4
|
||||
public modules. These are:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>
|
||||
<tt>llvm</tt> — top-level package, common classes (like exceptions)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt>llvm.core</tt> — IR-related APIs
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt>llvm.ee</tt> — execution engine related APIs
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt>llvm.passes</tt> — pass manager and passes related APIs
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>The modules contain only classes and (integer) constants. Mostly simple
|
||||
Python constructs are used (deliberately) —
|
||||
<a href="http://docs.python.org/lib/built-in-funcs.html">property()</a> and
|
||||
<a href="http://wiki.python.org/moin/PythonDecoratorLibrary">property
|
||||
decorators</a> are probably the most exotic animals around. The APIs are
|
||||
designed to be navigable (and guessable!) once you know a few
|
||||
conventions. These conventions are highlighted in the sections below.</p>
|
||||
<p>Here is a quick overview of the contents of each package:</p>
|
||||
<div class="title">llvm</div><ul>
|
||||
<li>
|
||||
<p>
|
||||
LLVMException — exception class (currently the only one)
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="title">llvm.core</div><ul>
|
||||
<li>
|
||||
<p>
|
||||
Module — represents an LLVM Module
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Type — represents an LLVM Type
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
IntegerType, FunctionType, StructType, ArrayType, PointerType,
|
||||
VectorType — derived classes of Type
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
TypeHandle — used for constructing recursive (self-referencing) types
|
||||
(e.g. linked list nodes)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Value — represents an LLVM Value
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Constant, GlobalValue, GlobalVariable, Argument, Function,
|
||||
Instruction, CallOrInvokeInstruction, PHINode, SwitchInstruction —
|
||||
various derived classes of Value
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
BasicBlock — another derived of Value, represents an LLVM basic block
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Builder — used for creating instructions, wraps LLVM IRBuilder helper
|
||||
class
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
ModuleProvider — required to use modules in execution engine and pass
|
||||
manager
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
constants <tt>TYPE_*</tt> that represents various types
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
constants <tt>CC_*</tt> that represent calling conventions
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
constants <tt>IPRED_*</tt> and <tt>RPRED_*</tt> that represent integer and real
|
||||
comparison predicates (like less than, greater than etc.)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
constants <tt>LINKAGE_*</tt> that represent linkage of symbols (external,
|
||||
internal etc.)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
constants <tt>VISIBILITY_*</tt> that represents visibility of symbols
|
||||
(default, hidden, protected)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
constants <tt>ATTR_*</tt> that represent function parameter attributes
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="title">llvm.ee</div><ul>
|
||||
<li>
|
||||
<p>
|
||||
ExecutionEngine — represents an execution engine (which can be an
|
||||
either an interpreter or a JIT)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
TargetData — represents the ABI of the target platform (details like
|
||||
sizes and alignment of primitive types, endinanness etc)
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="title">llvm.passes</div><ul>
|
||||
<li>
|
||||
<p>
|
||||
PassManager — represents an LLVM pass manager
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
FunctionPassManager — represents an LLVM function pass manager
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
constants <tt>PASS_*</tt> that represent various passes
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="title">A note on the 'import'ing of these modules</div>
|
||||
<p>Pythonically, modules are imported with the statement <tt>"import
|
||||
llvm.core"</tt> and not <tt>"from llvm.core import *"</tt>. However, you might find
|
||||
it more convenient to import llvm-py modules thus:</p>
|
||||
<div class="listingblock">
|
||||
<div class="content"><!-- Generator: GNU source-highlight 2.4
|
||||
by Lorenzo Bettini
|
||||
http://www.lorenzobettini.it
|
||||
http://www.gnu.org/software/src-highlite -->
|
||||
<pre><tt><span style="font-weight: bold"><span style="color: #000080">from</span></span> llvm <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="color: #990000">*</span>
|
||||
<span style="font-weight: bold"><span style="color: #000080">from</span></span> llvm<span style="color: #990000">.</span>core <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="color: #990000">*</span>
|
||||
<span style="font-weight: bold"><span style="color: #000080">from</span></span> llvm<span style="color: #990000">.</span>ee <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="color: #990000">*</span>
|
||||
<span style="font-weight: bold"><span style="color: #000080">from</span></span> llvm<span style="color: #990000">.</span>passes <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="color: #990000">*</span>
|
||||
</tt></pre></div></div>
|
||||
<p>This avoids quite some typing. Both conventions work, however.</p>
|
||||
<div class="admonitionblock">
|
||||
<table><tr>
|
||||
<td class="icon">
|
||||
<img src="./images/icons/tip.png" alt="Tip" />
|
||||
</td>
|
||||
<td class="content">Python-style documentation strings (<tt><em>doc</em></tt>) are present in
|
||||
llvm-py. You can use the <tt>help()</tt> of the interactive Python
|
||||
interpreter or the <tt>object?</tt> of <a href="http://ipython.scipy.org/moin/">IPython</a>
|
||||
to get online help. (Note: not complete yet!)</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<h3>Module (llvm.core)</h3>
|
||||
<p>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 <tt>Module.new</tt>:</p>
|
||||
<div class="listingblock">
|
||||
<div class="content"><!-- Generator: GNU source-highlight 2.4
|
||||
by Lorenzo Bettini
|
||||
http://www.lorenzobettini.it
|
||||
http://www.gnu.org/software/src-highlite -->
|
||||
<pre><tt><span style="font-style: italic"><span style="color: #9A1900">#!/usr/bin/env python</span></span>
|
||||
|
||||
<span style="font-weight: bold"><span style="color: #000080">from</span></span> llvm <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="color: #990000">*</span>
|
||||
<span style="font-weight: bold"><span style="color: #000080">from</span></span> llvm<span style="color: #990000">.</span>core <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="color: #990000">*</span>
|
||||
|
||||
<span style="font-style: italic"><span style="color: #9A1900"># create a module</span></span>
|
||||
my<span style="color: #009900">_</span>module <span style="color: #990000">=</span> <span style="color: #009900">Module</span><span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">new</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'my_module'</span><span style="color: #990000">)</span>
|
||||
</tt></pre></div></div>
|
||||
<p>The constructor of the Module class should <strong>not</strong> be used to instantiate
|
||||
a Module object. This is a common feature for all llvm-py classes.</p>
|
||||
<div class="admonitionblock">
|
||||
<table><tr>
|
||||
<td class="icon">
|
||||
<img src="./images/icons/tip.png" alt="Tip" />
|
||||
</td>
|
||||
<td class="content">
|
||||
<div class="title">Convention</div>
|
||||
<p><strong>All</strong> llvm-py objects are instantiated using static methods of
|
||||
corresponding classes. Constructors <em>should not</em> be used.</p>
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<p>The argument <em>my_module</em> is a module identifier (a plain string).</p>
|
||||
<h3>Types (llvm.core)</h3>
|
||||
<p>Types are what you think they are. A instance of <tt>llvm.core.Type</tt>, or
|
||||
one of its derived classes, represent a type. llvm-py does not use as
|
||||
many classes to represent types as does LLVM itself. Some types are
|
||||
represented using <tt>llvm.core.Type</tt> itself and the rest are represented
|
||||
using derived classes of <tt>llvm.core.Type</tt>. As usual, an instance is created
|
||||
via one of the static methods of <tt>Type</tt>. These methods return an
|
||||
instance of either <tt>llvm.core.Type</tt> itself or one of its derived
|
||||
classes.</p>
|
||||
<p>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.</p>
|
||||
<div class="tableblock">
|
||||
<table rules="all"
|
||||
frame="border"
|
||||
cellspacing="0" cellpadding="4">
|
||||
<col width="400" />
|
||||
<col width="240" />
|
||||
<col width="160" />
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">
|
||||
Name
|
||||
</th>
|
||||
<th align="left">
|
||||
Constructor Method
|
||||
</th>
|
||||
<th align="left">
|
||||
Class
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<td align="left">
|
||||
integer of bitwidth <em>n</em>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.int(n)</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>IntegerType</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
32-bit float
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.float()</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
64-bit double
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.double()</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
80-bit float
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.x86_fp80()</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
128-bit float (112-bit mantissa)
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.fp128()</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
128-bit float (two 64-bits)
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.ppc_fp128()</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
function
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.function(r, p, v)</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>FunctionType</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
unpacked struct
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.struct(eltys)</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>StructType</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
packed struct
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.packed_struct(eltys)</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>StructType</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
array
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.array(elty, count)</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>ArrayType</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
pointer to value of type <em>pty</em>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.pointer(pty, addrspc)</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>PointerType</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
vector
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.vector(elty, count)</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>VectorType</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
void
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.void()</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
label
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.label()</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
opaque
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type.opaque()</tt>
|
||||
</td>
|
||||
<td align="left">
|
||||
<tt>Type</tt>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h3>Values (llvm.core)</h3>
|
||||
<p>TODO</p>
|
||||
<h3>Instructions (llvm.core)</h3>
|
||||
<p>TODO</p>
|
||||
<h3>Basic Block (llvm.core)</h3>
|
||||
<p>TODO</p>
|
||||
<h3>Builder (llvm.core)</h3>
|
||||
<p>TODO</p>
|
||||
<h3>Module Provider (llvm.core)</h3>
|
||||
<p>TODO</p>
|
||||
<h3>Execution Engine (llvm.ee)</h3>
|
||||
<p>TODO</p>
|
||||
<h3>Target Data (llvm.ee)</h3>
|
||||
<p>TODO</p>
|
||||
<h3>Pass Managers and Passes (llvm.passes)</h3>
|
||||
<p>TODO</p>
|
||||
</div>
|
||||
<h2>Annotated Examples</h2>
|
||||
<div class="sectionbody">
|
||||
<p>TODO</p>
|
||||
</div>
|
||||
<h2>About the llvm-py Project</h2>
|
||||
<div class="sectionbody">
|
||||
<p>llvm-py lives at
|
||||
<a href="http://mdevan.nfshost.com/llvm-py/">http://mdevan.nfshost.com/llvm-py/</a>.
|
||||
The code (subversion repository) and the issue tracker are hosted on google
|
||||
code, at
|
||||
<a href="http://code.google.com/p/llvm-py/">http://code.google.com/p/llvm-py/</a>.
|
||||
llvm-py is distributed under the new BSD license, the full license
|
||||
text is in the file named
|
||||
<a href="http://code.google.com/p/llvm-py/source/browse/trunk/LICENSE">LICENSE</a>
|
||||
available in the source distribution.</p>
|
||||
<p>The entire llvm-py website is generated from marked up text files
|
||||
using the tool <a href="http://www.methods.co.nz/asciidoc/"><em>AsciiDoc</em></a>. These text
|
||||
files and the generated HTML pages are available in the source
|
||||
distribution.</p>
|
||||
<p>llvm-py is an ongoing, live project. Your contributions in any form
|
||||
are most welcome. You can checkout the latest SVN HEAD from
|
||||
<a href="http://code.google.com/p/llvm-py/source/checkout">here</a>.</p>
|
||||
<p>Mahadevan R wrote llvm-py and works on it in his spare time. He can be
|
||||
reached at <em>mdevan.foobar@gmail.com</em>.</p>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Web pages © Mahadevan R. Generated with <a href="http://www.methods.co.nz/asciidoc/">asciidoc</a>.
|
||||
Last updated 09-Jun-2008.
|
||||
Last updated 10-Jun-2008.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue