File: codebuilder.py

package info (click to toggle)
pypy 5.6.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 97,040 kB
  • ctags: 185,069
  • sloc: python: 1,147,862; ansic: 49,642; cpp: 5,245; asm: 5,169; makefile: 529; sh: 481; xml: 232; lisp: 45
file content (264 lines) | stat: -rw-r--r-- 9,048 bytes parent folder | download | duplicates (8)
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
from rpython.jit.backend.zarch import conditions as c
from rpython.jit.backend.zarch import registers as r
from rpython.jit.backend.zarch import locations as l
from rpython.jit.backend.zarch.arch import STD_FRAME_SIZE_IN_BYTES
from rpython.jit.backend.zarch.instruction_builder import build_instr_codes
from rpython.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin
from rpython.jit.backend.llsupport.assembler import GuardToken
from rpython.rlib.objectmodel import we_are_translated
from rpython.rlib.unroll import unrolling_iterable
from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
from rpython.tool.udir import udir
from rpython.jit.backend.detect_cpu import autodetect
from rpython.jit.backend.zarch.arch import WORD

clear_cache = rffi.llexternal(
    "__clear_cache",
    [llmemory.Address, llmemory.Address],
    lltype.Void,
    _nowrapper=True,
    sandboxsafe=True)

def binary_helper_call(name):
    function = getattr(support, 'arm_%s' % name)

    def f(self, c=c.AL):
        """Generates a call to a helper function, takes its
        arguments in r0 and r1, result is placed in r0"""
        addr = rffi.cast(lltype.Signed, function)
        self.BL(addr, c)
    return f

class ZARCHGuardToken(GuardToken):
    def __init__(self, cpu, gcmap, descr, failargs, faillocs,
                 guard_opnum, frame_depth, faildescrindex, fcond=c.cond_none):
        GuardToken.__init__(self, cpu, gcmap, descr, failargs, faillocs,
                            guard_opnum, frame_depth, faildescrindex)
        self.fcond = fcond

class AbstractZARCHBuilder(object):

    def write_i64(self, word):
        self.writechar(chr((word >> 56) & 0xFF))
        self.writechar(chr((word >> 48) & 0xFF))
        self.writechar(chr((word >> 40) & 0xFF))
        self.writechar(chr((word >> 32) & 0xFF))
        self.writechar(chr((word >> 24) & 0xFF))
        self.writechar(chr((word >> 16) & 0xFF))
        self.writechar(chr((word >> 8) & 0xFF))
        self.writechar(chr(word & 0xFF))

    def write_i32(self, word):
        self.writechar(chr((word >> 24) & 0xFF))
        self.writechar(chr((word >> 16) & 0xFF))
        self.writechar(chr((word >> 8) & 0xFF))
        self.writechar(chr(word & 0xFF))

    def write_i16(self, word):
        self.writechar(chr((word >> 8) & 0xFF))
        self.writechar(chr(word & 0xFF))

    def write(self, bytestr):
        for char in bytestr:
            self.writechar(char)

build_instr_codes(AbstractZARCHBuilder)

class InstrBuilder(BlockBuilderMixin, AbstractZARCHBuilder):

    RAW_CALL_REG = r.r14

    def __init__(self, pool=None):
        AbstractZARCHBuilder.__init__(self)
        self.init_block_builder()
        self.pool = pool
        #
        # ResOperation --> offset in the assembly.
        # ops_offset[None] represents the beginning of the code after the last op
        # (i.e., the tail of the loop)
        self.ops_offset = {}

    def mark_op(self, op):
        pos = self.get_relative_pos()
        self.ops_offset[op] = pos

    def _dump_trace(self, addr, name, formatter=-1):
        if not we_are_translated():
            if formatter != -1:
                name = name % formatter
            dir = udir.ensure('asm', dir=True)
            f = dir.join(name).open('wb')
            data = rffi.cast(rffi.CCHARP, addr)
            for i in range(self.currpos()):
                f.write(data[i])
            f.close() 
    def clear_cache(self, addr):
        if we_are_translated():
            startaddr = rffi.cast(llmemory.Address, addr)
            endaddr = rffi.cast(llmemory.Address,
                            addr + self.get_relative_pos())
            clear_cache(startaddr, endaddr)

    def copy_to_raw_memory(self, addr):
        self._copy_to_raw_memory(addr)
        self.clear_cache(addr)
        self._dump(addr, "jit-backend-dump", "s390x")

    def load(self, treg, sreg, offset):
        self.LG(treg, l.addr(offset, sreg))

    def store(self, val, dst, off):
        self.STG(val, l.addr(off, dst))

    def store_update(self, valreg, treg, offset):
        self.STG(valreg, l.addr(offset, treg))

    def nop(self):
        # if the mask is zero it act as a NOP
        # there is no special 'no operation' instruction
        self.BCR_rr(0x0, 0x0)

    def currpos(self):
        return self.get_relative_pos()

    def b_abs(self, addr):
        self.load_imm(r.r14, addr)
        self.BCR(c.ANY, r.r14)

    def b_cond_offset(self, offset, condition):
        assert condition != c.cond_none
        self.BRCL(condition, l.imm(offset))

    def b_offset(self, reladdr):
        offset = reladdr - self.get_relative_pos()
        if -2**15 <= offset <= 2**15-1:
            self.BRC(c.ANY, l.imm(offset))
        else:
            # we have big loops!
            self.BRCL(c.ANY, l.imm(offset))

    def reserve_guard_branch(self):
        self.BRCL(l.imm(0x0), l.imm(0))

    def trap(self):
        self.TRAP2()

    def trace(self):
        self.LGHI(r.r2, l.imm(17))
        self.XGR(r.r3, r.r3)
        self.SVC(l.imm(17))

    def cmp_op(self, a, b, pool=False, imm=False, signed=True, fp=False):
        if fp == True:
            if pool:
                self.CDB(a, b)
            else:
                self.CDBR(a, b)
        else:
            if signed:
                if pool:
                    # 64 bit immediate signed
                    self.CG(a, b)
                elif imm:
                    self.CGFI(a, b)
                else:
                    # 64 bit signed
                    self.CGR(a, b)
            else:
                if pool:
                    # 64 bit immediate unsigned
                    self.CLG(a, b)
                elif imm:
                    self.CLGFI(a, b)
                else:
                    # 64 bit unsigned
                    self.CLGR(a, b)

    def load_imm(self, dest_reg, word):
        if -2**15 <= word <= 2**15-1:
            self.LGHI(dest_reg, l.imm(word))
        elif -2**31 <= word <= 2**31-1:
            self.LGFI(dest_reg, l.imm(word))
        else:
            if self.pool and self.pool.contains_constant(word):
                self.LG(dest_reg, l.pool(self.pool.get_direct_offset(word)))
                return
            self.IILF(dest_reg, l.imm(word & 0xFFFFffff))
            self.IIHF(dest_reg, l.imm((word >> 32) & 0xFFFFffff))

    def load_imm_plus(self, dest_reg, word):
        """Like load_imm(), but with one instruction less, and
        leaves the loaded value off by some signed 16-bit difference.
        Returns that difference."""
        diff = rffi.cast(lltype.Signed, rffi.cast(rffi.SHORT, word))
        word -= diff
        assert word & 0xFFFF == 0
        self.load_imm(dest_reg, word)
        return diff

    def sync(self):
        self.BCR_rr(0xf,0)

    def raw_call(self, call_reg=r.r14):
        """Emit a call to the address stored in the register 'call_reg',
        which must be either RAW_CALL_REG or r11.  This is a regular C
        function pointer, which means on big-endian that it is actually
        the address of a three-words descriptor.
        """
        self.BASR(r.r14, call_reg)

    def reserve_cond_jump(self, short=False):
        self.trap()        # conditional jump, patched later
        self.trap()
        if not short:
            # 6 bytes instead of 2
            self.trap()

    def branch_absolute(self, addr):
        self.load_imm(r.r14, addr)
        self.BASR(r.r14, r.r14)

    def store_link(self):
        self.STMG(r.r14, r.r15, l.addr(14*WORD, r.SP))

    def restore_link(self):
        off = STD_FRAME_SIZE_IN_BYTES
        self.LMG(r.r14, r.r15, l.addr(off+14*WORD, r.SP))

    def push_std_frame(self, additional_bytes=0):
        off = (STD_FRAME_SIZE_IN_BYTES + additional_bytes)
        self.STG(r.SP, l.addr(-off, r.SP))
        self.LAY(r.SP, l.addr(-off, r.SP))

    def pop_std_frame(self, additional_bytes=0):
        self.LAY(r.SP, l.addr(STD_FRAME_SIZE_IN_BYTES + additional_bytes, r.SP))

    def get_assembler_function(self):
        "NOT_RPYTHON: tests only"
        from rpython.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
        class FakeCPU:
            HAS_CODEMAP = False
            asmmemmgr = AsmMemoryManager()
        addr = self.materialize(FakeCPU(), [])
        return rffi.cast(lltype.Ptr(lltype.FuncType([], lltype.Signed)), addr)

class OverwritingBuilder(BlockBuilderMixin, AbstractZARCHBuilder):
    def __init__(self, mc, start, num_insts=0):
        AbstractZARCHBuilder.__init__(self)
        self.init_block_builder()
        self.mc = mc
        self.index = start

    def writechar(self, c):
        self.mc.overwrite(self.index, c)
        self.index += 1

    def overwrite(self):
        pass

_classes = (AbstractZARCHBuilder,)

# Used to build the MachineCodeBlockWrapper
all_instructions = sorted([name for cls in _classes for name in cls.__dict__ \
                          if name.split('_')[0].isupper() and '_' in name and \
                             not name.endswith('_byte_count')])