15
15
16
16
log = getLogger (__name__ )
17
17
18
- def check_cycle (reg , assignments ):
18
+ def check_cycle (reg , assignments , mapping = None ):
19
19
"""Walk down the assignment list of a register,
20
20
return the path walked if it is encountered again.
21
21
@@ -37,31 +37,38 @@ def check_cycle(reg, assignments):
37
37
>>> check_cycle('a', {'a': 'b', 'b': 'c', 'c': 'd', 'd': 'a'})
38
38
['a', 'b', 'c', 'd']
39
39
"""
40
- return check_cycle_ (reg , assignments , [])
41
-
42
- def check_cycle_ (reg , assignments , path ):
43
- target = assignments [reg ]
40
+ if mapping is None :
41
+ mapping = {}
42
+ return check_cycle_ (reg , assignments , [], mapping )
43
+
44
+ def check_cycle_ (reg , assignments , path , mapping ):
45
+ target = assignments .get (reg )
46
+ if target is None :
47
+ real_reg = mapping .get (reg , reg )
48
+ reg , target = next ((k , v ) for k ,v in assignments .items () if mapping .get (k , k ) == real_reg )
44
49
path .append (reg )
45
50
51
+ real_target = mapping .get (target , target )
52
+
46
53
# No cycle, some other value (e.g. 1)
47
- if target not in assignments :
54
+ if all ( real_target != mapping . get ( k , k ) for k in assignments ) :
48
55
return []
49
56
50
57
# Found a cycle
51
- if target in path :
58
+ if any ( real_target == mapping . get ( k , k ) for k in path ) :
52
59
# Does the cycle *start* with target?
53
60
# This determines whether the original register is
54
61
# in the cycle, or just depends on registers in one.
55
- if target == path [0 ]:
62
+ if real_target == mapping . get ( path [0 ], path [ 0 ]) :
56
63
return path
57
64
58
65
# Just depends on one.
59
66
return []
60
67
61
68
# Recurse
62
- return check_cycle_ (target , assignments , path )
69
+ return check_cycle_ (target , assignments , path , mapping )
63
70
64
- def extract_dependencies (reg , assignments ):
71
+ def extract_dependencies (reg , assignments , mapping = None ):
65
72
"""Return a list of all registers which directly
66
73
depend on the specified register.
67
74
@@ -77,7 +84,9 @@ def extract_dependencies(reg, assignments):
77
84
['b', 'c']
78
85
"""
79
86
# sorted() is only for determinism
80
- return sorted ([k for k ,v in assignments .items () if v == reg ])
87
+ if mapping is None :
88
+ mapping = {}
89
+ return sorted ([k for k ,v in assignments .items () if mapping .get (v , v ) == mapping .get (reg , reg )])
81
90
82
91
83
92
def resolve_order (reg , deps ):
@@ -110,7 +119,7 @@ def depends_on_cycle(reg, assignments, in_cycles):
110
119
reg = assignments .get (reg , None )
111
120
return False
112
121
113
- def regsort (in_out , all_regs , tmp = None , xchg = True , randomize = None ):
122
+ def regsort (in_out , all_regs , mapping = None , tmp = None , xchg = True , randomize = None ):
114
123
"""
115
124
Sorts register dependencies.
116
125
@@ -233,6 +242,12 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
233
242
if randomize is None :
234
243
randomize = context .randomize
235
244
245
+ if mapping is None :
246
+ if hasattr (all_regs , 'keys' ):
247
+ mapping = all_regs
248
+ else :
249
+ mapping = {}
250
+
236
251
sentinel = object ()
237
252
238
253
# Drop all registers which will be set to themselves.
@@ -242,7 +257,7 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
242
257
243
258
# Collapse constant values
244
259
#
245
- # For eaxmple , {'eax': 0, 'ebx': 0} => {'eax': 0, 'ebx': 'eax'}
260
+ # For example , {'eax': 0, 'ebx': 0} => {'eax': 0, 'ebx': 'eax'}
246
261
v_k = defaultdict (list )
247
262
for k ,v in sorted (in_out .items ()):
248
263
if v not in all_regs and v != 0 :
@@ -263,7 +278,9 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
263
278
# which are also 'outputs'.
264
279
#
265
280
# For example, {'eax': 1, 'ebx': 2, 'ecx': 'edx'}
266
- if not any (v in in_out for k ,v in in_out .items ()):
281
+ inps = {mapping .get (k , k ) for k in in_out }
282
+ outs = {mapping .get (v , v ) for v in in_out .values ()}
283
+ if not inps & outs :
267
284
result = [('mov' , k ,in_out [k ]) for k in sorted (in_out )]
268
285
269
286
if randomize :
@@ -280,7 +297,7 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
280
297
# Output: {'A': [], 'B': ['A', 'C'], 'C': []}
281
298
#
282
299
# In this case, both A and C must be set before B.
283
- deps = {r : extract_dependencies (r , in_out ) for r in in_out }
300
+ deps = {r : extract_dependencies (r , in_out , mapping ) for r in in_out }
284
301
285
302
# Final result which will be returned
286
303
result = []
@@ -299,7 +316,7 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
299
316
300
317
while cycle_candidates :
301
318
reg = cycle_candidates [0 ]
302
- cycle = check_cycle (reg , in_out )
319
+ cycle = check_cycle (reg , in_out , mapping )
303
320
304
321
if cycle :
305
322
if randomize :
@@ -395,6 +412,10 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
395
412
396
413
if tmp :
397
414
for cycle in cycles :
415
+ if len (cycle ) == 1 :
416
+ [reg ] = cycle
417
+ result .append (('mov' , reg , in_out [reg ]))
418
+ continue
398
419
399
420
first = cycle [0 ]
400
421
last = cycle [- 1 ]
@@ -411,6 +432,9 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
411
432
else :
412
433
for cycle in cycles :
413
434
size = len (cycle )
435
+ if size == 1 :
436
+ [reg ] = cycle
437
+ result .append (('mov' , reg , in_out [reg ]))
414
438
for i in range (size - 1 ):
415
439
result .append (('xchg' , cycle [i ], cycle [(i + 1 ) % size ]))
416
440
0 commit comments