1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
from rpython.jit.backend.x86.regloc import ImmediateAssemblerLocation,\
FrameLoc
def remap_frame_layout(assembler, src_locations, dst_locations, tmpreg):
pending_dests = len(dst_locations)
srccount = {} # maps dst_locations to how many times the same
# location appears in src_locations
for dst in dst_locations:
key = dst._getregkey()
assert key not in srccount, "duplicate value in dst_locations!"
srccount[key] = 0
for i in range(len(dst_locations)):
src = src_locations[i]
if isinstance(src, ImmediateAssemblerLocation):
continue
key = src._getregkey()
if key in srccount:
if key == dst_locations[i]._getregkey():
# ignore a move "x = x"
# setting any "large enough" negative value is ok, but
# be careful of overflows, don't use -sys.maxint
srccount[key] = -len(dst_locations) - 1
pending_dests -= 1
else:
srccount[key] += 1
while pending_dests > 0:
progress = False
for i in range(len(dst_locations)):
dst = dst_locations[i]
key = dst._getregkey()
if srccount[key] == 0:
srccount[key] = -1 # means "it's done"
pending_dests -= 1
src = src_locations[i]
if not isinstance(src, ImmediateAssemblerLocation):
key = src._getregkey()
if key in srccount:
srccount[key] -= 1
_move(assembler, src, dst, tmpreg)
progress = True
if not progress:
# we are left with only pure disjoint cycles
sources = {} # maps dst_locations to src_locations
for i in range(len(dst_locations)):
src = src_locations[i]
dst = dst_locations[i]
sources[dst._getregkey()] = src
#
for i in range(len(dst_locations)):
dst = dst_locations[i]
originalkey = dst._getregkey()
if srccount[originalkey] >= 0:
assembler.regalloc_push(dst)
while True:
key = dst._getregkey()
assert srccount[key] == 1
# ^^^ because we are in a simple cycle
srccount[key] = -1
pending_dests -= 1
src = sources[key]
if src._getregkey() == originalkey:
break
_move(assembler, src, dst, tmpreg)
dst = src
assembler.regalloc_pop(dst)
assert pending_dests == 0
def _move(assembler, src, dst, tmpreg):
if dst.is_memory_reference() and src.is_memory_reference():
if isinstance(src, ImmediateAssemblerLocation):
assembler.regalloc_immedmem2mem(src, dst)
return
if tmpreg is None:
assembler.regalloc_push(src)
assembler.regalloc_pop(dst)
return
assembler.regalloc_mov(src, tmpreg)
src = tmpreg
assembler.regalloc_mov(src, dst)
def remap_frame_layout_mixed(assembler,
src_locations1, dst_locations1, tmpreg1,
src_locations2, dst_locations2, tmpreg2):
# find and push the xmm stack locations from src_locations2 that
# are going to be overwritten by dst_locations1
from rpython.jit.backend.x86.arch import WORD
extrapushes = []
dst_keys = {}
for loc in dst_locations1:
dst_keys[loc._getregkey()] = None
src_locations2red = []
dst_locations2red = []
for i in range(len(src_locations2)):
loc = src_locations2[i]
dstloc = dst_locations2[i]
if isinstance(loc, FrameLoc):
key = loc._getregkey()
if (key in dst_keys or (loc.get_width() > WORD and
(key + WORD) in dst_keys)):
assembler.regalloc_push(loc)
extrapushes.append(dstloc)
continue
src_locations2red.append(loc)
dst_locations2red.append(dstloc)
src_locations2 = src_locations2red
dst_locations2 = dst_locations2red
#
# remap the integer and pointer registers and stack locations
remap_frame_layout(assembler, src_locations1, dst_locations1, tmpreg1)
#
# remap the xmm registers and stack locations
remap_frame_layout(assembler, src_locations2, dst_locations2, tmpreg2)
#
# finally, pop the extra xmm stack locations
while len(extrapushes) > 0:
loc = extrapushes.pop()
assembler.regalloc_pop(loc)
|