package untitled14
import (
"fmt"
"strconv"
)
type operator struct {
symbol string
swap bool
throughput, latency uint
gap uint
}
type node struct {
id string
ref, constant uint
start, gap uint
value uint64
opt bool
op *operator
operands []*node
parents []*node
}
type tree struct {
level [][]*node
}
const (
cflag = "@c"
high = "@h"
assign = "="
add = "+"
mul = "*"
)
var operators = map[string]*operator{
high: &operator{symbol: high, throughput: 0, latency: 0},
assign: &operator{symbol: assign, throughput: 1, latency: 4},
add: &operator{symbol: add, throughput: 1, latency: 2, swap: true},
mul: &operator{symbol: mul, throughput: 2, latency: 6, swap: true},
}
func step(m map[string]*node, out string, op *operator, in ...string) {
o := &node{id: out, op: op, constant: 1}
inputs := []*node(nil)
for _, v := range in {
var r *node
if isNum(v[0]) {
r = &node{id: v, constant: 1}
} else {
var ok bool
r, ok = m[v]
if !ok {
r = &node{id: v}
m[v] = r
}
r.ref++
}
r.parents = append(r.parents, o)
inputs = append(inputs, r)
}
o.operands = inputs
m[out] = o
}
func serach(r *tree, i int, n *node) {
if i >= len(r.level) {
r.level = append(r.level, nil)
}
r.level[i] = append(r.level[i], n)
for _, v := range n.operands {
serach(r, i+1, v)
}
}
func buildTree(root *node) *tree {
t := &tree{make([][]*node, 1)}
serach(t, 0, root)
return t
}
type pool struct {
pool map[string]bool
i, max int
}
func newPool() *pool {
return &pool{pool: make(map[string]bool)}
}
func (r *pool) alloc() string {
s := "$" + itoa(r.i)
r.i++
if r.i > r.max {
r.max = r.i
}
return s
}
func (r *pool) get() string {
for k, v := range r.pool {
if v {
return k
}
}
return r.alloc()
}
func (r *pool) put(s string) {
r.pool[s] = true
}
func (r *pool) del(s string) {
r.pool[s] = false
}
func optimize(root *node, r *pool) error {
constant := uint(1)
for _, v := range root.operands {
if !v.opt {
err := optimize(v, r)
if err != nil {
return err
}
v.opt = true
}
constant &= v.constant
root.constant = constant
}
for _, v := range root.operands {
v.ref--
if v.ref == 0 {
r.put(v.id)
}
}
if root.op != nil {
if root.op.swap {
if !(len(root.operands) == 2 || len(root.operands) == 3 && root.operands[2].id == cflag) {
return fmt.Errorf("swap: %d while %d", 2, len(root.operands))
}
if root.operands[0].ref > root.operands[1].ref {
t := root.operands[0]
root.operands[0] = root.operands[1]
root.operands[1] = t
}
}
if root.operands[0].ref == 0 {
root.id = root.operands[0].id
} else {
root.id = r.get()
}
}
if root.constant == 1 {
root.ref = 0
root.op = nil
root.operands = nil
} else {
r.del(root.id)
}
return nil
}
func f(p []*node) {
}
func chronograph(root *node) {
for _, v := range root.operands {
if v.op != nil {
chronograph(v)
if v.start > root.start {
root.start = v.start
}
}
}
if root.op != nil {
root.start += root.op.latency
}
}
func build(string) []*node {
return nil
}
func itoa(i int) string {
return strconv.Itoa(i)
}
func isNum(b byte) bool {
return b >= '0' && b <= '9'
}
func init() {
for _, v := range operators {
v.gap = v.latency - v.throughput
}
}
func TestOptimize(t *testing.T) {
m := make(map[string]*node)
step(m, "#0", operators[add], "b", "c")
step(m, "#1", operators[add], "#0", "c")
step(m, "#2", operators[mul], "39", "18")
step(m, "r", operators[mul], "#1", "#2")
buf := bytes.NewBuffer(nil)
err := optimize(m["r"], newPool())
if err != nil {
t.Fatal(err)
}
write(buf, buildTree(m["r"]))
expect := `b
b c
b c
b c
`
if buf.String() != expect {
t.Fatal(buf.String())
}
chronograph(m["r"])
fmt.Println(buf.String())
}