Patch #424475: Speed-up tp_compare usage, by special-casing the common
case of objects with equal types which support tp_compare. Give
type objects a tp_compare function.
Also add c<0 tests before a few PyErr_Occurred tests.
diff --git a/Objects/object.c b/Objects/object.c
index 8462971..680a7d4 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -477,16 +477,6 @@
 	if (PyInstance_Check(w))
 		return (*w->ob_type->tp_compare)(v, w);
 
-	/* If the types are equal, don't bother with coercions etc. */
-	if (v->ob_type == w->ob_type) {
-		if ((f = v->ob_type->tp_compare) == NULL)
-			return 2;
-		c = (*f)(v, w);
-		if (PyErr_Occurred())
-			return -2;
-		return c < 0 ? -1 : c > 0 ? 1 : 0;
-	}
-
 	/* Try coercion; if it fails, give up */
 	c = PyNumber_CoerceEx(&v, &w);
 	if (c < 0)
@@ -499,7 +489,7 @@
 		c = (*f)(v, w);
 		Py_DECREF(v);
 		Py_DECREF(w);
-		if (PyErr_Occurred())
+		if (c < 0 && PyErr_Occurred())
 			return -2;
 		return c < 0 ? -1 : c > 0 ? 1 : 0;
 	}
@@ -509,7 +499,7 @@
 		c = (*f)(w, v); /* swapped! */
 		Py_DECREF(v);
 		Py_DECREF(w);
-		if (PyErr_Occurred())
+		if (c < 0 && PyErr_Occurred())
 			return -2;
 		return c < 0 ? 1 : c > 0 ? -1 : 0; /* negated! */
 	}
@@ -590,12 +580,18 @@
    -1 if v < w;
     0 if v == w;
     1 if v > w;
+   If the object implements a tp_compare function, it returns
+   whatever this function returns (whether with an exception or not).
 */
 static int
 do_cmp(PyObject *v, PyObject *w)
 {
 	int c;
+	cmpfunc f;
 
+	if (v->ob_type == w->ob_type
+	    && (f = v->ob_type->tp_compare) != NULL)
+		return (*f)(v, w);
 	c = try_rich_to_3way_compare(v, w);
 	if (c < 2)
 		return c;
@@ -760,16 +756,9 @@
 }
 
 static PyObject *
-try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
+convert_3way_to_object(int op, int c)
 {
-	int c;
 	PyObject *result;
-
-	c = try_3way_compare(v, w);
-	if (c >= 2)
-		c = default_3way_compare(v, w);
-	if (c <= -2)
-		return NULL;
 	switch (op) {
 	case Py_LT: c = c <  0; break;
 	case Py_LE: c = c <= 0; break;
@@ -782,11 +771,51 @@
 	Py_INCREF(result);
 	return result;
 }
+	
+
+static PyObject *
+try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
+{
+	int c;
+
+	c = try_3way_compare(v, w);
+	if (c >= 2)
+		c = default_3way_compare(v, w);
+	if (c <= -2)
+		return NULL;
+	return convert_3way_to_object(op, c);
+}
 
 static PyObject *
 do_richcmp(PyObject *v, PyObject *w, int op)
 {
 	PyObject *res;
+	cmpfunc f;
+
+	/* If the types are equal, don't bother with coercions etc. 
+	   Instances are special-cased in try_3way_compare, since
+	   a result of 2 does *not* mean one value being greater
+	   than the other. */
+	if (v->ob_type == w->ob_type
+	    && (f = v->ob_type->tp_compare) != NULL
+	    && !PyInstance_Check(v)) {
+		int c;
+		richcmpfunc f1;
+		if ((f1 = RICHCOMPARE(v->ob_type)) != NULL) {
+			/* If the type has richcmp, try it first.
+			   try_rich_compare would try it two-sided,
+			   which is not needed since we've a single
+			   type only. */
+			res = (*f1)(v, w, op);
+			if (res != Py_NotImplemented)
+				return res;
+			Py_DECREF(res);
+		}
+		c = (*f)(v, w);
+		if (c < 0 && PyErr_Occurred())
+			return NULL;
+		return convert_3way_to_object(op, c);
+	}
 
 	res = try_rich_compare(v, w, op);
 	if (res != Py_NotImplemented)
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index c96c0aa..795714d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -23,6 +23,16 @@
 	return NULL;
 }
 
+static int
+type_compare(PyObject *v, PyObject *w)
+{
+	/* This is called with type objects only. So we
+	   can just compare the addresses. */
+	Py_uintptr_t vv = (Py_uintptr_t)v;
+	Py_uintptr_t ww = (Py_uintptr_t)w;
+	return (vv < ww) ? -1 : (vv > ww) ? 1 : 0;
+}
+
 static PyObject *
 type_repr(PyTypeObject *v)
 {
@@ -41,12 +51,12 @@
 	0,			/*tp_print*/
 	(getattrfunc)type_getattr, /*tp_getattr*/
 	0,			/*tp_setattr*/
-	0,			/*tp_compare*/
+	type_compare,		/*tp_compare*/
 	(reprfunc)type_repr,	/*tp_repr*/
 	0,			/*tp_as_number*/
 	0,			/*tp_as_sequence*/
 	0,			/*tp_as_mapping*/
-	0,			/*tp_hash*/
+	_Py_HashPointer,	/*tp_hash*/
 	0,			/*tp_call*/
 	0,			/*tp_str*/
 	0,			/*tp_xxx1*/