from pypy.rpython.lltypesystem import lltype from pypy.translator.gensupp import NameManager # # use __slots__ declarations for node classes etc # possible to turn it off while refactoring, experimenting # USESLOTS = True PyObjPtr = lltype.Ptr(lltype.PyObject) def barebonearray(ARRAY): """Check if ARRAY is a 'simple' array type, i.e. doesn't need a length nor GC headers.""" return (ARRAY._hints.get('nolength', False) and ARRAY._gckind != 'gc' and ARRAY.OF is not lltype.Void) # # helpers # def cdecl(ctype, cname, is_thread_local=False): """ Produce a C declaration from a 'type template' and an identifier. The type template must contain a '@' sign at the place where the name should be inserted, according to the strange C syntax rules. """ # the (@) case is for functions, where if there is a plain (@) around # the function name, we don't need the very confusing parenthesis __thread = "" if is_thread_local: __thread = "__thread " return __thread + ctype.replace('(@)', '@').replace('@', cname).strip() def forward_cdecl(ctype, cname, standalone, is_thread_local=False): __thread = "" if is_thread_local: __thread = "__thread " cdecl_str = __thread + cdecl(ctype, cname) if standalone: return 'extern ' + cdecl_str else: return cdecl_str def somelettersfrom(s): upcase = [c for c in s if c.isupper()] if not upcase: upcase = [c for c in s.title() if c.isupper()] locase = [c for c in s if c.islower()] if locase and upcase: return ''.join(upcase).lower() else: return s[:2].lower() def is_pointer_to_forward_ref(T): if not isinstance(T, lltype.Ptr): return False return isinstance(T.TO, lltype.ForwardReference) def llvalue_from_constant(c): try: T = c.concretetype except AttributeError: T = PyObjPtr if T == PyObjPtr and not isinstance(c.value, lltype._ptr): return lltype.pyobjectptr(c.value) else: if T == lltype.Void: return None else: ACTUAL_TYPE = lltype.typeOf(c.value) # If the type is still uncomputed, we can't make this # check. Something else will blow up instead, probably # very confusingly. if not is_pointer_to_forward_ref(ACTUAL_TYPE): assert ACTUAL_TYPE == T return c.value class CNameManager(NameManager): def __init__(self, global_prefix='pypy_'): NameManager.__init__(self, global_prefix=global_prefix) # keywords cannot be reused. This is the C99 draft's list. self.make_reserved_names(''' auto enum restrict unsigned break extern return void case float short volatile char for signed while const goto sizeof _Bool continue if static _Complex default inline struct _Imaginary do int switch double long typedef else register union ''') def _char_repr(c): if c in '\\"': return '\\' + c if ' ' <= c < '\x7F': return c return '\\%03o' % ord(c) def _line_repr(s): return ''.join([_char_repr(c) for c in s]) def c_string_constant(s): '''Returns a " "-delimited string literal for C.''' lines = [] for i in range(0, len(s), 64): lines.append('"%s"' % _line_repr(s[i:i+64])) return '\n'.join(lines) def c_char_array_constant(s): '''Returns an initializer for a constant char[N] array, where N is exactly len(s). This is either a " "-delimited string or a { }-delimited array of small integers. ''' if s.endswith('\x00') and 1 < len(s) < 1024: # C++ is stricter than C: we can only use a " " literal # if the last character is NULL, because such a literal # always has an extra implicit NULL terminator. return c_string_constant(s[:-1]) else: lines = [] for i in range(0, len(s), 20): lines.append(','.join([str(ord(c)) for c in s[i:i+20]])) if len(lines) > 1: return '{\n%s}' % ',\n'.join(lines) else: return '{%s}' % ', '.join(lines) def gen_assignments(assignments): # Generate a sequence of assignments that is possibly reordered # to avoid clashes -- i.e. do the equivalent of a tuple assignment, # reading all sources first, writing all targets next, but optimized srccount = {} dest2src = {} for typename, dest, src in assignments: if src != dest: # ignore 'v=v;' srccount[src] = srccount.get(src, 0) + 1 dest2src[dest] = src, typename while dest2src: progress = False for dst in dest2src.keys(): if dst not in srccount: src, typename = dest2src.pop(dst) yield '%s = %s;' % (dst, src) srccount[src] -= 1 if not srccount[src]: del srccount[src] progress = True if not progress: # we are left with only pure disjoint cycles; break them while dest2src: dst, (src, typename) = dest2src.popitem() assert srccount[dst] == 1 startingpoint = dst tmpdecl = cdecl(typename, 'tmp') code = ['{ %s = %s;' % (tmpdecl, dst)] while src != startingpoint: code.append('%s = %s;' % (dst, src)) dst = src src, typename = dest2src.pop(dst) assert srccount[dst] == 1 code.append('%s = tmp; }' % (dst,)) yield ' '.join(code) # logging import py from pypy.tool.ansi_print import ansi_log log = py.log.Producer("c") py.log.setconsumer("c", ansi_log)