@@ -102,8 +102,8 @@ type blockEffects struct {
102
102
liveout bitvec.BitVec
103
103
}
104
104
105
- // A collection of global state used by liveness analysis.
106
- type liveness struct {
105
+ // A collection of global state used by Liveness analysis.
106
+ type Liveness struct {
107
107
fn * ir.Func
108
108
f * ssa.Func
109
109
vars []* ir.Name
@@ -235,7 +235,7 @@ func getvariables(fn *ir.Func) ([]*ir.Name, map[*ir.Name]int32) {
235
235
return vars , idx
236
236
}
237
237
238
- func (lv * liveness ) initcache () {
238
+ func (lv * Liveness ) initcache () {
239
239
if lv .cache .initialized {
240
240
base .Fatalf ("liveness cache initialized twice" )
241
241
return
@@ -281,7 +281,7 @@ const (
281
281
// valueEffects returns the index of a variable in lv.vars and the
282
282
// liveness effects v has on that variable.
283
283
// If v does not affect any tracked variables, it returns -1, 0.
284
- func (lv * liveness ) valueEffects (v * ssa.Value ) (int32 , liveEffect ) {
284
+ func (lv * Liveness ) valueEffects (v * ssa.Value ) (int32 , liveEffect ) {
285
285
n , e := affectedVar (v )
286
286
if e == 0 || n == nil { // cheapest checks first
287
287
return - 1 , 0
@@ -392,8 +392,8 @@ type livenessFuncCache struct {
392
392
// Constructs a new liveness structure used to hold the global state of the
393
393
// liveness computation. The cfg argument is a slice of *BasicBlocks and the
394
394
// vars argument is a slice of *Nodes.
395
- func newliveness (fn * ir.Func , f * ssa.Func , vars []* ir.Name , idx map [* ir.Name ]int32 , stkptrsize int64 ) * liveness {
396
- lv := & liveness {
395
+ func newliveness (fn * ir.Func , f * ssa.Func , vars []* ir.Name , idx map [* ir.Name ]int32 , stkptrsize int64 ) * Liveness {
396
+ lv := & Liveness {
397
397
fn : fn ,
398
398
f : f ,
399
399
vars : vars ,
@@ -447,14 +447,14 @@ func newliveness(fn *ir.Func, f *ssa.Func, vars []*ir.Name, idx map[*ir.Name]int
447
447
return lv
448
448
}
449
449
450
- func (lv * liveness ) blockEffects (b * ssa.Block ) * blockEffects {
450
+ func (lv * Liveness ) blockEffects (b * ssa.Block ) * blockEffects {
451
451
return & lv .be [b .ID ]
452
452
}
453
453
454
454
// Generates live pointer value maps for arguments and local variables. The
455
455
// this argument and the in arguments are always assumed live. The vars
456
456
// argument is a slice of *Nodes.
457
- func (lv * liveness ) pointerMap (liveout bitvec.BitVec , vars []* ir.Name , args , locals bitvec.BitVec ) {
457
+ func (lv * Liveness ) pointerMap (liveout bitvec.BitVec , vars []* ir.Name , args , locals bitvec.BitVec ) {
458
458
var slotsSeen map [int64 ]* ir.Name
459
459
checkForDuplicateSlots := base .Debug .MergeLocals != 0
460
460
if checkForDuplicateSlots {
@@ -504,7 +504,7 @@ func IsUnsafe(f *ssa.Func) bool {
504
504
}
505
505
506
506
// markUnsafePoints finds unsafe points and computes lv.unsafePoints.
507
- func (lv * liveness ) markUnsafePoints () {
507
+ func (lv * Liveness ) markUnsafePoints () {
508
508
if IsUnsafe (lv .f ) {
509
509
// No complex analysis necessary.
510
510
lv .allUnsafe = true
@@ -647,7 +647,7 @@ func (lv *liveness) markUnsafePoints() {
647
647
// This does not necessarily mean the instruction is a safe-point. In
648
648
// particular, call Values can have a stack map in case the callee
649
649
// grows the stack, but not themselves be a safe-point.
650
- func (lv * liveness ) hasStackMap (v * ssa.Value ) bool {
650
+ func (lv * Liveness ) hasStackMap (v * ssa.Value ) bool {
651
651
if ! v .Op .IsCall () {
652
652
return false
653
653
}
@@ -663,7 +663,7 @@ func (lv *liveness) hasStackMap(v *ssa.Value) bool {
663
663
// Initializes the sets for solving the live variables. Visits all the
664
664
// instructions in each basic block to summarizes the information at each basic
665
665
// block
666
- func (lv * liveness ) prologue () {
666
+ func (lv * Liveness ) prologue () {
667
667
lv .initcache ()
668
668
669
669
for _ , b := range lv .f .Blocks {
@@ -685,7 +685,7 @@ func (lv *liveness) prologue() {
685
685
}
686
686
687
687
// Solve the liveness dataflow equations.
688
- func (lv * liveness ) solve () {
688
+ func (lv * Liveness ) solve () {
689
689
// These temporary bitvectors exist to avoid successive allocations and
690
690
// frees within the loop.
691
691
nvars := int32 (len (lv .vars ))
@@ -745,7 +745,7 @@ func (lv *liveness) solve() {
745
745
746
746
// Visits all instructions in a basic block and computes a bit vector of live
747
747
// variables at each safe point locations.
748
- func (lv * liveness ) epilogue () {
748
+ func (lv * Liveness ) epilogue () {
749
749
nvars := int32 (len (lv .vars ))
750
750
liveout := bitvec .New (nvars )
751
751
livedefer := bitvec .New (nvars ) // always-live variables
@@ -914,7 +914,7 @@ func (lv *liveness) epilogue() {
914
914
// is actually a net loss: we save about 50k of argument bitmaps but the new
915
915
// PCDATA tables cost about 100k. So for now we keep using a single index for
916
916
// both bitmap lists.
917
- func (lv * liveness ) compact (b * ssa.Block ) {
917
+ func (lv * Liveness ) compact (b * ssa.Block ) {
918
918
pos := 0
919
919
if b == lv .f .Entry {
920
920
// Handle entry stack map.
@@ -939,7 +939,7 @@ func (lv *liveness) compact(b *ssa.Block) {
939
939
lv .livevars = lv .livevars [:0 ]
940
940
}
941
941
942
- func (lv * liveness ) enableClobber () {
942
+ func (lv * Liveness ) enableClobber () {
943
943
// The clobberdead experiment inserts code to clobber pointer slots in all
944
944
// the dead variables (locals and args) at every synchronous safepoint.
945
945
if ! base .Flag .ClobberDead {
@@ -994,7 +994,7 @@ func (lv *liveness) enableClobber() {
994
994
995
995
// Inserts code to clobber pointer slots in all the dead variables (locals and args)
996
996
// at every synchronous safepoint in b.
997
- func (lv * liveness ) clobber (b * ssa.Block ) {
997
+ func (lv * Liveness ) clobber (b * ssa.Block ) {
998
998
// Copy block's values to a temporary.
999
999
oldSched := append ([]* ssa.Value {}, b .Values ... )
1000
1000
b .Values = b .Values [:0 ]
@@ -1029,7 +1029,7 @@ func (lv *liveness) clobber(b *ssa.Block) {
1029
1029
// clobber generates code to clobber pointer slots in all dead variables
1030
1030
// (those not marked in live). Clobbering instructions are added to the end
1031
1031
// of b.Values.
1032
- func clobber (lv * liveness , b * ssa.Block , live bitvec.BitVec ) {
1032
+ func clobber (lv * Liveness , b * ssa.Block , live bitvec.BitVec ) {
1033
1033
for i , n := range lv .vars {
1034
1034
if ! live .Get (int32 (i )) && ! n .Addrtaken () && ! n .OpenDeferSlot () && ! n .IsOutputParamHeapAddr () {
1035
1035
// Don't clobber stack objects (address-taken). They are
@@ -1102,7 +1102,7 @@ func clobberPtr(b *ssa.Block, v *ir.Name, offset int64) {
1102
1102
b .NewValue0IA (src .NoXPos , ssa .OpClobber , types .TypeVoid , offset , v )
1103
1103
}
1104
1104
1105
- func (lv * liveness ) showlive (v * ssa.Value , live bitvec.BitVec ) {
1105
+ func (lv * Liveness ) showlive (v * ssa.Value , live bitvec.BitVec ) {
1106
1106
if base .Flag .Live == 0 || ir .FuncName (lv .fn ) == "init" || strings .HasPrefix (ir .FuncName (lv .fn ), "." ) {
1107
1107
return
1108
1108
}
@@ -1119,6 +1119,24 @@ func (lv *liveness) showlive(v *ssa.Value, live bitvec.BitVec) {
1119
1119
return
1120
1120
}
1121
1121
1122
+ pos , s := lv .format (v , live )
1123
+
1124
+ base .WarnfAt (pos , "%s" , s )
1125
+ }
1126
+
1127
+ func (lv * Liveness ) Format (v * ssa.Value ) string {
1128
+ if v == nil {
1129
+ _ , s := lv .format (nil , lv .stackMaps [0 ])
1130
+ return s
1131
+ }
1132
+ if idx := lv .livenessMap .Get (v ); idx .StackMapValid () {
1133
+ _ , s := lv .format (v , lv .stackMaps [idx ])
1134
+ return s
1135
+ }
1136
+ return ""
1137
+ }
1138
+
1139
+ func (lv * Liveness ) format (v * ssa.Value , live bitvec.BitVec ) (src.XPos , string ) {
1122
1140
pos := lv .fn .Nname .Pos ()
1123
1141
if v != nil {
1124
1142
pos = v .Pos
@@ -1149,11 +1167,10 @@ func (lv *liveness) showlive(v *ssa.Value, live bitvec.BitVec) {
1149
1167
for _ , v := range names {
1150
1168
s += " " + v
1151
1169
}
1152
-
1153
- base .WarnfAt (pos , "%s" , s )
1170
+ return pos , s
1154
1171
}
1155
1172
1156
- func (lv * liveness ) printbvec (printed bool , name string , live bitvec.BitVec ) bool {
1173
+ func (lv * Liveness ) printbvec (printed bool , name string , live bitvec.BitVec ) bool {
1157
1174
if live .IsEmpty () {
1158
1175
return printed
1159
1176
}
@@ -1177,7 +1194,7 @@ func (lv *liveness) printbvec(printed bool, name string, live bitvec.BitVec) boo
1177
1194
}
1178
1195
1179
1196
// printeffect is like printbvec, but for valueEffects.
1180
- func (lv * liveness ) printeffect (printed bool , name string , pos int32 , x bool ) bool {
1197
+ func (lv * Liveness ) printeffect (printed bool , name string , pos int32 , x bool ) bool {
1181
1198
if ! x {
1182
1199
return printed
1183
1200
}
@@ -1197,7 +1214,7 @@ func (lv *liveness) printeffect(printed bool, name string, pos int32, x bool) bo
1197
1214
// Prints the computed liveness information and inputs, for debugging.
1198
1215
// This format synthesizes the information used during the multiple passes
1199
1216
// into a single presentation.
1200
- func (lv * liveness ) printDebug () {
1217
+ func (lv * Liveness ) printDebug () {
1201
1218
fmt .Printf ("liveness: %s\n " , ir .FuncName (lv .fn ))
1202
1219
1203
1220
for i , b := range lv .f .Blocks {
@@ -1309,7 +1326,7 @@ func (lv *liveness) printDebug() {
1309
1326
// first word dumped is the total number of bitmaps. The second word is the
1310
1327
// length of the bitmaps. All bitmaps are assumed to be of equal length. The
1311
1328
// remaining bytes are the raw bitmaps.
1312
- func (lv * liveness ) emit () (argsSym , liveSym * obj.LSym ) {
1329
+ func (lv * Liveness ) emit () (argsSym , liveSym * obj.LSym ) {
1313
1330
// Size args bitmaps to be just large enough to hold the largest pointer.
1314
1331
// First, find the largest Xoffset node we care about.
1315
1332
// (Nodes without pointers aren't in lv.vars; see ShouldTrack.)
@@ -1370,7 +1387,7 @@ func (lv *liveness) emit() (argsSym, liveSym *obj.LSym) {
1370
1387
// structure read by the garbage collector.
1371
1388
// Returns a map from GC safe points to their corresponding stack map index,
1372
1389
// and a map that contains all input parameters that may be partially live.
1373
- func Compute (curfn * ir.Func , f * ssa.Func , stkptrsize int64 , pp * objw.Progs ) (Map , map [* ir .Name ]bool ) {
1390
+ func Compute (curfn * ir.Func , f * ssa.Func , stkptrsize int64 , pp * objw.Progs , retLiveness bool ) (Map , map [* ir .Name ]bool , * Liveness ) {
1374
1391
// Construct the global liveness state.
1375
1392
vars , idx := getvariables (curfn )
1376
1393
lv := newliveness (curfn , f , vars , idx , stkptrsize )
@@ -1432,10 +1449,15 @@ func Compute(curfn *ir.Func, f *ssa.Func, stkptrsize int64, pp *objw.Progs) (Map
1432
1449
p .To .Sym = x
1433
1450
}
1434
1451
1435
- return lv .livenessMap , lv .partLiveArgs
1452
+ retLv := lv
1453
+ if ! retLiveness {
1454
+ retLv = nil
1455
+ }
1456
+
1457
+ return lv .livenessMap , lv .partLiveArgs , retLv
1436
1458
}
1437
1459
1438
- func (lv * liveness ) emitStackObjects () * obj.LSym {
1460
+ func (lv * Liveness ) emitStackObjects () * obj.LSym {
1439
1461
var vars []* ir.Name
1440
1462
for _ , n := range lv .fn .Dcl {
1441
1463
if shouldTrack (n ) && n .Addrtaken () && n .Esc () != ir .EscHeap {
0 commit comments