github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/test/fixedbugs/issue18902.go (about) 1 // run 2 // +build !nacl 3 4 // Copyright 2016 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 // Runs a build -S to capture the assembly language 9 // output, checks that the line numbers associated with 10 // the stream of instructions do not change "too much". 11 // The changes that fixes this (that reduces the amount 12 // of change) does so by treating register spill, reload, 13 // copy, and rematerializations as being "unimportant" and 14 // just assigns them the line numbers of whatever "real" 15 // instructions preceded them. 16 17 // nacl is excluded because this runs a compiler. 18 19 package main 20 21 import ( 22 "bufio" 23 "bytes" 24 "fmt" 25 "os" 26 "os/exec" 27 "strconv" 28 "strings" 29 ) 30 31 // updateEnv modifies env to ensure that key=val 32 func updateEnv(env *[]string, key, val string) { 33 if val != "" { 34 var found bool 35 key = key + "=" 36 for i, kv := range *env { 37 if strings.HasPrefix(kv, key) { 38 (*env)[i] = key + val 39 found = true 40 break 41 } 42 } 43 if !found { 44 *env = append(*env, key+val) 45 } 46 } 47 } 48 49 func main() { 50 testarch := os.Getenv("TESTARCH") // Targets other platform in test compilation. 51 debug := os.Getenv("TESTDEBUG") != "" // Output the relevant assembly language. 52 53 cmd := exec.Command("go", "build", "-gcflags", "-S", "fixedbugs/issue18902b.go") 54 var buf bytes.Buffer 55 cmd.Stdout = &buf 56 cmd.Stderr = &buf 57 cmd.Env = os.Environ() 58 59 updateEnv(&cmd.Env, "GOARCH", testarch) 60 61 err := cmd.Run() 62 if err != nil { 63 fmt.Printf("%s\n%s", err, buf.Bytes()) 64 return 65 } 66 begin := "\"\".(*gcSortBuf).flush" // Text at beginning of relevant dissassembly. 67 s := buf.String() 68 i := strings.Index(s, begin) 69 if i < 0 { 70 fmt.Printf("Failed to find expected symbol %s in output\n%s\n", begin, s) 71 return 72 } 73 s = s[i:] 74 r := strings.NewReader(s) 75 scanner := bufio.NewScanner(r) 76 first := true // The first line after the begin text will be skipped 77 beforeLineNumber := "issue18902b.go:" // Text preceding line number in each line. 78 lbln := len(beforeLineNumber) 79 80 var scannedCount, changes, sumdiffs float64 81 82 prevVal := 0 83 for scanner.Scan() { 84 line := scanner.Text() 85 if first { 86 first = false 87 continue 88 } 89 i = strings.Index(line, beforeLineNumber) 90 if i < 0 { 91 // Done reading lines 92 if scannedCount < 200 { // When test was written, 251 lines observed on amd64 93 fmt.Printf("Scanned only %d lines, was expecting more than 200", scannedCount) 94 return 95 } 96 // Note: when test was written, before changes=92, after=50 (was 62 w/o rematerialization NoXPos in *Value.copyInto()) 97 // and before sumdiffs=784, after=180 (was 446 w/o rematerialization NoXPos in *Value.copyInto()) 98 // Set the dividing line between pass and fail at the midpoint. 99 // Normalize against instruction count in case we unroll loops, etc. 100 if changes/scannedCount >= (50+92)/(2*scannedCount) || sumdiffs/scannedCount >= (180+784)/(2*scannedCount) { 101 fmt.Printf("Line numbers change too much, # of changes=%.f, sumdiffs=%.f, # of instructions=%.f\n", changes, sumdiffs, scannedCount) 102 } 103 return 104 } 105 scannedCount++ 106 i += lbln 107 lineVal, err := strconv.Atoi(line[i : i+3]) 108 if err != nil { 109 fmt.Printf("Expected 3-digit line number after %s in %s\n", beforeLineNumber, line) 110 } 111 if prevVal == 0 { 112 prevVal = lineVal 113 } 114 diff := lineVal - prevVal 115 if diff < 0 { 116 diff = -diff 117 } 118 if diff != 0 { 119 changes++ 120 sumdiffs += float64(diff) 121 } 122 // If things change too much, set environment variable TESTDEBUG to help figure out what's up. 123 // The "before" behavior can be recreated in DebugFriendlySetPosFrom (currently in gc/ssa.go) 124 // by inserting unconditional 125 // s.SetPos(v.Pos) 126 // at the top of the function. 127 128 if debug { 129 fmt.Printf("%d %.f %.f %s\n", lineVal, changes, sumdiffs, line) 130 } 131 prevVal = lineVal 132 } 133 if err := scanner.Err(); err != nil { 134 fmt.Println("Reading standard input:", err) 135 return 136 } 137 }