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  }