~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to pypy/jit/codegen/i386/regalloc.py

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Register allocation.
 
2
 
 
3
"""
 
4
 
 
5
import sys
 
6
from pypy.rlib.objectmodel import we_are_translated
 
7
from pypy.rpython.lltypesystem import lltype
 
8
from pypy.jit.codegen.i386.operation import *
 
9
 
 
10
DEBUG_STACK = False
 
11
 
 
12
 
 
13
class StackOpCache:
 
14
    INITIAL_STACK_EBP_OFS = -1
 
15
stack_op_cache = StackOpCache()
 
16
stack_op_cache.lst = []
 
17
 
 
18
def stack_op(n):
 
19
    "Return the mem operand that designates the nth stack-spilled location"
 
20
    assert n >= 0
 
21
    lst = stack_op_cache.lst
 
22
    while len(lst) <= n:
 
23
        ofs = WORD * (StackOpCache.INITIAL_STACK_EBP_OFS - len(lst))
 
24
        lst.append(mem(ebp, ofs))
 
25
    return lst[n]
 
26
 
 
27
def stack_n_from_op(op):
 
28
    ofs = op.ofs_relative_to_ebp()
 
29
    return StackOpCache.INITIAL_STACK_EBP_OFS - ofs / WORD
 
30
 
 
31
def write_stack_reserve(mc, stackn):
 
32
    addr = mc.tell()
 
33
    mc.SUB(esp, IMM32(WORD * stackn))     # always encode offset on 32 bits
 
34
    return addr
 
35
 
 
36
def write_stack_adj(mc, stackn):
 
37
    addr = mc.tell()
 
38
    # always encode offset on 32 bits
 
39
    mc.LEA(esp, fixedsize_ebp_ofs(-WORD * stackn))
 
40
    return addr
 
41
 
 
42
 
 
43
class RegAllocator(object):
 
44
 
 
45
    def __init__(self, operations):
 
46
        self.operations = operations
 
47
        self.operationindex = len(operations)
 
48
        self.lifetime = {}                 # {variable: operation_index}
 
49
        self.suggested_location = {}       # {variable: location}
 
50
        self.var2loc = {gv_frame_base: ebp}
 
51
 
 
52
    # ----------
 
53
 
 
54
    def set_final(self, final_vars_gv, locations=None):
 
55
        for i in range(len(final_vars_gv)):
 
56
            v = final_vars_gv[i]
 
57
            self.using(v)
 
58
            if locations is not None:
 
59
                self.suggested_location[v] = locations[i]
 
60
 
 
61
    def compute_lifetimes(self):
 
62
        for i in range(len(self.operations)-1, -1, -1):
 
63
            self.operationindex = i
 
64
            op = self.operations[i]
 
65
            if not op.side_effects and op not in self.lifetime:
 
66
                self.operations[i] = dead_operation   # operation not used
 
67
            else:
 
68
                op.mark_used_vars(self)
 
69
 
 
70
    def using(self, v):
 
71
        if v.is_const or v in self.lifetime:
 
72
            return False
 
73
        else:
 
74
            self.lifetime[v] = self.operationindex
 
75
            return True    # variable is dying here
 
76
 
 
77
    def using_inplace(self, v, vtarget):
 
78
        if self.using(v):
 
79
            # this operation 'vtarget' can modify its argument 'v'
 
80
            # in-place, and 'v' is not alive after the operation.
 
81
            # Propagate the suggested location for 'vtarget' backwards to 'v'.
 
82
            try:
 
83
                self.suggested_location[v] = self.suggested_location[vtarget]
 
84
                return True    # got a suggestion
 
85
            except KeyError:
 
86
                pass
 
87
        return False    # got no suggestion
 
88
 
 
89
    def suggests(self, v, loc):
 
90
        self.suggested_location[v] = loc
 
91
 
 
92
    def varsused(self):
 
93
        return self.lifetime.keys()
 
94
 
 
95
    # ----------
 
96
 
 
97
    AVAILABLE_REGS = (eax.bitmask |
 
98
                      edx.bitmask |
 
99
                      ecx.bitmask |
 
100
                      ebx.bitmask |
 
101
                      esi.bitmask |
 
102
                      edi.bitmask)
 
103
 
 
104
    def init_reg_alloc(self, inputvars_gv, inputlocations):
 
105
        self.registers_free = self.AVAILABLE_REGS     # bitmask
 
106
        self.cc_used_by = None
 
107
        self.stack_op_used = {}
 
108
        self.nstackidx = 0
 
109
        self.nstackmax = 0
 
110
        self.vars_in_use = {}     # {variable: dying_operation_index}
 
111
        self.operationindex = 0
 
112
        self.inputvars_gv = inputvars_gv
 
113
        self.inputlocations = inputlocations
 
114
 
 
115
    def force_loc_used(self, v, loc):
 
116
        ok = self.consume_loc(v, loc)
 
117
        assert ok
 
118
 
 
119
    def consume_loc(self, v, loc):
 
120
        if isinstance(loc, MODRM):
 
121
            if loc not in self.stack_op_used:
 
122
                self.stack_op_used[loc] = None
 
123
                n = stack_n_from_op(loc)
 
124
                if n >= self.nstackmax:
 
125
                    self.nstackmax = n + 1
 
126
                return True
 
127
        elif isinstance(loc, REG):
 
128
            if self.registers_free & loc.bitmask:
 
129
                self.registers_free &= ~loc.bitmask
 
130
                return True
 
131
        elif isinstance(loc, CCFLAG):
 
132
            if self.cc_used_by is None:
 
133
                self.cc_used_by = v
 
134
                return True
 
135
        return False
 
136
 
 
137
    def _no_longer_in_use(self, v):
 
138
        del self.vars_in_use[v]
 
139
        loc = self.var2loc[v]
 
140
        if isinstance(loc, CCFLAG):
 
141
            assert self.cc_used_by is v
 
142
        self._mark_loc_as_free(loc)
 
143
 
 
144
    def _mark_loc_as_free(self, loc):
 
145
        if isinstance(loc, MODRM):
 
146
            del self.stack_op_used[loc]
 
147
        elif isinstance(loc, REG):
 
148
            self.registers_free |= loc.bitmask
 
149
        elif isinstance(loc, CCFLAG):
 
150
            self.cc_used_by = None
 
151
 
 
152
    def generate_operations(self, mc):
 
153
        if not we_are_translated():
 
154
            print
 
155
 
 
156
        # reserve locations for the inputvars
 
157
        for i in range(len(self.inputvars_gv)):
 
158
            v = self.inputvars_gv[i]
 
159
            if v in self.lifetime:   # else: input argument is not used
 
160
                loc = self.inputlocations[i]
 
161
                if v in self.var2loc:   # duplicate inputvars_gv, which is ok
 
162
                    assert self.var2loc[v] == loc
 
163
                else:
 
164
                    self.var2loc[v] = loc
 
165
                    self.vars_in_use[v] = self.lifetime[v]
 
166
                    self.force_loc_used(v, loc)
 
167
                if not we_are_translated():
 
168
                    print 'in %20s:  %s' % (loc, short(v))
 
169
 
 
170
        self._check()
 
171
        self.mc = mc
 
172
        # Generate all operations.
 
173
        # Actual registers or stack locations are allocated as we go.
 
174
        for i in range(len(self.operations)):
 
175
            self.registers_pinned = 0        # bitmask
 
176
            op = self.operations[i]
 
177
            if op.clobbers_cc:
 
178
                self.clobber_cc()
 
179
                self._check()
 
180
            op.generate(self)
 
181
            if not we_are_translated():
 
182
                self._showprogress()
 
183
            self.operationindex = i + 1
 
184
 
 
185
    def _showprogress(self):
 
186
        class Collector:
 
187
            def __init__(self):
 
188
                self.lst = []
 
189
                self.using = self.lst.append
 
190
            def using_inplace(self, v, _):
 
191
                self.lst.append(v)
 
192
            def suggests(self, v, loc):
 
193
                pass
 
194
        col = Collector()
 
195
        i = self.operationindex
 
196
        op = self.operations[i]
 
197
        op.mark_used_vars(col)
 
198
        args = [short(v) for v in col.lst]
 
199
        args = ', '.join(args)
 
200
        print ' | %20s:  %s (%s)' % (self.var2loc.get(op, ''),
 
201
                                     short(op), args)
 
202
        for v, endtime in self.vars_in_use.items():
 
203
            assert endtime > i
 
204
        self._check()
 
205
 
 
206
    def _use_another_stack_loc(self):
 
207
        for i in range(self.nstackidx, self.nstackmax):
 
208
            loc = stack_op(i)
 
209
            if loc not in self.stack_op_used:
 
210
                self.nstackidx = i + 1
 
211
                break
 
212
        else:
 
213
            for i in range(self.nstackidx):
 
214
                loc = stack_op(i)
 
215
                if loc not in self.stack_op_used:
 
216
                    self.nstackidx = i + 1
 
217
                    break
 
218
            else:
 
219
                i = self.nstackidx = self.nstackmax
 
220
                self.nstackmax = i + 1
 
221
                loc = stack_op(i)
 
222
                assert loc not in self.stack_op_used
 
223
        self.stack_op_used[loc] = None
 
224
        return loc
 
225
 
 
226
    def reserve_extra_stack(self, extra):
 
227
        max = self.nstackmax
 
228
        base = max - extra
 
229
        if base < 0:
 
230
            base = 0
 
231
        while max > base and stack_op(max-1) not in self.stack_op_used:
 
232
            max -= 1
 
233
        self.nstackmax = max + extra
 
234
 
 
235
    def get_operand(self, v):
 
236
        if v.is_const:
 
237
            return imm(v.revealconst(lltype.Signed))
 
238
        else:
 
239
            return self.var2loc[v]
 
240
 
 
241
    def grab_operand(self, v):
 
242
        """Like get_operand() but if the result is in a register, it won't
 
243
        be spilled before the end of the current instruction."""
 
244
        loc = self.get_operand(v)
 
245
        if isinstance(loc, REG):
 
246
            self.registers_pinned |= loc.bitmask
 
247
        return loc
 
248
 
 
249
    def _use_next_modrm(self, v, regnum_must_be_before=8):
 
250
        """Select the next mod/rm location to use for the new operation 'v'.
 
251
        If 'v' is None, this will always return a register; else it might
 
252
        decide to immediately create 'v' in a stack location.
 
253
        """
 
254
        #print self.registers_free
 
255
        if self.registers_free:
 
256
            for i in range(regnum_must_be_before-1, -1, -1):
 
257
                if self.registers_free & (1 << i):
 
258
                    self.registers_free &= ~ (1 << i)
 
259
                    return registers[i]
 
260
        # spill the register holding the variable that has the longest
 
261
        # time remaining to live (it may be our 'v' itself)
 
262
        if v is None:
 
263
            dyinglimit = self.operationindex  # must pick vars dying after that
 
264
            spillvar = None
 
265
        else:
 
266
            dyinglimit = self.lifetime[v]
 
267
            spillvar = v  # initial guess, can be overridden in the loop below
 
268
        regloc = None
 
269
        for v1, dying in self.vars_in_use.iteritems():
 
270
            if dying > dyinglimit:
 
271
                loc = self.var2loc[v1]
 
272
                if not isinstance(loc, REG):
 
273
                    continue
 
274
                if loc.op >= regnum_must_be_before:
 
275
                    continue   # never reached if regnum_must_be_before == 8
 
276
                if loc.bitmask & self.registers_pinned:
 
277
                    continue   # don't spill this register
 
278
                regloc = loc
 
279
                dyinglimit = dying
 
280
                spillvar = v1
 
281
        if spillvar is None:
 
282
            raise OutOfRegistersError
 
283
        #print 'time span of %s: now is %d, lives until %d' % (
 
284
        #    v, self.operationindex, self.lifetime[v])
 
285
        if spillvar is v:
 
286
            return self._use_another_stack_loc()
 
287
        else:
 
288
            assert regloc is not None
 
289
            self._spill(spillvar, regloc)
 
290
            return regloc
 
291
 
 
292
    def _spill(self, spillvar, oldloc):
 
293
        spillloc = self._use_another_stack_loc()
 
294
        if not we_are_translated():
 
295
            print ' # %20s:  SPILL %s' % (spillloc, oldloc)
 
296
        self.mc.MOV(spillloc, oldloc)
 
297
        self.var2loc[spillvar] = spillloc
 
298
        return spillloc
 
299
 
 
300
    def _use_next_reg(self):
 
301
        return self._use_next_modrm(None)
 
302
 
 
303
    def _use_next_reg_abcd(self):
 
304
        return self._use_next_modrm(None, regnum_must_be_before=4)
 
305
 
 
306
    def _created(self, v, loc):
 
307
        assert v not in self.var2loc
 
308
        assert loc is not None
 
309
        self.vars_in_use[v] = ltime = self.lifetime[v]
 
310
        assert ltime > self.operationindex
 
311
        self.var2loc[v] = loc
 
312
        if isinstance(loc, REG):
 
313
            self.registers_pinned |= loc.bitmask
 
314
 
 
315
    def release(self, v):
 
316
        """Stop using argument 'v'.  Must be called for each used argument.
 
317
        Warning: if an operation uses v1 and v2, and if v1 could be equal to
 
318
        v2, then calling release(v1) will also immediately release(v2)...
 
319
        The best is to call release() on all operands at once.
 
320
        """
 
321
        ok = self.lastuse(v) and v in self.vars_in_use
 
322
        if ok:
 
323
            self._no_longer_in_use(v)
 
324
        return ok
 
325
 
 
326
    def lastuse(self, v):
 
327
        """Is this the last time the argument 'v' is used?"""
 
328
        if v.is_const:
 
329
            return False
 
330
        else:
 
331
            endtime = self.lifetime[v]
 
332
            assert endtime >= self.operationindex
 
333
            return endtime == self.operationindex
 
334
 
 
335
    def create(self, v, suggested_loc=None):
 
336
        """Create the result of the operation 'v', possibly at the
 
337
        suggested location.  CAN SPILL ONE REGISTER."""
 
338
        if suggested_loc is not None and self.consume_loc(v, suggested_loc):
 
339
            self._created(v, suggested_loc)
 
340
            return suggested_loc
 
341
        suggested_loc = self.suggested_location.get(v, None)
 
342
        if suggested_loc is not None and self.consume_loc(v, suggested_loc):
 
343
            self._created(v, suggested_loc)
 
344
            return suggested_loc
 
345
        loc = self._use_next_modrm(v)
 
346
        self._created(v, loc)
 
347
        return loc
 
348
 
 
349
    def create_reg(self, v, srcloc=None):
 
350
        """Create the result of the operation 'v' in any register
 
351
        currently available.  CAN SPILL ONE REGISTER."""
 
352
        suggested_loc = self.suggested_location.get(v, None)
 
353
        if (isinstance(suggested_loc, REG) and
 
354
            self.consume_loc(v, suggested_loc)):
 
355
            loc = suggested_loc
 
356
        else:
 
357
            loc = self._use_next_reg()
 
358
        self._created(v, loc)
 
359
        if srcloc is not None and loc is not srcloc:
 
360
            # if srcop was spilled, srcloc still contains its value right now
 
361
            # and then it's possible that srcop == dstop (no MOV needed then)
 
362
            self.mc.MOV(loc, srcloc)
 
363
        return loc
 
364
 
 
365
    def create_exactly_at(self, v, loc):
 
366
        """Create the result of the operation 'v' at 'loc'."""
 
367
        ok = self.consume_loc(v, loc)
 
368
        assert ok
 
369
        self._created(v, loc)
 
370
 
 
371
    def create_in_cc(self, v, ccloc):
 
372
        """Create the result of the operation 'v' in the given cc flags.
 
373
        Doesn't move stuff around."""
 
374
        assert self.cc_used_by is None
 
375
        self._created(v, ccloc)
 
376
        self.cc_used_by = v
 
377
 
 
378
    def create_scratch_reg(self, srcloc=None):
 
379
        """Return a scratch register for the current operation.
 
380
        Warning, this might be the same register as one of the input args.
 
381
        CAN SPILL ONE REGISTER.  You must eventually call end_clobber()."""
 
382
        reg = self._use_next_reg()
 
383
        if srcloc is not None and reg is not srcloc:
 
384
            self.mc.MOV(reg, srcloc)
 
385
        return reg
 
386
 
 
387
    def create_scratch_reg8(self, srcloc=None):
 
388
        reg32 = self._use_next_reg_abcd()
 
389
        reg8 = reg32.lowest8bits()
 
390
        if srcloc is not None and reg8 is not srcloc and reg32 is not srcloc:
 
391
            if srcloc.width == 1:
 
392
                self.mc.MOV(reg8, srcloc)
 
393
            else:
 
394
                self.mc.MOV(reg32, srcloc)
 
395
        return reg8
 
396
 
 
397
    def operation_result_is_used(self, v):
 
398
        return v in self.lifetime
 
399
 
 
400
    def clobber(self, reg):
 
401
        """Clobbers a register, i.e. move away a value that would be there.
 
402
        It might go to a different register or to the stack.
 
403
        You must eventually call end_clobber()."""
 
404
        assert isinstance(reg, REG)
 
405
        if not self.registers_free & reg.bitmask:
 
406
            assert not (reg.bitmask & self.registers_pinned)
 
407
            for v1 in self.vars_in_use:
 
408
                if self.var2loc[v1] == reg:
 
409
                    self._move_away(v1)
 
410
                    break
 
411
            assert self.registers_free & reg.bitmask
 
412
        self.registers_free &= ~reg.bitmask
 
413
 
 
414
    def clobber2(self, reg1, reg2):
 
415
        """Clobbers two registers.  Unlike two individual clobber() calls,
 
416
        where the first call might overwrite the other reg, this one
 
417
        preserves the current content of both 'reg1' and 'reg2'.
 
418
        You must eventually call end_clobber() twice."""
 
419
        if not self.registers_free & reg2.bitmask:
 
420
            # order trick: if reg2 is free but reg1 used, doing clobber() in
 
421
            # the following order could first move reg1 to reg2, and then
 
422
            # immediately away from reg2.
 
423
            self.clobber(reg1)     # <- here reg1 cannot go to reg2
 
424
            self.clobber(reg2)
 
425
        else:
 
426
            self.clobber(reg2)     # reg2 is free, so it doesn't go anywhere
 
427
            self.clobber(reg1)
 
428
 
 
429
    def clobber3(self, reg1, reg2, reg3):
 
430
        if not self.registers_free & reg3.bitmask:
 
431
            self.clobber2(reg1, reg2)    # they cannot go to reg3
 
432
            self.clobber(reg3)
 
433
        else:
 
434
            self.clobber(reg3)           # free, so doesn't go anywhere
 
435
            self.clobber2(reg1, reg2)
 
436
 
 
437
    def end_clobber(self, reg):
 
438
        if isinstance(reg, REG):
 
439
            bitmask = reg.bitmask
 
440
        else:
 
441
            assert isinstance(reg, REG8)
 
442
            assert reg.op < 4
 
443
            bitmask = reg.bitmask
 
444
        self.registers_free |= bitmask
 
445
 
 
446
    def clobber_cc(self):
 
447
        v = self.cc_used_by
 
448
        if v is not None:
 
449
            self.cc_used_by = None
 
450
            # pick a newloc that is either one of [eax, ecx, edx, ebx]
 
451
            # or a stack location
 
452
            oldloc = self.var2loc[v]
 
453
            newloc = self._use_next_modrm(v, regnum_must_be_before=4)
 
454
            if not we_are_translated():
 
455
                print ' # %20s:  MOVE AWAY FROM %s' % (newloc, oldloc)
 
456
            assert isinstance(oldloc, CCFLAG)
 
457
            mc = self.mc
 
458
            newloc8 = newloc.lowest8bits()
 
459
            if isinstance(newloc, REG):
 
460
                oldloc.SETCOND(mc, newloc8)
 
461
                mc.MOVZX(newloc, newloc8)
 
462
            else:
 
463
                mc.MOV(newloc, imm8(0))
 
464
                oldloc.SETCOND(mc, newloc8)
 
465
            self._mark_loc_as_free(oldloc)
 
466
            self.var2loc[v] = newloc
 
467
 
 
468
    def lock(self, loc):
 
469
        """Temporarily prevent 'loc' from being overwritten by the
 
470
        functions marked as 'moves stuff around'.  Return True if the
 
471
        lock is sucessful, False if the location was not free in the
 
472
        first place."""
 
473
        return self.consume_loc(None, loc)
 
474
 
 
475
    def unlock(self, loc):
 
476
        """Call sometime after a lock() that returned True."""
 
477
        self._mark_loc_as_free(loc)
 
478
 
 
479
    def _move_away(self, v):
 
480
        # move 'v' away, into a newly allocated register or stack location,
 
481
        # possibly spilling another register
 
482
        oldloc = self.var2loc[v]
 
483
        newloc = self._use_next_modrm(v)
 
484
        if not we_are_translated():
 
485
            print ' # %20s:  MOVE AWAY FROM %s' % (newloc, oldloc)
 
486
        self.mc.MOV(newloc, oldloc)
 
487
        self._mark_loc_as_free(oldloc)
 
488
        self.var2loc[v] = newloc
 
489
        return newloc
 
490
 
 
491
    def _check(self):
 
492
        if not we_are_translated():
 
493
            def unpackbitmask(x):
 
494
                return dict.fromkeys([r for r in registers if x & r.bitmask])
 
495
            rf = unpackbitmask(self.AVAILABLE_REGS)
 
496
            locs_seen = {}
 
497
            for v in self.vars_in_use:
 
498
                loc = self.var2loc[v]
 
499
                assert loc not in locs_seen
 
500
                locs_seen[loc] = v
 
501
                if isinstance(loc, REG):
 
502
                    del rf[loc]
 
503
            assert unpackbitmask(self.registers_free) == rf
 
504
 
 
505
    # ----------
 
506
 
 
507
    def generate_final_moves(self, final_vars_gv, locations):
 
508
        # XXX naive algo for now
 
509
        pops = []
 
510
        for i in range(len(final_vars_gv)):
 
511
            v = final_vars_gv[i]
 
512
            if not v.is_const:
 
513
                srcloc = self.var2loc[v]
 
514
                dstloc = locations[i]
 
515
                if srcloc != dstloc:
 
516
                    if not we_are_translated():
 
517
                        print ' > %20s--->->->---%s' % (srcloc, dstloc)
 
518
                    if isinstance(srcloc, CCFLAG):
 
519
                        self.mc.PUSH(imm8(0))
 
520
                        srcloc.SETCOND(self.mc, mem8(esp))
 
521
                    else:
 
522
                        self.mc.PUSH(srcloc)
 
523
                    pops.append(dstloc)
 
524
        while pops:
 
525
            dstloc = pops.pop()
 
526
            self.mc.POP(dstloc)
 
527
        for i in range(len(final_vars_gv)):
 
528
            v = final_vars_gv[i]
 
529
            if v.is_const:
 
530
                dstloc = locations[i]
 
531
                self.mc.MOV(dstloc, imm(v.revealconst(lltype.Signed)))
 
532
 
 
533
 
 
534
class OutOfRegistersError(Exception):
 
535
    pass
 
536
 
 
537
def short(op, memo={}):
 
538
    key = op.__class__.__name__
 
539
    d = memo.setdefault(key, {})
 
540
    try:
 
541
        n = d[op]
 
542
    except KeyError:
 
543
        n = d[op] = len(d)
 
544
    return '%s-%d' % (key, n)
 
545
 
 
546
# ____________________________________________________________
 
547
 
 
548
class DeadOperation(Operation):
 
549
    clobbers_cc = False
 
550
    side_effects = False
 
551
    def mark_used_vars(self, allocator):
 
552
        pass
 
553
    def generate(self, allocator):
 
554
        pass
 
555
dead_operation = DeadOperation()
 
556
gv_frame_base = GenVar()
 
557
 
 
558
class Place(Operation):
 
559
    """Place of a variable that must live in the stack.  Its position is
 
560
    choosen by the register allocator and put in the 'offset' attribute."""
 
561
    def __init__(self, x):
 
562
        self.x = x
 
563
    def mark_used_vars(self, allocator):
 
564
        if self.x is not None:
 
565
            allocator.using(self.x)
 
566
    def get_offset(self):
 
567
        return self.offset
 
568
    def generate(self, allocator):
 
569
        assert allocator.operation_result_is_used(self), "place not absorbed!"
 
570
        loc = allocator._use_another_stack_loc()
 
571
        allocator._created(self, loc)
 
572
        if self.x is not None:
 
573
            srcop = allocator.get_operand(self.x)
 
574
            try:
 
575
                allocator.mc.MOV(loc, srcop)
 
576
            except FailedToImplement:
 
577
                # loc and srcop are both in the stack - need a temporary reg
 
578
                tmpop = allocator.create_scratch_reg(srcop)
 
579
                # loc and srcop still valid, as they are already in the stack
 
580
                # so cannot have been spilled by create_scratch_reg()
 
581
                allocator.mc.MOV(loc, tmpop)
 
582
                allocator.end_clobber(tmpop)
 
583
            allocator.release(self.x)
 
584
            self.x = None     # hack to avoid that the Place keeps a lot of
 
585
                              # memory around
 
586
        self.offset = loc.ofs_relative_to_ebp()
 
587
 
 
588
class OpAbsorbPlace(Op1):
 
589
    clobbers_cc = False
 
590
    def generate(self, allocator):
 
591
        allocator.release(self.x)
 
592
        if allocator.operation_result_is_used(self):
 
593
            loc = allocator.get_operand(self.x)
 
594
            allocator.create_exactly_at(self, loc)
 
595
 
 
596
class StorageInStack(Place):
 
597
    def generate(self, allocator):
 
598
        # force the variable to be in the stack
 
599
        srcop = allocator.get_operand(self.x)
 
600
        if not isinstance(srcop, MODRM):
 
601
            oldop = srcop
 
602
            srcop = allocator._spill(self.x, srcop)
 
603
            allocator._mark_loc_as_free(oldop)
 
604
        # record its location
 
605
        self.offset = srcop.ofs_relative_to_ebp()
 
606
        # hack to avoid this instance keeping a lot of memory around
 
607
        self.x = None
 
608
 
 
609
class OpTouch(Operation):
 
610
    side_effects = True     # don't remove me!
 
611
    def __init__(self, args_gv):
 
612
        self.args_gv = args_gv
 
613
    def mark_used_vars(self, allocator):
 
614
        for v in self.args_gv:
 
615
            allocator.using(v)
 
616
    def generate(self, allocator):
 
617
        for v in self.args_gv:
 
618
            allocator.release(v)