[dev.ssa] cmd/internal/ssa: delete ssac
We don't need this standalone tool any more. We can now feed the
ssa compiler directly from the Go frontend.
Change-Id: I922f1e061c2d3db6bf77acc137d4d1fc7dc86c0d
Reviewed-on: https://go-review.googlesource.com/10034
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/src/cmd/internal/ssa/ssac/.gitignore b/src/cmd/internal/ssa/ssac/.gitignore
deleted file mode 100644
index ab17b9d..0000000
--- a/src/cmd/internal/ssa/ssac/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-ssac
diff --git a/src/cmd/internal/ssa/ssac/fib.goir b/src/cmd/internal/ssa/ssac/fib.goir
deleted file mode 100644
index 0875d63..0000000
--- a/src/cmd/internal/ssa/ssac/fib.goir
+++ /dev/null
@@ -1,47 +0,0 @@
- (TYPE T127bd68 int)
- (TYPE T127bd68 int)
- (TYPE T127bd68 int)
- (TYPE T127bd68 int)
- (TYPE T7faedc523360 (FUNC (int) (int)))
- (TYPE T127bd68 int)
- (TYPE T127bd68 int)
- (TYPE T7faedc523360 (FUNC (int) (int)))
- (TYPE T127bd68 int)
- (TYPE T127bd68 int)
- (TYPE T127bd68 int)
- (TYPE T127bd68 int)
- (TYPE T127bd68 int)
- (TYPE T127bd68 int)
- (DCL n T127bd68)
- (AS n (LOAD (FP T127bd68 0)))
- (DCL ~r1 T127bd68)
- (DCL n T127bd68)
- (DCL autotmp_0000 T127bd68)
- (DCL fib T7faedc523360)
- (DCL n T127bd68)
- (DCL autotmp_0001 T127bd68)
- (DCL fib T7faedc523360)
- (DCL n T127bd68)
- (DCL ~r1 T127bd68)
- (DCL autotmp_0000 T127bd68)
- (DCL autotmp_0001 T127bd68)
- (DCL autotmp_0001 T127bd68)
- (DCL autotmp_0000 T127bd68)
- (IF (LT n (CINT 2)) .then0 .else0)
- (LABEL .then0)
- (AS ~r1 n)
- (AS (FP T127bd68 8) ~r1)
- (RETURN)
- (GOTO .end0)
- (LABEL .else0)
- (GOTO .end0)
- (LABEL .end0)
- (AS (SP T127bd68 0) (SUB n (CINT 1)))
- (CALL fib)
- (AS autotmp_0000 (LOAD (SP T127bd68 8)))
- (AS (SP T127bd68 0) (SUB n (CINT 2)))
- (CALL fib)
- (AS autotmp_0001 (LOAD (SP T127bd68 8)))
- (AS ~r1 (ADD autotmp_0000 autotmp_0001))
- (AS (FP T127bd68 8) ~r1)
- (RETURN)
diff --git a/src/cmd/internal/ssa/ssac/fibiter.goir b/src/cmd/internal/ssa/ssac/fibiter.goir
deleted file mode 100644
index 98b2b2b..0000000
--- a/src/cmd/internal/ssa/ssac/fibiter.goir
+++ /dev/null
@@ -1,62 +0,0 @@
- (NAME runtime·fibiter)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (TYPE Tf5dd68 int)
- (DCL a Tf5dd68)
- (DCL a Tf5dd68)
- (DCL b Tf5dd68)
- (DCL b Tf5dd68)
- (DCL i Tf5dd68)
- (DCL i Tf5dd68)
- (DCL i Tf5dd68)
- (DCL n Tf5dd68)
- (DCL autotmp_0002 Tf5dd68)
- (DCL i Tf5dd68)
- (DCL i Tf5dd68)
- (DCL autotmp_0002 Tf5dd68)
- (DCL autotmp_0002 Tf5dd68)
- (DCL autotmp_0003 Tf5dd68)
- (DCL a Tf5dd68)
- (DCL b Tf5dd68)
- (DCL a Tf5dd68)
- (DCL b Tf5dd68)
- (DCL b Tf5dd68)
- (DCL autotmp_0003 Tf5dd68)
- (DCL ~r1 Tf5dd68)
- (DCL a Tf5dd68)
- (AS n (LOAD (FP Tf5dd68 0)))
- (AS a (CINT 0))
- (AS b (CINT 1))
- (AS i (CINT 0))
- (GOTO .top0)
- (LABEL .top0)
- (IF (LT i n) .body0 .end0)
- (LABEL .body0)
- (AS autotmp_0003 (ADD a b))
- (AS a b)
- (AS b autotmp_0003)
- (AS autotmp_0002 i)
- (AS i (ADD autotmp_0002 (CINT 1)))
- (GOTO .top0)
- (LABEL .end0)
- (AS (FP Tf5dd68 8) a)
- (RETURN)
diff --git a/src/cmd/internal/ssa/ssac/main.go b/src/cmd/internal/ssa/ssac/main.go
deleted file mode 100644
index 2afa7c6..0000000
--- a/src/cmd/internal/ssa/ssac/main.go
+++ /dev/null
@@ -1,439 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-// Stub package for testing ssa compiler backend. Will eventually
-// be deleted when ssa is called directly from the main compiler.
-
-import (
- "bufio"
- "flag"
- "fmt"
- "io"
- "os"
- "strconv"
- "strings"
-
- "cmd/internal/ssa"
-)
-
-// testing harness which runs the compiler using an IR read from a file
-func main() {
- flag.Parse()
- file := flag.Arg(0)
- r, err := os.Open(file)
- if err != nil {
- panic(err)
- }
- f := buildFunc(readFunc(r))
- ssa.Compile(f)
- // TODO: output f
-}
-
-// readFunc reads the intermediate representation generated by the
-// compiler frontend and returns it as a list of sexpressions.
-func readFunc(r io.Reader) []sexpr {
- var lines []sexpr
- s := bufio.NewScanner(r)
- for s.Scan() {
- line := s.Text()
- e := parseSexpr(strings.Trim(line, " "))
-
- if !e.compound {
- panic("bad stmt: " + line)
- }
- if e.parts[0].compound {
- panic("bad op: " + line)
- }
- lines = append(lines, e)
- }
- return lines
-}
-
-// buildFunc converts from the 6g IR dump format to the internal
-// form. Builds SSA and all that.
-func buildFunc(lines []sexpr) *ssa.Func {
- f := new(ssa.Func)
-
- // We construct SSA using an algorithm similar to
- // Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau
- // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
-
- // allocate starting block
- f.Entry = f.NewBlock(ssa.BlockPlain)
- // TODO: all args. Make a struct containing args/returnvals, declare
- // an FP which contains a pointer to that struct.
-
- var exit *ssa.Block // all returns (if any) branch to here TODO: defers & panics?
-
- // add a block for each label
- // Also a few other preprocessing steps, all in one pass.
- labels := map[string]*ssa.Block{}
- types := map[string]ssa.Type{}
- callFallthrough := map[int]*ssa.Block{}
- for i, e := range lines {
- switch e.parts[0].name {
- case "LABEL":
- labels[e.parts[1].name] = f.NewBlock(ssa.BlockPlain)
- case "NAME":
- f.Name = e.parts[1].name
- case "RETURN":
- if exit == nil {
- exit = f.NewBlock(ssa.BlockExit)
- }
- case "TYPE":
- types[e.parts[1].name] = parseSexprType(e.parts[2])
- case "CALL":
- // allocate a new block for fallthrough
- callFallthrough[i] = f.NewBlock(ssa.BlockPlain)
- if exit == nil {
- exit = f.NewBlock(ssa.BlockExit)
- }
- }
- }
-
- // map from block id to sexprs in that block
- blocklines := make([][]sexpr, f.NumBlocks())
-
- // Add sexprs to the correct block. Add edges between blocks.
- b := f.Entry
- var i int
- for j, e := range lines {
- if b == nil && e.parts[0].name != "LABEL" {
- // dead code (e.g. return in "if" branch makes the "goto end" statement dead)
- continue
- }
- switch e.parts[0].name {
- case "IF":
- if b.Kind != ssa.BlockPlain {
- panic("bad b state")
- }
- b.Kind = ssa.BlockIf
- edge(b, labels[e.parts[2].name])
- edge(b, labels[e.parts[3].name])
- blocklines[b.ID] = lines[i : j+1]
- b = nil
- case "GOTO":
- edge(b, labels[e.parts[1].name])
- blocklines[b.ID] = lines[i:j]
- b = nil
- case "LABEL":
- b = labels[e.parts[1].name]
- i = j + 1
- case "RETURN":
- if b.Kind != ssa.BlockPlain {
- panic("bad b state")
- }
- edge(b, exit)
- blocklines[b.ID] = lines[i:j]
- b = nil
- case "CALL":
- if b.Kind != ssa.BlockPlain {
- panic("bad b state")
- }
- b.Kind = ssa.BlockCall
- c := callFallthrough[j]
- edge(b, c)
- edge(b, exit)
- blocklines[b.ID] = lines[i : j+1]
- b = c
- i = j + 1
- }
- // note that we don't keep goto/label/return sexprs
- }
- if b != nil {
- panic("control flow falls off end of function")
- }
-
- // Read types for each variable
- // Number the variables densely
- varids := map[string]int{} // map from variable name to id
- var varnames []string // map from id to variable name
- var vartypes []ssa.Type // map from variable id to type
- for _, e := range lines {
- if e.parts[0].name != "DCL" {
- continue
- }
- name := e.parts[1].name
- if _, ok := varids[name]; ok {
- continue
- }
- id := len(varids)
- if id == 1<<31-1 {
- panic("too many variables")
- }
- fmt.Printf("var %d = %s\n", id, name)
- varids[name] = id
- varnames = append(varnames, name)
- vartypes = append(vartypes, types[e.parts[2].name])
- }
- memID := len(varids)
- fmt.Printf("var %d = .mem\n", memID)
- varids[".mem"] = memID // TODO: need .mem here?
- varnames = append(varnames, ".mem")
- vartypes = append(vartypes, ssa.TypeMem)
-
- // map from variable ID to current Value of that variable
- curBlock := NewSparseMap(len(varids))
-
- var state ssaFuncState
- state.types = types
- state.varids = varids
- state.varnames = varnames
- state.vartypes = vartypes
- state.curBlock = curBlock
- state.done = make([]bool, f.NumBlocks())
- state.defs = map[blockvar]*ssa.Value{}
- state.memID = memID
-
- // Convert each block to ssa
- // TODO: order blocks for maximum happiness - we want to process
- // all the predecessors of a block before processing the block itself,
- // if at all possible.
- for _, b := range f.Blocks {
- fmt.Printf("processing block %d\n", b.ID)
- curBlock.Clear()
- for _, e := range blocklines[b.ID] {
- switch e.parts[0].name {
- case "AS":
- if e.parts[1].compound {
- // store expression
- lhs := genExpr(&state, b, e.parts[1])
- rhs := genExpr(&state, b, e.parts[2])
- mem := genVar(&state, b, memID)
- v := b.NewValue(ssa.OpStore, ssa.TypeMem, nil)
- v.AddArg(lhs)
- v.AddArg(rhs)
- v.AddArg(mem)
- curBlock.Put(memID, v)
- } else {
- // variable assignment
- v := genExpr(&state, b, e.parts[2])
- curBlock.Put(varids[e.parts[1].name], v)
- }
- case "DCL":
- // nothing to do
- case "IF":
- b.Control = genExpr(&state, b, e.parts[1])
- case "CALL":
- // only direct call for now - indirect call takes addr value as well
- v := b.NewValue(ssa.OpStaticCall, ssa.TypeMem, e.parts[1].name)
- v.AddArg(genVar(&state, b, memID))
- curBlock.Put(memID, v)
- b.Control = v
- }
- }
- // link up forward references to their actual values
- for _, v := range b.Values {
- if v.Op != ssa.OpFwdRef {
- continue
- }
- varid := v.Aux.(int)
- w := genVar(&state, b, varid)
- v.Op = ssa.OpCopy
- v.Aux = nil
- v.AddArg(w)
- }
-
- // record final values at the end of the block
- for _, e := range curBlock.Contents() {
- state.defs[blockvar{b.ID, e.Key}] = e.Val
- // TODO: somehow avoid storing dead values to this map.
- }
- curBlock.Clear()
- state.done[b.ID] = true
- }
-
- // the final store value is returned
- if exit != nil {
- exit.Control = genVar(&state, exit, memID)
- }
-
- return f
-}
-
-func edge(a, b *ssa.Block) {
- a.Succs = append(a.Succs, b)
- b.Preds = append(b.Preds, a)
-}
-
-func genVar(state *ssaFuncState, b *ssa.Block, id int) *ssa.Value {
- // look up variable
- v := state.curBlock.Get(id)
- if v != nil {
- // variable was defined previously in this block
- // (or we memoized the result)
- return v
- }
-
- // Variable comes in from outside of basic block.
- v = lookupVarIncoming(state, b, id)
-
- // memoize result so future callers will not look it up again
- state.curBlock.Put(id, v)
- return v
-}
-
-func genExpr(state *ssaFuncState, b *ssa.Block, e sexpr) *ssa.Value {
- if !e.compound {
- return genVar(state, b, state.varids[e.name])
- }
- switch e.parts[0].name {
- case "ADD":
- x := genExpr(state, b, e.parts[1])
- y := genExpr(state, b, e.parts[2])
- v := b.NewValue(ssa.OpAdd, x.Type, nil)
- v.AddArg(x)
- v.AddArg(y)
- return v
- case "SUB":
- x := genExpr(state, b, e.parts[1])
- y := genExpr(state, b, e.parts[2])
- v := b.NewValue(ssa.OpSub, x.Type, nil)
- v.AddArg(x)
- v.AddArg(y)
- return v
- case "CINT":
- c, err := strconv.ParseInt(e.parts[1].name, 10, 64)
- if err != nil {
- panic("bad cint value")
- }
- return b.Func.ConstInt(ssa.TypeInt64, c)
- case "LT":
- x := genExpr(state, b, e.parts[1])
- y := genExpr(state, b, e.parts[2])
- v := b.NewValue(ssa.OpLess, ssa.TypeBool, nil)
- v.AddArg(x)
- v.AddArg(y)
- return v
- /*
- case "FP":
- typ := state.types[e.parts[1].name]
- offset, err := strconv.ParseInt(e.parts[2].name, 10, 64)
- if err != nil {
- panic(err)
- }
- v := b.NewValue(ssa.OpFPAddr, types.NewPointer(typ), offset)
- return v
- case "SP":
- typ := state.types[e.parts[1].name]
- offset, err := strconv.ParseInt(e.parts[2].name, 10, 64)
- if err != nil {
- panic(err)
- }
- v := b.NewValue(ssa.OpSPAddr, types.NewPointer(typ), offset)
- return v
- case "LOAD":
- p := genExpr(state, b, e.parts[1])
- v := b.NewValue(ssa.OpLoad, p.Type.(*types.Pointer).Elem(), nil)
- v.AddArg(p)
- v.AddArg(genVar(state, b, state.memID))
- return v
- */
- default:
- fmt.Println(e.parts[0].name)
- panic("unknown op")
- }
-}
-
-// map key combining block id and variable id
-type blockvar struct {
- bid ssa.ID
- varid int
-}
-
-type ssaFuncState struct {
- types map[string]ssa.Type
- varnames []string
- varids map[string]int
- vartypes []ssa.Type
- curBlock *SparseMap // value of each variable in block we're working on
- defs map[blockvar]*ssa.Value // values for variables at the end of blocks
- done []bool
- memID int
-}
-
-// Find the value of the variable with the given id leaving block b.
-func lookupVarOutgoing(state *ssaFuncState, b *ssa.Block, id int) *ssa.Value {
- fmt.Printf("lookupOutgoing var=%d block=%d\n", id, b.ID)
- v := state.defs[blockvar{b.ID, id}]
- if v != nil {
- return v
- }
- if state.done[b.ID] {
- // The variable was not defined in this block, and we haven't
- // memoized the answer yet. Look it up recursively. This might
- // cause infinite recursion, so add a copy first.
- v = b.NewValue(ssa.OpCopy, state.vartypes[id], nil)
- state.defs[blockvar{b.ID, id}] = v
- v.AddArg(lookupVarIncoming(state, b, id))
- return v
- }
- // We don't know about defined variables in this block (yet).
- // Make a forward reference for this variable.
- fmt.Printf("making fwdRef for var=%d in block=%d\n", id, b.ID)
- v = b.NewValue(ssa.OpFwdRef, state.vartypes[id], id)
-
- // memoize result
- state.defs[blockvar{b.ID, id}] = v
- return v
-}
-
-// Find the Value of the variable coming into block b.
-func lookupVarIncoming(state *ssaFuncState, b *ssa.Block, id int) *ssa.Value {
- fmt.Printf("lookupIncoming var=%d block=%d\n", id, b.ID)
- var v *ssa.Value
- switch len(b.Preds) {
- case 0:
- // TODO: handle function args some other way (assignments in starting block?)
- // TODO: error if variable isn't a function arg (including mem input)
- v = b.NewValue(ssa.OpArg, state.vartypes[id], state.varnames[id])
- case 1:
- v = lookupVarOutgoing(state, b.Preds[0], id)
- default:
- v = b.NewValue(ssa.OpCopy, state.vartypes[id], nil)
-
- args := make([]*ssa.Value, len(b.Preds))
- for i, p := range b.Preds {
- args[i] = lookupVarOutgoing(state, p, id)
- }
-
- // if <=1 value that isn't this variable's fwdRef, don't make phi
- v.Op = ssa.OpPhi
- v.AddArgs(args...) // note: order corresponding to b.Pred
- }
- return v
-}
-
-func parseSexprType(e sexpr) ssa.Type {
- if !e.compound {
- switch e.name {
- case "int":
- // TODO: pick correct width
- return ssa.TypeInt64
- default:
- fmt.Println(e.name)
- panic("unknown type")
- }
- }
- /*
- if e.parts[0].name == "FUNC" {
- // TODO: receiver? Already folded into args? Variadic?
- var args, rets []*types.Var
- for _, s := range e.parts[1].parts {
- t := parseSexprType(s)
- args = append(args, types.NewParam(0, nil, "noname", t))
- }
- for _, s := range e.parts[2].parts {
- t := parseSexprType(s)
- rets = append(rets, types.NewParam(0, nil, "noname", t))
- }
- sig := types.NewSignature(nil, nil, types.NewTuple(args...), types.NewTuple(rets...), false)
- return ssa.Type(sig)
- }
- */
- // TODO: array/struct/...
- panic("compound type")
-}
diff --git a/src/cmd/internal/ssa/ssac/sexpr.go b/src/cmd/internal/ssa/ssac/sexpr.go
deleted file mode 100644
index 77e8923..0000000
--- a/src/cmd/internal/ssa/ssac/sexpr.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import "strings"
-
-// an sexpr is an s-expression. It is either a token or a
-// parenthesized list of s-expressions.
-//
-// Used just for initial development. Should we keep it for testing, or
-// ditch it once we've plugged into the main compiler output?
-
-type sexpr struct {
- compound bool
- name string // !compound
- parts []sexpr // compound
-}
-
-func (s *sexpr) String() string {
- if !s.compound {
- return s.name
- }
- x := "("
- for i, p := range s.parts {
- if i != 0 {
- x += " "
- }
- x += p.String()
- }
- return x + ")"
-}
-
-func parseSexpr(s string) sexpr {
- var e string
- e, s = grabOne(s)
- if len(e) > 0 && e[0] == '(' {
- e = e[1 : len(e)-1]
- var parts []sexpr
- for e != "" {
- var p string
- p, e = grabOne(e)
- parts = append(parts, parseSexpr(p))
- }
- return sexpr{true, "", parts}
- }
- return sexpr{false, e, nil}
-}
-
-// grabOne peels off first token or parenthesized string from s.
-// returns first thing and the remainder of s.
-func grabOne(s string) (string, string) {
- for len(s) > 0 && s[0] == ' ' {
- s = s[1:]
- }
- if len(s) == 0 || s[0] != '(' {
- i := strings.Index(s, " ")
- if i < 0 {
- return s, ""
- }
- return s[:i], s[i:]
- }
- d := 0
- i := 0
- for {
- if len(s) == i {
- panic("unterminated s-expression: " + s)
- }
- if s[i] == '(' {
- d++
- }
- if s[i] == ')' {
- d--
- if d == 0 {
- i++
- return s[:i], s[i:]
- }
- }
- i++
- }
-}
diff --git a/src/cmd/internal/ssa/ssac/sparsemap.go b/src/cmd/internal/ssa/ssac/sparsemap.go
deleted file mode 100644
index b7a0fb0..0000000
--- a/src/cmd/internal/ssa/ssac/sparsemap.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-// Maintains a map[int]*ssa.Value, but cheaper.
-
-// from http://research.swtch.com/sparse
-// in turn, from Briggs and Torczon
-
-import (
- "cmd/internal/ssa"
-)
-
-type SparseMap struct {
- dense []SparseMapEntry
- sparse []int
-}
-type SparseMapEntry struct {
- Key int
- Val *ssa.Value
-}
-
-// NewSparseMap returns a SparseMap that can have
-// integers between 0 and n-1 as keys.
-func NewSparseMap(n int) *SparseMap {
- return &SparseMap{nil, make([]int, n)}
-}
-
-func (s *SparseMap) Get(x int) *ssa.Value {
- i := s.sparse[x]
- if i < len(s.dense) && s.dense[i].Key == x {
- return s.dense[i].Val
- }
- return nil
-}
-
-func (s *SparseMap) Put(x int, v *ssa.Value) {
- i := s.sparse[x]
- if i < len(s.dense) && s.dense[i].Key == x {
- s.dense[i].Val = v
- return
- }
- i = len(s.dense)
- s.dense = append(s.dense, SparseMapEntry{x, v})
- s.sparse[x] = i
-}
-
-func (s *SparseMap) Remove(x int) {
- i := s.sparse[x]
- if i < len(s.dense) && s.dense[i].Key == x {
- y := s.dense[len(s.dense)-1]
- s.dense[i] = y
- s.sparse[y.Key] = i
- s.dense = s.dense[:len(s.dense)-1]
- }
-}
-
-func (s *SparseMap) Clear() {
- s.dense = s.dense[:0]
-}
-
-// Contents returns a slice of key/value pairs.
-// Caller must not modify any returned entries.
-// The return value is invalid after the SparseMap is modified in any way.
-func (s *SparseMap) Contents() []SparseMapEntry {
- return s.dense
-}