type use struct {
dist int32 // distance from start of the block to a use of a value
+ line int32 // line number of the use
next *use // linked list of uses of a value in nondecreasing dist order
}
}
type startReg struct {
- r register
- vid ID // pre-regalloc value needed in this register
+ r register
+ vid ID // pre-regalloc value needed in this register
+ line int32 // line number of use of this register
}
// freeReg frees up register r. Any current user of r is kicked out.
// Adds a use record for id at distance dist from the start of the block.
// All calls to addUse must happen with nonincreasing dist.
-func (s *regAllocState) addUse(id ID, dist int32) {
+func (s *regAllocState) addUse(id ID, dist int32, line int32) {
r := s.freeUseRecords
if r != nil {
s.freeUseRecords = r.next
r = &use{}
}
r.dist = dist
+ r.line = line
r.next = s.values[id].uses
s.values[id].uses = r
if r.next != nil && dist > r.next.dist {
// Walk backwards through the block doing liveness analysis.
liveSet.clear()
for _, e := range s.live[b.ID] {
- s.addUse(e.ID, int32(len(b.Values))+e.dist) // pseudo-uses from beyond end of block
+ s.addUse(e.ID, int32(len(b.Values))+e.dist, e.line) // pseudo-uses from beyond end of block
liveSet.add(e.ID)
}
if v := b.Control; v != nil && s.values[v.ID].needReg {
- s.addUse(v.ID, int32(len(b.Values))) // psuedo-use by control value
+ s.addUse(v.ID, int32(len(b.Values)), b.Line) // psuedo-use by control value
liveSet.add(v.ID)
}
for i := len(b.Values) - 1; i >= 0; i-- {
if !s.values[a.ID].needReg {
continue
}
- s.addUse(a.ID, int32(i))
+ s.addUse(a.ID, int32(i), v.Line)
liveSet.add(a.ID)
}
}
// specially during merge edge processing.
continue
}
- regList = append(regList, startReg{r, v.ID})
+ regList = append(regList, startReg{r, v.ID, s.values[v.ID].uses.line})
}
s.startRegs[b.ID] = regList
vid ID // pre-regalloc value
c *Value // cached value
final bool // this is a satisfied destination
+ line int32 // line number of use of the value
}
type dstRecord struct {
loc Location // register or stack slot
vid ID // pre-regalloc value it should contain
splice **Value // place to store reference to the generating instruction
+ line int32 // line number of use of this location
}
// setup initializes the edge state for shuffling.
// Live registers can be sources.
for _, x := range srcReg {
- e.set(&e.s.registers[x.r], x.v.ID, x.c, false)
+ e.set(&e.s.registers[x.r], x.v.ID, x.c, false, 0) // don't care the line number of the source
}
// So can all of the spill locations.
for _, spillID := range stacklive {
v := e.s.orig[spillID]
spill := e.s.values[v.ID].spill
- e.set(e.s.f.getHome(spillID), v.ID, spill, false)
+ e.set(e.s.f.getHome(spillID), v.ID, spill, false, 0) // don't care the line number of the source
}
// Figure out all the destinations we need.
dsts := e.destinations[:0]
for _, x := range dstReg {
- dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil})
+ dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil, x.line})
}
// Phis need their args to end up in a specific location.
for _, v := range e.b.Values {
if loc == nil {
continue
}
- dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx]})
+ dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Line})
}
e.destinations = dsts
for len(dsts) > 0 {
i := 0
for _, d := range dsts {
- if !e.processDest(d.loc, d.vid, d.splice) {
+ if !e.processDest(d.loc, d.vid, d.splice, d.line) {
// Failed - save for next iteration.
dsts[i] = d
i++
// Copy any cycle location to a temp register. This duplicates
// one of the cycle entries, allowing the just duplicated value
// to be overwritten and the cycle to proceed.
- loc := dsts[0].loc
+ d := dsts[0]
+ loc := d.loc
vid := e.contents[loc].vid
c := e.contents[loc].c
r := e.findRegFor(c.Type)
fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c)
}
if _, isReg := loc.(*Register); isReg {
- c = e.p.NewValue1(c.Line, OpCopy, c.Type, c)
+ c = e.p.NewValue1(d.line, OpCopy, c.Type, c)
} else {
e.s.lateSpillUse(vid)
- c = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
+ c = e.p.NewValue1(d.line, OpLoadReg, c.Type, c)
}
- e.set(r, vid, c, false)
+ e.set(r, vid, c, false, d.line)
}
}
// processDest generates code to put value vid into location loc. Returns true
// if progress was made.
-func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool {
+func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32) bool {
occupant := e.contents[loc]
if occupant.vid == vid {
// Value is already in the correct place.
- e.contents[loc] = contentRecord{vid, occupant.c, true}
+ e.contents[loc] = contentRecord{vid, occupant.c, true, line}
if splice != nil {
(*splice).Uses--
*splice = occupant.c
e.erase(loc) // see pre-clobber comment below
r := e.findRegFor(v.Type)
x = v.copyInto(e.p)
- e.set(r, vid, x, false)
+ e.set(r, vid, x, false, line)
// Make sure we spill with the size of the slot, not the
// size of x (which might be wider due to our dropping
// of narrowing conversions).
- x = e.p.NewValue1(x.Line, OpStoreReg, loc.(LocalSlot).Type, x)
+ x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, x)
}
} else {
// Emit move from src to dst.
_, srcReg := src.(*Register)
if srcReg {
if dstReg {
- x = e.p.NewValue1(c.Line, OpCopy, c.Type, c)
+ x = e.p.NewValue1(line, OpCopy, c.Type, c)
} else {
- x = e.p.NewValue1(c.Line, OpStoreReg, loc.(LocalSlot).Type, c)
+ x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, c)
}
} else {
if dstReg {
e.s.lateSpillUse(vid)
- x = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
+ x = e.p.NewValue1(line, OpLoadReg, c.Type, c)
} else {
// mem->mem. Use temp register.
r := e.findRegFor(c.Type)
e.s.lateSpillUse(vid)
- t := e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
- e.set(r, vid, t, false)
- x = e.p.NewValue1(c.Line, OpStoreReg, loc.(LocalSlot).Type, t)
+ t := e.p.NewValue1(line, OpLoadReg, c.Type, c)
+ e.set(r, vid, t, false, line)
+ x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, t)
}
}
}
- e.set(loc, vid, x, true)
+ e.set(loc, vid, x, true, line)
if splice != nil {
(*splice).Uses--
*splice = x
}
// set changes the contents of location loc to hold the given value and its cached representative.
-func (e *edgeState) set(loc Location, vid ID, c *Value, final bool) {
+func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, line int32) {
e.s.f.setHome(c, loc)
e.erase(loc)
- e.contents[loc] = contentRecord{vid, c, final}
+ e.contents[loc] = contentRecord{vid, c, final, line}
a := e.cache[vid]
if len(a) == 0 {
e.cachedVals = append(e.cachedVals, vid)
// Add a destination to move this value back into place.
// Make sure it gets added to the tail of the destination queue
// so we make progress on other moves first.
- e.extra = append(e.extra, dstRecord{loc, cr.vid, nil})
+ e.extra = append(e.extra, dstRecord{loc, cr.vid, nil, cr.line})
}
// Remove c from the list of cached values.
for _, c := range a {
if r, ok := e.s.f.getHome(c.ID).(*Register); ok && m>>uint(r.Num)&1 != 0 {
x := e.p.NewValue1(c.Line, OpStoreReg, c.Type, c)
- e.set(t, vid, x, false)
+ e.set(t, vid, x, false, c.Line)
if e.s.f.pass.debug > regDebug {
fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())
}
type liveInfo struct {
ID ID // ID of value
dist int32 // # of instructions before next use
+ line int32 // line number of next use
}
// dblock contains information about desired & avoid registers at the end of a block.
// to beginning-of-block distance.
live.clear()
for _, e := range s.live[b.ID] {
- live.set(e.ID, e.dist+int32(len(b.Values)))
+ live.set(e.ID, e.dist+int32(len(b.Values)), e.line)
}
// Mark control value as live
if b.Control != nil && s.values[b.Control.ID].needReg {
- live.set(b.Control.ID, int32(len(b.Values)))
+ live.set(b.Control.ID, int32(len(b.Values)), b.Line)
}
// Propagate backwards to the start of the block
}
for _, a := range v.Args {
if s.values[a.ID].needReg {
- live.set(a.ID, int32(i))
+ live.set(a.ID, int32(i), v.Line)
}
}
}
// Start t off with the previously known live values at the end of p.
t.clear()
for _, e := range s.live[p.ID] {
- t.set(e.ID, e.dist)
+ t.set(e.ID, e.dist, e.line)
}
update := false
d := e.val + delta
if !t.contains(e.key) || d < t.get(e.key) {
update = true
- t.set(e.key, d)
+ t.set(e.key, d, e.aux)
}
}
// Also add the correct arg from the saved phi values.
id := v.Args[i].ID
if s.values[id].needReg && (!t.contains(id) || delta < t.get(id)) {
update = true
- t.set(id, delta)
+ t.set(id, delta, v.Line)
}
}
l = make([]liveInfo, 0, t.size())
}
for _, e := range t.contents() {
- l = append(l, liveInfo{e.key, e.val})
+ l = append(l, liveInfo{e.key, e.val, e.aux})
}
s.live[p.ID] = l
changed = true