Revert non-recursive tree walk. Make CFG re-entrant.
This commit is contained in:
4
gi.go
4
gi.go
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
//}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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, "}")
|
||||
|
||||
@@ -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{})}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user