From: Daniel Morsing Date: Fri, 12 Jun 2015 13:23:29 +0000 (+0100) Subject: [dev.ssa] initial implementation of PAUTO|PHEAP variables X-Git-Tag: go1.7beta1~1623^2^2~437 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c31b6dd0be202698a142568d8a8762db74b4516d;p=gostls13.git [dev.ssa] initial implementation of PAUTO|PHEAP variables Call to the runtime to generate escaping variables and use the returned address when accessing these variables. Fix a couple of errors on the way. The rule for CALLstatic was missed during the Aux refactor and OCONVNOP wasn't converted. Change-Id: I2096beff92cca92d648bfb6e8ec0b120f02f44af Reviewed-on: https://go-review.googlesource.com/11072 Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index dec4de0e10..1d7cb287a7 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -226,8 +226,23 @@ func (s *state) stmt(n *Node) { s.stmtList(n.List) case ODCL: - // TODO: old gen pass uses dcl node as the point where - // escaping variables' new functions are called. Do that here + if n.Left.Class&PHEAP == 0 { + return + } + if compiling_runtime != 0 { + log.Fatalf("%v escapes to heap, not allowed in runtime.", n) + } + + // TODO: the old pass hides the details of PHEAP + // variables behind ONAME nodes. Figure out if it's better + // to rewrite the tree and make the heapaddr construct explicit + // or to keep this detail hidden behind the scenes. + palloc := prealloc[n.Left] + if palloc == nil { + palloc = callnew(n.Left.Type) + prealloc[n.Left] = palloc + } + s.assign(OAS, n.Left.Name.Heapaddr, palloc) case OLABEL, OGOTO: // get block at label, or make one @@ -247,32 +262,8 @@ func (s *state) stmt(n *Node) { } case OAS, OASWB: - // TODO: do write barrier - var val *ssa.Value - if n.Right == nil { - // n.Right == nil means use the zero value of the assigned type. - t := n.Left.Type - switch { - case t.IsString(): - val = s.entryNewValue0(ssa.OpConst, n.Left.Type) - case t.IsInteger(): - val = s.entryNewValue0(ssa.OpConst, n.Left.Type) - case t.IsBoolean(): - val = s.entryNewValue0A(ssa.OpConst, n.Left.Type, false) // TODO: store bools as 0/1 in AuxInt? - default: - log.Fatalf("zero for type %v not implemented", t) - } - } else { - val = s.expr(n.Right) - } - if n.Left.Op == ONAME && canSSA(n.Left) { - // Update variable assignment. - s.vars[n.Left.Sym.Name] = val - return - } - // not ssa-able. Treat as a store. - addr := s.addr(n.Left) - s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, addr, val, s.mem()) + s.assign(n.Op, n.Left, n.Right) + case OIF: cond := s.expr(n.Left) b := s.endBlock() @@ -478,6 +469,36 @@ func (s *state) expr(n *Node) *ssa.Value { } } +func (s *state) assign(op uint8, left *Node, right *Node) { + // TODO: do write barrier + // if op == OASWB + var val *ssa.Value + if right == nil { + // right == nil means use the zero value of the assigned type. + t := left.Type + switch { + case t.IsString(): + val = s.entryNewValue0(ssa.OpConst, left.Type) + case t.IsInteger(): + val = s.entryNewValue0(ssa.OpConst, left.Type) + case t.IsBoolean(): + val = s.entryNewValue0A(ssa.OpConst, left.Type, false) // TODO: store bools as 0/1 in AuxInt? + default: + log.Fatalf("zero for type %v not implemented", t) + } + } else { + val = s.expr(right) + } + if left.Op == ONAME && canSSA(left) { + // Update variable assignment. + s.vars[left.Sym.Name] = val + return + } + // not ssa-able. Treat as a store. + addr := s.addr(left) + s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, addr, val, s.mem()) +} + // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result. func (s *state) addr(n *Node) *ssa.Value { switch n.Op { @@ -489,6 +510,8 @@ func (s *state) addr(n *Node) *ssa.Value { case PPARAMOUT: // store to parameter slot return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.fp) + case PAUTO | PHEAP: + return s.expr(n.Name.Heapaddr) default: // TODO: address of locals log.Fatalf("variable address of %v not implemented", n) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 58ab25b392..b62c8767d1 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -58,7 +58,7 @@ (If (SETB cmp) yes no) -> (ULT cmp yes no) (If cond yes no) && cond.Op == OpAMD64MOVBload -> (NE (TESTB cond cond) yes no) -(StaticCall [target] mem) -> (CALLstatic [target] mem) +(StaticCall {target} mem) -> (CALLstatic {target} mem) (ClosureCall entry closure mem) -> (CALLclosure entry closure mem) // Rules below here apply some simple optimizations after lowering. diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index d466e154e7..a3ec3e7cc1 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -1093,22 +1093,22 @@ func rewriteValueAMD64(v *Value, config *Config) bool { end78e66b6fc298684ff4ac8aec5ce873c9: ; case OpStaticCall: - // match: (StaticCall [target] mem) + // match: (StaticCall {target} mem) // cond: - // result: (CALLstatic [target] mem) + // result: (CALLstatic {target} mem) { - target := v.AuxInt + target := v.Aux mem := v.Args[0] v.Op = OpAMD64CALLstatic v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AuxInt = target + v.Aux = target v.AddArg(mem) return true } - goto endcf02eb60d90086f6c42bfdc5842b145d - endcf02eb60d90086f6c42bfdc5842b145d: + goto end1948857a7cfc2a4f905045e58d3b9ec1 + end1948857a7cfc2a4f905045e58d3b9ec1: ; case OpStore: // match: (Store ptr val mem)