Commit 80bfb75c authored by Giovanni Bajo's avatar Giovanni Bajo

test: in asmcheck, dump only the functions which fail

Before this change, in case of any failure, asmcheck was
dumping to stderr the whole output of compile -S, which
can be very long if it contains multiple functions.

Make it so it filters the output to only display the
assembly output of functions for which at least one opcode
check failed. This greatly simplifies debugging.

Change-Id: I1bbf54473b8252a3384e2c1dade82d926afc119d
Reviewed-on: https://go-review.googlesource.com/98444
Run-TryBot: Giovanni Bajo <rasky@develer.com>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent 8ce74b7d
...@@ -1294,10 +1294,11 @@ var ( ...@@ -1294,10 +1294,11 @@ var (
) )
type wantedAsmOpcode struct { type wantedAsmOpcode struct {
line int fileline string // original source file/line (eg: "/path/foo.go:45")
opcode *regexp.Regexp line int // original source line
negative bool opcode *regexp.Regexp // opcode check to be performed on assembly output
found bool negative bool // true if the check is supposed to fail rather than pass
found bool // true if the opcode check matched at least one in the output
} }
func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpcode, []string) { func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpcode, []string) {
...@@ -1353,6 +1354,7 @@ func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpc ...@@ -1353,6 +1354,7 @@ func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpc
archs[arch] = true archs[arch] = true
ops[arch][lnum] = append(ops[arch][lnum], wantedAsmOpcode{ ops[arch][lnum] = append(ops[arch][lnum], wantedAsmOpcode{
negative: negative, negative: negative,
fileline: lnum,
line: i + 1, line: i + 1,
opcode: oprx, opcode: oprx,
}) })
...@@ -1371,28 +1373,46 @@ func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpc ...@@ -1371,28 +1373,46 @@ func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpc
} }
func (t *test) asmCheck(outStr string, fn string, arch string, fullops map[string][]wantedAsmOpcode) (err error) { func (t *test) asmCheck(outStr string, fn string, arch string, fullops map[string][]wantedAsmOpcode) (err error) {
defer func() { // The assembly output contains the concatenated dump of multiple functions.
if *verbose && err != nil { // the first line of each function begins at column 0, while the rest is
log.Printf("%s gc output:\n%s", t, outStr) // indented by a tabulation. These data structures help us index the
} // output by function.
}() functionMarkers := make([]int, 1)
lineFuncMap := make(map[string]int)
lines := strings.Split(outStr, "\n")
rxLine := regexp.MustCompile(fmt.Sprintf(`\((%s:\d+)\)\s+(.*)`, regexp.QuoteMeta(fn))) rxLine := regexp.MustCompile(fmt.Sprintf(`\((%s:\d+)\)\s+(.*)`, regexp.QuoteMeta(fn)))
for _, line := range strings.Split(outStr, "\n") { for nl, line := range lines {
// Check if this line begins a function
if len(line) > 0 && line[0] != '\t' {
functionMarkers = append(functionMarkers, nl)
}
// Search if this line contains a assembly opcode (which is prefixed by the
// original source file/line in parenthesis)
matches := rxLine.FindStringSubmatch(line) matches := rxLine.FindStringSubmatch(line)
if len(matches) == 0 { if len(matches) == 0 {
continue continue
} }
srcFileLine, asm := matches[1], matches[2]
// Associate the original file/line information to the current
// function in the output; it will be useful to dump it in case
// of error.
lineFuncMap[srcFileLine] = len(functionMarkers) - 1
ops := fullops[matches[1]] // If there are opcode checks associated to this source file/line,
asm := matches[2] // run the checks.
if ops, found := fullops[srcFileLine]; found {
for i := range ops { for i := range ops {
if !ops[i].found && ops[i].opcode.FindString(asm) != "" { if !ops[i].found && ops[i].opcode.FindString(asm) != "" {
ops[i].found = true ops[i].found = true
} }
} }
} }
}
functionMarkers = append(functionMarkers, len(lines))
var failed []wantedAsmOpcode var failed []wantedAsmOpcode
for _, ops := range fullops { for _, ops := range fullops {
...@@ -1413,9 +1433,19 @@ func (t *test) asmCheck(outStr string, fn string, arch string, fullops map[strin ...@@ -1413,9 +1433,19 @@ func (t *test) asmCheck(outStr string, fn string, arch string, fullops map[strin
return failed[i].line < failed[j].line return failed[i].line < failed[j].line
}) })
lastFunction := -1
var errbuf bytes.Buffer var errbuf bytes.Buffer
fmt.Fprintln(&errbuf) fmt.Fprintln(&errbuf)
for _, o := range failed { for _, o := range failed {
// Dump the function in which this opcode check was supposed to
// pass but failed.
funcIdx := lineFuncMap[o.fileline]
if funcIdx != 0 && funcIdx != lastFunction {
funcLines := lines[functionMarkers[funcIdx]:functionMarkers[funcIdx+1]]
log.Println(strings.Join(funcLines, "\n"))
lastFunction = funcIdx // avoid printing same function twice
}
if o.negative { if o.negative {
fmt.Fprintf(&errbuf, "%s:%d: %s: wrong opcode found: %q\n", t.goFileName(), o.line, arch, o.opcode.String()) fmt.Fprintf(&errbuf, "%s:%d: %s: wrong opcode found: %q\n", t.goFileName(), o.line, arch, o.opcode.String())
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment