// A liveSlot is a slot that's live in loc at entry/exit of a block.
type liveSlot struct {
+ // An inlined VarLoc, so it packs into 16 bytes instead of 20.
+ Registers RegisterSet
+ StackOffset
+
slot SlotID
- loc VarLoc
+}
+
+func (loc liveSlot) absent() bool {
+ return loc.Registers == 0 && !loc.onStack()
+}
+
+// StackOffset encodes whether a value is on the stack and if so, where. It is
+// a 31-bit integer followed by a presence flag at the low-order bit.
+type StackOffset int32
+
+func (s StackOffset) onStack() bool {
+ return s != 0
+}
+
+func (s StackOffset) stackOffsetValue() int32 {
+ return int32(s) >> 1
}
// stateAtPC is the current state of all variables at some point.
registers[i] = registers[i][:0]
}
for _, live := range live {
- slots[live.slot] = live.loc
- if live.loc.Registers == 0 {
+ slots[live.slot] = VarLoc{live.Registers, live.StackOffset}
+ if live.Registers == 0 {
continue
}
- mask := uint64(live.loc.Registers)
+ mask := uint64(live.Registers)
for {
if mask == 0 {
break
}
var storage []string
- if loc.OnStack {
+ if loc.onStack() {
storage = append(storage, "stack")
}
storage = append(storage, s.registers[reg].String())
}
- if len(storage) == 0 {
- storage = append(storage, "!!!no storage!!!")
- }
return strings.Join(storage, ",")
}
// The registers this variable is available in. There can be more than
// one in various situations, e.g. it's being moved between registers.
Registers RegisterSet
- // OnStack indicates that the variable is on the stack at StackOffset.
- OnStack bool
- StackOffset int32
+
+ StackOffset
}
-func (loc *VarLoc) absent() bool {
- return loc.Registers == 0 && !loc.OnStack
+func (loc VarLoc) absent() bool {
+ return loc.Registers == 0 && !loc.onStack()
}
var BlockStart = &Value{
}
func (s *debugState) blockEndStateString(b *BlockDebug) string {
- endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.slots))}
+ endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.registers))}
endState.reset(b.endState)
return s.stateString(endState)
}
if slotLoc.absent() {
continue
}
- state.cache.AppendLiveSlot(liveSlot{SlotID(slotID), slotLoc})
+ state.cache.AppendLiveSlot(liveSlot{slot: SlotID(slotID), Registers: slotLoc.Registers, StackOffset: slotLoc.StackOffset})
}
locs.endState = state.cache.GetLiveSlotSlice()
}
slotLocs := state.currentState.slots
for _, predSlot := range p0 {
- slotLocs[predSlot.slot] = predSlot.loc
+ slotLocs[predSlot.slot] = VarLoc{predSlot.Registers, predSlot.StackOffset}
state.liveCount[predSlot.slot] = 1
}
for i := 1; i < len(preds); i++ {
for _, predSlot := range blockLocs[preds[i].ID].endState {
state.liveCount[predSlot.slot]++
liveLoc := slotLocs[predSlot.slot]
- if !liveLoc.OnStack || !predSlot.loc.OnStack || liveLoc.StackOffset != predSlot.loc.StackOffset {
- liveLoc.OnStack = false
+ if !liveLoc.onStack() || !predSlot.onStack() || liveLoc.StackOffset != predSlot.StackOffset {
liveLoc.StackOffset = 0
}
- liveLoc.Registers &= predSlot.loc.Registers
+ liveLoc.Registers &= predSlot.Registers
slotLocs[predSlot.slot] = liveLoc
}
}
// but it's probably not worth checking more than the first.
unchanged := true
for _, predSlot := range p0 {
- if state.liveCount[predSlot.slot] != len(preds) || slotLocs[predSlot.slot] != predSlot.loc {
+ if state.liveCount[predSlot.slot] != len(preds) ||
+ slotLocs[predSlot.slot].Registers != predSlot.Registers ||
+ slotLocs[predSlot.slot].StackOffset != predSlot.StackOffset {
unchanged = false
break
}
continue
}
regs := last.Registers &^ (1 << uint8(reg))
- setSlot(slot, VarLoc{regs, last.OnStack, last.StackOffset})
+ setSlot(slot, VarLoc{regs, last.StackOffset})
}
locs.registers[reg] = locs.registers[reg][:0]
switch {
case v.Op == OpArg:
home := state.f.getHome(v.ID).(LocalSlot)
- stackOffset := state.stackOffset(home)
+ stackOffset := state.stackOffset(home)<<1 | 1
for _, slot := range vSlots {
if state.loggingEnabled {
state.logf("at %v: arg %v now on stack in location %v\n", v.ID, state.slots[slot], home)
}
}
- setSlot(slot, VarLoc{0, true, stackOffset})
+ setSlot(slot, VarLoc{0, StackOffset(stackOffset)})
}
case v.Op == OpStoreReg:
home := state.f.getHome(v.ID).(LocalSlot)
- stackOffset := state.stackOffset(home)
+ stackOffset := state.stackOffset(home)<<1 | 1
for _, slot := range vSlots {
last := locs.slots[slot]
if last.absent() {
break
}
- setSlot(slot, VarLoc{last.Registers, true, stackOffset})
+ setSlot(slot, VarLoc{last.Registers, StackOffset(stackOffset)})
if state.loggingEnabled {
state.logf("at %v: %v spilled to stack location %v\n", v.ID, state.slots[slot], home)
}
for _, slot := range locs.registers[vReg.num] {
last := locs.slots[slot]
- setSlot(slot, VarLoc{last.Registers &^ (1 << uint8(vReg.num)), last.OnStack, last.StackOffset})
+ setSlot(slot, VarLoc{last.Registers &^ (1 << uint8(vReg.num)), last.StackOffset})
}
locs.registers[vReg.num] = locs.registers[vReg.num][:0]
locs.registers[vReg.num] = append(locs.registers[vReg.num], vSlots...)
var loc VarLoc
loc.Registers |= 1 << uint8(vReg.num)
if last := locs.slots[slot]; !last.absent() {
- loc.OnStack = last.OnStack
loc.StackOffset = last.StackOffset
loc.Registers |= last.Registers
}
if pending.absent() || new.absent() {
return false
}
- if pending.OnStack {
- return new.OnStack && pending.StackOffset == new.StackOffset
+ if pending.onStack() {
+ return pending.StackOffset == new.StackOffset
}
if pending.Registers != 0 && new.Registers != 0 {
return firstReg(pending.Registers) == firstReg(new.Registers)
slot := state.slots[slotID]
if !loc.absent() {
- if loc.OnStack {
- if loc.StackOffset == 0 {
+ if loc.onStack() {
+ if loc.stackOffsetValue() == 0 {
list = append(list, dwarf.DW_OP_call_frame_cfa)
} else {
list = append(list, dwarf.DW_OP_fbreg)
- list = dwarf.AppendSleb128(list, int64(loc.StackOffset))
+ list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue()))
}
} else {
regnum := Ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()]
// Append a pointer-sized uint to buf.
func appendPtr(ctxt *obj.Link, buf []byte, word uint64) []byte {
- if cap(buf) < len(buf)+100 {
- b := make([]byte, len(buf), 100+cap(buf)*2)
+ if cap(buf) < len(buf)+20 {
+ b := make([]byte, len(buf), 20+cap(buf)*2)
copy(b, buf)
buf = b
}