Skip to content

Commit c345a39

Browse files
committed
cmd/compile: get rid of BlockCall
No need for it, we can treat calls as (mostly) normal values that take a memory and return a memory. Lowers the number of basic blocks needed to represent a function. "go test -c net/http" uses 27% fewer basic blocks. Probably doesn't affect generated code much, but should help various passes whose running time and/or space depends on the number of basic blocks. Fixes #15631 Change-Id: I0bf21e123f835e2cfa382753955a4f8bce03dfa6 Reviewed-on: https://go-review.googlesource.com/28950 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Josh Bleecher Snyder <[email protected]>
1 parent d00a3ce commit c345a39

21 files changed

+125
-87
lines changed

src/cmd/compile/internal/amd64/ssa.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
10651065
s.SetLineno(b.Line)
10661066

10671067
switch b.Kind {
1068-
case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
1068+
case ssa.BlockPlain, ssa.BlockCheck:
10691069
if b.Succs[0].Block() != next {
10701070
p := gc.Prog(obj.AJMP)
10711071
p.To.Type = obj.TYPE_BRANCH

src/cmd/compile/internal/arm/ssa.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
994994
s.SetLineno(b.Line)
995995

996996
switch b.Kind {
997-
case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
997+
case ssa.BlockPlain, ssa.BlockCheck:
998998
if b.Succs[0].Block() != next {
999999
p := gc.Prog(obj.AJMP)
10001000
p.To.Type = obj.TYPE_BRANCH

src/cmd/compile/internal/arm64/ssa.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
890890
s.SetLineno(b.Line)
891891

892892
switch b.Kind {
893-
case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
893+
case ssa.BlockPlain, ssa.BlockCheck:
894894
if b.Succs[0].Block() != next {
895895
p := gc.Prog(obj.AJMP)
896896
p.To.Type = obj.TYPE_BRANCH

src/cmd/compile/internal/gc/ssa.go

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2894,7 +2894,6 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
28942894
}
28952895

28962896
// call target
2897-
bNext := s.f.NewBlock(ssa.BlockPlain)
28982897
var call *ssa.Value
28992898
switch {
29002899
case k == callDefer:
@@ -2912,29 +2911,29 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
29122911
Fatalf("bad call type %v %v", n.Op, n)
29132912
}
29142913
call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2915-
2916-
// Finish call block
29172914
s.vars[&memVar] = call
2918-
b := s.endBlock()
2919-
b.Kind = ssa.BlockCall
2920-
b.SetControl(call)
2921-
b.AddEdgeTo(bNext)
2915+
2916+
// Finish block for defers
29222917
if k == callDefer {
2923-
// Add recover edge to exit code.
2918+
b := s.endBlock()
29242919
b.Kind = ssa.BlockDefer
2920+
b.SetControl(call)
2921+
bNext := s.f.NewBlock(ssa.BlockPlain)
2922+
b.AddEdgeTo(bNext)
2923+
// Add recover edge to exit code.
29252924
r := s.f.NewBlock(ssa.BlockPlain)
29262925
s.startBlock(r)
29272926
s.exit()
29282927
b.AddEdgeTo(r)
29292928
b.Likely = ssa.BranchLikely
2929+
s.startBlock(bNext)
29302930
}
29312931

2932-
// Start exit block, find address of result.
2933-
s.startBlock(bNext)
29342932
// Keep input pointer args live across calls. This is a bandaid until 1.8.
29352933
for _, n := range s.ptrargs {
29362934
s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
29372935
}
2936+
// Find address of result.
29382937
res := n.Left.Type.Results()
29392938
if res.NumFields() == 0 || k != callNormal {
29402939
// call has no return value. Continue with the next statement.
@@ -3276,9 +3275,9 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
32763275
call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
32773276
s.vars[&memVar] = call
32783277

3279-
// Finish block
3280-
b := s.endBlock()
32813278
if !returns {
3279+
// Finish block
3280+
b := s.endBlock()
32823281
b.Kind = ssa.BlockExit
32833282
b.SetControl(call)
32843283
call.AuxInt = off - Ctxt.FixedFrameSize()
@@ -3287,11 +3286,6 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
32873286
}
32883287
return nil
32893288
}
3290-
b.Kind = ssa.BlockCall
3291-
b.SetControl(call)
3292-
bNext := s.f.NewBlock(ssa.BlockPlain)
3293-
b.AddEdgeTo(bNext)
3294-
s.startBlock(bNext)
32953289

32963290
// Keep input pointer args live across calls. This is a bandaid until 1.8.
32973291
for _, n := range s.ptrargs {
@@ -4267,7 +4261,7 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
42674261
}
42684262
// Emit control flow instructions for block
42694263
var next *ssa.Block
4270-
if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
4264+
if i < len(f.Blocks)-1 && Debug['N'] == 0 {
42714265
// If -N, leave next==nil so every block with successors
42724266
// ends in a JMP (except call blocks - plive doesn't like
42734267
// select{send,recv} followed by a JMP call). Helps keep

src/cmd/compile/internal/mips64/ssa.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
765765
s.SetLineno(b.Line)
766766

767767
switch b.Kind {
768-
case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
768+
case ssa.BlockPlain, ssa.BlockCheck:
769769
if b.Succs[0].Block() != next {
770770
p := gc.Prog(obj.AJMP)
771771
p.To.Type = obj.TYPE_BRANCH

src/cmd/compile/internal/ppc64/ssa.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
972972
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
973973
}
974974

975-
case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
975+
case ssa.BlockPlain, ssa.BlockCheck:
976976
if b.Succs[0].Block() != next {
977977
p := gc.Prog(obj.AJMP)
978978
p.To.Type = obj.TYPE_BRANCH

src/cmd/compile/internal/ssa/check.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,6 @@ func checkFunc(f *Func) {
8080
if !b.Control.Type.IsBoolean() {
8181
f.Fatalf("if block %s has non-bool control value %s", b, b.Control.LongString())
8282
}
83-
case BlockCall:
84-
if len(b.Succs) != 1 {
85-
f.Fatalf("call block %s len(Succs)==%d, want 1", b, len(b.Succs))
86-
}
87-
if b.Control == nil {
88-
f.Fatalf("call block %s has no control value", b)
89-
}
90-
if !b.Control.Type.IsMemory() {
91-
f.Fatalf("call block %s has non-memory control value %s", b, b.Control.LongString())
92-
}
9383
case BlockDefer:
9484
if len(b.Succs) != 2 {
9585
f.Fatalf("defer block %s len(Succs)==%d, want 2", b, len(b.Succs))

src/cmd/compile/internal/ssa/deadcode.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ func liveValues(f *Func, reachable []bool) []bool {
5454
var q []*Value // stack-like worklist of unscanned values
5555

5656
// Starting set: all control values of reachable blocks are live.
57+
// Calls are live (because callee can observe the memory state).
5758
for _, b := range f.Blocks {
5859
if !reachable[b.ID] {
5960
continue
@@ -62,6 +63,12 @@ func liveValues(f *Func, reachable []bool) []bool {
6263
live[v.ID] = true
6364
q = append(q, v)
6465
}
66+
for _, v := range b.Values {
67+
if opcodeTable[v.Op].call && !live[v.ID] {
68+
live[v.ID] = true
69+
q = append(q, v)
70+
}
71+
}
6572
}
6673

6774
// Compute transitive closure of live values.

src/cmd/compile/internal/ssa/gen/386Ops.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,11 +389,11 @@ func init() {
389389
},
390390
},
391391

392-
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
393-
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
394-
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
395-
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
396-
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
392+
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
393+
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
394+
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
395+
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
396+
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
397397

398398
// arg0 = destination pointer
399399
// arg1 = source pointer

src/cmd/compile/internal/ssa/gen/AMD64Ops.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -436,11 +436,11 @@ func init() {
436436
},
437437
},
438438

439-
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
440-
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
441-
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
442-
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
443-
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
439+
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
440+
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
441+
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
442+
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
443+
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
444444

445445
// arg0 = destination pointer
446446
// arg1 = source pointer

src/cmd/compile/internal/ssa/gen/ARM64Ops.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,11 @@ func init() {
318318
{name: "CSELULT0", argLength: 2, reg: gp1flags1, asm: "CSEL"}, // returns arg0 if flags indicates unsigned LT, 0 otherwise, arg1=flags
319319

320320
// function calls
321-
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
322-
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
323-
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
324-
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
325-
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
321+
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
322+
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
323+
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
324+
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
325+
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
326326

327327
// pseudo-ops
328328
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}}, // panic if arg0 is nil. arg1=mem.

src/cmd/compile/internal/ssa/gen/ARMOps.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,11 +363,11 @@ func init() {
363363
{name: "SRAcond", argLength: 3, reg: gp2flags1, asm: "SRA"}, // arg0 >> 31 if flags indicates HS, arg0 >> arg1 otherwise, signed shift, arg2=flags
364364

365365
// function calls
366-
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
367-
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R7"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
368-
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
369-
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
370-
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
366+
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
367+
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R7"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
368+
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
369+
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
370+
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
371371

372372
// pseudo-ops
373373
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}}, // panic if arg0 is nil. arg1=mem.

src/cmd/compile/internal/ssa/gen/MIPS64Ops.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,11 @@ func init() {
264264
{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32
265265

266266
// function calls
267-
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
268-
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
269-
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
270-
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
271-
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
267+
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
268+
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
269+
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem
270+
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
271+
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
272272

273273
// duffzero
274274
// arg0 = address of memory to zero

0 commit comments

Comments
 (0)