[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