Commit 4bce9494 authored by Robert Bradshaw's avatar Robert Bradshaw

gcc branch prediction

For some reason, it actually makes it slower in some of the most common cases (now commented out). Why? It does help in others.
parent 08b3b0de
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# #
import Naming import Naming
import Options
from Pyrex.Utils import open_new_file from Pyrex.Utils import open_new_file
from PyrexTypes import py_object_type, typecast from PyrexTypes import py_object_type, typecast
...@@ -294,6 +295,10 @@ class CCodeWriter: ...@@ -294,6 +295,10 @@ class CCodeWriter:
doc_code, doc_code,
term)) term))
def put_error_if_neg(self, pos, value):
# return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) # TODO this path is almost _never_ taken, yet this macro makes is slower!
return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
def error_goto(self, pos): def error_goto(self, pos):
lbl = self.error_label lbl = self.error_label
self.use_label(lbl) self.use_label(lbl)
...@@ -305,6 +310,21 @@ class CCodeWriter: ...@@ -305,6 +310,21 @@ class CCodeWriter:
pos[1], pos[1],
lbl) lbl)
def error_goto_if(self, cond, pos):
if Options.gcc_branch_hints or 0: # TODO this path is almost _never_ taken, yet this macro makes is slower!
return "if (unlikely(%s)) %s" % (cond, self.error_goto(pos))
else:
return "if (%s) %s" % (cond, self.error_goto(pos))
def error_goto_if_null(self, cname, pos):
return self.error_goto_if("!%s" % cname, pos)
def error_goto_if_neg(self, cname, pos):
return self.error_goto_if("%s < 0" % cname, pos)
def error_goto_if_PyErr(self, pos):
return self.error_goto_if("PyErr_Occurred()", pos)
def lookup_filename(self, filename): def lookup_filename(self, filename):
try: try:
index = self.filename_table[filename] index = self.filename_table[filename]
......
This diff is collapsed.
...@@ -155,6 +155,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -155,6 +155,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# code.putln('#include "%s"' % filename) # code.putln('#include "%s"' % filename)
code.putln('') code.putln('')
code.put(Nodes.utility_function_predeclarations) code.put(Nodes.utility_function_predeclarations)
code.put(Nodes.branch_prediction_macros)
#if Options.intern_names: #if Options.intern_names:
# code.putln(Nodes.get_name_interned_predeclaration) # code.putln(Nodes.get_name_interned_predeclaration)
#else: #else:
...@@ -1207,13 +1208,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1207,13 +1208,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
objstruct = type.objstruct_cname objstruct = type.objstruct_cname
else: else:
objstruct = "struct %s" % type.objstruct_cname objstruct = "struct %s" % type.objstruct_cname
code.putln('%s = __Pyx_ImportType("%s", "%s", sizeof(%s)); if (!%s) %s' % ( code.putln('%s = __Pyx_ImportType("%s", "%s", sizeof(%s)); %s' % (
type.typeptr_cname, type.typeptr_cname,
type.module_name, type.module_name,
type.name, type.name,
objstruct, objstruct,
type.typeptr_cname, code.error_goto_if_null(type.typeptr_cname, pos)))
code.error_goto(pos)))
self.use_type_import_utility_code(env) self.use_type_import_utility_code(env)
if type.vtabptr_cname: if type.vtabptr_cname:
code.putln( code.putln(
......
...@@ -744,7 +744,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -744,7 +744,7 @@ class CFuncDefNode(FuncDefNode):
typeptr_cname = arg.type.typeptr_cname typeptr_cname = arg.type.typeptr_cname
arg_code = "((PyObject *)%s)" % arg.cname arg_code = "((PyObject *)%s)" % arg.cname
code.putln( code.putln(
'if (!__Pyx_ArgTypeTest(%s, %s, %d, "%s")) %s' % ( 'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s"))) %s' % (
arg_code, arg_code,
typeptr_cname, typeptr_cname,
not arg.not_none, not arg.not_none,
...@@ -1029,7 +1029,7 @@ class DefNode(FuncDefNode): ...@@ -1029,7 +1029,7 @@ class DefNode(FuncDefNode):
Naming.kwdlist_cname] + arg_addrs Naming.kwdlist_cname] + arg_addrs
pt_argstring = string.join(pt_arglist, ", ") pt_argstring = string.join(pt_arglist, ", ")
code.put( code.put(
'if (!PyArg_ParseTupleAndKeywords(%s)) ' % 'if (unlikely(!PyArg_ParseTupleAndKeywords(%s))) ' %
pt_argstring) pt_argstring)
error_return_code = "return %s;" % self.error_value() error_return_code = "return %s;" % self.error_value()
if has_starargs: if has_starargs:
...@@ -1102,11 +1102,11 @@ class DefNode(FuncDefNode): ...@@ -1102,11 +1102,11 @@ class DefNode(FuncDefNode):
new_type = arg.type new_type = arg.type
func = new_type.from_py_function func = new_type.from_py_function
if func: if func:
code.putln("%s = %s(%s); if (PyErr_Occurred()) %s" % ( code.putln("%s = %s(%s); %s" % (
arg.entry.cname, arg.entry.cname,
func, func,
arg.hdr_cname, arg.hdr_cname,
code.error_goto(arg.pos))) code.error_goto_if_PyErr(arg.pos)))
else: else:
error(arg.pos, error(arg.pos,
"Cannot convert Python object argument to type '%s'" "Cannot convert Python object argument to type '%s'"
...@@ -1116,12 +1116,11 @@ class DefNode(FuncDefNode): ...@@ -1116,12 +1116,11 @@ class DefNode(FuncDefNode):
old_type = arg.hdr_type old_type = arg.hdr_type
func = old_type.to_py_function func = old_type.to_py_function
if func: if func:
code.putln("%s = %s(%s); if (!%s) %s" % ( code.putln("%s = %s(%s); %s" % (
arg.entry.cname, arg.entry.cname,
func, func,
arg.hdr_cname, arg.hdr_cname,
arg.entry.cname, code.error_goto_if_null(arg.entry.cname, arg.pos)))
code.error_goto(arg.pos)))
else: else:
error(arg.pos, error(arg.pos,
"Cannot convert argument of type '%s' to Python object" "Cannot convert argument of type '%s' to Python object"
...@@ -1141,7 +1140,7 @@ class DefNode(FuncDefNode): ...@@ -1141,7 +1140,7 @@ class DefNode(FuncDefNode):
typeptr_cname = arg.type.typeptr_cname typeptr_cname = arg.type.typeptr_cname
arg_code = "((PyObject *)%s)" % arg.entry.cname arg_code = "((PyObject *)%s)" % arg.entry.cname
code.putln( code.putln(
'if (!__Pyx_ArgTypeTest(%s, %s, %d, "%s")) %s' % ( 'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s"))) %s' % (
arg_code, arg_code,
typeptr_cname, typeptr_cname,
not arg.not_none, not arg.not_none,
...@@ -1623,13 +1622,12 @@ class InPlaceAssignmentNode(AssignmentNode): ...@@ -1623,13 +1622,12 @@ class InPlaceAssignmentNode(AssignmentNode):
self.dup.generate_result_code(code) self.dup.generate_result_code(code)
if self.lhs.type.is_pyobject: if self.lhs.type.is_pyobject:
code.putln( code.putln(
"%s = %s(%s, %s); if (!%s) %s" % ( "%s = %s(%s, %s); %s" % (
self.result.result_code, self.result.result_code,
self.py_operation_function(), self.py_operation_function(),
self.dup.py_result(), self.dup.py_result(),
self.rhs.py_result(), self.rhs.py_result(),
self.result.py_result(), code.error_goto_if_null(self.result.py_result(), self.pos)))
code.error_goto(self.pos)))
self.rhs.generate_disposal_code(code) self.rhs.generate_disposal_code(code)
self.dup.generate_disposal_code(code) self.dup.generate_disposal_code(code)
self.lhs.generate_assignment_code(self.result, code) self.lhs.generate_assignment_code(self.result, code)
...@@ -1910,7 +1908,7 @@ class AssertStatNode(StatNode): ...@@ -1910,7 +1908,7 @@ class AssertStatNode(StatNode):
if self.value: if self.value:
self.value.generate_evaluation_code(code) self.value.generate_evaluation_code(code)
code.putln( code.putln(
"if (!%s) {" % "if (unlikely(!%s)) {" %
self.cond.result_code) self.cond.result_code)
if self.value: if self.value:
code.putln( code.putln(
...@@ -2563,22 +2561,20 @@ class FromImportStatNode(StatNode): ...@@ -2563,22 +2561,20 @@ class FromImportStatNode(StatNode):
if Options.intern_names: if Options.intern_names:
for cname, target in self.interned_items: for cname, target in self.interned_items:
code.putln( code.putln(
'%s = PyObject_GetAttr(%s, %s); if (!%s) %s' % ( '%s = PyObject_GetAttr(%s, %s); %s' % (
self.item.result_code, self.item.result_code,
self.module.py_result(), self.module.py_result(),
cname, cname,
self.item.result_code, code.error_goto_if_null(self.item.result_code, self.pos)))
code.error_goto(self.pos)))
target.generate_assignment_code(self.item, code) target.generate_assignment_code(self.item, code)
else: else:
for name, target in self.items: for name, target in self.items:
code.putln( code.putln(
'%s = PyObject_GetAttrString(%s, "%s"); if (!%s) %s' % ( '%s = PyObject_GetAttrString(%s, "%s"); %s' % (
self.item.result_code, self.item.result_code,
self.module.py_result(), self.module.py_result(),
name, name,
self.item.result_code, code.error_goto_if_null(self.item.result_code, self.pos)))
code.error_goto(self.pos)))
target.generate_assignment_code(self.item, code) target.generate_assignment_code(self.item, code)
self.module.generate_disposal_code(code) self.module.generate_disposal_code(code)
...@@ -2602,6 +2598,19 @@ static inline int __Pyx_PyObject_IsTrue(PyObject* x) { ...@@ -2602,6 +2598,19 @@ static inline int __Pyx_PyObject_IsTrue(PyObject* x) {
""" """
if Options.gcc_branch_hints:
branch_prediction_macros = \
"""
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
"""
else:
branch_prediction_macros = \
"""
#define likely(x) (x)
#define unlikely(x) (x)
"""
#get_name_predeclaration = \ #get_name_predeclaration = \
#"static PyObject *__Pyx_GetName(PyObject *dict, char *name); /*proto*/" #"static PyObject *__Pyx_GetName(PyObject *dict, char *name); /*proto*/"
......
...@@ -6,3 +6,4 @@ intern_names = 1 # Intern global variable and attribute names ...@@ -6,3 +6,4 @@ intern_names = 1 # Intern global variable and attribute names
cache_builtins = 1 # Perform lookups on builtin names only once cache_builtins = 1 # Perform lookups on builtin names only once
embed_pos_in_docstring = 0 embed_pos_in_docstring = 0
gcc_branch_hints = 1
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment