]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/internal/ssa: delete ssac
authorKeith Randall <khr@golang.org>
Wed, 13 May 2015 21:18:12 +0000 (14:18 -0700)
committerKeith Randall <khr@golang.org>
Thu, 14 May 2015 03:20:30 +0000 (03:20 +0000)
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>
src/cmd/internal/ssa/ssac/.gitignore [deleted file]
src/cmd/internal/ssa/ssac/fib.goir [deleted file]
src/cmd/internal/ssa/ssac/fibiter.goir [deleted file]
src/cmd/internal/ssa/ssac/main.go [deleted file]
src/cmd/internal/ssa/ssac/sexpr.go [deleted file]
src/cmd/internal/ssa/ssac/sparsemap.go [deleted file]

diff --git a/src/cmd/internal/ssa/ssac/.gitignore b/src/cmd/internal/ssa/ssac/.gitignore
deleted file mode 100644 (file)
index ab17b9d..0000000
+++ /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 (file)
index 0875d63..0000000
+++ /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 (file)
index 98b2b2b..0000000
+++ /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 (file)
index 2afa7c6..0000000
+++ /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 (file)
index 77e8923..0000000
+++ /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 (file)
index b7a0fb0..0000000
+++ /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
-}