Repository navigation
GH-128939: Refactor JIT optimize structs - #128940
Conversation
|
Can you add a test that the tuple information is actually propagated? Either through testing type guard elimination happens or something. Unless you plan to refactor the tests as well :). |
|
Random comment: JIT is an acronym, and we use the "JIT" capitalization elsewhere. "Jit" just looks... wrong. |
brandtbucher
left a comment
There was a problem hiding this comment.
Various thoughts and questions I had while reading through. I think this is going to be a very nice improvement, though!
Other thoughts:
- It's probably worth adding a helper for immortality checks. Basically, check if we have an immortal constant, or a known
booltype. The bool part is nice, but easy to forget. - Any plans to update the
_Py_uop_naming to be "JIT"-ier?
| typedef union _jit_opt_symbol { | ||
| uint8_t tag; | ||
| JitOptKnownClass cls; | ||
| JitOptKnownValue value; | ||
| JitOptKnownVersion version; | ||
| JitOptTuple tuple; | ||
| } JitOptSymbol; |
There was a problem hiding this comment.
Could this be:
| typedef union _jit_opt_symbol { | |
| uint8_t tag; | |
| JitOptKnownClass cls; | |
| JitOptKnownValue value; | |
| JitOptKnownVersion version; | |
| JitOptTuple tuple; | |
| } JitOptSymbol; | |
| typedef struct { | |
| uint8_t tag; | |
| union { | |
| JitOptKnownClass cls; | |
| JitOptKnownValue value; | |
| JitOptKnownVersion version; | |
| JitOptTuple tuple; | |
| }; | |
| } JitOptSymbol; |
Then we wouldn't need to repeat the tag in each struct.
Or does the current scheme potentially pack better?
There was a problem hiding this comment.
It packs better. Because structs align according to the alignment of their members, we would end up using 8 bytes for the tag if it weren't part of each struct.
| typedef struct _jit_opt_known_class { | ||
| uint8_t tag; | ||
| uint32_t version; | ||
| PyTypeObject *type; | ||
| } JitOptKnownClass; |
There was a problem hiding this comment.
We could probably just get the version by doing cls.type->tp_version_tag, right? Having both here just creates opportunities for them to be stale or out-of-sync, I think.
There was a problem hiding this comment.
sym->cls.type->tp_version_tag is the version tag of the value's class now. sym->version.version is the version tag it would have should execution reach this point in the code. Not quite the same thing.
There was a problem hiding this comment.
I would imagine that a sym->cls.version that's out-of-sync with sym->cls.type->tp_version_tag should result in the bottom type, then, right? It's not possible in future code, since the cached tag is stale.
| typedef struct _jit_opt_tuple { | ||
| uint8_t tag; | ||
| uint8_t length; | ||
| uint16_t items[6]; |
There was a problem hiding this comment.
I think we have room for 7, right?
| uint16_t items[6]; | |
| uint16_t items[7]; |
| case JIT_SYM_KNOWN_VALUE_TAG: | ||
| Py_CLEAR(sym->value.value); | ||
| sym_set_bottom(ctx, sym); | ||
| return false; | ||
| case JIT_SYM_TUPLE_TAG: | ||
| sym_set_bottom(ctx, sym); | ||
| return false; |
There was a problem hiding this comment.
These could potentially have the same version tag, right? Looking up a method or whatever on a constant value is a normal thing to do.
| case JIT_SYM_TUPLE_TAG: | ||
| sym_set_bottom(ctx, sym); | ||
| return; |
There was a problem hiding this comment.
This also seems like it could potentially be fine (transitioning from an abstract tuple to a concrete one)... could potentially need to do something recursive for the elements, though.
| JitOptSymbol * | ||
| _Py_uop_sym_new_unknown(JitOptContext *ctx) | ||
| { | ||
| return sym_new(ctx); |
There was a problem hiding this comment.
Should this be checked for NULL and replaced with out_of_space like the others?
| _Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item) | ||
| { | ||
|
|
||
| if (sym->tag != JIT_SYM_TUPLE_TAG || item < 0 || item >= sym->tuple.length) { |
There was a problem hiding this comment.
We can handle negative indexes pretty easily here, right?
Also, this can probably be updated to work correctly for constant tuples.
There was a problem hiding this comment.
Negative indexes are errors at this level. If we add a symbolic version of this, we would handle negative indexes there.
| int | ||
| _Py_uop_sym_tuple_length(JitOptSymbol *sym) | ||
| { | ||
| if (sym->tag != JIT_SYM_TUPLE_TAG) { |
There was a problem hiding this comment.
Same here, this can probably be updated to work for constants.
| if (size > 6) { | ||
| res->tag = JIT_SYM_KNOWN_CLASS_TAG; | ||
| res->cls.type = &PyTuple_Type; | ||
| } |
There was a problem hiding this comment.
There are probably cases where this can be represented as a constant value (when all items are known).
There was a problem hiding this comment.
Hm, although it could get tricky because nothing owns that constant, so we have to be careful not to promote its uses to constant loads.
There was a problem hiding this comment.
A constant tuple holds no more information than a tuple of constants, so there would be no advantage.
There was a problem hiding this comment.
Well, it can have more than 7 items... but sure, that probably isn't very common.
Readability. Is |
At some point, yes. |
| self.assertIn("_BINARY_OP_ADD_INT", uops) | ||
| self.assertNotIn("_GUARD_BOTH_INT", uops) | ||
| self.assertNotIn("_GUARD_NOS_INT", uops) | ||
| self.assertNotIn("_GUARD_TOS_INT", uops) |
There was a problem hiding this comment.
This kind of check can easily pass by accident if there's typo or bytecodes change.
Would be good to have a helper that asserts also that the thing not in is an actual uop id.
There was a problem hiding this comment.
It would.
I'll do that in another PR though.
I don't know, "JIT show" seems like the pretty obvious CamelCase reading. Similar to how "GILState" is "GIL State" and not "GILs tate". Not a hill I'm willing to die on, it just looks kinda weird (like "Ast" or "Ascii" or "Gil" would). |
Converts the ad-hoc set of flags in
_Py_UopsSymbolinto a tagged union.This:
enumin a switch allows the C compiler to tell us if we miss any cases_Py_Uopsto start withJitOpt.