Skip to content

bpo-46528: Simplify the VM's stack manipulations #30902

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 26, 2022

Conversation

brandtbucher
Copy link
Member

@brandtbucher brandtbucher commented Jan 26, 2022

...as discussed in faster-cpython/ideas#228:

  • Replace DUP_TOP with COPY(1).
  • Replace DUP_TOP_TWO with COPY(2), COPY(2).
  • Introduce a new SWAP instruction.
    • Replace ROT_TWO with SWAP(2).
    • Replace ROT_THREE with SWAP(3), SWAP(2).
    • Remove ROT_FOUR.
    • Replace ROT_N(n) with SWAP(n), SWAP(n - 1), ..., SWAP(2).
    • Optimize runs of SWAP instructions.

https://bugs.python.org/issue46528

@sweeneyde
Copy link
Member

I threw together a test for the basic swaptimize algorithm and it passes some test cases, so that's nice:

def permutation(swaps, N=None):
    if N is None:
        N = max(swaps)
    perm = list(range(N))
    for s in swaps:
        perm[0], perm[s-1] = perm[s-1], perm[0]
    return perm


def swaptimize(*old_swaps):
    assert old_swaps
    if len(old_swaps) == 1:
        return tuple(old_swaps)

    perm = permutation(old_swaps)

    swaps = []
    for i, x in enumerate(perm):
        # March forward, searching for an un-traversed cycle.
        if x is None or x == i:
            continue
        # Traverse this cycle.
        j = i
        while True:
            if j != 0:
                swaps.append(j + 1)
            if perm[j] is None:
                # Back to the start of the cycle.
                assert j == i
                break
            next_j = perm[j]
            perm[j] = None
            j = next_j

    swaps = tuple(reversed(swaps))

    assert permutation(old_swaps, len(perm)) == permutation(swaps, len(perm))
    assert len(swaps) <= len(old_swaps)

    return swaps

assert swaptimize(1) == (1,) # This should be ()?
assert swaptimize(2) == (2,)
assert swaptimize(3) == (3,)
assert swaptimize(10) == (10,)

assert swaptimize(2, 2, 5, 5) == ()
assert swaptimize(10, 20, 20, 10) == ()
assert swaptimize(2, 3, 4, 3) == (3, 4, 3, 2)

from random import randint

for i in range(100_000):
    for n in range(1, 20):
        swaptimize(*[randint(2, 20) for _ in range(n)])

@brandtbucher brandtbucher merged commit 8548366 into python:main Jan 26, 2022
@brandtbucher brandtbucher deleted the swap branch July 21, 2022 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants