From: Robert Bradshaw Date: Thu, 11 Oct 2007 08:33:28 +0000 (-0700) Subject: Interned integer constants, created at module load time. X-Git-Tag: 0.9.6.14~29^2~122 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=9c1bf4c52dd1dbb466e0683997759832bf3b0633;p=cython.git Interned integer constants, created at module load time. For example, in the SAGE source we have 1158 PyInt_FromLong(0) 776 PyInt_FromLong(1) 258 PyInt_FromLong(2) 33 PyInt_FromLong(3) 21 PyInt_FromLong(10) and a thousand or so others... Who knows how many of these are in loops too. --- diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index b0526ef4..4a234c8c 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -596,6 +596,24 @@ class CharNode(ConstNode): class IntNode(ConstNode): type = PyrexTypes.c_long_type + def analyse_types(self, env): + self.entry = env.get_py_num(self.value) + + def coerce_to(self, dst_type, env): + # Arrange for a Python version of the string to be pre-allocated + # when coercing to a Python type. + if dst_type.is_pyobject: + self.type = PyrexTypes.py_object_type + # We still need to perform normal coerce_to processing on the + # result, because we might be coercing to an extension type, + # in which case a type test node will be needed. + return ConstNode.coerce_to(self, dst_type, env) + + def calculate_result_code(self): + if self.type.is_pyobject: + return self.entry.cname + else: + return str(self.value) class FloatNode(ConstNode): type = PyrexTypes.c_double_type @@ -2323,6 +2341,8 @@ unop_node_classes = { def unop_node(pos, operator, operand): # Construct unnop node of appropriate class for # given operator. + if isinstance(operand, IntNode) and operator == '-': + return IntNode(pos = operand.pos, value = -int(operand.value)) return unop_node_classes[operator](pos, operator = operator, operand = operand) @@ -2744,7 +2764,7 @@ class BoolBinopNode(ExprNode): if self.type.is_pyobject: test_result = self.temp_bool.result_code code.putln( - "%s = PyObject_IsTrue(%s); %s" % ( + "%s = __Pyx_PyObject_IsTrue(%s); %s" % ( test_result, self.operand1.py_result(), code.error_goto_if_neg(test_result, self.pos))) diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 47acf235..4aeff24f 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -125,6 +125,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("") code.putln("/* Implementation of %s */" % env.qualified_name) self.generate_const_definitions(env, code) + self.generate_interned_num_decls(env, code) self.generate_interned_name_decls(env, code) self.generate_py_string_decls(env, code) self.generate_cached_builtins_decls(env, code) @@ -1238,6 +1239,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.error_goto(self.pos))); def generate_intern_code(self, env, code): + for entry in env.pynum_entries: + code.putln("%s = PyInt_FromLong(%s); %s;" % ( + entry.cname, + entry.init, + code.error_goto_if_null(entry.cname, self.pos))) if env.intern_map: env.use_utility_code(Nodes.init_intern_tab_utility_code); code.putln( diff --git a/Cython/Compiler/Naming.py b/Cython/Compiler/Naming.py index 6ea000f2..152edb07 100644 --- a/Cython/Compiler/Naming.py +++ b/Cython/Compiler/Naming.py @@ -21,6 +21,7 @@ pymethdef_prefix = pyrex_prefix + "mdef_" methtab_prefix = pyrex_prefix + "methods_" memtab_prefix = pyrex_prefix + "members_" interned_prefix = pyrex_prefix + "n_" +interned_num_prefix = pyrex_prefix + "num_" objstruct_prefix = pyrex_prefix + "obj_" typeptr_prefix = pyrex_prefix + "ptype_" prop_set_prefix = pyrex_prefix + "setprop_" diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 6ba8f543..8c20c1c2 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -115,6 +115,18 @@ class BlockNode: for entry in entries: code.putln( "static PyObject *%s;" % entry.pystring_cname) + + def generate_interned_num_decls(self, env, code): + # Flush accumulated interned nums from the global scope + # and generate declarations for them. + genv = env.global_scope() + entries = genv.interned_nums + if entries: + code.putln("") + for entry in entries: + code.putln( + "static PyObject *%s;" % entry.cname) + del entries[:] def generate_cached_builtins_decls(self, env, code): entries = env.builtin_scope().undeclared_cached_entries @@ -556,6 +568,7 @@ class FuncDefNode(StatNode, BlockNode): # Code for nested function definitions would go here # if we supported them, which we probably won't. # ----- Top-level constants used by this function + self.generate_interned_num_decls(lenv, code) self.generate_interned_name_decls(lenv, code) self.generate_py_string_decls(lenv, code) self.generate_cached_builtins_decls(lenv, code) diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index b9a97cf3..f18ce2b5 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -123,6 +123,7 @@ class Scope: # free_temp_entries [Entry] Temp variables currently unused # temp_counter integer Counter for naming temp vars # cname_to_entry {string : Entry} Temp cname to entry mapping + # int_to_entry {int : Entry} Temp cname to entry mapping # pow_function_used boolean The C pow() function is used # return_type PyrexType or None Return type of function owning scope # is_py_class_scope boolean Is a Python class scope @@ -169,6 +170,7 @@ class Scope: self.cname_to_entry = {} self.pow_function_used = 0 self.string_to_entry = {} + self.num_to_entry = {} self.pystring_entries = [] def __str__(self): @@ -394,6 +396,28 @@ class Scope: entry.pystring_cname = entry.cname + "p" self.pystring_entries.append(entry) self.global_scope().all_pystring_entries.append(entry) + + def add_py_num(self, value): + # Add an entry for an int constant. + cname = "%s%s" % (Naming.interned_num_prefix, value) + cname = cname.replace('-', 'neg_').replace('.','_') + entry = Entry("", cname, c_long_type, init = value) + entry.used = 1 + entry.is_interned = 1 + self.const_entries.append(entry) + self.interned_nums.append(entry) + return entry + + def get_py_num(self, value): + # Get entry for int constant. Returns an existing + # one if possible, otherwise creates a new one. + genv = self.global_scope() + entry = genv.num_to_entry.get(value) + if not entry: + entry = genv.add_py_num(value) + genv.num_to_entry[value] = entry + genv.pynum_entries.append(entry) + return entry def new_const_cname(self): # Create a new globally-unique name for a constant. @@ -608,8 +632,10 @@ class ModuleScope(Scope): self.cimported_modules = [] self.intern_map = {} self.interned_names = [] + self.interned_nums = [] self.all_pystring_entries = [] self.types_imported = {} + self.pynum_entries = [] def qualifying_scope(self): return self.parent_module