mirror of
https://github.com/golang/go
synced 2024-11-27 00:11:19 -07:00
cmd/compile: modify debug-hash to support match exclusion
The goal here is to enable a search that will locate all the instances of a failure, not just the first one. This helps with searches for loopvar-change breakage, FP differences from fused-multiply-add, and allows certain semantics queries that can be implemented as compiler changes (for example, where does integer overflow routinely occur?) Change-Id: Ic28f1695d47e421c2089d1f3f7c4b40c56db970f Reviewed-on: https://go-review.googlesource.com/c/go/+/481195 Run-TryBot: David Chase <drchase@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
f9cf2c4d04
commit
ef9c211de8
@ -39,6 +39,7 @@ type HashDebug struct {
|
|||||||
posTmp []src.Pos
|
posTmp []src.Pos
|
||||||
bytesTmp bytes.Buffer
|
bytesTmp bytes.Buffer
|
||||||
matches []hashAndMask // A hash matches if one of these matches.
|
matches []hashAndMask // A hash matches if one of these matches.
|
||||||
|
excludes []hashAndMask // explicitly excluded hash suffixes
|
||||||
yes, no bool
|
yes, no bool
|
||||||
fileSuffixOnly bool // for Pos hashes, remove the directory prefix.
|
fileSuffixOnly bool // for Pos hashes, remove the directory prefix.
|
||||||
inlineSuffixOnly bool // for Pos hashes, remove all but the most inline position.
|
inlineSuffixOnly bool // for Pos hashes, remove all but the most inline position.
|
||||||
@ -76,15 +77,23 @@ var LoopVarHash *HashDebug // for debugging shared/private loop variable changes
|
|||||||
//
|
//
|
||||||
// 3. is "n" or "N" (returns false)
|
// 3. is "n" or "N" (returns false)
|
||||||
//
|
//
|
||||||
// 4. is a suffix of the sha1 hash of pkgAndName (returns true)
|
// 4. does not explicitly exclude the sha1 hash of pkgAndName (see step 6)
|
||||||
//
|
//
|
||||||
// 5. OR
|
// 5. is a suffix of the sha1 hash of pkgAndName (returns true)
|
||||||
// if the value is in the regular language "[01]+(/[01]+)+"
|
//
|
||||||
// test the [01]+ substrings after in order returning true
|
// 6. OR
|
||||||
// for the first one that suffix-matches. The substrings AFTER
|
// if the (non-empty) value is in the regular language
|
||||||
// the first slash are numbered 0,1, etc and are named
|
// "(-[01]+/)+?([01]+(/[01]+)+?"
|
||||||
// fmt.Sprintf("%s%d", varname, number)
|
// (exclude..)(....include...)
|
||||||
// Clause 5 is not really intended for human use and only
|
// test the [01]+ exclude substrings, if any suffix-match, return false (4 above)
|
||||||
|
// test the [01]+ include substrings, if any suffix-match, return true
|
||||||
|
// The include substrings AFTER the first slash are numbered 0,1, etc and
|
||||||
|
// are named fmt.Sprintf("%s%d", varname, number)
|
||||||
|
// As an extra-special case for multiple failure search,
|
||||||
|
// an excludes-only string ending in a slash (terminated, not separated)
|
||||||
|
// implicitly specifies the include string "0/1", that is, match everything.
|
||||||
|
// (Exclude strings are used for automated search for multiple failures.)
|
||||||
|
// Clause 6 is not really intended for human use and only
|
||||||
// matters for failures that require multiple triggers.
|
// matters for failures that require multiple triggers.
|
||||||
//
|
//
|
||||||
// Otherwise it returns false.
|
// Otherwise it returns false.
|
||||||
@ -169,11 +178,35 @@ func NewHashDebug(ev, s string, file writeSyncer) *HashDebug {
|
|||||||
return hd
|
return hd
|
||||||
}
|
}
|
||||||
ss := strings.Split(s, "/")
|
ss := strings.Split(s, "/")
|
||||||
hd.matches = append(hd.matches, toHashAndMask(ss[0], ev))
|
// first remove any leading exclusions; these are preceded with "-"
|
||||||
|
i := 0
|
||||||
|
for len(ss) > 0 {
|
||||||
|
s := ss[0]
|
||||||
|
if len(s) == 0 || len(s) > 0 && s[0] != '-' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ss = ss[1:]
|
||||||
|
hd.excludes = append(hd.excludes, toHashAndMask(s[1:], fmt.Sprintf("%s%d", "HASH_EXCLUDE", i)))
|
||||||
|
i++
|
||||||
|
}
|
||||||
// hash searches may use additional EVs with 0, 1, 2, ... suffixes.
|
// hash searches may use additional EVs with 0, 1, 2, ... suffixes.
|
||||||
for i := 1; i < len(ss); i++ {
|
i = 0
|
||||||
evi := fmt.Sprintf("%s%d", ev, i-1) // convention is extras begin indexing at zero
|
for _, s := range ss {
|
||||||
hd.matches = append(hd.matches, toHashAndMask(ss[i], evi))
|
if s == "" {
|
||||||
|
if i != 0 || len(ss) > 1 && ss[1] != "" || len(ss) > 2 {
|
||||||
|
Fatalf("Empty hash match string for %s should be first (and only) one", ev)
|
||||||
|
}
|
||||||
|
// Special case of should match everything.
|
||||||
|
hd.matches = append(hd.matches, toHashAndMask("0", fmt.Sprintf("%s0", ev)))
|
||||||
|
hd.matches = append(hd.matches, toHashAndMask("1", fmt.Sprintf("%s1", ev)))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
hd.matches = append(hd.matches, toHashAndMask(s, fmt.Sprintf("%s", ev)))
|
||||||
|
} else {
|
||||||
|
hd.matches = append(hd.matches, toHashAndMask(s, fmt.Sprintf("%s%d", ev, i-1)))
|
||||||
|
}
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
return hd
|
return hd
|
||||||
|
|
||||||
@ -216,6 +249,36 @@ func (d *HashDebug) DebugHashMatch(pkgAndName string) bool {
|
|||||||
return d.DebugHashMatchParam(pkgAndName, 0)
|
return d.DebugHashMatchParam(pkgAndName, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *HashDebug) excluded(hash uint64) bool {
|
||||||
|
for _, m := range d.excludes {
|
||||||
|
if (m.hash^hash)&m.mask == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashString(hash uint64) string {
|
||||||
|
hstr := ""
|
||||||
|
if hash == 0 {
|
||||||
|
hstr = "0"
|
||||||
|
} else {
|
||||||
|
for ; hash != 0; hash = hash >> 1 {
|
||||||
|
hstr = string('0'+byte(hash&1)) + hstr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hstr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *HashDebug) match(hash uint64) *hashAndMask {
|
||||||
|
for i, m := range d.matches {
|
||||||
|
if (m.hash^hash)&m.mask == 0 {
|
||||||
|
return &d.matches[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// DebugHashMatchParam returns true if either the variable used to create d is
|
// DebugHashMatchParam returns true if either the variable used to create d is
|
||||||
// unset, or if its value is y, or if it is a suffix of the base-two
|
// unset, or if its value is y, or if it is a suffix of the base-two
|
||||||
// representation of the hash of pkgAndName and param. If the variable is not
|
// representation of the hash of pkgAndName and param. If the variable is not
|
||||||
@ -236,20 +299,14 @@ func (d *HashDebug) DebugHashMatchParam(pkgAndName string, param uint64) bool {
|
|||||||
|
|
||||||
hash := hashOf(pkgAndName, param)
|
hash := hashOf(pkgAndName, param)
|
||||||
|
|
||||||
for _, m := range d.matches {
|
// Return false for explicitly excluded hashes
|
||||||
if (m.hash^hash)&m.mask == 0 {
|
if d.excluded(hash) {
|
||||||
hstr := ""
|
return false
|
||||||
if hash == 0 {
|
|
||||||
hstr = "0"
|
|
||||||
} else {
|
|
||||||
for ; hash != 0; hash = hash >> 1 {
|
|
||||||
hstr = string('0'+byte(hash&1)) + hstr
|
|
||||||
}
|
}
|
||||||
}
|
if m := d.match(hash); m != nil {
|
||||||
d.logDebugHashMatch(m.name, pkgAndName, hstr, param)
|
d.logDebugHashMatch(m.name, pkgAndName, hashString(hash), param)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,20 +341,14 @@ func (d *HashDebug) debugHashMatchPos(ctxt *obj.Link, pos src.XPos) bool {
|
|||||||
|
|
||||||
hash := hashOfBytes(b, 0)
|
hash := hashOfBytes(b, 0)
|
||||||
|
|
||||||
for _, m := range d.matches {
|
// Return false for explicitly excluded hashes
|
||||||
if (m.hash^hash)&m.mask == 0 {
|
if d.excluded(hash) {
|
||||||
hstr := ""
|
return false
|
||||||
if hash == 0 {
|
|
||||||
hstr = "0"
|
|
||||||
} else {
|
|
||||||
for ; hash != 0; hash = hash >> 1 {
|
|
||||||
hstr = string('0'+byte(hash&1)) + hstr
|
|
||||||
}
|
}
|
||||||
}
|
if m := d.match(hash); m != nil {
|
||||||
d.logDebugHashMatchLocked(m.name, "POS="+string(b), hstr, 0)
|
d.logDebugHashMatchLocked(m.name, "POS="+string(b), hashString(hash), 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user