Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32k
GH-106008: Make implicit boolean conversions explicit#106003
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
A few minor comments, otherwise LGTM.
Python/bytecodes.c Outdated
} | ||
inst(TO_BOOL_BOOL, (unused/1, unused/2, value -- value)) { | ||
// Coolest (and dumbest-named) specialization ever: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
True, but the not the most useful comment for someone trying to understand the code 🙂
Python/bytecodes.c Outdated
inst(TO_BOOL_NONE, (unused/1, unused/2, value -- res)) { | ||
// This one is a bit weird, because we expect *some* failures... | ||
// it might be worth combining with TO_BOOL_ALWAYS_TRUE somehow: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I think we decided it wasn't, as it reflects the underlying type instability when doingif x:
as a stand in forif x is None
.
Python/bytecodes.c Outdated
inst(TO_BOOL_STR, (unused/1, unused/2, value -- res)) { | ||
DEOPT_IF(!PyUnicode_CheckExact(value), TO_BOOL); | ||
STAT_INC(TO_BOOL, hit); | ||
if (Py_Is(value, &_Py_STR(empty))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Usevalue == &_Py_STR(empty)
. The semantics isvalue == ""
, notvalue is ""
.
In general I wouldn't usePy_Is
except when you want the exact semantics of Python'sx is y
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Hm, I mean, weare checking for the identity of the singleton string here. I'll just change it, though.
markshannonJun 26, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Hypothetically we could have more than one""
object. I don't think that" ".strip() is ""
is part of the language spec, soPy_Is
doesn't add any safety, just obfuscation.
We can also potentially have tagged ints, in which casePy_Is
would need to become a lot more complex, butvalue == &_Py_STR(empty)
would remain efficient.
Python/bytecodes.c Outdated
inst(TO_BOOL_ALWAYS_TRUE, (unused/1, version/2, value -- res)) { | ||
// This one is a bit weird, because we expect *some* failures... | ||
// it might be worth combining with TO_BOOL_NONE somehow: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
See comment above.
} | ||
} | ||
assert(PyBool_Check(cond)); | ||
JUMPBY(oparg * Py_IsFalse(cond)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is so much more pleasing 🙂
@@ -107,6 +107,8 @@ _Py_GetSpecializationStats(void) { | |||
err += add_stat_dict(stats, COMPARE_OP, "compare_op"); | |||
err += add_stat_dict(stats, UNPACK_SEQUENCE, "unpack_sequence"); | |||
err += add_stat_dict(stats, FOR_ITER, "for_iter"); | |||
err += add_stat_dict(stats, TO_BOOL, "to_bool"); | |||
err += add_stat_dict(stats, SEND, "send"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks, I tend to forget about the stats dict .
Note for possible future PR: We could, at the cost of two bits in Rather than check the version number, check the For abi4, we could add a per-object bit to handle immutable objects like ints and strings. |
Python/flowgraph.c Outdated
} | ||
} | ||
Py_DECREF(newconst); | ||
return index; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
windows compiler warning here, implicit cast from Py_ssize_t to int
Uh oh!
There was an error while loading.Please reload this page.
Merging is currently blocked on#106250. |
Hey@brandtbucher, I have a question about this PR. In#106393 I had to change the code in
to
The reason is that the uop executor currently exits whenever it jumps, and your original code from this PRalways jumps. Did you (or@markshannon) have a reason to prefer the If there's no deep reason I'll keep it the way I coded it up; but if there is (maybe it came out faster in a micro-benchmark?) then I suppose I could fix it another way in the uop interpreter (e.g. only exiting if the jump offset is nonzero). |
That the implementation of branches is itself branchless has a certain aesthetic appeal 🙂. TBH, that's the main reason. The multiplication form will be quicker for unpredictable branches, and slower for predictable ones in the tier 1 interpreter. |
Uh oh!
There was an error while loading.Please reload this page.
...and specialize them!
This adds a new
TO_BOOL
bytecode that prefixes allUNARY_NOT
,POP_JUMP_IF_TRUE
, andPOP_JUMP_IF_FALSE
instructions, which now require an exact boolean. We also use a spare bit inCOMPARE_OP
's oparg to indicate whether the result should be converted to bool (this saves aTO_BOOL
for most branches, and is a no-op for allCOMPARE_OP
specializations)."0% faster". Stats show a93.5% hit rate for the new instructions.
📚 Documentation preview 📚:https://cpython-previews--106003.org.readthedocs.build/