Author: Richard Plangger <[email protected]>
Branch: s390x-backend
Changeset: r80195:6177697cbd11
Date: 2015-10-14 12:25 +0200
http://bitbucket.org/pypy/pypy/changeset/6177697cbd11/
Log: started the auto instruction encoding, AR_rr correctly assembles
diff --git a/rpython/jit/backend/zarch/codebuilder.py
b/rpython/jit/backend/zarch/codebuilder.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/zarch/codebuilder.py
@@ -0,0 +1,93 @@
+from rpython.jit.backend.zarch import conditions as cond
+from rpython.jit.backend.zarch import registers as reg
+from rpython.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
+from rpython.tool.udir import udir
+from rpython.jit.backend.detect_cpu import autodetect
+
+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=cond.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
+
+
+codes = {
+ 'ADD_rr': 0x1A,
+}
+
+def encode_rr(reg1, reg2):
+ return chr(((reg2 & 0x0f) << 4) | (reg1 & 0xf))
+
+class AbstractZARCHBuilder(object):
+ def write32(self, word):
+ self.writechar(chr(word & 0xFF))
+ self.writechar(chr((word >> 8) & 0xFF))
+ self.writechar(chr((word >> 16) & 0xFF))
+ self.writechar(chr((word >> 24) & 0xFF))
+
+ def AR_rr(self, reg1, reg2):
+ self.writechar(chr(0x1A))
+ self.writechar(encode_rr(reg1, reg2))
+
+class InstrBuilder(BlockBuilderMixin, AbstractZARCHBuilder):
+
+ def __init__(self):
+ AbstractZARCHBuilder.__init__(self)
+ self.init_block_builder()
+ #
+ # 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", 'arm')
+
+ def currpos(self):
+ return self.get_relative_pos()
+
+#define_instructions(AbstractARMBuilder)
+
+_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()])
diff --git a/rpython/jit/backend/zarch/runner.py
b/rpython/jit/backend/zarch/runner.py
--- a/rpython/jit/backend/zarch/runner.py
+++ b/rpython/jit/backend/zarch/runner.py
@@ -9,7 +9,7 @@
def cast_ptr_to_int(x):
adr = llmemory.cast_ptr_to_adr(x)
- return adr
+ return adr # TODO
cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)'
cast_ptr_to_int = staticmethod(cast_ptr_to_int)
diff --git a/rpython/jit/backend/zarch/test/test_assembler.py
b/rpython/jit/backend/zarch/test/test_assembler.py
--- a/rpython/jit/backend/zarch/test/test_assembler.py
+++ b/rpython/jit/backend/zarch/test/test_assembler.py
@@ -18,7 +18,6 @@
CPU = getcpuclass()
-
class TestRunningAssembler(object):
def setup_method(self, method):
cpu = CPU(None, None)
diff --git a/rpython/jit/backend/zarch/test/test_auto_encoding.py
b/rpython/jit/backend/zarch/test/test_auto_encoding.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/zarch/test/test_auto_encoding.py
@@ -0,0 +1,280 @@
+import os, random, struct
+import subprocess
+import py
+from rpython.jit.backend.zarch import codebuilder
+from rpython.rlib.rarithmetic import intmask
+from rpython.tool.udir import udir
+
+INPUTNAME = 'checkfile_%s.s'
+FILENAME = 'checkfile_%s.o'
+BEGIN_TAG = '<<<zarch-test-begin>>>'
+END_TAG = '<<<zarch-test-end>>>'
+
+class CodeCheckerMixin(object):
+ def __init__(self, expected, accept_unnecessary_prefix):
+ self.expected = expected
+ self.accept_unnecessary_prefix = accept_unnecessary_prefix
+ self.index = 0
+
+ def begin(self, op):
+ self.op = op
+ self.instrindex = self.index
+
+ def writechar(self, char):
+ if char != self.expected[self.index:self.index+1]:
+ if (char == self.accept_unnecessary_prefix
+ and self.index == self.instrindex):
+ return # ignore the extra character '\x40'
+ print self.op
+ print "\x09from codebuilder.py:",
hexdump(self.expected[self.instrindex:self.index] + char)+"..."
+ print "\x09from 'as': ",
hexdump(self.expected[self.instrindex:self.index+15])+"..."
+ raise Exception("Differs")
+ self.index += 1
+
+ def done(self):
+ assert len(self.expected) == self.index
+
+ def stack_frame_size_delta(self, delta):
+ pass # ignored
+
+ def check_stack_size_at_ret(self):
+ pass # ignored
+
+class CodeCheckerZARCH(CodeCheckerMixin, codebuilder.InstrBuilder):
+ pass
+
+def hexdump(s):
+ return ' '.join(["%02X" % ord(c) for c in s])
+
+def reduce_to_32bit(s):
+ if s[:2] != '%r':
+ return s
+ if s[2:].isdigit():
+ return s + 'd'
+ else:
+ return '%e' + s[2:]
+
+# ____________________________________________________________
+
+COUNT1 = 15
+suffixes = {0:'', 1:'b', 2:'w', 4:'l', 8:'q'}
+
+
+class TestZARCH(object):
+ WORD = 8
+ TESTDIR = 'zarch'
+ REGS = range(15+1)
+ REGNAMES = ['%%r%d' % i for i in REGS]
+ accept_unnecessary_prefix = None
+ methname = '?'
+
+ def reg_tests(self):
+ return self.REGS
+
+ def stack_bp_tests(self, count=COUNT1):
+ return ([0, 4, -4, 124, 128, -128, -132] +
+ [random.randrange(-0x20000000, 0x20000000) * 4
+ for i in range(count)])
+
+ def stack_sp_tests(self, count=COUNT1):
+ return ([0, 4, 124, 128] +
+ [random.randrange(0, 0x20000000) * 4
+ for i in range(count)])
+
+ def memory_tests(self):
+ return [(reg, ofs)
+ for reg in self.NONSPECREGS
+ for ofs in self.stack_bp_tests(5)
+ ]
+
+ def array_tests(self):
+ return [(reg1, reg2, scaleshift, ofs)
+ for reg1 in self.NONSPECREGS
+ for reg2 in self.NONSPECREGS
+ for scaleshift in [0, 1, 2, 3]
+ for ofs in self.stack_bp_tests(1)
+ ]
+
+ def imm8_tests(self):
+ v = ([-128,-1,0,1,127] +
+ [random.randrange(-127, 127) for i in range(COUNT1)])
+ return v
+
+ def imm32_tests(self):
+ v = ([-0x80000000, 0x7FFFFFFF, 128, 256, -129, -255] +
+ [random.randrange(-32768,32768)<<16 |
+ random.randrange(0,65536) for i in range(COUNT1)] +
+ [random.randrange(128, 256) for i in range(COUNT1)])
+ return self.imm8_tests() + v
+
+ def relative_tests(self):
+ py.test.skip("explicit test required for %r" % (self.methname,))
+
+ def get_all_tests(self):
+ return {
+ 'r': self.reg_tests,
+ }
+
+ def assembler_operand_reg(self, regnum):
+ return self.REGNAMES[regnum]
+
+ def assembler_operand_reg8(self, regnum):
+ assert regnum & rx86.BYTE_REG_FLAG
+ return self.REGNAMES8[regnum &~ rx86.BYTE_REG_FLAG]
+
+ def assembler_operand_xmm_reg(self, regnum):
+ return self.XMMREGNAMES[regnum]
+
+ def assembler_operand_stack_bp(self, position):
+ return '%d(%s)' % (position, self.REGNAMES[5])
+
+ def assembler_operand_stack_sp(self, position):
+ return '%d(%s)' % (position, self.REGNAMES[4])
+
+ def assembler_operand_memory(self, (reg1, offset)):
+ if not offset: offset = ''
+ return '%s(%s)' % (offset, self.REGNAMES[reg1])
+
+ def assembler_operand_array(self, (reg1, reg2, scaleshift, offset)):
+ if not offset: offset = ''
+ return '%s(%s,%s,%d)' % (offset, self.REGNAMES[reg1],
+ self.REGNAMES[reg2], 1<<scaleshift)
+
+ def assembler_operand_imm(self, value):
+ return '$%d' % value
+
+ def assembler_operand_imm_addr(self, value):
+ return '%d' % value
+
+ def get_all_assembler_operands(self):
+ return {
+ 'r': self.assembler_operand_reg,
+ }
+
+ def run_test(self, methname, instrname, argmodes, args_lists,
+ instr_suffix=None):
+ global labelcount
+ labelcount = 0
+ oplist = []
+ testdir = udir.ensure(self.TESTDIR, dir=1)
+ inputname = str(testdir.join(INPUTNAME % methname))
+ filename = str(testdir.join(FILENAME % methname))
+ with open(inputname, 'w') as g:
+ g.write('\x09.string "%s"\n' % BEGIN_TAG)
+ #
+ for args in args_lists:
+ suffix = ""
+ if instr_suffix is not None:
+ suffix = instr_suffix # overwrite
+
+ assembler_operand = self.get_all_assembler_operands()
+ ops = []
+ for mode, v in zip(argmodes, args):
+ ops.append(assembler_operand[mode](v))
+ ops.reverse()
+ #
+ op = '\t%s%s %s' % (instrname.lower(), suffix,
+ ', '.join(ops))
+ g.write('%s\n' % op)
+ oplist.append(op)
+ g.write('\t.string "%s"\n' % END_TAG)
+ proc = subprocess.Popen(['as', '-m' + str(self.WORD*8), '-mzarch',
+ inputname, '-o', filename],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = proc.communicate()
+ if proc.returncode or stderr:
+ raise Exception("could not execute assembler. error:\n%s" %
(stderr))
+ with open(inputname, 'r') as g:
+ got = g.read()
+ error = [line for line in got.splitlines() if 'error' in line.lower()]
+ if error:
+ raise Exception("Assembler got an error: %r" % error[0])
+ error = [line for line in got.splitlines()
+ if 'warning' in line.lower()]
+ if error:
+ raise Exception("Assembler got a warning: %r" % error[0])
+ try:
+ with open(filename, 'rb') as f:
+ data = f.read()
+ i = data.find(BEGIN_TAG)
+ assert i>=0
+ j = data.find(END_TAG, i)
+ assert j>=0
+ as_code = data[i+len(BEGIN_TAG)+1:j]
+ except IOError:
+ raise Exception("Assembler did not produce output?")
+ return oplist, as_code
+
+ def make_all_tests(self, methname, modes, args=[]):
+ if modes:
+ tests = self.get_all_tests()
+ m = modes[0]
+ lst = tests[m]()
+ random.shuffle(lst)
+ if methname == 'PSRAD_xi' and m == 'i':
+ lst = [x for x in lst if 0 <= x <= 31]
+ result = []
+ for v in lst:
+ result += self.make_all_tests(methname, modes[1:], args+[v])
+ return result
+ else:
+ # special cases
+ if methname in ('ADD_ri', 'AND_ri', 'CMP_ri', 'OR_ri',
+ 'SUB_ri', 'XOR_ri', 'SBB_ri'):
+ if args[0] == rx86.R.eax:
+ return [] # ADD EAX, constant: there is a special encoding
+ if methname in ('CMP8_ri',):
+ if args[0] == rx86.R.al:
+ return [] # CMP AL, constant: there is a special encoding
+ if methname == 'XCHG_rr' and rx86.R.eax in args:
+ return [] # special encoding
+ if methname == 'MOV_rj' and args[0] == rx86.R.eax:
+ return [] # MOV EAX, [immediate]: there is a special encoding
+ if methname == 'MOV_jr' and args[1] == rx86.R.eax:
+ return [] # MOV [immediate], EAX: there is a special encoding
+ if methname == 'MOV8_rj' and args[0] == rx86.R.al:
+ return [] # MOV AL, [immediate]: there is a special encoding
+ if methname == 'MOV8_jr' and args[1] == rx86.R.al:
+ return [] # MOV [immediate], AL: there is a special encoding
+
+ return [args]
+
+ def should_skip_instruction(self, instrname, argmodes):
+ return False
+
+ def complete_test(self, methname):
+ if '_' in methname:
+ instrname, argmodes = methname.split('_')
+ else:
+ instrname, argmodes = methname, ''
+
+ if self.should_skip_instruction(instrname, argmodes):
+ print "Skipping %s" % methname
+ return
+
+ instr_suffix = None
+
+ print "Testing %s with argmodes=%r" % (instrname, argmodes)
+ self.methname = methname
+ ilist = self.make_all_tests(methname, argmodes)
+ oplist, as_code = self.run_test(methname, instrname, argmodes, ilist,
+ instr_suffix)
+ cc = CodeCheckerZARCH(as_code, self.accept_unnecessary_prefix)
+ for op, args in zip(oplist, ilist):
+ if op:
+ cc.begin(op)
+ getattr(cc, methname)(*args)
+ cc.done()
+
+ def setup_class(cls):
+ import os
+ g = os.popen('as -version </dev/null -o /dev/null 2>&1')
+ data = g.read()
+ g.close()
+ if not data.startswith('GNU assembler'):
+ py.test.skip("full tests require the GNU 'as' assembler")
+
+ @py.test.mark.parametrize("name", codebuilder.all_instructions)
+ def test_all(self, name):
+ self.complete_test(name)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit