• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Nix flake for RPython interpreters


Commit MetaInfo

Revisão86c548543683f7b611db4351c39fce3e3147c885 (tree)
Hora2024-04-20 04:17:28
AutorCorbin <cds@corb...>
CommiterCorbin

Mensagem de Log

bf: Add optimizing ops, peephole, delooper.

Simpler than it sounds! I get to exploit the Abelian group actions on
the two pairs of ops Inc/Dec and Right/Left to track them with integers,
and they are free other than the type tag; this works because integers
are the initial Abelian group.

I've seen a couple folks go further down this particular direction, but
I'm going to say that this is sufficient for now, because we're now 20%
faster on Mandelbrot than Brown's original interpreter. Our main source
of speedups is fundamentally from reducing the tape from a
dynamically-allocated compound structure into a statically-allocated
arena. We also use op fusion to overcome otherwise-difficult sequences
for the JIT, like repeated subtraction and copying/moving memory.

Mudança Sumário

Diff

--- a/bf/bf.py
+++ b/bf/bf.py
@@ -13,7 +13,8 @@ def printableProgram(program): return program.asStr()
1313 jitdriver = JitDriver(greens=['program'], reds=['position', 'tape'],
1414 get_printable_location=printableProgram)
1515
16-class Op(object): pass
16+class Op(object):
17+ _immutable_fields_ = "width",
1718
1819 class _Input(Op):
1920 def asStr(self): return ','
@@ -27,35 +28,41 @@ class _Output(Op):
2728 os.write(1, chr(tape[position]))
2829 return position
2930 Output = _Output()
30-class _Inc(Op):
31- def asStr(self): return '+'
31+class Add(Op):
32+ _immutable_fields_ = "imm",
33+ def __init__(self, imm): self.imm = imm
34+ def asStr(self): return "add(%d)" % self.imm
3235 def runOn(self, tape, position):
33- tape[position] += 1
36+ tape[position] += self.imm
3437 return position
35-Inc = _Inc()
36-class _Dec(Op):
37- def asStr(self): return '-'
38+Inc = Add(1)
39+Dec = Add(-1)
40+class Shift(Op):
41+ _immutable_fields_ = "width",
42+ def __init__(self, width): self.width = width
43+ def asStr(self): return "shift(%d)" % self.width
44+ def runOn(self, tape, position): return position + self.width
45+Left = Shift(-1)
46+Right = Shift(1)
47+class _Zero(Op):
48+ def asStr(self): return "0"
3849 def runOn(self, tape, position):
39- tape[position] -= 1
50+ tape[position] = 0
4051 return position
41-Dec = _Dec()
42-class _Left(Op):
43- def asStr(self): return '<'
52+Zero = _Zero()
53+class ZeroAdd(Op):
54+ _immutable_fields_ = "offset",
55+ def __init__(self, offset): self.offset = offset
56+ def asStr(self): return "zeroadd(%d)" % self.offset
4457 def runOn(self, tape, position):
45- if position == 0: raise Exception("Stack underflow")
46- return position - 1
47-Left = _Left()
48-class _Right(Op):
49- def asStr(self): return '>'
50- def runOn(self, tape, position):
51- if len(tape) <= position: tape.extend([0] * 1000)
52- return position + 1
53-Right = _Right()
58+ tape[position + self.offset] += tape[position]
59+ tape[position] = 0
60+ return position
5461 class Loop(Op):
5562 _immutable_fields_ = "ops[*]",
5663 def __init__(self, ops): self.ops = ops
5764 def asStr(self):
58- return '[' + ''.join([op.asStr() for op in self.ops]) + ']'
65+ return '[' + '; '.join([op.asStr() for op in self.ops]) + ']'
5966 def runOn(self, tape, position):
6067 while tape[position]:
6168 jitdriver.jit_merge_point(program=self,
@@ -63,6 +70,35 @@ class Loop(Op):
6370 for op in self.ops: position = op.runOn(tape, position)
6471 return position
6572
73+def peep(ops):
74+ rv = []
75+ temp = ops[0]
76+ for op in ops[1:]:
77+ if isinstance(temp, Shift) and isinstance(op, Shift):
78+ temp = Shift(temp.width + op.width)
79+ elif isinstance(temp, Add) and isinstance(op, Add):
80+ temp = Add(temp.imm + op.imm)
81+ else:
82+ rv.append(temp)
83+ temp = op
84+ rv.append(temp)
85+ return rv
86+
87+def oppositeShifts(op1, op2):
88+ if not isinstance(op1, Shift) or not isinstance(op2, Shift): return False
89+ return op1.width == -op2.width
90+
91+def isConstAdd(op, imm): return isinstance(op, Add) and op.imm == imm
92+
93+def loopish(ops):
94+ if len(ops) == 1 and isConstAdd(ops[0], -1):
95+ return Zero
96+ elif (len(ops) == 4 and
97+ isConstAdd(ops[0], -1) and isConstAdd(ops[2], 1) and
98+ oppositeShifts(ops[1], ops[3])):
99+ return ZeroAdd(ops[1].width)
100+ return Loop(ops[:])
101+
66102 parseTable = {
67103 ',': Input, '.': Output,
68104 '+': Inc, '-': Dec,
@@ -75,17 +111,22 @@ def parse(s):
75111 if char in parseTable: ops[-1].append(parseTable[char])
76112 elif char == '[': ops.append([])
77113 elif char == ']':
78- loop = Loop(ops.pop()[:])
114+ loop = loopish(peep(ops.pop()))
79115 ops[-1].append(loop)
80116
81- return ops.pop()
117+ return peep(ops.pop())
82118
83119 def entryPoint(argv):
84- if len(argv) < 2:
85- print "You must supply a filename"
120+ if len(argv) < 2 or "-h" in argv:
121+ print "Usage: bf [-c <number of cells>] [-h] <program.bf>"
86122 return 1
87- with open(argv[1]) as handle: program = parse(handle.read())
88- tape = [0] * 30000
123+ cells = 30000
124+ if argv[1] == "-c":
125+ cells = int(argv[2])
126+ path = argv[3]
127+ else: path = argv[1]
128+ with open(path) as handle: program = parse(handle.read())
129+ tape = [0] * cells
89130 position = 0
90131 for op in program: position = op.runOn(tape, position)
91132 return 0