On 6/18/2021 8:13 PM, Chris Angelico wrote:
On Sat, Jun 19, 2021 at 9:50 AM Terry Reedy <tjre...@udel.edu> wrote:
Why are there two separate bytecode blocks for the "raise Exception"?

Because one block must POP_TOP and other must not.

I'd have thought that the double condition would still be evaluated as
one thing, or at least that the jump destinations for both the
early-abort and the main evaluation should be the same.

To reuse the exception block with POP_TOP, could jump over it after the
2nd compare.

Hmm, fair enough I guess. The compiler figured that it'd be faster to
duplicate the executable code rather than have the jump.

I would not assume that any alternative was considered.

It made for a
somewhat confusing disassembly, but I presume it's faster to run.

For the simplest and fasted bytecode, write normal logic and let x be
reloaded instead of duplicated and rotated.

  >>> import dis
  >>> def f(x):
...     if x <= 0 or 10 <= x: raise Exception
...
...
  >>> dis.dis(f)
    2           0 LOAD_FAST                0 (x)
                2 LOAD_CONST               1 (0)
                4 COMPARE_OP               1 (<=)
                6 POP_JUMP_IF_TRUE         8 (to 16)
                8 LOAD_CONST               2 (10)
               10 LOAD_FAST                0 (x)
               12 COMPARE_OP               1 (<=)
               14 POP_JUMP_IF_FALSE       10 (to 20)
          >>   16 LOAD_GLOBAL              0 (Exception)
               18 RAISE_VARARGS            1
          >>   20 LOAD_CONST               0 (None)
               22 RETURN_VALUE
  >>>


Makes sense. I'm not sure if this would actually run faster, but I
can't really justify warping my code around the disassembly :)

Thanks for the explanation. I guess I just assumed the interpreter
would prefer a jump to the duplication, but that's a decision it's
free to take!

--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to