[pypy-svn] r24883 - in pypy/dist/pypy/translator/llvm/pyllvm: . test
ericvrp at codespeak.net
ericvrp at codespeak.net
Thu Mar 23 16:23:50 CET 2006
Author: ericvrp
Date: Thu Mar 23 16:23:48 2006
New Revision: 24883
Added:
pypy/dist/pypy/translator/llvm/pyllvm/test/__init__.py
pypy/dist/pypy/translator/llvm/pyllvm/test/ll_snippet.py
Modified:
pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp
pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py
Log:
Added pyllvm tests and trying to replace already generated function
with new versions.
Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp
==============================================================================
--- pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp (original)
+++ pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp Thu Mar 23 16:23:48 2006
@@ -27,15 +27,59 @@
} PyExecutionEngine;
+/*
+XXX we should probably support parsing one function at a time too.
+This would enable use to use self->exec->recompileAndRelinkFunction(Function* F)
+to support rebinding to a new (more blocks?) function. (or self modifying code)
+*/
static PyObject *ee_parse(PyExecutionEngine *self, PyObject *args) {
- char *llcode;
- if (!PyArg_ParseTuple(args, "s", &llcode)) {
- return NULL;
+ // check number of parameters
+ if (PyTuple_Size(args) < 1 or PyTuple_Size(args) > 2) {
+ PyErr_SetString(PyExc_TypeError, "expected one or two parameters");
+ return NULL;
+ }
+
+ // get first parameter (llcode)
+ PyObject *pyllcode = PyTuple_GetItem(args, 0);
+ if (!PyString_Check(pyllcode)) {
+ PyErr_SetString(PyExc_TypeError, "first arg expected as string with llcode");
+ return NULL;
+ }
+ const char* llcode = PyString_AsString(pyllcode);
+
+ // get optional second parameter (fnname)
+ const char* fnname = NULL;
+ if (PyTuple_Size(args) > 1) {
+ PyObject *pyfnname = PyTuple_GetItem(args, 1);
+ if (!PyString_Check(pyllcode)) {
+ PyErr_SetString(PyExc_TypeError, "second arg expected as string with functionname");
+ return NULL;
+ }
+ fnname = PyString_AsString(pyfnname);
}
+ // parse and verify llcode
try {
- ParseAssemblyString((const char *) llcode, &self->exec->getModule());
+ if (fnname) {
+ // XXX ParseAssemblyString(llcode, &self->exec->getModule()); //redefinition
+ /*Module* M =*/ ParseAssemblyString(llcode, NULL);
+ Function *fn = self->exec->getModule().getNamedFunction(std::string(fnname));
+ if (fn == NULL) {
+ PyErr_SetString(PyExc_Exception, "Failed to resolve function to be replaced");
+ return NULL;
+ }
+ self->exec->recompileAndRelinkFunction(fn);
+
+ // TODO replace fn with whatever ParseAssemblyString made of llcode
+
+ PyErr_SetString(PyExc_Exception, "function replacing not supported yet");
+ return NULL;
+
+ } else {
+ ParseAssemblyString(llcode, &self->exec->getModule());
+ }
+
verifyModule(self->exec->getModule(), ThrowExceptionAction);
Py_INCREF(Py_None);
return Py_None;
@@ -137,7 +181,7 @@
static PyObject *ee_call(PyExecutionEngine *self, PyObject *args) {
if (PyTuple_Size(args) == 0) {
- PyErr_SetString(PyExc_TypeError, "first arg expected as string");
+ PyErr_SetString(PyExc_TypeError, "missing functionname");
return NULL;
}
@@ -146,7 +190,6 @@
PyErr_SetString(PyExc_TypeError, "first arg expected as string");
return NULL;
}
-
char *fnname = PyString_AsString(pyfnname);
try {
Added: pypy/dist/pypy/translator/llvm/pyllvm/test/__init__.py
==============================================================================
Added: pypy/dist/pypy/translator/llvm/pyllvm/test/ll_snippet.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/pyllvm/test/ll_snippet.py Thu Mar 23 16:23:48 2006
@@ -0,0 +1,32 @@
+calc = """int %calc(int %n) {
+ %tmp.0 = call int %add1(int %n)
+ ret int %tmp.0
+}
+declare int %add1(int)"""
+
+add1 = """int %add1(int %n) {
+ %tmp.0 = add int %n, 1
+ ret int %tmp.0
+}"""
+
+add1_version2 = """int %add1(int %n) {
+ %tmp.0 = add int %n, 100 ;used for testing function replacement
+ ret int %tmp.0
+}"""
+
+global_int_a_is_100 = """%a = global int 100"""
+
+add1_to_global_int_a = """
+int %add1_to_global_int_a() {
+ %tmp.0 = load int* %a
+ %tmp.1 = add int %tmp.0, 1
+ store int %tmp.1, int* %a
+ ret int %tmp.1
+}"""
+
+sub10_from_global_int_a = """int %sub10_from_global_int_a() {
+ %tmp.0 = load int* %a
+ %tmp.1 = sub int %tmp.0, 10
+ store int %tmp.1, int* %a
+ ret int %tmp.1
+}"""
Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original)
+++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Thu Mar 23 16:23:48 2006
@@ -4,7 +4,12 @@
py.test.skip("llvm not found")
from pypy.translator.llvm.pyllvm.build import pyllvm
+from pypy.translator.llvm.pyllvm.test import ll_snippet
+#XXX When running this with py.test a segfault occurs instead of a nice traceback.
+# I don't know currently (and don't care either because I intend to switch to ctypes anyway)
+# What I do in this case is find out the failing test (py.test -v) and run that one on
+# its own with "py.test -k <testcase>". Have fun!
def test_execution_engine():
ee = pyllvm.get_ee()
@@ -37,13 +42,18 @@
assert returnId > 0
assert name in ('gethellostr', 'hello')
assert len(args) == 0
+ py.test.raises(Exception, ee.functions, 1)
+ py.test.raises(Exception, ee.functions, "string")
def test_call_parse_once():
ee = get_fresh_ee()
ee.parse(codepath.join("hello.s").read())
assert ee.call("hello") == 0
assert ee.call("gethellostr") == "hello world\n"
+ py.test.raises(Exception, ee.call)
+ py.test.raises(Exception, ee.call, 1)
py.test.raises(Exception, ee.call, "gethellostrx")
+ py.test.raises(Exception, ee.call, "gethellostrx", 1)
py.test.raises(Exception, ee.call, "gethellostr", 1)
def test_call_parse_twice():
@@ -53,12 +63,53 @@
ee.parse(codepath.join("addnumbers.s").read())
assert ee.call("add", 10, 32) == 42
assert ee.call("gethellostr") == "hello world\n"
+ py.test.raises(Exception, ee.parse)
+ py.test.raises(Exception, ee.parse, 1)
+ py.test.raises(Exception, ee.parse, "abc")
+
+def test_call_between_parsed_code():
+ """we parse add1 last on purpose to see if the JIT resolves
+ the function at execution time. Not sure if we really need this
+ particular feature. It appears that 'calc' requires a forward
+ declaration to add1 otherwise a segfault will occur!"""
+ ee = get_fresh_ee()
+ ee.parse(ll_snippet.calc)
+ ee.parse(ll_snippet.add1)
+ assert ee.call("add1", 41) == 42
+ assert ee.call("calc", 122) == 123
+
+def test_replace_function():
+ """similar to test_call_between_parsed_code with additional complexity
+ because we rebind the add1 function to another version after it the
+ first version already has been used."""
+ py.test.skip("function replacement support in progress")
+ ee = get_fresh_ee()
+ ee.parse(ll_snippet.calc)
+ ee.parse(ll_snippet.add1)
+ assert ee.call("add1", 41) == 42
+ assert ee.call("calc", 122) == 123
+ ee.parse(ll_snippet.add1_version2, "add1")
+ assert ee.call("add1", 42) == 142
+ assert ee.call("calc", 142) == 242
-def TODOtest_call_between_parsed_code():
- pass
+def test_share_data_between_parsed_code():
+ ee = get_fresh_ee()
+ ee.parse(ll_snippet.global_int_a_is_100)
+ ee.parse(ll_snippet.add1_to_global_int_a)
+ ee.parse(ll_snippet.sub10_from_global_int_a)
+ assert ee.call("add1_to_global_int_a") == 101
+ assert ee.call("sub10_from_global_int_a") == 91
+ assert ee.call("add1_to_global_int_a") == 92
+ assert ee.call("sub10_from_global_int_a") == 82
-def TODOtest_share_data_between_parsed_code():
+def TODOtest_native_code(): #examine JIT generate native (assembly) code
pass
def TODOtest_delete_function():
pass
+
+def TODOtest_add_to_function():
+ pass
+
+def TODOtest_optimize_functions(): #add/del/list llvm transformation passes
+ pass
More information about the Pypy-commit
mailing list