Author: Manuel Jacob
Branch: llvm-translation-backend
Changeset: r66466:8835602e0b39
Date: 2012-03-04 16:38 +0100
http://bitbucket.org/pypy/pypy/changeset/8835602e0b39/
Log: Improve LLVM assembly output and add tests for it.
diff --git a/pypy/translator/llvm/genllvm.py b/pypy/translator/llvm/genllvm.py
--- a/pypy/translator/llvm/genllvm.py
+++ b/pypy/translator/llvm/genllvm.py
@@ -20,7 +20,6 @@
self.f = f
self.names_counter = {}
self.types = {}
- self.globals_counter = count()
self.globals_ = {None: 'null'}
self.delayed_ptrs = []
@@ -59,8 +58,13 @@
self.types[type_] = '[%s x %s]' % (type_.length, _T(type_.OF))
elif isinstance(type_, lltype.Struct):
self.types[type_] = name = self._unique('%struct.' + type_._name)
- self.f.write('%s = type { %s }\n' % (
- name, _Tm(type_._flds[fld] for fld in type_._names)))
+ tmp = (' %s%s%s ; %s' % (
+ ';' if type_._flds[fld] is lltype.Void else '',
+ _T(type_._flds[fld]),
+ ',' if fld != type_._names[-1] else '',
+ fld)
+ for fld in type_._names)
+ self.f.write('%s = type {\n%s\n}\n' % (name, '\n'.join(tmp)))
elif isinstance(type_, lltype.Array):
of = _T(type_.OF)
name = '%array_of_' + of.strip('%').replace('*', '_ptr')
@@ -93,7 +97,11 @@
self.f.writelines(writer.lines)
return
- name = '@global_%s' % next(self.globals_counter)
+ if isinstance(type_, lltype.FixedSizeArray):
+ tmp = 'array'
+ else:
+ tmp = _T(type_).strip('%').replace('*', '_ptr')
+ name = self._unique('@global_' + tmp)
if isinstance(type_, lltype.Array):
typedef = '{ i64, [%s x %s] }' % (len(obj.items), _T(type_.OF))
self.globals_[obj] = 'bitcast(%s* %s to %s*)' % (
@@ -105,24 +113,53 @@
self.f.write('%s = global %s %s\n' % (
name, typedef, self.repr_obj(type_, obj)))
- def _repr_array(self, flds):
- if all(_V(t, i) == 'null' for t, i in flds):
- return 'zeroinitializer'
- return '[ %s ]' % _TVm(flds)
+ def _zeroinitialized(self, type_, obj):
+ if isinstance(type_, lltype.Primitive):
+ return obj == type_._defl()
+ elif isinstance(type_, lltype.Ptr):
+ return not obj
+ elif isinstance(type_, lltype.Struct):
+ return all(self._zeroinitialized(type_._flds[na], getattr(obj, na))
+ for na in type_._names)
+ elif isinstance(type_, lltype.Array):
+ return len(obj.items) == 0
+ elif isinstance(type_, lltype.OpaqueType):
+ return True
+ elif isinstance(type_, llgroup.GroupType):
+ return True
+ else:
+ raise TypeError('type_ is %r' % type_)
+
+ def _repr_array(self, of, items):
+ if of is lltype.Char:
+ return 'c"%s"' % ''.join(items).replace('\00', r'\00')
+ tmp = (_TVm(of, items[i:i+16]) for i in xrange(0, len(items), 16))
+ cmms = [','] * (len(items) // 16) + ['']
+ return '[\n%s]' % (''.join(' %s%s\n' % i for i in zip(tmp, cmms)))
def repr_obj(self, type_, obj):
- if isinstance(type_, lltype.FixedSizeArray):
- flds = [(type_.OF, getattr(obj, na)) for na in type_._names]
- return self._repr_array(flds)
+ if self._zeroinitialized(type_, obj):
+ return 'zeroinitializer'
+ elif isinstance(type_, lltype.FixedSizeArray):
+ return self._repr_array(type_.OF, map(obj._getattr, type_._names))
elif isinstance(type_, lltype.Struct):
- flds = [(type_._flds[na], getattr(obj, na)) for na in type_._names]
- if all(_V(t, i) == 'null' for t, i in flds):
- return 'zeroinitializer'
- return '{ %s }' % _TVm(flds)
+ tmp = (' %s%s %s%s ; %s' % (
+ ';' if type_._flds[fld] is lltype.Void else '',
+ _T(type_._flds[fld]),
+ _V(type_._flds[fld], getattr(obj, fld))
+ .replace('\n', '\n '),
+ ',' if fld != type_._names[-1] else '',
+ fld)
+ for fld in type_._names)
+ return '{\n%s\n}' % ('\n'.join(tmp))
+
elif isinstance(type_, lltype.Array):
- return '{ i64 %s, [%s x %s ] %s }' % (
- len(obj.items), len(obj.items), _T(type_.OF),
- self._repr_array([(type_.OF, i) for i in obj.items]))
+ if all(self._zeroinitialized(type_.OF, i) for i in obj.items):
+ data = 'zeroinitializer'
+ else:
+ data = self._repr_array(type_.OF, obj.items)
+ return '{ i64 %s, [%s x %s] %s }' % (
+ len(obj.items), len(obj.items), _T(type_.OF), data)
elif isinstance(type_, lltype.OpaqueType):
return 'null'
elif isinstance(type_, llgroup.GroupType):
@@ -141,7 +178,7 @@
return str(value)
if isinstance(value, ComputedIntSymbolic):
- return value.compute_fn()
+ return str(value.compute_fn())
elif isinstance(value, llmemory.AddressOffset):
return '0' # XXX
raise NotImplementedError
@@ -216,13 +253,10 @@
"""Represent multiple values. `vals` is an iterable of LLValues."""
return ', '.join(V(val) for val in vals)
-def _TVm(vocs):
- """
- Represent multiple types and values. `vocs` is an iterable of
- (LLType, LLValue) pairs.
- """
- return ', '.join('%s %s' % (_T(type_), _V(type_, val))
- for type_, val in vocs if type_ is not lltype.Void)
+def _TVm(type_, values):
+ """Represent multiple `values` of type `type_`."""
+ tstr = _T(type_)
+ return ', '.join('%s %s' % (tstr, _V(type_, value)) for value in values)
def TVm(vocs):
"""
diff --git a/pypy/translator/llvm/test/test_genllvm.py
b/pypy/translator/llvm/test/test_genllvm.py
--- a/pypy/translator/llvm/test/test_genllvm.py
+++ b/pypy/translator/llvm/test/test_genllvm.py
@@ -1,4 +1,7 @@
+from cStringIO import StringIO
+from pypy.rpython.lltypesystem import lltype, rffi
from pypy.translator.interactive import Translation
+from pypy.translator.llvm import genllvm
def compile(func, argtypes=None, gc=False):
@@ -16,6 +19,141 @@
return translation.compile_llvm()
+class TestPrimitives(object):
+ def setup(self):
+ genllvm.database = None
+
+ def test_repr_signed(self):
+ assert genllvm.TV(genllvm.C(rffi.r_long(-1))) == 'i64 -1'
+
+ def test_repr_unsigned(self):
+ assert genllvm.TV(genllvm.C(rffi.r_ulong(1))) == 'i64 1'
+
+ def test_repr_char(self):
+ assert genllvm.TV(genllvm.C(chr(123))) == 'i8 123'
+
+ def test_repr_bool(self):
+ assert genllvm.TV(genllvm.C(True)) == 'i1 true'
+ assert genllvm.TV(genllvm.C(False)) == 'i1 false'
+
+ def test_repr_float(self):
+ assert genllvm.TV(genllvm.C(0.3)) == 'double 0.3'
+
+
+class TestDatabase(object):
+ def setup_method(self, meth):
+ self.f = StringIO()
+ genllvm.database = genllvm.Database(None, self.f)
+
+ def test_repr_fixed_size_array(self):
+ array = lltype.FixedSizeArray(lltype.Signed, 2)._container_example()
+ assert genllvm.TV(genllvm.C(array)) == '[2 x i64] zeroinitializer'
+ array.setitem(0, 1)
+ array.setitem(1, 2)
+ assert genllvm.TV(genllvm.C(array)) == ('[2 x i64] [\n'
+ ' i64 1, i64 2\n'
+ ']')
+ assert self.f.getvalue() == ''
+
+ def test_repr_string(self):
+ array = lltype.FixedSizeArray(lltype.Char, 7)._container_example()
+ for i, c in enumerate("string\00"):
+ array.setitem(i, c)
+ assert genllvm.TV(genllvm.C(array)) == r'[7 x i8] c"string\00"'
+ assert self.f.getvalue() == ''
+
+ def test_repr_struct(self):
+ struct = lltype.Struct(
+ 'spam', ('eggs', lltype.Signed))._container_example()
+ assert genllvm.TV(genllvm.C(struct)) == '%struct.spam zeroinitializer'
+ struct.eggs = 1
+ assert genllvm.TV(genllvm.C(struct)) == ('%struct.spam {\n'
+ ' i64 1 ; eggs\n'
+ '}')
+ assert self.f.getvalue() == ('%struct.spam = type {\n'
+ ' i64 ; eggs\n'
+ '}\n')
+
+ def test_repr_struct_nested(self):
+ struct = lltype.Struct(
+ 'spam', ('eggs', lltype.Struct(
+ 'foo', ('bar', lltype.Signed))))._container_example()
+ assert genllvm.TV(genllvm.C(struct)) == '%struct.spam zeroinitializer'
+ struct.eggs.bar = 1
+ assert genllvm.TV(genllvm.C(struct)) == ('%struct.spam {\n'
+ ' %struct.foo {\n'
+ ' i64 1 ; bar\n'
+ ' } ; eggs\n'
+ '}')
+ assert self.f.getvalue() == ('%struct.foo = type {\n'
+ ' i64 ; bar\n'
+ '}\n'
+ '%struct.spam = type {\n'
+ ' %struct.foo ; eggs\n'
+ '}\n')
+
+ def test_repr_array(self):
+ array = lltype.Array(lltype.Signed)._container_example()
+ assert genllvm.TV(genllvm.C(array)) == (
+ '%array_of_i64 { i64 1, [1 x i64] zeroinitializer }')
+ array.setitem(0, 1)
+ assert genllvm.TV(genllvm.C(array)) == (
+ '%array_of_i64 { i64 1, [1 x i64] [\n'
+ ' i64 1\n'
+ '] }')
+ assert self.f.getvalue() == '%array_of_i64 = type { i64, [0 x i64] }\n'
+
+ def test_repr_array_of_ptr(self):
+ struct_ptr_type = lltype.Ptr(lltype.Struct('x', ('y', lltype.Signed)))
+ array = lltype.Array(struct_ptr_type)._container_example()
+ assert genllvm.TV(genllvm.C(array)) == (
+ '%array_of_struct.x_ptr '
+ '{ i64 1, [1 x %struct.x*] zeroinitializer }')
+ array.setitem(0, struct_ptr_type._example())
+ assert genllvm.TV(genllvm.C(array)) == (
+ '%array_of_struct.x_ptr { i64 1, [1 x %struct.x*] [\n'
+ ' %struct.x* @global_struct.x\n'
+ '] }')
+ assert self.f.getvalue() == (
+ '%struct.x = type {\n'
+ ' i64 ; y\n'
+ '}\n'
+ '%array_of_struct.x_ptr = type { i64, [0 x %struct.x*] }\n'
+ '@global_struct.x = global %struct.x zeroinitializer\n')
+
+ def test_repr_func_type(self):
+ func_type = lltype.FuncType([lltype.Signed], lltype.Void)
+ assert genllvm._T(func_type) == 'void (i64)'
+
+ def test_repr_fixed_size_array_ptr(self):
+ array_ptr = lltype.Ptr(
+ lltype.FixedSizeArray(lltype.Signed, 2))._example()
+ assert genllvm.TV(genllvm.C(array_ptr)) == '[2 x i64]* @global_array'
+ assert self.f.getvalue() == (
+ '@global_array = global [2 x i64] zeroinitializer\n')
+
+ def test_repr_struct_ptr(self):
+ struct_ptr = lltype.Ptr(
+ lltype.Struct('spam', ('eggs', lltype.Signed)))._example()
+ assert genllvm.TV(genllvm.C(struct_ptr)) == (
+ '%struct.spam* @global_struct.spam')
+ assert self.f.getvalue() == (
+ '%struct.spam = type {\n'
+ ' i64 ; eggs\n'
+ '}\n'
+ '@global_struct.spam = global %struct.spam zeroinitializer\n')
+
+ def test_repr_array_ptr(self):
+ array_ptr = lltype.Ptr(lltype.Array(lltype.Signed))._example()
+ assert genllvm.TV(genllvm.C(array_ptr)) == (
+ '%array_of_i64* bitcast({ i64, [1 x i64] }* '
+ '@global_array_of_i64 to %array_of_i64*)')
+ assert self.f.getvalue() == (
+ '%array_of_i64 = type { i64, [0 x i64] }\n'
+ '@global_array_of_i64 = global { i64, [1 x i64] } '
+ '{ i64 1, [1 x i64] zeroinitializer }\n')
+
+
class TestSimple(object):
def test_pass(self):
def f():
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit