Author: Manuel Jacob
Branch: llvm-translation-backend
Changeset: r66473:29ac85ea68f2
Date: 2012-04-04 19:28 +0200
http://bitbucket.org/pypy/pypy/changeset/29ac85ea68f2/
Log: Enable minimark gc for TestLowLevelTypeLLVM and TestTypedLLVM.
diff --git a/pypy/rlib/rstack.py b/pypy/rlib/rstack.py
--- a/pypy/rlib/rstack.py
+++ b/pypy/rlib/rstack.py
@@ -21,9 +21,8 @@
compilation_info = ExternalCompilationInfo(
include_dirs=[local(pypydir) / 'translator' / 'c'],
- # XXX functions from src/stack.h should be defined in a .c file
includes=['src/stack.h'],
- separate_module_sources=[''] # include src/stack.h
+ separate_module_files=[str(local(pypydir) / 'translator' / 'c' / 'src' /
'stack.c')]
)
def llexternal(name, args, res, _callable=None):
diff --git a/pypy/translator/c/src/stack.c b/pypy/translator/c/src/stack.c
new file mode 100644
--- /dev/null
+++ b/pypy/translator/c/src/stack.c
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include "src/thread.h"
+
+#ifndef MAX_STACK_SIZE
+# define MAX_STACK_SIZE (3 << 18) /* 768 kb */
+#endif
+
+/* the current stack is in the interval [end-length:end]. We assume a
+ stack that grows downward here. */
+char *_LLstacktoobig_stack_end = NULL;
+long _LLstacktoobig_stack_length = MAX_STACK_SIZE;
+char _LLstacktoobig_report_error = 1;
+static RPyThreadStaticTLS end_tls_key;
+
+long LL_stack_get_end() { return (long)_LLstacktoobig_stack_end; }
+long LL_stack_get_length() { return (long)_LLstacktoobig_stack_length; }
+long LL_stack_get_end_adr() { return (long)&_LLstacktoobig_stack_end; }
/* JIT */
+long LL_stack_get_length_adr() { return (long)&_LLstacktoobig_stack_length;
}/* JIT */
+
+void LL_stack_criticalcode_start() { _LLstacktoobig_report_error = 0; }
+void LL_stack_criticalcode_stop() { _LLstacktoobig_report_error = 1; }
+
+void LL_stack_set_length_fraction(double fraction)
+{
+ _LLstacktoobig_stack_length = (long)(MAX_STACK_SIZE * fraction);
+}
+
+char LL_stack_too_big_slowpath(long current)
+{
+ long diff, max_stack_size;
+ char *baseptr, *curptr = (char*)current;
+
+ /* The stack_end variable is updated to match the current value
+ if it is still 0 or if we later find a 'curptr' position
+ that is above it. The real stack_end pointer is stored in
+ thread-local storage, but we try to minimize its overhead by
+ keeping a local copy in _LLstacktoobig_stack_end. */
+
+ if (_LLstacktoobig_stack_end == NULL) {
+ /* not initialized */
+ /* XXX We assume that initialization is performed early,
+ when there is still only one thread running. This
+ allows us to ignore race conditions here */
+ char *errmsg = RPyThreadStaticTLS_Create(&end_tls_key);
+ if (errmsg) {
+ /* XXX should we exit the process? */
+ fprintf(stderr, "Internal PyPy error: %s\n", errmsg);
+ return 1;
+ }
+ }
+
+ baseptr = (char *) RPyThreadStaticTLS_Get(end_tls_key);
+ max_stack_size = _LLstacktoobig_stack_length;
+ if (baseptr == NULL) {
+ /* first time we see this thread */
+ }
+ else {
+ diff = baseptr - curptr;
+ if (((unsigned long)diff) <= (unsigned long)max_stack_size) {
+ /* within bounds, probably just had a thread switch */
+ _LLstacktoobig_stack_end = baseptr;
+ return 0;
+ }
+ if (((unsigned long)-diff) <= (unsigned long)max_stack_size) {
+ /* stack underflowed: the initial estimation of
+ the stack base must be revised */
+ }
+ else { /* stack overflow (probably) */
+ return _LLstacktoobig_report_error;
+ }
+ }
+
+ /* update the stack base pointer to the current value */
+ baseptr = curptr;
+ RPyThreadStaticTLS_Set(end_tls_key, baseptr);
+ _LLstacktoobig_stack_end = baseptr;
+ return 0;
+}
diff --git a/pypy/translator/c/src/stack.h b/pypy/translator/c/src/stack.h
--- a/pypy/translator/c/src/stack.h
+++ b/pypy/translator/c/src/stack.h
@@ -2,15 +2,6 @@
/************************************************************/
/*** C header subsection: stack operations ***/
-#ifndef MAX_STACK_SIZE
-# define MAX_STACK_SIZE (3 << 18) /* 768 kb */
-#endif
-
-/* This include must be done in any case to initialise
- * the header dependencies early (winsock2, before windows.h).
- * It is needed to have RPyThreadStaticTLS, too. */
-#include "thread.h"
-
extern char *_LLstacktoobig_stack_end;
extern long _LLstacktoobig_stack_length;
extern char _LLstacktoobig_report_error;
@@ -19,13 +10,13 @@
void LL_stack_set_length_fraction(double);
/* some functions referenced from pypy.rlib.rstack */
-long LL_stack_get_end() { return (long)_LLstacktoobig_stack_end; }
-long LL_stack_get_length() { return (long)_LLstacktoobig_stack_length; }
-long LL_stack_get_end_adr() { return (long)&_LLstacktoobig_stack_end; }
/* JIT */
-long LL_stack_get_length_adr() { return (long)&_LLstacktoobig_stack_length;
}/* JIT */
+long LL_stack_get_end();
+long LL_stack_get_length();
+long LL_stack_get_end_adr();
+long LL_stack_get_length_adr();
-void LL_stack_criticalcode_start() { _LLstacktoobig_report_error = 0; }
-void LL_stack_criticalcode_stop() { _LLstacktoobig_report_error = 1; }
+void LL_stack_criticalcode_start();
+void LL_stack_criticalcode_stop();
#ifdef __GNUC__
@@ -33,73 +24,3 @@
#else
# define PYPY_INHIBIT_TAIL_CALL() /* add hints for other compilers here */
#endif
-
-
-#ifndef PYPY_NOT_MAIN_FILE
-#include <stdio.h>
-
-/* the current stack is in the interval [end-length:end]. We assume a
- stack that grows downward here. */
-char *_LLstacktoobig_stack_end = NULL;
-long _LLstacktoobig_stack_length = MAX_STACK_SIZE;
-char _LLstacktoobig_report_error = 1;
-static RPyThreadStaticTLS end_tls_key;
-
-void LL_stack_set_length_fraction(double fraction)
-{
- _LLstacktoobig_stack_length = (long)(MAX_STACK_SIZE * fraction);
-}
-
-char LL_stack_too_big_slowpath(long current)
-{
- long diff, max_stack_size;
- char *baseptr, *curptr = (char*)current;
-
- /* The stack_end variable is updated to match the current value
- if it is still 0 or if we later find a 'curptr' position
- that is above it. The real stack_end pointer is stored in
- thread-local storage, but we try to minimize its overhead by
- keeping a local copy in _LLstacktoobig_stack_end. */
-
- if (_LLstacktoobig_stack_end == NULL) {
- /* not initialized */
- /* XXX We assume that initialization is performed early,
- when there is still only one thread running. This
- allows us to ignore race conditions here */
- char *errmsg = RPyThreadStaticTLS_Create(&end_tls_key);
- if (errmsg) {
- /* XXX should we exit the process? */
- fprintf(stderr, "Internal PyPy error: %s\n", errmsg);
- return 1;
- }
- }
-
- baseptr = (char *) RPyThreadStaticTLS_Get(end_tls_key);
- max_stack_size = _LLstacktoobig_stack_length;
- if (baseptr == NULL) {
- /* first time we see this thread */
- }
- else {
- diff = baseptr - curptr;
- if (((unsigned long)diff) <= (unsigned long)max_stack_size) {
- /* within bounds, probably just had a thread switch */
- _LLstacktoobig_stack_end = baseptr;
- return 0;
- }
- if (((unsigned long)-diff) <= (unsigned long)max_stack_size) {
- /* stack underflowed: the initial estimation of
- the stack base must be revised */
- }
- else { /* stack overflow (probably) */
- return _LLstacktoobig_report_error;
- }
- }
-
- /* update the stack base pointer to the current value */
- baseptr = curptr;
- RPyThreadStaticTLS_Set(end_tls_key, baseptr);
- _LLstacktoobig_stack_end = baseptr;
- return 0;
-}
-
-#endif
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
@@ -90,10 +90,10 @@
elif isinstance(value, llmemory.GCHeaderOffset):
return '0'
elif isinstance(value, llmemory.CompositeOffset):
- assert len(value.offsets) == 2
- offset1, offset2 = value.offsets
- return 'add(i64 {}, i64 {})'.format(self.repr_value(offset1),
- self.repr_value(offset2))
+ x = self.repr_value(value.offsets[0])
+ for offset in value.offsets[1:]:
+ x = 'add(i64 {}, i64 {})'.format(x, self.repr_value(offset))
+ return x
elif isinstance(value, llmemory.AddressOffset):
indices = []
to = self.add_offset_indices(indices, value)
@@ -105,7 +105,7 @@
', '.join(indices))
elif isinstance(value, llgroup.GroupMemberOffset):
grpptr = get_repr(value.grpptr)
- grpptr.V
+ grpptr.type_.to.write_group(grpptr.value._obj)
member = get_repr(value.member)
return ('ptrtoint({member.T} getelementptr({grpptr.T} null, '
'i64 0, i32 {value.index}) to i32)').format(**locals())
@@ -129,15 +129,22 @@
if not indices:
indices.append('i64 0')
if isinstance(offset, llmemory.FieldOffset):
+ type_ = database.get_type(offset.TYPE)
indices.append('i32 {}'.format(
- offset.TYPE._names_without_voids().index(offset.fldname)))
+ type_.fldnames_wo_voids.index(offset.fldname)))
return offset.TYPE._flds[offset.fldname]
if isinstance(offset, llmemory.ArrayLengthOffset):
- indices.append('i32 0')
+ if offset.TYPE._gckind == 'gc':
+ indices.append('i32 1')
+ else:
+ indices.append('i32 0')
return lltype.Signed
if isinstance(offset, llmemory.ArrayItemsOffset):
if not offset.TYPE._hints.get("nolength", False):
- indices.append('i32 1')
+ if offset.TYPE._gckind == 'gc':
+ indices.append('i32 2')
+ else:
+ indices.append('i32 1')
return lltype.FixedSizeArray(offset.TYPE.OF, 0)
raise NotImplementedError
@@ -238,6 +245,7 @@
LLVMVoid = VoidType()
LLVMSigned = IntegralType(8, False)
LLVMUnsigned = IntegralType(8, True)
+LLVMShort = IntegralType(4, False)
LLVMChar = CharType(1)
LLVMUniChar = CharType(4)
LLVMBool = BoolType()
@@ -312,19 +320,20 @@
class StructType(Type):
- def setup(self, name, fields):
+ def setup(self, name, fields, is_gc=False):
self.name = name
+ self.is_gc = is_gc
+ if is_gc:
+ fields = database.genllvm.gcpolicy.get_gc_fields() + fields
self.fields = fields
- self.fldnames_without_voids = zip(*fields)[1]
+ self.fldnames_wo_voids = [f for t, f in fields if t is not LLVMVoid]
self.varsize = fields[-1][0].varsize
self.size_variants = {}
def setup_from_lltype(self, db, type_):
- self.name = '%struct.' + type_._name
- self.fields = [(db.get_type(type_._flds[f]), f) for f in type_._names]
- self.fldnames_without_voids = type_._names_without_voids()
- self.varsize = self.fields[-1][0].varsize
- self.size_variants = {}
+ fields = [(db.get_type(type_._flds[f]), f) for f in type_._names]
+ is_gc = type_._gckind == 'gc' and type_._first_struct() == (None, None)
+ self.setup('%struct.' + type_._name, fields, is_gc)
def repr_type(self, extra_len=None):
if extra_len not in self.size_variants:
@@ -335,7 +344,7 @@
else:
name = self.name
self.size_variants[extra_len] = name = database.unique_name(name)
- lastname = self.fldnames_without_voids[-1]
+ lastname = self.fldnames_wo_voids[-1]
tmp = (' {semicolon}{fldtype}{comma} ; {fldname}\n'.format(
semicolon=';' if fldtype is LLVMVoid else '',
fldtype=fldtype.repr_type(extra_len),
@@ -346,6 +355,8 @@
return self.size_variants[extra_len]
def is_zero(self, value):
+ if self.is_gc:
+ return False
return all(ft.is_zero(getattr(value, fn)) for ft, fn in self.fields)
def get_extra_len(self, value):
@@ -355,19 +366,24 @@
def repr_value(self, value, extra_len=None):
if self.is_zero(value):
return 'zeroinitializer'
- lastname = self.fldnames_without_voids[-1]
+ if self.is_gc:
+ data = database.genllvm.gcpolicy.get_gc_field_values(value)
+ data.extend(getattr(value, fn) for _, fn in self.fields[1:])
+ else:
+ data = [getattr(value, fn) for _, fn in self.fields]
+ lastname = self.fldnames_wo_voids[-1]
tmp = (' {semicolon}{fldtype} {fldvalue}{comma} ; {fldname}'.format(
semicolon=';' if fldtype is LLVMVoid else '',
fldtype=fldtype.repr_type(extra_len),
- fldvalue=fldtype.repr_value(getattr(value, fldname),
- extra_len).replace('\n', '\n '),
+ fldvalue=fldtype.repr_value(fldvalue, extra_len)
+ .replace('\n', '\n '),
comma=',' if fldname is not lastname else '',
fldname=fldname)
- for fldtype, fldname in self.fields)
+ for (fldtype, fldname), fldvalue in zip(self.fields, data))
return '{{\n{}\n}}'.format('\n'.join(tmp))
def add_indices(self, gep, attr):
- index = self.fldnames_without_voids.index(attr.value)
+ index = self.fldnames_wo_voids.index(attr.value)
gep.add_field_index(index)
return self.fields[index][0]
@@ -466,10 +482,14 @@
self.len = value.getlength()
self.items = value
+ def _parentstructure(self):
+ return self.items
+
class ArrayType(Type):
varsize = True
- def setup(self, of):
+ def setup(self, of, is_gc=False):
+ self.is_gc = is_gc
tmp = '%array_of_' + of.repr_type().lstrip('%').replace('*', '_ptr')\
.replace('[', '_')\
.replace(']', '_')\
@@ -479,11 +499,11 @@
self.bare_array_type = BareArrayType()
self.bare_array_type.setup(of, None)
self.struct_type = StructType()
- self.struct_type.setup(
- tmp, [(LLVMSigned, 'len'), (self.bare_array_type, 'items')])
+ fields = [(LLVMSigned, 'len'), (self.bare_array_type, 'items')]
+ self.struct_type.setup(tmp, fields, is_gc)
def setup_from_lltype(self, db, type_):
- self.setup(db.get_type(type_.OF))
+ self.setup(db.get_type(type_.OF), type_._gckind == 'gc')
def repr_type(self, extra_len=None):
return self.struct_type.repr_type(extra_len)
@@ -501,7 +521,10 @@
return self.struct_type.repr_type_and_value(ArrayHelper(value))
def add_indices(self, gep, index):
- gep.add_field_index(1)
+ if self.is_gc:
+ gep.add_field_index(2)
+ else:
+ gep.add_field_index(1)
return self.bare_array_type.add_indices(gep, index)
@@ -510,11 +533,21 @@
class GroupType(Type):
+ def __init__(self):
+ self.written = None
+
def setup_from_lltype(self, db, type_):
self.typestr = '%group_' + type_.name
def repr_ref(self, ptr_type, obj):
- groupname = ptr_type.refs[obj] = '@group_' + obj.name
+ ptr_type.refs[obj] = '@group_' + obj.name
+
+ def write_group(self, obj):
+ if self.written is not None:
+ assert self.written == obj.members
+ return
+ self.written = obj.members
+ groupname = '@group_' + obj.name
group = Group()
fields = []
for i, member in enumerate(obj.members):
@@ -602,6 +635,10 @@
elif isinstance(type_, lltype.FixedSizeArray):
class_ = BareArrayType
elif isinstance(type_, lltype.Struct):
+ if type_._hints.get('typeptr', False):
+ self.types[type_] = ret = StructType()
+ ret.setup('%struct.' + type_._name, [], True)
+ return ret
if type_._hints.get("union", False):
class_ = UnionType
else:
@@ -966,7 +1003,10 @@
if isinstance(type_, BareArrayType):
self.w('{result.V} = add i64 0, {type_.length}'.format(**locals()))
else:
- gep.add_field_index(0)
+ if type_.is_gc:
+ gep.add_field_index(1)
+ else:
+ gep.add_field_index(0)
t = self._tmp()
gep.assign(t)
self.w('{result.V} = load i64* {t.V}'.format(**locals()))
@@ -1089,9 +1129,13 @@
self.w('{result.V} = inttoptr i64 {t3.V} to {result.T}'
.format(**locals()))
- def op_gc_gettypeptr_group(self, result, v_obj, grpptr, skipoffset,
vtableinfo):
- # XXX
- self.w('{result.V} = inttoptr i64 0 to {result.T}'.format(**locals()))
+ def op_gc_gettypeptr_group(self, result, obj, grpptr, skipoffset, vtinfo):
+ t1 = self._tmp(LLVMSigned)
+ t2 = self._tmp(LLVMShort)
+ self._get_element(t1, obj, ConstantRepr(LLVMVoid, '_gc_header'),
+ ConstantRepr(LLVMVoid, vtinfo.value[2]))
+ self._cast(t2, t1)
+ self.op_get_next_group_member(result, grpptr, t2, skipoffset)
def op_gc_reload_possibly_moved(self, result, v_newaddr, v_targetvar):
pass
@@ -1142,11 +1186,69 @@
self.genllvm = genllvm
self.gctransformer = RawGCTransformer(genllvm.translator)
+ def transform_graph(self, graph):
+ self.gctransformer.transform_graph(graph)
+
class FrameworkGCPolicy(GCPolicy):
def __init__(self, genllvm):
self.genllvm = genllvm
self.gctransformer = FrameworkGCTransformer(genllvm.translator)
+ self._considered_constant = set()
+
+ def transform_graph(self, graph):
+ for block in graph.iterblocks():
+ for arg in block.inputargs:
+ if isinstance(arg, Constant):
+ self._consider_constant(arg.concretetype, arg.value)
+ for link in block.exits:
+ for arg in link.args:
+ if isinstance(arg, Constant):
+ self._consider_constant(arg.concretetype, arg.value)
+ for op in block.operations:
+ for arg in op.args:
+ if isinstance(arg, Constant):
+ self._consider_constant(arg.concretetype, arg.value)
+ self.gctransformer.transform_graph(graph)
+
+ def _consider_constant(self, type_, value):
+ if isinstance(type_, lltype.Ptr):
+ type_ = type_.TO
+ value = value._obj
+ if value is None:
+ return
+ if isinstance(type_, lltype.ContainerType):
+ if value in self._considered_constant:
+ return
+ self._considered_constant.add(value)
+ value = lltype.top_container(value)
+ type_ = lltype.typeOf(value)
+ if isinstance(type_, lltype.Struct):
+ for f in type_._names:
+ self._consider_constant(type_._flds[f], getattr(value, f))
+ self.gctransformer.consider_constant(type_, value)
+
+ def get_gc_fields(self):
+ return [(database.get_type(self.gctransformer.HDR), '_gc_header')]
+
+ def get_gc_field_values(self, obj):
+ obj = lltype.top_container(obj)
+ needs_hash = self.get_prebuilt_hash(obj) is not None
+ hdr = self.gctransformer.gc_header_for(obj, needs_hash)
+ return [hdr._obj]
+
+ # from c backend
+ def get_prebuilt_hash(self, obj):
+ # for prebuilt objects that need to have their hash stored and
+ # restored. Note that only structures that are StructNodes all
+ # the way have their hash stored (and not e.g. structs with var-
+ # sized arrays at the end). 'obj' must be the top_container.
+ TYPE = lltype.typeOf(obj)
+ if not isinstance(TYPE, lltype.GcStruct):
+ return None
+ if TYPE._is_varsize():
+ return None
+ return getattr(obj, '_hash_cache_', None)
class CTypesFuncWrapper(object):
@@ -1208,7 +1310,7 @@
def _to_ctype_StringRepr(self, repr_, ctype, value):
llvm_type = database.get_type(repr_.lowleveltype)
- arr = self._get_ctype(llvm_type.to, len(value))(0, (len(value), value))
+ arr = self._get_ctype(llvm_type.to, len(value))((0,), 0, (len(value),
value))
return ctypes.cast(ctypes.pointer(arr), ctype)
def _to_ctype(self, repr_, ctype, value):
@@ -1272,7 +1374,7 @@
hasattr(graph.returnblock.inputargs[0], 'concretetype')):
self.transformed_graphs.add(graph)
self.exctransformer.create_exception_handling(graph)
- self.gcpolicy.gctransformer.transform_graph(graph)
+ self.gcpolicy.transform_graph(graph)
remove_double_links(self.translator.annotator, graph)
def gen_source(self, entry_point):
@@ -1281,9 +1383,6 @@
self.entry_point = entry_point
self.base_path = udir.join(uniquemodulename('main'))
- for graph in self.translator.graphs:
- self.transform_graph(graph)
-
bk = self.translator.annotator.bookkeeper
ep_ptr = getfunctionptr(bk.getdesc(entry_point).getuniquegraph())
@@ -1299,6 +1398,14 @@
f.write('declare i8* @llvm.frameaddress(i32)\n')
database = Database(self, f)
+ for graph in self.translator.graphs:
+ self.transform_graph(graph)
+
+ f.write('%ctor = type { i32, void ()* }\n')
+ sr = get_repr(self.gcpolicy.gctransformer.frameworkgc_setup_ptr)
+ f.write('@llvm.global_ctors = appending global [1 x %ctor] '
+ '[%ctor {{ i32 65535, void ()* @{} }}]\n'.format(sr.V[1:]))
+
if self.standalone:
raise NotImplementedError
else:
@@ -1310,7 +1417,7 @@
def compile_module(self):
eci = ExternalCompilationInfo().merge(*self.ecis)
- eci = eci.convert_sources_to_files()
+ eci = eci.convert_sources_to_files(being_main=True)
cmdexec('clang -O2 -shared -fPIC {0}{1}{2}.ll -o {2}.so'.format(
''.join('-I{} '.format(ic) for ic in eci.include_dirs),
''.join(smf + ' ' for smf in eci.separate_module_files),
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
@@ -211,7 +211,7 @@
from pypy.config.pypyoption import get_pypy_config
config = get_pypy_config(translating=True)
config.translation.backendopt.raisingop2direct_call = True
- config.translation.gc = 'none'
+ config.translation.gc = 'minimark'
config.translation.simplifying = True
t = TranslationContext(config=config)
if argtypes is None:
@@ -225,6 +225,7 @@
gen_llvm = genllvm.GenLLVM(t, False)
if hasattr(self, 'include_also_eci'):
gen_llvm.ecis.append(self.include_also_eci)
+ del self.include_also_eci
gen_llvm.gen_source(func)
return gen_llvm.compile_module()
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit