"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.