modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/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", "tool", "compile", "-S", "fixedbugs/issue18902b.go") 54 var buf bytes.Buffer 55 cmd.Stdout = &buf 56 cmd.Stderr = &buf 57 cmd.Env = os.Environ() 58 59 if testarch != "" { 60 updateEnv(&cmd.Env, "GOARCH", testarch) 61 updateEnv(&cmd.Env, "GOOS", "linux") // Simplify multi-arch testing 62 } 63 64 err := cmd.Run() 65 if err != nil { 66 fmt.Printf("%s\n%s", err, buf.Bytes()) 67 return 68 } 69 begin := "\"\".(*gcSortBuf).flush" // Text at beginning of relevant dissassembly. 70 s := buf.String() 71 i := strings.Index(s, begin) 72 if i < 0 { 73 fmt.Printf("Failed to find expected symbol %s in output\n%s\n", begin, s) 74 return 75 } 76 s = s[i:] 77 r := strings.NewReader(s) 78 scanner := bufio.NewScanner(r) 79 first := true // The first line after the begin text will be skipped 80 beforeLineNumber := "issue18902b.go:" // Text preceding line number in each line. 81 lbln := len(beforeLineNumber) 82 83 var scannedCount, changes, sumdiffs float64 84 85 prevVal := 0 86 for scanner.Scan() { 87 line := scanner.Text() 88 if first { 89 first = false 90 continue 91 } 92 i = strings.Index(line, beforeLineNumber) 93 if i < 0 { 94 // Done reading lines 95 const minLines = 150 96 if scannedCount <= minLines { // When test was written, 251 lines observed on amd64; arm64 now obtains 184 97 fmt.Printf("Scanned only %d lines, was expecting more than %d\n", int(scannedCount), minLines) 98 return 99 } 100 // Note: when test was written, before changes=92, after=50 (was 62 w/o rematerialization NoXPos in *Value.copyInto()) 101 // and before sumdiffs=784, after=180 (was 446 w/o rematerialization NoXPos in *Value.copyInto()) 102 // Set the dividing line between pass and fail at the midpoint. 103 // Normalize against instruction count in case we unroll loops, etc. 104 if changes/scannedCount >= (50+92)/(2*scannedCount) || sumdiffs/scannedCount >= (180+784)/(2*scannedCount) { 105 fmt.Printf("Line numbers change too much, # of changes=%.f, sumdiffs=%.f, # of instructions=%.f\n", changes, sumdiffs, scannedCount) 106 } 107 return 108 } 109 scannedCount++ 110 i += lbln 111 lineVal, err := strconv.Atoi(line[i : i+3]) 112 if err != nil { 113 fmt.Printf("Expected 3-digit line number after %s in %s\n", beforeLineNumber, line) 114 } 115 if prevVal == 0 { 116 prevVal = lineVal 117 } 118 diff := lineVal - prevVal 119 if diff < 0 { 120 diff = -diff 121 } 122 if diff != 0 { 123 changes++ 124 sumdiffs += float64(diff) 125 } 126 // If things change too much, set environment variable TESTDEBUG to help figure out what's up. 127 // The "before" behavior can be recreated in DebugFriendlySetPosFrom (currently in gc/ssa.go) 128 // by inserting unconditional 129 // s.SetPos(v.Pos) 130 // at the top of the function. 131 132 if debug { 133 fmt.Printf("%d %.f %.f %s\n", lineVal, changes, sumdiffs, line) 134 } 135 prevVal = lineVal 136 } 137 if err := scanner.Err(); err != nil { 138 fmt.Println("Reading standard input:", err) 139 return 140 } 141 }