Skip to content

Instantly share code, notes, and snippets.

@benhoyt
Created June 27, 2017 20:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benhoyt/e5ba19afe7b869fd743c1c39fc2afdf8 to your computer and use it in GitHub Desktop.
Save benhoyt/e5ba19afe7b869fd743c1c39fc2afdf8 to your computer and use it in GitHub Desktop.
Add COMPARE_IS_NONE opcode to CPython for performance
b66bbc41ce52efe667af0ba47a6098216b758236
diff --git a/Include/opcode.h b/Include/opcode.h
index 99c3b0ef81..dceedc662a 100644
--- a/Include/opcode.h
+++ b/Include/opcode.h
@@ -12,6 +12,8 @@ extern "C" {
#define ROT_THREE 3
#define DUP_TOP 4
#define DUP_TOP_TWO 5
+#define COMPARE_IS_NONE 6
+#define COMPARE_IS_NOT_NONE 7
#define NOP 9
#define UNARY_POSITIVE 10
#define UNARY_NEGATIVE 11
diff --git a/Lib/opcode.py b/Lib/opcode.py
index dffb38c314..53fac107c1 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -60,6 +60,8 @@ def_op('ROT_TWO', 2)
def_op('ROT_THREE', 3)
def_op('DUP_TOP', 4)
def_op('DUP_TOP_TWO', 5)
+def_op('COMPARE_IS_NONE', 6)
+def_op('COMPARE_IS_NOT_NONE', 7)
def_op('NOP', 9)
def_op('UNARY_POSITIVE', 10)
diff --git a/Python/ceval.c b/Python/ceval.c
index 3243a4f8a0..40d697c193 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1235,6 +1235,28 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
FAST_DISPATCH();
}
+ TARGET(COMPARE_IS_NONE) {
+ PyObject *top = TOP();
+ PyObject *res = (top == Py_None) ? Py_True : Py_False;
+ Py_INCREF(res);
+ Py_DECREF(top);
+ SET_TOP(res);
+ PREDICT(POP_JUMP_IF_FALSE);
+ PREDICT(POP_JUMP_IF_TRUE);
+ DISPATCH();
+ }
+
+ TARGET(COMPARE_IS_NOT_NONE) {
+ PyObject *top = TOP();
+ PyObject *res = (top != Py_None) ? Py_True : Py_False;
+ Py_INCREF(res);
+ Py_DECREF(top);
+ SET_TOP(res);
+ PREDICT(POP_JUMP_IF_FALSE);
+ PREDICT(POP_JUMP_IF_TRUE);
+ DISPATCH();
+ }
+
TARGET(UNARY_POSITIVE) {
PyObject *value = TOP();
PyObject *res = PyNumber_Positive(value);
diff --git a/Python/compile.c b/Python/compile.c
index 280ddc39e3..8fc39d092e 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -867,6 +867,10 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
case DUP_TOP_TWO:
return 2;
+ case COMPARE_IS_NONE:
+ case COMPARE_IS_NOT_NONE:
+ return 0;
+
case UNARY_POSITIVE:
case UNARY_NEGATIVE:
case UNARY_NOT:
@@ -3419,6 +3423,24 @@ compiler_compare(struct compiler *c, expr_ty e)
VISIT(c, expr, e->v.Compare.left);
n = asdl_seq_LEN(e->v.Compare.ops);
assert(n > 0);
+
+ if (n == 1) {
+ cmpop_ty cmp = (cmpop_ty)asdl_seq_GET(e->v.Compare.ops, 0);
+ expr_ty exp = (expr_ty)asdl_seq_GET(e->v.Compare.comparators, 0);
+ if (exp->kind == NameConstant_kind && exp->v.NameConstant.value == Py_None) {
+ if (cmp == Is) {
+ ADDOP(c, COMPARE_IS_NONE);
+ return 1;
+ } else if (cmp == IsNot) {
+ ADDOP(c, COMPARE_IS_NOT_NONE);
+ return 1;
+ }
+ }
+ VISIT(c, expr, exp);
+ ADDOP_I(c, COMPARE_OP, cmpop(cmp));
+ return 1;
+ }
+
if (n > 1) {
cleanup = compiler_new_block(c);
if (cleanup == NULL)
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index 567f8723a6..d2156ca154 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -5,8 +5,8 @@ static void *opcode_targets[256] = {
&&TARGET_ROT_THREE,
&&TARGET_DUP_TOP,
&&TARGET_DUP_TOP_TWO,
- &&_unknown_opcode,
- &&_unknown_opcode,
+ &&TARGET_COMPARE_IS_NONE,
+ &&TARGET_COMPARE_IS_NOT_NONE,
&&_unknown_opcode,
&&TARGET_NOP,
&&TARGET_UNARY_POSITIVE,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment