| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
(Semantics aren't there yet, and the test fails.)
First use of conditional stack effects.
|
|
||
| // error: LOAD_ATTR has irregular stack effect | ||
| inst(LOAD_ATTR) { | ||
| inst(LOAD_ATTR, (unused/9, owner -- res, res2 if (oparg & 1))) { |
There was a problem hiding this comment.
Check out my comment in the generated code about 'res2'.
Sorry, something went wrong.
| PREDICTED(LOAD_ATTR); | ||
| PyObject *owner = PEEK(1); | ||
| PyObject *res; | ||
| PyObject *res2; |
There was a problem hiding this comment.
Should this initialize res2 = NULL? Right now I get compiler warnings (in GitHub) about a possibly uninitialized variable:
‘res2’ may be used uninitialized in this function [-Wmaybe-uninitialized]
presumably from the PUSH() on L1798.
Sorry, something went wrong.
There was a problem hiding this comment.
I think the issue is that the compiler can't see that if (oparg & 1) is the same as if (_cond_res2), so it can't tell that res2 is always initialised when it is used. Not sure what to do about it, add a syntax in the DSL to access the condition from within the bytecode definition?
Sorry, something went wrong.
There was a problem hiding this comment.
I'll just initialize it to NULL. Perhaps some later phase of optimization will recognize that for the dead value it is.
Sorry, something went wrong.
There was a problem hiding this comment.
I think if we rename _cond_res2 to res2_exists and then in the body of the bytecode we do if(res2_exists) /* use res2 */ instead of if(oparg &1) /* use res2 */ then it would make the code clearer. It's also safer, because if you change the args to the instr then oparg&1 might not be correct anymore, but res2_exists will be automatically updated.
Sorry, something went wrong.
There was a problem hiding this comment.
Okay, let's try that. I had a commit in the queue that initializes the variable to NULL, which I think would also get rid of the problem (if not I'd be very surprised) but since I didn't push that let's first try it with your idea.
Sorry, something went wrong.
There was a problem hiding this comment.
Hm, looks like it doesn't help, the error is still there. So instead let me try this with the (much simpler) "= NULL" solution, which has to work. In fact, I may also drop the flag variable idea, and solve the warning about bool by writing X ? 1 : 0 instead of X != 0.
Sorry, something went wrong.
| } | ||
| JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); | ||
| POKE(1, res); | ||
| if (oparg & 1) { PUSH(res2); } |
There was a problem hiding this comment.
Here (I think).
Sorry, something went wrong.
- UndefinedLocalError when generating metadata for an 'op' - Accidental newline inserted in test_generator.py
| POKE(1, xx); | ||
| if (oparg & 2) { PUSH(output); } | ||
| PUSH(zz); |
There was a problem hiding this comment.
Could we stick with PEEK and POKE and here have something like this?
| POKE(1, xx); | |
| if (oparg & 2) { PUSH(output); } | |
| PUSH(zz); | |
| POKE((oparg & 2) + 2, xx); | |
| if (oparg & 2) { POKE((oparg & 2) + 1, output); } | |
| POKE(1, zz); |
Sorry, something went wrong.
There was a problem hiding this comment.
Interesting. This would favor cases where the conditional is at the bottom of the inputs (e.g. a if (...), b, c). But I think it would become quite horrible if you have several conditions, like we have in MAKE_FUNCTION.
Sorry, something went wrong.
There was a problem hiding this comment.
If there are several conditions then the concatenation of the conditions (and the unconditional 1's) gives you the index.
The generator will be simpler, the generated code will have these expressions for indices, but I think that's probably easier to follow than a mixture of pushes and pokes.
Sorry, something went wrong.
There was a problem hiding this comment.
I'll play around with that.
Sorry, something went wrong.
There was a problem hiding this comment.
Have a look. The generator sure is a lot simpler, I think I can live with the more complicated generated code. What made this solution so nice is that we already had the symbolic size -- the condition just gets added into that. Thanks for the nudge!
Sorry, something went wrong.
There was a problem hiding this comment.
Notes to self.
Sorry, something went wrong.
| At most one of these will be non-zero / non-empty. | ||
| """ | ||
| if effect.size: | ||
| assert not effect.cond, "Manual effects should be conditional" |
There was a problem hiding this comment.
This message is incorrect.
Sorry, something went wrong.
| if "boerenkool" in dst.name or "boerenkool" in src.name: | ||
| breakpoint() |
There was a problem hiding this comment.
Debug output accidentally left in.
Sorry, something went wrong.
| # elif m := re.match(r"^POP\(\)$", dst.name): | ||
| # if src.cond: | ||
| # self.emit(f"if ({src.cond}) {{ PUSH({cast}{src.name}); }}") | ||
| # else: | ||
| # self.emit(f"PUSH({cast}{src.name});") |
There was a problem hiding this comment.
Delete commented-out block.
Sorry, something went wrong.
| else: | ||
| # Write output register assignments | ||
| for oeffect, reg in zip(self.output_effects, self.output_registers): | ||
| src = StackEffect(reg, "") |
There was a problem hiding this comment.
Don't need this.
Sorry, something went wrong.
| STACK_GROW(((oparg & 1) != 0)); | ||
| POKE(1, res); | ||
| if (oparg & 1) { POKE(1 + ((oparg & 1) != 0), res2); } |
There was a problem hiding this comment.
It's unfortunate that all new versions test for oparg & 1 several times, whereas the original version tested that condition exactly once.
Sorry, something went wrong.
There was a problem hiding this comment.
I assumed the compiler would do this, but we could assign ((oparg& i) != 0) to something. I think it’s only used as a condition in one place, in other places it’s just int arithmetic.
Sorry, something went wrong.
|
I don't understand what this warning is about: comparison of constant ‘0’ with boolean expression is always true [-Wbool-compare] |
Sorry, something went wrong.
I assume it's about this line (L1797): STACK_GROW(((oparg & 1) != 0)); The compiler probably reasons that x >= 0 where x has type bool is always true and is trying to warn you that you've got a trivial condition (the expansion of STACK_GROW(n) uses assert(n >= 0) and presumably assert(x) expands to something like if (!x) ...). That's silly since it doesn't warn us about the equally trivial 1 >= 0 that appears in the expansion of STACK_GROW(1) -- I'm guessing it's more likely to warn based on types rather than values. I'm not sure what to do about it. PS. I'm still looking into your suggestion to assign the condition to a flag variable, it's a bit messy. |
Sorry, something went wrong.
|
Here's the new version. Let me know if you like it enough to go ahead -- if not, I can easily roll it back. Note that I also fixed a bunch of typing issues (which caught one genuine bug). |
Sorry, something went wrong.
I think this is easier to read. The warning about the bool comparison is gone too. There's just the one about res being potentially unassigned. |
Sorry, something went wrong.
| // Dummy variables for stack effects. | ||
| static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub; | ||
| static PyObject *container, *start, *stop, *v, *lhs, *rhs; | ||
| static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2; |
There was a problem hiding this comment.
We will also need static int res2_exists, and a bunch of other things, before I land this.
Sorry, something went wrong.
This hopefully avoids a silly compiler warning.
|
Finally this has no compiler warnings on GitHub. I prefer this version, the changes to generate_cases.py are simpler than the version with flags. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
We can now write
inst(OP, (foo if (oparg & 1) -- bar if (oparg & 2)) { ... }which pops foo off the stack if oparg & 1, otherwise setting it to NULL, and pushes bar onto the stack if oparg & 2 (otherwise ignoring it).
This syntax cannot be combined with an array size on the same effect, but it can be combined with a type (untested). In addition, it is incompatible with an array size closer to the stack top, e.g. foo if (oparg&1), bar[oparg>>1] is not supported (I don't think it's used, and generating code for it would be slightly awkward, but could be done if needed).
The implementation switches to using POP() and PUSH() (from PEEK() and POKE()) for those variables that are either conditional or whose position relative to the bottom (!) of the stack depends on a condition. (See the added test for details.)
To demonstrate this, I converted LOAD_ATTR (but not its specializations).