[pypy-svn] r67905 - in pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86: . test
arigo at codespeak.net
arigo at codespeak.net
Sat Sep 26 12:09:30 CEST 2009
Author: arigo
Date: Sat Sep 26 12:09:29 2009
New Revision: 67905
Modified:
pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py
pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py
pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py
Log:
Some more instructions, and start fixing test_ri386_auto_encoding.py.
Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py
==============================================================================
--- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py (original)
+++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py Sat Sep 26 12:09:29 2009
@@ -59,29 +59,19 @@
return encode_immediate, argnum, width
# ____________________________________________________________
-# Emit a mod/rm referencing a stack location
-# This depends on the fact that our function prologue contains
-# exactly 4 PUSHes.
-
-def get_ebp_ofs(position):
- # Argument is a stack position (0, 1, 2...).
- # Returns (ebp-16), (ebp-20), (ebp-24)...
- # This depends on the fact that our function prologue contains
- # exactly 4 PUSHes.
- return -WORD * (4 + position)
+# Emit a mod/rm referencing a stack location (%ebp+arg)
def single_byte(value):
return -128 <= value < 128
@specialize.arg(2)
def encode_stack(mc, arg, allow_single_byte, orbyte):
- offset = get_ebp_ofs(arg)
- if allow_single_byte and single_byte(offset):
+ if allow_single_byte and single_byte(arg):
mc.writechar(chr(0x40 | ebp | orbyte))
- mc.writeimm8(offset)
+ mc.writeimm8(arg)
else:
mc.writechar(chr(0x80 | ebp | orbyte))
- mc.writeimm32(offset)
+ mc.writeimm32(arg)
return 0
def stack(argnum, allow_single_byte=True):
@@ -109,6 +99,23 @@
encoding_steps = unrolling_iterable(encoding_steps)
return encode
+def common_modes(group):
+ base = group * 8
+ INSN_ri8 = insn('\x83', orbyte(group<<3), register(1), '\xC0',
+ immediate(2,'b'))
+ INSN_ri32 = insn('\x81', orbyte(group<<3), register(1), '\xC0',
+ immediate(2))
+ INSN_rr = insn(chr(base+1), register(2,8), register(1,1), '\xC0')
+ INSN_rs = insn(chr(base+3), register(1,8), stack(2))
+
+ def INSN_ri(mc, reg, immed):
+ if single_byte(immed):
+ INSN_ri8(mc, reg, immed)
+ else:
+ INSN_ri32(mc, reg, immed)
+
+ return INSN_ri, INSN_rr, INSN_rs
+
# ____________________________________________________________
@@ -137,6 +144,12 @@
MOV_sr = insn('\x89', register(2,8), stack(1))
MOV_rs = insn('\x8B', register(1,8), stack(2))
- NOP = insn('\x90')
+ ADD_ri, ADD_rr, ADD_rs = common_modes(0)
+ OR_ri, OR_rr, OR_rs = common_modes(1)
+ AND_ri, AND_rr, AND_rs = common_modes(4)
+ SUB_ri, SUB_rr, SUB_rs = common_modes(5)
+ XOR_ri, XOR_rr, XOR_rs = common_modes(6)
+ CMP_ri, CMP_rr, CMP_rs = common_modes(7)
- ADD_rr = insn('\x01', register(2,8), register(1), '\xC0')
+ NOP = insn('\x90')
+ RET = insn('\xC3')
Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py
==============================================================================
--- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py (original)
+++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py Sat Sep 26 12:09:29 2009
@@ -19,7 +19,7 @@
def test_mov_si():
s = CodeBuilder()
- s.MOV_si(5, 1<<24)
+ s.MOV_si(-36, 1<<24)
assert s.getvalue() == '\xC7\x45\xDC\x00\x00\x00\x01'
def test_mov_rr():
@@ -29,12 +29,12 @@
def test_mov_sr():
s = CodeBuilder()
- s.MOV_sr(5, edx)
+ s.MOV_sr(-36, edx)
assert s.getvalue() == '\x89\x55\xDC'
def test_mov_rs():
s = CodeBuilder()
- s.MOV_rs(edx, 5)
+ s.MOV_rs(edx, -36)
assert s.getvalue() == '\x8B\x55\xDC'
def test_nop_add_rr():
Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py
==============================================================================
--- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py (original)
+++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py Sat Sep 26 12:09:29 2009
@@ -1,7 +1,6 @@
-import os, random, string, struct
+import os, random, struct
import py
-from pypy.jit.backend.x86 import ri386 as i386
-from pypy.jit.backend.x86.ri386setup import all_instructions
+from pypy.jit.backend.x86 import ri386
from pypy.tool.udir import udir
INPUTNAME = str(udir.join('checkfile.s'))
@@ -12,61 +11,31 @@
COUNT1 = 15
COUNT2 = 25
-
-sizes = {
- i386.EAX: 4,
- i386.ECX: 4,
- i386.EDX: 4,
- i386.EBX: 4,
- i386.ESP: 4,
- i386.EBP: 4,
- i386.ESI: 4,
- i386.EDI: 4,
-
- i386.AL: 1,
- i386.CL: 1,
- i386.DL: 1,
- i386.BL: 1,
- i386.AH: 1,
- i386.CH: 1,
- i386.DH: 1,
- i386.BH: 1,
-
- i386.REG: 4,
- i386.MODRM: 4,
- i386.MODRM64: 8,
- i386.IMM32: 4,
- i386.REG8: 1,
- i386.MODRM8: 1,
- i386.IMM8: 1,
- i386.IMM16: 2,
- #i386.REL8: 1,
- i386.REL32: 4,
-}
-
suffixes = {0:'', 1:'b', 2:'w', 4:'l'}
def reg_tests():
- return i386.registers[:]
+ return range(8)
-def reg8_tests():
- return i386.registers8[:]
+def stack_tests():
+ return ([0, 4, -4, 124, 128, -128, -132] +
+ [random.randrange(-0x20000000, 0x20000000) * 4
+ for i in range(COUNT1)])
def imm8_tests():
v = [-128,-1,0,1,127] + [random.randrange(-127, 127) for i in range(COUNT1)]
- return map(i386.imm8, v)
+ return v
def imm16_tests():
v = [-32768,32767] + [random.randrange(-32767, -128) for i in range(COUNT1)] \
+ [random.randrange(128, 32767) for i in range(COUNT1)]
- return map(i386.imm16, v)
+ return v
def imm32_tests():
v = ([0x80000000, 0x7FFFFFFF, 128, 256, -129, -255] +
[random.randrange(0,65536)<<16 |
random.randrange(0,65536) for i in range(COUNT1)] +
[random.randrange(128, 256) for i in range(COUNT1)])
- return map(i386.imm32, filter(lambda x: x<-128 or x>=128, v))
+ return imm8_tests() + v
def pick1(memSIB, cache=[]):
base = random.choice([None, None, None] + i386.registers)
@@ -98,53 +67,47 @@
return i386.registers8 + [pick1(i386.memSIB8) for i in range(COUNT2)]
tests = {
- i386.EAX: lambda: [i386.eax],
- i386.ECX: lambda: [i386.ecx],
- i386.EDX: lambda: [i386.edx],
- i386.EBX: lambda: [i386.ebx],
- i386.ESP: lambda: [i386.esp],
- i386.EBP: lambda: [i386.ebp],
- i386.ESI: lambda: [i386.esi],
- i386.EDI: lambda: [i386.edi],
-
- i386.AL: lambda: [i386.al],
- i386.CL: lambda: [i386.cl],
- i386.DL: lambda: [i386.dl],
- i386.BL: lambda: [i386.bl],
- i386.AH: lambda: [i386.ah],
- i386.CH: lambda: [i386.ch],
- i386.DH: lambda: [i386.dh],
- i386.BH: lambda: [i386.bh],
-
- i386.REG: reg_tests,
- i386.MODRM: modrm_tests,
- i386.MODRM64: modrm64_tests,
- i386.XMMREG: xmm_tests,
- i386.IMM32: imm32_tests,
- i386.REG8: reg8_tests,
- i386.MODRM8: modrm8_tests,
- i386.IMM8: imm8_tests,
- i386.IMM16: imm16_tests,
- #i386.REL8: imm8_tests,
- i386.REL32: lambda: [], # XXX imm32_tests,
+ 'r': reg_tests,
+ 's': stack_tests,
+ 'i': imm32_tests,
+ }
+
+regnames = ['%eax', '%ecx', '%edx', '%ebx', '%esp', '%ebp', '%esi', '%edi']
+def assembler_operand_reg(regnum):
+ return regnames[regnum]
+
+def assembler_operand_stack(position):
+ if position == 0:
+ return '(%ebp)'
+ else:
+ return '%d(%%ebp)' % position
+
+def assembler_operand_imm(value):
+ return '$%d' % value
+
+assembler_operand = {
+ 'r': assembler_operand_reg,
+ 's': assembler_operand_stack,
+ 'i': assembler_operand_imm,
}
-def run_test(instrname, instr, args_lists):
+def run_test(instrname, argmodes, args_lists):
global labelcount
- instrname = instr.as_alias or instrname
labelcount = 0
oplist = []
g = open(INPUTNAME, 'w')
g.write('\x09.string "%s"\n' % BEGIN_TAG)
for args in args_lists:
suffix = ""
- all = instr.as_all_suffixes
- for m, extra in args:
- if m in (i386.MODRM, i386.MODRM8) or all:
- if not instrname == 'FNSTCW':
- suffix = suffixes[sizes[m]] + suffix
+## all = instr.as_all_suffixes
+## for m, extra in args:
+## if m in (i386.MODRM, i386.MODRM8) or all:
+## suffix = suffixes[sizes[m]] + suffix
+ if argmodes:
+ suffix = 'l'
+
following = ""
- if instr.indirect:
+ if False: # instr.indirect:
suffix = ""
if args[-1][0] == i386.REL32: #in (i386.REL8,i386.REL32):
labelcount += 1
@@ -157,15 +120,17 @@
k = -1
else:
k = len(args)
- for m, extra in args[:k]:
- assert m != i386.REL32 #not in (i386.REL8,i386.REL32)
- ops = [extra.assembler() for m, extra in args]
+ #for m, extra in args[:k]:
+ # assert m != i386.REL32 #not in (i386.REL8,i386.REL32)
+ ops = []
+ for mode, v in zip(argmodes, args):
+ ops.append(assembler_operand[mode](v))
ops.reverse()
- op = '\x09%s%s %s%s' % (instrname, suffix, string.join(ops, ", "),
- following)
+ op = '\t%s%s %s%s' % (instrname.lower(), suffix,
+ ', '.join(ops), following)
g.write('%s\n' % op)
oplist.append(op)
- g.write('\x09.string "%s"\n' % END_TAG)
+ g.write('\t.string "%s"\n' % END_TAG)
g.close()
os.system('as "%s" -o "%s"' % (INPUTNAME, FILENAME))
try:
@@ -174,75 +139,66 @@
raise Exception("Assembler error")
data = f.read()
f.close()
-## os.unlink(FILENAME)
-## os.unlink(INPUTNAME)
- i = string.find(data, BEGIN_TAG)
+ i = data.find(BEGIN_TAG)
assert i>=0
- j = string.find(data, END_TAG, i)
+ j = data.find(END_TAG, i)
assert j>=0
as_code = data[i+len(BEGIN_TAG)+1:j]
return oplist, as_code
-##def getreg(m, extra):
-## if m>=0:
-## return m
-## if m==i386.REG or m==i386.REG8:
-## return extra
-## if m==i386.MODRM or m==i386.MODRM8:
-## if extra[0]==i386.memRegister:
-## return extra[1][0]
-
-def rec_test_all(instrname, modes, args=[]):
+def make_all_tests(methname, modes, args=[]):
if modes:
m = modes[0]
- if instrname.startswith('F') and m is i386.MODRM:
- lst = modrm_noreg_tests()
- else:
- lst = tests[m]()
+ lst = tests[m]()
random.shuffle(lst)
result = []
- for extra in lst:
- result += rec_test_all(instrname, modes[1:], args+[(m,extra)])
+ for v in lst:
+ result += make_all_tests(methname, modes[1:], args+[v])
return result
else:
- if instrname == "MOV":
-## if args[0] == args[1]:
-## return [] # MOV reg, same reg
- if ((args[0][1] in (i386.eax, i386.al))
- and args[1][1].assembler().lstrip('-').isdigit()):
- return [] # MOV accum, [constant-address]
- if ((args[1][1] in (i386.eax, i386.al))
- and args[0][1].assembler().lstrip('-').isdigit()):
- return [] # MOV [constant-address], accum
- if instrname == "MOV16":
- return [] # skipped
- if instrname == "LEA":
- if (args[1][1].__class__ != i386.MODRM or
- args[1][1].is_register()):
- return []
- if instrname == "INT":
- if args[0][1].value == 3:
- return []
- if instrname in ('SHL', 'SHR', 'SAR'):
- if args[1][1].assembler() == '$1':
- return []
- if instrname in ('MOVZX', 'MOVSX'):
- if args[1][1].width == 4:
- return []
- if instrname == "TEST":
- if (args[0] != args[1] and
- isinstance(args[0][1], i386.REG) and
- isinstance(args[1][1], i386.REG)):
- return [] # TEST reg1, reg2 <=> TEST reg2, reg1
- if instrname.endswith('cond'):
- return []
+ # special cases
+ if methname in ('ADD_ri', 'AND_ri', 'CMP_ri', 'OR_ri',
+ 'SUB_ri', 'XOR_ri'):
+ if args[0] == ri386.eax:
+ return [] # ADD EAX, constant: there is a special encoding
+## if methname == "MOV_":
+#### if args[0] == args[1]:
+#### return [] # MOV reg, same reg
+## if ((args[0][1] in (i386.eax, i386.al))
+## and args[1][1].assembler().lstrip('-').isdigit()):
+## return [] # MOV accum, [constant-address]
+## if ((args[1][1] in (i386.eax, i386.al))
+## and args[0][1].assembler().lstrip('-').isdigit()):
+## return [] # MOV [constant-address], accum
+## if instrname == "MOV16":
+## return [] # skipped
+## if instrname == "LEA":
+## if (args[1][1].__class__ != i386.MODRM or
+## args[1][1].is_register()):
+## return []
+## if instrname == "INT":
+## if args[0][1].value == 3:
+## return []
+## if instrname in ('SHL', 'SHR', 'SAR'):
+## if args[1][1].assembler() == '$1':
+## return []
+## if instrname in ('MOVZX', 'MOVSX'):
+## if args[1][1].width == 4:
+## return []
+## if instrname == "TEST":
+## if (args[0] != args[1] and
+## isinstance(args[0][1], i386.REG) and
+## isinstance(args[1][1], i386.REG)):
+## return [] # TEST reg1, reg2 <=> TEST reg2, reg1
+## if instrname.endswith('cond'):
+## return []
return [args]
def hexdump(s):
- return string.join(["%02X" % ord(c) for c in s], " ")
+ return ' '.join(["%02X" % ord(c) for c in s])
-class CodeChecker(i386.I386CodeBuilder):
+class CodeChecker(ri386.I386CodeBuilder):
def __init__(self, expected):
self.expected = expected
@@ -252,39 +208,32 @@
self.op = op
self.instrindex = self.index
- def write(self, data):
- end = self.index+len(data)
- if data != self.expected[self.index:end]:
+ def writechar(self, char):
+ if char != self.expected[self.index:self.index+1]:
print self.op
- print "\x09from ri386.py:", hexdump(self.expected[self.instrindex:self.index] + data)+"..."
- print "\x09from 'as': ", hexdump(self.expected[self.instrindex:end])+"..."
+ print "\x09from ri386.py:", hexdump(self.expected[self.instrindex:self.index] + char)+"..."
+ print "\x09from 'as': ", hexdump(self.expected[self.instrindex:self.index+1])+"..."
raise Exception("Differs")
- self.index += len(data)
+ self.index += 1
+
+ def done(self):
+ assert len(self.expected) == self.index
-def complete_test(instrname, instr):
- print "Testing %s\x09(%d encodings)" % (instrname, len(instr.modes))
- ilist = []
- for modes in instr.modes:
- ilist += rec_test_all(instrname, modes)
- oplist, as_code = run_test(instrname, instr, ilist)
+def complete_test(methname):
+ if '_' in methname:
+ instrname, argmodes = methname.split('_')
+ else:
+ instrname, argmodes = methname, ''
+ print "Testing %s with argmodes=%r" % (instrname, argmodes)
+ ilist = make_all_tests(methname, argmodes)
+ oplist, as_code = run_test(instrname, argmodes, ilist)
cc = CodeChecker(as_code)
for op, args in zip(oplist, ilist):
if op:
cc.begin(op)
- getattr(cc, instrname)(*[extra for m, extra in args])
-
-def complete_tests():
- FORBIDDEN = ['CMOVPE', 'CMOVPO'] # why doesn't 'as' know about them?
- items = i386.__dict__.items()
- items.sort()
- for key, value in items:
- if isinstance(value, i386.Instruction):
- if key in FORBIDDEN:
- print "Skipped", key
- else:
- complete_test(key,value)
- print "Ok."
+ getattr(cc, methname)(*args)
+ cc.done()
def test_auto():
import os
@@ -294,18 +243,15 @@
if not data.startswith('GNU assembler'):
py.test.skip("full tests require the GNU 'as' assembler")
- def do_test(name, insn):
- #print name
+ def do_test(name):
if name in ('CMOVPE', 'CMOVPO'):
py.test.skip("why doesn't 'as' know about CMOVPE/CMOVPO?")
- complete_test(name, insn)
+ complete_test(name)
+
+ for name in all_instructions:
+ yield do_test, name
+
- items = all_instructions.items()
- items.sort()
- for key, value in items:
- yield do_test, key, value
- del key, value
-
-if __name__ == "__main__":
- #complete_test("TEST", i386.TEST)
- complete_tests()
+all_instructions = [name for name in ri386.I386CodeBuilder.__dict__
+ if name.split('_')[0].isupper()]
+all_instructions.sort()
More information about the Pypy-commit
mailing list