Commit 7af53d98 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

[dev.ssa] cmd/compile: implement OCAP

And dependent fixes and misc cleanup.

Co-hacking with josharian at Gophercon.

Change-Id: Ib85dc13b303929017eb0a4d2fc2f603485f7479b
Reviewed-on: https://go-review.googlesource.com/12027Reviewed-by: default avatarKeith Randall <khr@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
parent 050ce439
...@@ -199,7 +199,7 @@ type Type struct { ...@@ -199,7 +199,7 @@ type Type struct {
Note *string // literal string annotation Note *string // literal string annotation
// TARRAY // TARRAY
Bound int64 // negative is dynamic array Bound int64 // negative is slice
// TMAP // TMAP
Bucket *Type // internal type representing a hash bucket Bucket *Type // internal type representing a hash bucket
......
...@@ -6,6 +6,7 @@ package gc ...@@ -6,6 +6,7 @@ package gc
import ( import (
"fmt" "fmt"
"strings"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/internal/obj" "cmd/internal/obj"
...@@ -18,7 +19,7 @@ import ( ...@@ -18,7 +19,7 @@ import (
// it will never return nil, and the bool can be removed. // it will never return nil, and the bool can be removed.
func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
name := fn.Func.Nname.Sym.Name name := fn.Func.Nname.Sym.Name
usessa = len(name) > 4 && name[len(name)-4:] == "_ssa" usessa = strings.HasSuffix(name, "_ssa")
if usessa { if usessa {
dumplist("buildssa-enter", fn.Func.Enter) dumplist("buildssa-enter", fn.Func.Enter)
...@@ -293,6 +294,8 @@ func (s *state) stmt(n *Node) { ...@@ -293,6 +294,8 @@ func (s *state) stmt(n *Node) {
case OBLOCK: case OBLOCK:
s.stmtList(n.List) s.stmtList(n.List)
case OEMPTY:
case ODCL: case ODCL:
if n.Left.Class&PHEAP == 0 { if n.Left.Class&PHEAP == 0 {
return return
...@@ -527,14 +530,18 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -527,14 +530,18 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem()) return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
} }
case OLEN: case OLEN, OCAP:
switch { switch {
case n.Left.Type.Bound < 0: // slice case n.Left.Type.IsSlice():
return s.newValue1(ssa.OpSliceLen, s.config.Uintptr, s.expr(n.Left)) op := ssa.OpSliceLen
case n.Left.Type.IsString(): // string if n.Op == OCAP {
return s.newValue1(ssa.OpStringLen, s.config.Uintptr, s.expr(n.Left)) op = ssa.OpSliceCap
}
return s.newValue1(op, s.config.Int, s.expr(n.Left))
case n.Left.Type.IsString(): // string; not reachable for OCAP
return s.newValue1(ssa.OpStringLen, s.config.Int, s.expr(n.Left))
default: // array default: // array
return s.constInt(s.config.Uintptr, n.Left.Type.Bound) return s.constInt(s.config.Int, n.Left.Type.Bound)
} }
case OCALLFUNC: case OCALLFUNC:
...@@ -645,19 +652,19 @@ func (s *state) addr(n *Node) *ssa.Value { ...@@ -645,19 +652,19 @@ func (s *state) addr(n *Node) *ssa.Value {
// used for storing/loading arguments/returns to/from callees // used for storing/loading arguments/returns to/from callees
return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp) return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
case OINDEX: case OINDEX:
if n.Left.Type.Bound >= 0 { // array if n.Left.Type.IsSlice() {
a := s.addr(n.Left)
i := s.expr(n.Right)
len := s.constInt(s.config.Uintptr, n.Left.Type.Bound)
s.boundsCheck(i, len)
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
} else { // slice
a := s.expr(n.Left) a := s.expr(n.Left)
i := s.expr(n.Right) i := s.expr(n.Right)
len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, a) len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, a)
s.boundsCheck(i, len) s.boundsCheck(i, len)
p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a) p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a)
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i) return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i)
} else { // array
a := s.addr(n.Left)
i := s.expr(n.Right)
len := s.constInt(s.config.Uintptr, n.Left.Type.Bound)
s.boundsCheck(i, len)
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
} }
default: default:
s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0)) s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0))
......
...@@ -64,6 +64,10 @@ func (t *Type) IsString() bool { ...@@ -64,6 +64,10 @@ func (t *Type) IsString() bool {
return t.Etype == TSTRING return t.Etype == TSTRING
} }
func (t *Type) IsSlice() bool {
return t.Etype == TARRAY && t.Bound < 0
}
func (t *Type) Elem() ssa.Type { func (t *Type) Elem() ssa.Type {
return t.Type return t.Type
} }
......
...@@ -5,9 +5,10 @@ ...@@ -5,9 +5,10 @@
package ssa package ssa
type Config struct { type Config struct {
arch string // "amd64", etc. arch string // "amd64", etc.
ptrSize int64 // 4 or 8 ptrSize int64 // 4 or 8
Uintptr Type // pointer arithmetic type Uintptr Type // pointer arithmetic type
Int Type
lowerBlock func(*Block) bool // lowering function lowerBlock func(*Block) bool // lowering function
lowerValue func(*Value, *Config) bool // lowering function lowerValue func(*Value, *Config) bool // lowering function
fe Frontend // callbacks into compiler frontend fe Frontend // callbacks into compiler frontend
...@@ -48,10 +49,12 @@ func NewConfig(arch string, fe Frontend) *Config { ...@@ -48,10 +49,12 @@ func NewConfig(arch string, fe Frontend) *Config {
fe.Unimplementedf("arch %s not implemented", arch) fe.Unimplementedf("arch %s not implemented", arch)
} }
// cache the intptr type in the config // cache the frequently-used types in the config
c.Uintptr = TypeUInt32 c.Uintptr = TypeUInt32
c.Int = TypeInt32
if c.ptrSize == 8 { if c.ptrSize == 8 {
c.Uintptr = TypeUInt64 c.Uintptr = TypeUInt64
c.Int = TypeInt64
} }
return c return c
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment