Skip to content

Commit 2b58ca6

Browse files
committed
cmd/compile: begin OpArg and OpPhi location lists at block start
For the entry block, make the "first instruction" be truly the first instruction. This allows printing of incoming parameters with Delve. Also be sure Phis are marked as being at the start of their block. This is observed to move location list pointers, and where moved, they become correct. Leading zero-width instructions include LoweredGetClosurePtr. Because this instruction is actually architecture-specific, and it is now tested for in 3 different places, also created Op.isLoweredGetClosurePtr() to reduce future surprises. Change-Id: Ic043b7265835cf1790382a74334b5714ae4060af Reviewed-on: https://go-review.googlesource.com/c/145179 Run-TryBot: David Chase <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
1 parent 311d87d commit 2b58ca6

File tree

4 files changed

+60
-22
lines changed

4 files changed

+60
-22
lines changed

Diff for: src/cmd/compile/internal/gc/ssa.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -5190,6 +5190,10 @@ func genssa(f *ssa.Func, pp *Progs) {
51905190
e.curfn.Func.DebugInfo.GetPC = func(b, v ssa.ID) int64 {
51915191
switch v {
51925192
case ssa.BlockStart.ID:
5193+
if b == f.Entry.ID {
5194+
return 0 // Start at the very beginning, at the assembler-generated prologue.
5195+
// this should only happen for function args (ssa.OpArg)
5196+
}
51935197
return bstart[b].Pc
51945198
case ssa.BlockEnd.ID:
51955199
return e.curfn.Func.lsym.Size
@@ -5199,7 +5203,7 @@ func genssa(f *ssa.Func, pp *Progs) {
51995203
}
52005204
}
52015205

5202-
// Resolove branchers, and relax DefaultStmt into NotStmt
5206+
// Resolve branches, and relax DefaultStmt into NotStmt
52035207
for _, br := range s.Branches {
52045208
br.P.To.Val = s.bstart[br.B.ID]
52055209
if br.P.Pos.IsStmt() != src.PosIsStmt {

Diff for: src/cmd/compile/internal/ssa/debug.go

+35-8
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ func firstReg(set RegisterSet) uint8 {
826826
func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
827827
// Run through the function in program text order, building up location
828828
// lists as we go. The heavy lifting has mostly already been done.
829+
829830
for _, b := range state.f.Blocks {
830831
if !blockLocs[b.ID].relevant {
831832
continue
@@ -834,13 +835,24 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
834835
state.mergePredecessors(b, blockLocs)
835836

836837
zeroWidthPending := false
838+
apcChangedSize := 0 // size of changedVars for leading Args, Phi, ClosurePtr
839+
// expect to see values in pattern (apc)* (zerowidth|real)*
837840
for _, v := range b.Values {
838841
slots := state.valueNames[v.ID]
839842
reg, _ := state.f.getHome(v.ID).(*Register)
840-
changed := state.processValue(v, slots, reg)
843+
changed := state.processValue(v, slots, reg) // changed == added to state.changedVars
841844

842845
if opcodeTable[v.Op].zeroWidth {
843846
if changed {
847+
if v.Op == OpArg || v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() {
848+
// These ranges begin at true beginning of block, not after first instruction
849+
if zeroWidthPending {
850+
b.Func.Fatalf("Unexpected op mixed with OpArg/OpPhi/OpLoweredGetClosurePtr at beginning of block %s in %s\n%s", b, b.Func.Name, b.Func)
851+
}
852+
apcChangedSize = len(state.changedVars.contents())
853+
continue
854+
}
855+
// Other zero-width ops must wait on a "real" op.
844856
zeroWidthPending = true
845857
}
846858
continue
@@ -849,12 +861,25 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
849861
if !changed && !zeroWidthPending {
850862
continue
851863
}
864+
// Not zero-width; i.e., a "real" instruction.
852865

853866
zeroWidthPending = false
854-
for _, varID := range state.changedVars.contents() {
855-
state.updateVar(VarID(varID), v, state.currentState.slots)
867+
for i, varID := range state.changedVars.contents() {
868+
if i < apcChangedSize { // buffered true start-of-block changes
869+
state.updateVar(VarID(varID), v.Block, BlockStart)
870+
} else {
871+
state.updateVar(VarID(varID), v.Block, v)
872+
}
856873
}
857874
state.changedVars.clear()
875+
apcChangedSize = 0
876+
}
877+
for i, varID := range state.changedVars.contents() {
878+
if i < apcChangedSize { // buffered true start-of-block changes
879+
state.updateVar(VarID(varID), b, BlockStart)
880+
} else {
881+
state.updateVar(VarID(varID), b, BlockEnd)
882+
}
858883
}
859884
}
860885

@@ -877,8 +902,10 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
877902
}
878903

879904
// updateVar updates the pending location list entry for varID to
880-
// reflect the new locations in curLoc, caused by v.
881-
func (state *debugState) updateVar(varID VarID, v *Value, curLoc []VarLoc) {
905+
// reflect the new locations in curLoc, beginning at v in block b.
906+
// v may be one of the special values indicating block start or end.
907+
func (state *debugState) updateVar(varID VarID, b *Block, v *Value) {
908+
curLoc := state.currentState.slots
882909
// Assemble the location list entry with whatever's live.
883910
empty := true
884911
for _, slotID := range state.varSlots[varID] {
@@ -889,7 +916,7 @@ func (state *debugState) updateVar(varID VarID, v *Value, curLoc []VarLoc) {
889916
}
890917
pending := &state.pendingEntries[varID]
891918
if empty {
892-
state.writePendingEntry(varID, v.Block.ID, v.ID)
919+
state.writePendingEntry(varID, b.ID, v.ID)
893920
pending.clear()
894921
return
895922
}
@@ -908,9 +935,9 @@ func (state *debugState) updateVar(varID VarID, v *Value, curLoc []VarLoc) {
908935
}
909936
}
910937

911-
state.writePendingEntry(varID, v.Block.ID, v.ID)
938+
state.writePendingEntry(varID, b.ID, v.ID)
912939
pending.present = true
913-
pending.startBlock = v.Block.ID
940+
pending.startBlock = b.ID
914941
pending.startValue = v.ID
915942
for i, slot := range state.varSlots[varID] {
916943
pending.pieces[i] = curLoc[slot]

Diff for: src/cmd/compile/internal/ssa/schedule.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ func (h ValHeap) Less(i, j int) bool {
6262
return x.ID > y.ID
6363
}
6464

65+
func (op Op) isLoweredGetClosurePtr() bool {
66+
switch op {
67+
case OpAMD64LoweredGetClosurePtr, OpPPC64LoweredGetClosurePtr, OpARMLoweredGetClosurePtr, OpARM64LoweredGetClosurePtr,
68+
Op386LoweredGetClosurePtr, OpMIPS64LoweredGetClosurePtr, OpS390XLoweredGetClosurePtr, OpMIPSLoweredGetClosurePtr,
69+
OpWasmLoweredGetClosurePtr:
70+
return true
71+
}
72+
return false
73+
}
74+
6575
// Schedule the Values in each Block. After this phase returns, the
6676
// order of b.Values matters and is the order in which those values
6777
// will appear in the assembly output. For now it generates a
@@ -92,11 +102,7 @@ func schedule(f *Func) {
92102
// Compute score. Larger numbers are scheduled closer to the end of the block.
93103
for _, v := range b.Values {
94104
switch {
95-
case v.Op == OpAMD64LoweredGetClosurePtr || v.Op == OpPPC64LoweredGetClosurePtr ||
96-
v.Op == OpARMLoweredGetClosurePtr || v.Op == OpARM64LoweredGetClosurePtr ||
97-
v.Op == Op386LoweredGetClosurePtr || v.Op == OpMIPS64LoweredGetClosurePtr ||
98-
v.Op == OpS390XLoweredGetClosurePtr || v.Op == OpMIPSLoweredGetClosurePtr ||
99-
v.Op == OpWasmLoweredGetClosurePtr:
105+
case v.Op.isLoweredGetClosurePtr():
100106
// We also score GetLoweredClosurePtr as early as possible to ensure that the
101107
// context register is not stomped. GetLoweredClosurePtr should only appear
102108
// in the entry block where there are no phi functions, so there is no
@@ -189,9 +195,11 @@ func schedule(f *Func) {
189195
}
190196
}
191197

192-
if b.Control != nil && b.Control.Op != OpPhi {
198+
if b.Control != nil && b.Control.Op != OpPhi && b.Control.Op != OpArg {
193199
// Force the control value to be scheduled at the end,
194200
// unless it is a phi value (which must be first).
201+
// OpArg also goes first -- if it is stack it register allocates
202+
// to a LoadReg, if it is register it is from the beginning anyway.
195203
score[b.Control.ID] = ScoreControl
196204

197205
// Schedule values dependent on the control value at the end.

Diff for: src/cmd/compile/internal/ssa/tighten.go

+6-7
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ func tighten(f *Func) {
1313
canMove := make([]bool, f.NumValues())
1414
for _, b := range f.Blocks {
1515
for _, v := range b.Values {
16+
if v.Op.isLoweredGetClosurePtr() {
17+
// Must stay in the entry block.
18+
continue
19+
}
1620
switch v.Op {
17-
case OpPhi, OpArg, OpSelect0, OpSelect1,
18-
OpAMD64LoweredGetClosurePtr, Op386LoweredGetClosurePtr,
19-
OpARMLoweredGetClosurePtr, OpARM64LoweredGetClosurePtr,
20-
OpMIPSLoweredGetClosurePtr, OpMIPS64LoweredGetClosurePtr,
21-
OpS390XLoweredGetClosurePtr, OpPPC64LoweredGetClosurePtr,
22-
OpWasmLoweredGetClosurePtr:
21+
case OpPhi, OpArg, OpSelect0, OpSelect1:
2322
// Phis need to stay in their block.
24-
// GetClosurePtr & Arg must stay in the entry block.
23+
// Arg must stay in the entry block.
2524
// Tuple selectors must stay with the tuple generator.
2625
continue
2726
}

0 commit comments

Comments
 (0)