Revert non-recursive tree walk. Make CFG re-entrant.

This commit is contained in:
Marc Vertes
2018-02-05 13:40:23 +01:00
parent c63b81a87f
commit 24e3acd16a
7 changed files with 64 additions and 125 deletions

4
gi.go
View File

@@ -11,8 +11,8 @@ package main
func main() {
for a := 0; a < 10000; a++ {
//for a := 0; a < 20000000; a++ {
if (a & 0x8ff) == 0x800 {
//if (a & 0x8ffff) == 0x80000 {
if a & 0x8ff == 0x800 {
//if a & 0x8ffff == 0x80000 {
println(a)
}
}

View File

@@ -34,7 +34,6 @@ func Ast(src string) *Node {
if anc == nil {
root = nod
} else {
nod.rank = len(anc.Child)
anc.Child = append(anc.Child, nod)
}
st.push(nod)

View File

@@ -1,6 +1,7 @@
package interp
import (
"fmt"
"go/ast"
"go/token"
"reflect"
@@ -69,26 +70,26 @@ func (e *Node) Cfg() int {
n.isNop = true
n.run = nop
n.Start = n.Child[0].Start
n.Child[1].snext = n
n.Child[1].tnext = n
if len(n.Child) == 3 {
n.Child[2].snext = n
n.Child[2].tnext = n
}
n.Child[0].next[1] = n.Child[1].Start
n.Child[0].tnext = n.Child[1].Start
if len(n.Child) == 3 {
n.Child[0].next[0] = n.Child[2].Start
n.Child[0].fnext = n.Child[2].Start
} else {
n.Child[0].next[0] = n
n.Child[0].fnext = n
}
case *ast.ForStmt:
n.isNop = true
n.run = nop
// FIXME: works only if for node has 4 children
n.Start = n.Child[0].Start
n.Child[0].snext = n.Child[1].Start
n.Child[1].next[0] = n
n.Child[1].next[1] = n.Child[3].Start
n.Child[3].snext = n.Child[2].Start
n.Child[2].snext = n.Child[1].Start
n.Child[0].tnext = n.Child[1].Start
n.Child[1].fnext = n
n.Child[1].tnext = n.Child[3].Start
n.Child[3].tnext = n.Child[2].Start
n.Child[2].tnext = n.Child[1].Start
case *ast.BasicLit:
n.isConst = true
// FIXME: values must be converted to int or float if possible
@@ -125,11 +126,11 @@ func wireChild(n *Node) {
n.Start = n
}
for i := 1; i < len(n.Child); i++ {
n.Child[i-1].snext = n.Child[i].Start
n.Child[i-1].tnext = n.Child[i].Start
}
for i := len(n.Child) - 1; i >= 0; i-- {
if !n.Child[i].isLeaf() {
n.Child[i].snext = n
n.Child[i].tnext = n
break
}
}
@@ -138,11 +139,18 @@ func wireChild(n *Node) {
// optimisation: rewire CFG to skip nop nodes
func (e *Node) OptimCfg() {
e.Walk(nil, func(n *Node) {
for s := n.snext; s != nil && s.snext != nil; s = s.snext {
n.snext = s
}
for s := n.next[0]; s != nil && s.snext != nil; s = s.snext {
n.next[0] = s
for n.tnext != nil && n.tnext.isNop {
fmt.Println("next nop:", n.index, n.tnext.index)
n.tnext = n.tnext.tnext
}
//for s := n.tnext; s != nil && s.tnext != nil && s.fnext == nil; s = s.tnext {
// n.tnext = s
//}
//for s := n.tnext; s != nil && s.tnext != nil; s = s.tnext {
// n.tnext = s
//}
//for s := n.fnext; s != nil && s.tnext != nil; s = s.tnext {
// n.fnext = s
//}
})
}

View File

@@ -58,14 +58,11 @@ func (n *Node) CfgDot() {
return
}
fmt.Fprintf(dotin, "%d [label=\"%d %d\"]\n", n.index, n.index, n.findex)
if n.next[1] != nil {
fmt.Fprintf(dotin, "%d -> %d [color=green]\n", n.index, n.next[1].index)
}
if n.next[0] != nil {
fmt.Fprintf(dotin, "%d -> %d [color=red]\n", n.index, n.next[0].index)
}
if n.next[0] == nil && n.next[1] == nil && n.snext != nil {
fmt.Fprintf(dotin, "%d -> %d [color=purple]\n", n.index, n.snext.index)
if n.fnext != nil {
fmt.Fprintf(dotin, "%d -> %d [color=green]\n", n.index, n.tnext.index)
fmt.Fprintf(dotin, "%d -> %d [color=red]\n", n.index, n.fnext.index)
} else if n.tnext != nil {
fmt.Fprintf(dotin, "%d -> %d [color=purple]\n", n.index, n.tnext.index)
}
})
fmt.Fprintf(dotin, "}")

View File

@@ -13,9 +13,8 @@ type Node struct {
Child []*Node // child subtrees
anc *Node // ancestor
Start *Node // entry point in subtree (CFG)
snext *Node // successor (CFG)
next [2]*Node // conditional successors, for false and for true (CFG)
rank int // rank in child siblings (iterative walk)
tnext *Node // true branch successor (CFG)
fnext *Node // false branch successor (CFG)
index int // node index (dot display)
findex int // index of value in frame or frame size (func def)
run RunFun // function to run at CFG execution
@@ -60,54 +59,6 @@ func (n *Node) Walk(in func(n *Node), out func(n *Node)) {
}
}
// Same as n.Walk, non recursive
func (e *Node) Walk2(in func(n *Node), out func(n *Node)) {
if e == nil {
return
}
n := e
var up *Node
if in != nil {
in(n)
}
for {
if len(n.Child) > 0 {
if up != nil {
if rank := up.rank + 1; rank < len(n.Child) {
up = nil
n = n.Child[rank]
if in != nil {
in(n)
}
} else {
if out != nil {
out(n)
}
if n == e {
break
}
up = n
n = n.anc
}
} else {
n = n.Child[0]
if in != nil {
in(n)
}
}
} else {
if out != nil {
out(n)
}
if n == e {
break
}
up = n
n = n.anc
}
}
}
// NewInterpreter()creates and returns a new interpreter object
func NewInterpreter() *Interpreter {
return &Interpreter{sym: make(map[string]*interface{})}

View File

@@ -1,10 +1,11 @@
package interp
import (
"fmt"
"testing"
)
func TestWalk_1(t *testing.T) {
func ExampleWalk_1() {
src := `
package main
@@ -15,26 +16,33 @@ func main() {
n := Ast(src)
//n.AstDot()
n.Walk(func(n *Node) {
println("in:", n.index)
fmt.Println("in:", n.index)
}, func(n *Node) {
println("out:", n.index)
})
}
func TestWalk_2(t *testing.T) {
src := `
package main
func main() {
println(1)
}
`
n := Ast(src)
n.Walk2(func(n *Node) {
println("in:", n.index)
}, func(n *Node) {
println("out:", n.index)
fmt.Println("out:", n.index)
})
// Output:
// in: 1
// in: 2
// out: 2
// in: 3
// in: 4
// out: 4
// in: 5
// in: 6
// out: 6
// out: 5
// in: 7
// in: 8
// in: 9
// in: 10
// out: 10
// in: 11
// out: 11
// out: 9
// out: 8
// out: 7
// out: 3
// out: 1
}
func BenchmarkWalk(b *testing.B) {
@@ -57,26 +65,6 @@ func main() {
}
}
func BenchmarkWalk2(b *testing.B) {
src := `
package main
func main() {
println(1)
for a := 0; a < 10000; a++ {
if (a & 0x8ff) == 0x800 {
println(a)
}
}
}
`
n := Ast(src)
b.ResetTimer()
for i := 0; i < b.N; i++ {
n.Walk2(func(n *Node) {}, func(n *Node) {})
}
}
func ExampleEval_1() {
src := `
package main

View File

@@ -10,14 +10,10 @@ func (i *Interpreter) Run(entry *Node) {
// Start execution by runnning entry function and go to next
for n := entry; n != nil; {
n.run(n, f)
if n.snext != nil {
n = n.snext
} else if n.next[1] == nil && n.next[0] == nil {
break
} else if value(n, f).(bool) {
n = n.next[1]
if n.fnext == nil || value(n, f).(bool) {
n = n.tnext
} else {
n = n.next[0]
n = n.fnext
}
}
}