"Bit-borrow" two numbers

Jelly, 11 bytes

~1¦&N$^µ</¿

Try it online! or verify all test cases.

Background

We can extract the last set bit of an integer n as follows.

n + 1 toggles all trailing set bits of n and the adjacent unset bit. For example, 100112 + 1 = 101002.

Since ~n = -(n + 1) = -n - 1, -n = ~n + 1, so -n applies the above to the bitwise NOT of n (which toggles all bits), thus toggling all bits before the last 1.

For example, -101002 = ~101002 + 1 = 010112 + 1 = 011002.

By taking n & -n the bitwise AND of n and -n all bits before the last set bit are nullified (since unequal in n and -n), thus yielding the last set bit of n.

For example, 101002 & -101002 = 101002 & 011002 = 001002.

Thus XORing n with n & -n unsets the last set bit of n.

Conversely, to unset the last set bit of n, it suffices to apply the above to ~n, from where we derive the formula n ^ (~n & -~n).

How it works

~1¦&N$^µ</¿  Main link. Argument: A (list of pairs)

          ¿  While loop:
        </     Condition: Reduce p by less-than. True iff x < y.
       µ       Body chain:
~1¦              Apply bitwise NOT to the x, first item of the pair.
     $           Convert the two links to the left into a monadic chain.
    N              Negate; multiply [~x, y] by -1, yielding [-~x, -y].
   &               Logical AND. Yields [-~x & ~x, -y & y].
      ^            Vectorized XOR with p. Yields [(-~x & ~x) ^ x, (-y & y) ^ y].

J, 31 26 bytes

,`(($:~(OR>:))~(AND<:))@.<

Straight-forward approach using recursion and bitwise tricks. In order to turn off (set to 0) the right-most on (1) bit for a value n, you can perform bitwise-and between n and n-1, and to turn on (set to 1) the right-most off (0) bit for a value n, you can perform bitwise-or between n and n+1.

Usage

The input consists of two integers, one applied on the LHS and the other on the RHS, and the output is a list of the bit-borrowed values.

   f =: ,`(($:~(OR>:))~(AND<:))@.<
   2 f 3
3 2
   3 f 2
3 2
   8 f 23
31 0
   42 f 81
63 0
   38 f 41
47 32
   16 f 73
23 0
   17 f 17
17 17

Explanation

,`(($:~(OR>:))~(AND<:))@.<  Input: x on LHS, y on RHS
                            If x < y,
,                             Form a 2-element array [x, y] and return
                            Else
                   <:         Decrement y
                AND           Perform bitwise-and on y and y-1, call it y'
          >:                  Increment x
        OR                    Perform bitwise-or on x and x+1, call it x'
    $:                        Call recursively on x' and y' and return

Python, 42 bytes

f=lambda x,y:x<y and f(x|x+1,y&y-1)or(x,y)

Thanks to @jimmy23013 for golfing off 4 bytes! Thanks to @LeakyNun for golfing off 2 bytes!

Test it on Ideone.