Skip to content

Commit 2d78538

Browse files
committed
cmd/compile: refactor liveness analysis for moving to SSA
In the SSA CFG, TEXT, RET, and JMP instructions correspond to Blocks, not Values. Rework liveness analysis so that progeffects only cares about Progs that result from Values, and handle Blocks separately. Passes toolstash-check -all. Change-Id: Ic23719c75b0421fdb51382a08dac18c3ba042b32 Reviewed-on: https://go-review.googlesource.com/38085 Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Josh Bleecher Snyder <[email protected]>
1 parent a9824cd commit 2d78538

File tree

1 file changed

+62
-70
lines changed

1 file changed

+62
-70
lines changed

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

Lines changed: 62 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,9 @@ type Liveness struct {
9898
}
9999

100100
type progeffectscache struct {
101-
tailuevar []int32
102-
retuevar []int32
103-
textvarkill []int32
104101
textavarinit []int32
102+
retuevar []int32
103+
tailuevar []int32
105104
uevar [3]int32
106105
varkill [3]int32
107106
avarinit [3]int32
@@ -458,12 +457,12 @@ func (lv *Liveness) initcache() {
458457
// all the parameters for correctness, and similarly it must not
459458
// read the out arguments - they won't be set until the new
460459
// function runs.
460+
461461
lv.cache.tailuevar = append(lv.cache.tailuevar, int32(i))
462462

463463
if node.Addrtaken() {
464464
lv.cache.textavarinit = append(lv.cache.textavarinit, int32(i))
465465
}
466-
lv.cache.textvarkill = append(lv.cache.textvarkill, int32(i))
467466

468467
case PPARAMOUT:
469468
// If the result had its address taken, it is being tracked
@@ -500,31 +499,11 @@ func (lv *Liveness) progeffects(prog *obj.Prog) (uevar, varkill, avarinit []int3
500499
return
501500
}
502501

503-
// A return instruction with a p.to is a tail return, which brings
504-
// the stack pointer back up (if it ever went down) and then jumps
505-
// to a new function entirely. That form of instruction must read
506-
// all the parameters for correctness, and similarly it must not
507-
// read the out arguments - they won't be set until the new
508-
// function runs.
509-
if (prog.As == obj.AJMP || prog.As == obj.ARET) && prog.To.Type == obj.TYPE_MEM && prog.To.Name == obj.NAME_EXTERN {
510-
// This is a tail call. Ensure the arguments are still alive.
511-
// See issue 16016.
512-
return lv.cache.tailuevar, nil, nil
513-
}
514-
515-
if prog.As == obj.ARET {
516-
if prog.To.Type == obj.TYPE_NONE {
517-
return lv.cache.retuevar, nil, nil
518-
}
502+
switch prog.As {
503+
case obj.ATEXT, obj.ARET, obj.AJMP, obj.AUNDEF:
519504
return nil, nil, nil
520505
}
521506

522-
if prog.As == obj.ATEXT {
523-
// A text instruction marks the entry point to a function and
524-
// the definition point of all in arguments.
525-
return nil, lv.cache.textvarkill, lv.cache.textavarinit
526-
}
527-
528507
uevar = lv.cache.uevar[:0]
529508
varkill = lv.cache.varkill[:0]
530509
avarinit = lv.cache.avarinit[:0]
@@ -1020,17 +999,7 @@ func livenesssolve(lv *Liveness) {
1020999
for change := true; change; {
10211000
change = false
10221001
for _, bb := range lv.cfg {
1023-
any.Clear()
1024-
all.Clear()
1025-
for j, pred := range bb.pred {
1026-
if j == 0 {
1027-
any.Copy(pred.avarinitany)
1028-
all.Copy(pred.avarinitall)
1029-
} else {
1030-
any.Or(any, pred.avarinitany)
1031-
all.And(all, pred.avarinitall)
1032-
}
1033-
}
1002+
lv.avarinitanyall(bb, any, all)
10341003

10351004
any.AndNot(any, bb.varkill)
10361005
all.AndNot(all, bb.varkill)
@@ -1060,13 +1029,34 @@ func livenesssolve(lv *Liveness) {
10601029
for i := len(lv.cfg) - 1; i >= 0; i-- {
10611030
bb := lv.cfg[i]
10621031

1063-
// A variable is live on output from this block
1064-
// if it is live on input to some successor.
1065-
//
1066-
// out[b] = \bigcup_{s \in succ[b]} in[s]
10671032
newliveout.Clear()
1068-
for _, succ := range bb.succ {
1069-
newliveout.Or(newliveout, succ.livein)
1033+
if len(bb.succ) == 0 {
1034+
switch prog := bb.last; {
1035+
case prog.As == obj.ARET && prog.To.Type == obj.TYPE_NONE:
1036+
// ssa.BlockRet
1037+
for _, pos := range lv.cache.retuevar {
1038+
newliveout.Set(pos)
1039+
}
1040+
case (prog.As == obj.AJMP || prog.As == obj.ARET) && prog.To.Type == obj.TYPE_MEM && prog.To.Name == obj.NAME_EXTERN:
1041+
// ssa.BlockRetJmp
1042+
for _, pos := range lv.cache.tailuevar {
1043+
newliveout.Set(pos)
1044+
}
1045+
case prog.As == obj.AUNDEF:
1046+
// ssa.BlockExit
1047+
// nothing to do
1048+
default:
1049+
Fatalf("unexpected terminal prog: %v", prog)
1050+
}
1051+
} else {
1052+
// A variable is live on output from this block
1053+
// if it is live on input to some successor.
1054+
//
1055+
// out[b] = \bigcup_{s \in succ[b]} in[s]
1056+
newliveout.Copy(bb.succ[0].livein)
1057+
for _, succ := range bb.succ[1:] {
1058+
newliveout.Or(newliveout, succ.livein)
1059+
}
10701060
}
10711061

10721062
if !bb.liveout.Eq(newliveout) {
@@ -1128,18 +1118,7 @@ func livenessepilogue(lv *Liveness) {
11281118
// Compute avarinitany and avarinitall for entry to block.
11291119
// This duplicates information known during livenesssolve
11301120
// but avoids storing two more vectors for each block.
1131-
any.Clear()
1132-
all.Clear()
1133-
for j := 0; j < len(bb.pred); j++ {
1134-
pred := bb.pred[j]
1135-
if j == 0 {
1136-
any.Copy(pred.avarinitany)
1137-
all.Copy(pred.avarinitall)
1138-
} else {
1139-
any.Or(any, pred.avarinitany)
1140-
all.And(all, pred.avarinitall)
1141-
}
1142-
}
1121+
lv.avarinitanyall(bb, any, all)
11431122

11441123
// Walk forward through the basic block instructions and
11451124
// allocate liveness maps for those instructions that need them.
@@ -1248,21 +1227,6 @@ func livenessepilogue(lv *Liveness) {
12481227
// Found an interesting instruction, record the
12491228
// corresponding liveness information.
12501229

1251-
// Useful sanity check: on entry to the function,
1252-
// the only things that can possibly be live are the
1253-
// input parameters.
1254-
if p.As == obj.ATEXT {
1255-
for j := int32(0); j < liveout.n; j++ {
1256-
if !liveout.Get(j) {
1257-
continue
1258-
}
1259-
n := lv.vars[j]
1260-
if n.Class != PPARAM {
1261-
Fatalf("internal error: %v %L recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, n, p.Pc)
1262-
}
1263-
}
1264-
}
1265-
12661230
// Record live variables.
12671231
live := lv.livevars[pos]
12681232
live.Or(live, liveout)
@@ -1344,6 +1308,34 @@ func livenessepilogue(lv *Liveness) {
13441308
}
13451309

13461310
flusherrors()
1311+
1312+
// Useful sanity check: on entry to the function,
1313+
// the only things that can possibly be live are the
1314+
// input parameters.
1315+
for j, n := range lv.vars {
1316+
if n.Class != PPARAM && lv.livevars[0].Get(int32(j)) {
1317+
Fatalf("internal error: %v %L recorded as live on entry", Curfn.Func.Nname, n)
1318+
}
1319+
}
1320+
}
1321+
1322+
func (lv *Liveness) avarinitanyall(bb *BasicBlock, any, all bvec) {
1323+
if len(bb.pred) == 0 {
1324+
any.Clear()
1325+
all.Clear()
1326+
for _, pos := range lv.cache.textavarinit {
1327+
any.Set(pos)
1328+
all.Set(pos)
1329+
}
1330+
return
1331+
}
1332+
1333+
any.Copy(bb.pred[0].avarinitany)
1334+
all.Copy(bb.pred[0].avarinitall)
1335+
for _, pred := range bb.pred[1:] {
1336+
any.Or(any, pred.avarinitany)
1337+
all.And(all, pred.avarinitall)
1338+
}
13471339
}
13481340

13491341
// FNV-1 hash function constants.

0 commit comments

Comments
 (0)