mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/ssa: use math/bits for register sets
Using bits.TrailingZeroes instead of iterating over each bit is a small but easy win for the common case of only one or two registers being set. I copied in the implementation for use with pre-1.9 bootstraps. Change-Id: Ieaa768554d7d5239a5617fbf34f1ee0b32ce1de5 Reviewed-on: https://go-review.googlesource.com/92395 Run-TryBot: Heschi Kreinick <heschi@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
39eea62340
commit
7ac756f74b
3 changed files with 86 additions and 35 deletions
24
src/cmd/compile/internal/ssa/bits_bootstrap.go
Normal file
24
src/cmd/compile/internal/ssa/bits_bootstrap.go
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package ssa
|
||||||
|
|
||||||
|
const deBruijn64 = 0x03f79d71b4ca8b09
|
||||||
|
|
||||||
|
var deBruijn64tab = [64]byte{
|
||||||
|
0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
|
||||||
|
62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
|
||||||
|
63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
|
||||||
|
54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrailingZeros64 returns the number of trailing zero bits in x; the result is 64 for x == 0.
|
||||||
|
func TrailingZeros64(x uint64) int {
|
||||||
|
if x == 0 {
|
||||||
|
return 64
|
||||||
|
}
|
||||||
|
return int(deBruijn64tab[(x&-x)*deBruijn64>>(64-6)])
|
||||||
|
}
|
||||||
13
src/cmd/compile/internal/ssa/bits_go19.go
Normal file
13
src/cmd/compile/internal/ssa/bits_go19.go
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package ssa
|
||||||
|
|
||||||
|
import "math/bits"
|
||||||
|
|
||||||
|
func TrailingZeros64(x uint64) int {
|
||||||
|
return bits.TrailingZeros64(x)
|
||||||
|
}
|
||||||
|
|
@ -70,10 +70,16 @@ func (state *stateAtPC) reset(live []liveSlot) {
|
||||||
if live.loc.Registers == 0 {
|
if live.loc.Registers == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for reg, regMask := 0, 1; reg < len(registers); reg, regMask = reg+1, regMask<<1 {
|
|
||||||
if live.loc.Registers&RegisterSet(regMask) != 0 {
|
mask := uint64(live.loc.Registers)
|
||||||
registers[reg] = append(registers[reg], SlotID(live.slot))
|
for {
|
||||||
|
if mask == 0 {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
reg := uint8(TrailingZeros64(mask))
|
||||||
|
mask &^= 1 << reg
|
||||||
|
|
||||||
|
registers[reg] = append(registers[reg], SlotID(live.slot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.slots, state.registers = slots, registers
|
state.slots, state.registers = slots, registers
|
||||||
|
|
@ -90,10 +96,14 @@ func (b *BlockDebug) LocString(loc VarLoc) string {
|
||||||
storage = append(storage, "stack")
|
storage = append(storage, "stack")
|
||||||
}
|
}
|
||||||
|
|
||||||
for reg := 0; reg < 64; reg++ {
|
mask := uint64(loc.Registers)
|
||||||
if loc.Registers&(1<<uint8(reg)) == 0 {
|
for {
|
||||||
continue
|
if mask == 0 {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
reg := uint8(TrailingZeros64(mask))
|
||||||
|
mask &^= 1 << reg
|
||||||
|
|
||||||
if registers != nil {
|
if registers != nil {
|
||||||
storage = append(storage, registers[reg].String())
|
storage = append(storage, registers[reg].String())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -513,10 +523,15 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B
|
||||||
if slotLoc.Registers == 0 {
|
if slotLoc.Registers == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for reg, regMask := 0, 1; reg < len(state.registers); reg, regMask = reg+1, regMask<<1 {
|
mask := uint64(slotLoc.Registers)
|
||||||
if slotLoc.Registers&RegisterSet(regMask) != 0 {
|
for {
|
||||||
state.currentState.registers[reg] = append(state.currentState.registers[reg], SlotID(slotID))
|
if mask == 0 {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
reg := uint8(TrailingZeros64(mask))
|
||||||
|
mask &^= 1 << reg
|
||||||
|
|
||||||
|
state.currentState.registers[reg] = append(state.currentState.registers[reg], SlotID(slotID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.startState = state.cache.GetLiveSlotSlice()
|
result.startState = state.cache.GetLiveSlotSlice()
|
||||||
|
|
@ -539,28 +554,29 @@ func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register)
|
||||||
// Handle any register clobbering. Call operations, for example,
|
// Handle any register clobbering. Call operations, for example,
|
||||||
// clobber all registers even though they don't explicitly write to
|
// clobber all registers even though they don't explicitly write to
|
||||||
// them.
|
// them.
|
||||||
if clobbers := opcodeTable[v.Op].reg.clobbers; clobbers != 0 {
|
clobbers := uint64(opcodeTable[v.Op].reg.clobbers)
|
||||||
for reg := 0; reg < len(state.registers); reg++ {
|
for {
|
||||||
if clobbers&(1<<uint8(reg)) == 0 {
|
if clobbers == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
reg := uint8(TrailingZeros64(clobbers))
|
||||||
|
clobbers &^= 1 << reg
|
||||||
|
|
||||||
|
for _, slot := range locs.registers[reg] {
|
||||||
|
if state.loggingEnabled {
|
||||||
|
state.logf("at %v: %v clobbered out of %v\n", v.ID, state.slots[slot], &state.registers[reg])
|
||||||
|
}
|
||||||
|
|
||||||
|
last := locs.slots[slot]
|
||||||
|
if last.absent() {
|
||||||
|
state.f.Fatalf("at %v: slot %v in register %v with no location entry", v, state.slots[slot], &state.registers[reg])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
regs := last.Registers &^ (1 << uint8(reg))
|
||||||
for _, slot := range locs.registers[reg] {
|
setSlot(slot, VarLoc{regs, last.OnStack, last.StackOffset})
|
||||||
if state.loggingEnabled {
|
|
||||||
state.logf("at %v: %v clobbered out of %v\n", v.ID, state.slots[slot], &state.registers[reg])
|
|
||||||
}
|
|
||||||
|
|
||||||
last := locs.slots[slot]
|
|
||||||
if last.absent() {
|
|
||||||
state.f.Fatalf("at %v: slot %v in register %v with no location entry", v, state.slots[slot], &state.registers[reg])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
regs := last.Registers &^ (1 << uint8(reg))
|
|
||||||
setSlot(slot, VarLoc{regs, last.OnStack, last.StackOffset})
|
|
||||||
}
|
|
||||||
|
|
||||||
locs.registers[reg] = locs.registers[reg][:0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locs.registers[reg] = locs.registers[reg][:0]
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -692,14 +708,12 @@ func canMerge(pending, new VarLoc) bool {
|
||||||
|
|
||||||
// firstReg returns the first register in set that is present.
|
// firstReg returns the first register in set that is present.
|
||||||
func firstReg(set RegisterSet) uint8 {
|
func firstReg(set RegisterSet) uint8 {
|
||||||
for reg := 0; reg < 64; reg++ {
|
if set == 0 {
|
||||||
if set&(1<<uint8(reg)) != 0 {
|
// This is wrong, but there seem to be some situations where we
|
||||||
return uint8(reg)
|
// produce locations with no storage.
|
||||||
}
|
return 0
|
||||||
}
|
}
|
||||||
// This is wrong, but there seem to be some situations where we
|
return uint8(TrailingZeros64(uint64(set)))
|
||||||
// produce locations with no storage.
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildLocationLists builds location lists for all the user variables in
|
// buildLocationLists builds location lists for all the user variables in
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue