diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 763ac24a10..8353e0fdd3 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -205,6 +205,12 @@ func buildssa(fn *Node, worker int) *ssa.Func { s.popLine() } + for _, b := range s.f.Blocks { + if b.Pos != src.NoXPos { + updateUnsetPredPos(b) + } + } + s.insertPhis() // Don't carry reference this around longer than necessary @@ -215,6 +221,30 @@ func buildssa(fn *Node, worker int) *ssa.Func { return s.f } +func updateUnsetPredPos(b *ssa.Block) { + for _, e := range b.Preds { + p := e.Block() + if p.Pos == src.NoXPos && p.Kind == ssa.BlockPlain { + pos := b.Pos + // TODO: This ought to be produce a better result, but it causes + // line 46 ("scanner := bufio.NewScanner(reader)") + // to drop out of gdb-dbg and dlv-dbg debug-next traces for hist.go. + for _, v := range b.Values { + if v.Op == ssa.OpVarDef || v.Op == ssa.OpVarKill || v.Op == ssa.OpVarLive || v.Op == ssa.OpCopy && v.Type == types.TypeMem { + continue + } + if v.Pos != src.NoXPos { + pos = v.Pos + break + } + } + p.Pos = pos + updateUnsetPredPos(p) // We do not expect long chains of these, thus recursion is okay. + } + } + return +} + type state struct { // configuration (arch) information config *ssa.Config @@ -263,6 +293,8 @@ type state struct { // line number stack. The current line number is top of stack line []src.XPos + // the last line number processed; it may have been popped + lastPos src.XPos // list of panic calls by function name and line number. // Used to deduplicate panic calls. @@ -344,7 +376,14 @@ func (s *state) endBlock() *ssa.Block { s.defvars[b.ID] = s.vars s.curBlock = nil s.vars = nil - b.Pos = s.peekPos() + if len(b.Values) == 0 && b.Kind == ssa.BlockPlain { + // Empty plain blocks get the line of their successor (handled after all blocks created), + // except for increment blocks in For statements (handled in ssa conversion of OFOR), + // and for blocks ending in GOTO/BREAK/CONTINUE. + b.Pos = src.NoXPos + } else { + b.Pos = s.lastPos + } return b } @@ -357,7 +396,10 @@ func (s *state) pushLine(line src.XPos) { if Debug['K'] != 0 { Warn("buildssa: unknown position (line 0)") } + } else { + s.lastPos = line } + s.line = append(s.line, line) } @@ -515,8 +557,11 @@ func (s *state) stmtList(l Nodes) { // stmt converts the statement n to SSA and adds it to s. func (s *state) stmt(n *Node) { - s.pushLine(n.Pos) - defer s.popLine() + if !(n.Op == OVARKILL || n.Op == OVARLIVE) { + // OVARKILL and OVARLIVE are invisible to the programmer, so we don't use their line numbers to avoid confusion in debugging. + s.pushLine(n.Pos) + defer s.popLine() + } // If s.curBlock is nil, and n isn't a label (which might have an associated goto somewhere), // then this code is dead. Stop here. @@ -629,6 +674,7 @@ func (s *state) stmt(n *Node) { } b := s.endBlock() + b.Pos = s.lastPos // Do this even if b is an empty block. b.AddEdgeTo(lab.target) case OAS: @@ -805,6 +851,7 @@ func (s *state) stmt(n *Node) { } b := s.endBlock() + b.Pos = s.lastPos // Do this even if b is an empty block. b.AddEdgeTo(to) case OFOR, OFORUNTIL: @@ -870,6 +917,11 @@ func (s *state) stmt(n *Node) { } if b := s.endBlock(); b != nil { b.AddEdgeTo(bCond) + // It can happen that bIncr ends in a block containing only VARKILL, + // and that muddles the debugging experience. + if n.Op != OFORUNTIL && b.Pos == src.NoXPos { + b.Pos = bCond.Pos + } } if n.Op == OFORUNTIL { @@ -4642,6 +4694,7 @@ type FloatingEQNEJump struct { func (s *SSAGenState) oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump) { p := s.Prog(jumps.Jump) p.To.Type = obj.TYPE_BRANCH + p.Pos = b.Pos to := jumps.Index s.Branches = append(s.Branches, Branch{p, b.Succs[to].Block()}) } @@ -4658,6 +4711,7 @@ func (s *SSAGenState) FPJump(b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) s.oneFPJump(b, &jumps[1][0]) s.oneFPJump(b, &jumps[1][1]) q := s.Prog(obj.AJMP) + q.Pos = b.Pos q.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, Branch{q, b.Succs[1].Block()}) } diff --git a/src/cmd/compile/internal/ssa/debug_test.go b/src/cmd/compile/internal/ssa/debug_test.go new file mode 100644 index 0000000000..d41788103d --- /dev/null +++ b/src/cmd/compile/internal/ssa/debug_test.go @@ -0,0 +1,786 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssa_test + +import ( + "bytes" + "flag" + "fmt" + "internal/testenv" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "testing" + "time" +) + +var update = flag.Bool("u", false, "update debug_test reference files") +var verbose = flag.Bool("v", false, "print more information about what's happening") +var dryrun = flag.Bool("n", false, "just print the command line and first bits") +var delve = flag.Bool("d", false, "use delve instead of gdb") +var force = flag.Bool("f", false, "force run under not linux-amd64; also do not use tempdir") + +var hexRe = regexp.MustCompile("0x[a-zA-Z0-9]+") +var numRe = regexp.MustCompile("-?[0-9]+") +var stringRe = regexp.MustCompile("\"([^\\\"]|(\\.))*\"") + +// TestNexting go-builds a file, then uses a debugger (default gdb, optionally delve) +// to next through the generated executable, recording each line landed at, and +// then compares those lines with reference file(s). +// Flag -u updates the reference file(s). +// Flag -d changes the debugger to delve (and uses delve-specific reference files) +// Flag -v is ever-so-slightly verbose. +// Flag -n is for dry-run, and prints the shell and first debug commands. +// +// The file being tested may contain comments of the form +// //DBG-TAG=(v1,v2,v3) +// where DBG = {gdb,dlv} and TAG={dbg,opt} +// each variable may optionally be followed by a / and one or more of S,A,N +// to indicate normalization of Strings, (hex) addresses, and numbers. +// For example: +/* + if len(os.Args) > 1 { //gdb-dbg=(hist/A,cannedInput/A) //dlv-dbg=(hist/A,cannedInput/A) +*/ +// TODO: not implemented for Delve yet, but this is the plan +// +// After a compiler change that causes a difference in the debug behavior, check +// to see if it is sensible or not, and if it is, update the reference files with +// go test debug_test.go -args -u +// (for Delve) +// go test debug_test.go -args -u -d +func TestNexting(t *testing.T) { + testenv.MustHaveGoBuild(t) + testNexting(t, "hist", "dbg", "-N -l") + testNexting(t, "hist", "opt", "") +} + +func testNexting(t *testing.T, base, tag, gcflags string) { + // (1) In testdata, build sample.go into sample + // (2) Run debugger gathering a history + // (3) Read expected history from testdata/sample.nexts + // optionally, write out testdata/sample.nexts + + if !*delve && !*force && !(runtime.GOOS == "linux" && runtime.GOARCH == "amd64") { + // Running gdb on OSX/darwin is very flaky. + // It also probably requires an admin password typed into a dialog box. + // Various architectures tend to differ slightly sometimes, and keeping them + // all in sync is a pain for people who don't have them all at hand, + // so limit testing to amd64 (for now) + + t.Skip() + } + + exe := filepath.Join("testdata", base) + logbase := exe + "-" + tag + tmpbase := logbase + "-test" + + if !*force { + tmpdir, err := ioutil.TempDir("", "debug_test") + if err != nil { + panic(fmt.Sprintf("Problem creating TempDir, error %v\n", err)) + } + exe = filepath.Join(tmpdir, base) + tmpbase = exe + "-" + tag + "-test" + if *verbose { + fmt.Printf("Tempdir is %s\n", tmpdir) + } + defer os.RemoveAll(tmpdir) + } + + if gcflags == "" { + runGo(t, "", "build", "-o", exe, filepath.Join("testdata", base+".go")) + } else { + runGo(t, "", "build", "-o", exe, "-gcflags", gcflags, filepath.Join("testdata", base+".go")) + } + var h1 *nextHist + var nextlog, tmplog string + if *delve { + h1 = dlvTest(tag, exe, 1000) + nextlog = logbase + ".delve-nexts" + tmplog = tmpbase + ".delve-nexts" + } else { + h1 = gdbTest(tag, exe, 1000) + nextlog = logbase + ".gdb-nexts" + tmplog = tmpbase + ".gdb-nexts" + } + if *dryrun { + fmt.Printf("# Tag for above is %s\n", tag) + return + } + if *update { + h1.write(nextlog) + } else { + h0 := &nextHist{} + h0.read(nextlog) + if !h0.equals(h1) { + // Be very noisy about exactly what's wrong to simplify debugging. + h1.write(tmplog) + cmd := exec.Command("diff", "-u", nextlog, tmplog) + line := asCommandLine("", cmd) + bytes, err := cmd.CombinedOutput() + if err != nil && len(bytes) == 0 { + t.Fatalf("step/next histories differ, diff command %s failed with error=%v", line, err) + } + t.Fatalf("step/next histories differ, diff=\n%s", string(bytes)) + } + } +} + +type dbgr interface { + start() + do(s string) + stepnext(s string) bool // step or next, possible with parameter, gets line etc. returns true for success, false for unsure response + quit() + hist() *nextHist +} + +func gdbTest(tag, executable string, maxNext int, args ...string) *nextHist { + dbg := newGdb(tag, executable, args...) + dbg.start() + if *dryrun { + return nil + } + for i := 0; i < maxNext; i++ { + if !dbg.stepnext("n") { + break + } + } + h := dbg.hist() + return h +} + +func dlvTest(tag, executable string, maxNext int, args ...string) *nextHist { + dbg := newDelve(tag, executable, args...) + dbg.start() + if *dryrun { + return nil + } + for i := 0; i < maxNext; i++ { + if !dbg.stepnext("n") { + break + } + } + h := dbg.hist() + return h +} + +func runGo(t *testing.T, dir string, args ...string) string { + var stdout, stderr bytes.Buffer + cmd := exec.Command(testenv.GoToolPath(t), args...) + cmd.Dir = dir + if *dryrun { + fmt.Printf("%s\n", asCommandLine("", cmd)) + return "" + } + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + t.Fatalf("error running cmd (%s): %v\nstdout:\n%sstderr:\n%s\n", asCommandLine("", cmd), err, stdout.String(), stderr.String()) + } + + if s := stderr.String(); s != "" { + t.Fatalf("Stderr = %s\nWant empty", s) + } + + return stdout.String() +} + +type tstring struct { + o string + e string +} + +func (t tstring) String() string { + return t.o + t.e +} + +type pos struct { + line uint16 + file uint8 +} + +type nextHist struct { + f2i map[string]uint8 + fs []string + ps []pos // TODO: plan to automatically do the minimum distance conversion between a reference and a run for nicer errors. + texts []string + vars [][]string +} + +func (h *nextHist) write(filename string) { + file, err := os.Create(filename) + if err != nil { + panic(fmt.Sprintf("Problem opening %s, error %v\n", filename, err)) + } + defer file.Close() + var lastfile uint8 + for i, x := range h.texts { + p := h.ps[i] + if lastfile != p.file { + fmt.Fprintf(file, " %s\n", h.fs[p.file-1]) + lastfile = p.file + } + fmt.Fprintf(file, "%d:%s\n", p.line, x) + // Vars must begin with a dollar-sign. + // TODO, normalize between gdb and dlv into a common, comparable format. + for _, y := range h.vars[i] { + y = strings.TrimSpace(y) + if y[0] != '$' { + panic(fmt.Sprintf("Var line '%s' must begin with $, but does not\n", y)) + } + fmt.Fprintf(file, "%s\n", y) + } + } + file.Close() +} + +func (h *nextHist) read(filename string) { + h.f2i = make(map[string]uint8) + bytes, err := ioutil.ReadFile(filename) + if err != nil { + panic(fmt.Sprintf("Problem reading %s, error %v\n", filename, err)) + } + var lastfile string + lines := strings.Split(string(bytes), "\n") + for i, l := range lines { + if len(l) > 0 && l[0] != '#' { + if l[0] == ' ' { + // file -- first two characters expected to be " " + lastfile = strings.TrimSpace(l) + } else if l[0] == '$' { + h.addVar(l) + } else { + // line number -- : + colonPos := strings.Index(l, ":") + if colonPos == -1 { + panic(fmt.Sprintf("Line %d (%s) in file %s expected to contain ':' but does not.\n", i+1, l, filename)) + } + h.add(lastfile, l[0:colonPos], l[colonPos+1:]) + } + } + } +} + +func (h *nextHist) add(file, line, text string) { + fi := h.f2i[file] + if fi == 0 { + h.fs = append(h.fs, file) + fi = uint8(len(h.fs)) + h.f2i[file] = fi + } + + line = strings.TrimSpace(line) + var li int + var err error + if line != "" { + li, err = strconv.Atoi(line) + if err != nil { + panic(fmt.Sprintf("Non-numeric line: %s, error %v\n", line, err)) + } + } + h.ps = append(h.ps, pos{line: uint16(li), file: fi}) + h.texts = append(h.texts, text) + h.vars = append(h.vars, []string{}) +} + +func (h *nextHist) addVar(text string) { + l := len(h.texts) + h.vars[l-1] = append(h.vars[l-1], text) +} + +func invertMapSU8(hf2i map[string]uint8) map[uint8]string { + hi2f := make(map[uint8]string) + for hs, i := range hf2i { + hsi := strings.Index(hs, "/src/") + if hsi != -1 { + hs = hs[hsi+1:] + } + hi2f[i] = hs + } + return hi2f +} + +func (h *nextHist) equals(k *nextHist) bool { + if len(h.f2i) != len(k.f2i) { + return false + } + if len(h.ps) != len(k.ps) { + return false + } + hi2f := invertMapSU8(h.f2i) + ki2f := invertMapSU8(k.f2i) + + for i, hs := range hi2f { + if hs != ki2f[i] { + return false + } + } + + for i, x := range h.ps { + if k.ps[i] != x { + return false + } + } + return true +} + +/* Delve */ + +type delveState struct { + cmd *exec.Cmd + tag string + *ioState + atLineRe *regexp.Regexp // "\n =>" + funcFileLinePCre *regexp.Regexp // "^> ([^ ]+) ([^:]+):([0-9]+) .*[(]PC: (0x[a-z0-9]+)" + line string + file string + function string +} + +func newDelve(tag, executable string, args ...string) dbgr { + cmd := exec.Command("dlv", "exec", executable) + cmd.Env = replaceEnv(cmd.Env, "TERM", "dumb") + if len(args) > 0 { + cmd.Args = append(cmd.Args, "--") + cmd.Args = append(cmd.Args, args...) + } + s := &delveState{tag: tag, cmd: cmd} + // HAHA Delve has control characters embedded to change the color of the => and the line number + // that would be '(\\x1b\\[[0-9;]+m)?' OR TERM=dumb + s.atLineRe = regexp.MustCompile("\n=>[[:space:]]+[0-9]+:(.*)") + s.funcFileLinePCre = regexp.MustCompile("> ([^ ]+) ([^:]+):([0-9]+) .*[(]PC: (0x[a-z0-9]+)[)]\n") + s.ioState = newIoState(s.cmd) + return s +} + +func (s *delveState) stepnext(ss string) bool { + x := s.ioState.writeReadExpect(ss+"\n", "[(]dlv[)] ") + excerpts := s.atLineRe.FindStringSubmatch(x.o) + locations := s.funcFileLinePCre.FindStringSubmatch(x.o) + excerpt := "" + if len(excerpts) > 1 { + excerpt = excerpts[1] + } + if len(locations) > 0 { + if *verbose { + if s.file != locations[2] { + fmt.Printf("%s\n", locations[2]) + } + fmt.Printf(" %s\n", locations[3]) + } + s.line = locations[3] + s.file = locations[2] + s.function = locations[1] + s.ioState.history.add(s.file, s.line, excerpt) + return true + } + fmt.Printf("DID NOT MATCH EXPECTED NEXT OUTPUT\nO='%s'\nE='%s'\n", x.o, x.e) + return false +} + +func (s *delveState) start() { + if *dryrun { + fmt.Printf("%s\n", asCommandLine("", s.cmd)) + fmt.Printf("b main.main\n") + fmt.Printf("c\n") + return + } + err := s.cmd.Start() + if err != nil { + line := asCommandLine("", s.cmd) + panic(fmt.Sprintf("There was an error [start] running '%s', %v\n", line, err)) + } + s.ioState.readExpecting(-1, 5000, "Type 'help' for list of commands.") + expect("Breakpoint [0-9]+ set at ", s.ioState.writeRead("b main.main\n")) + s.stepnext("c") +} + +func (s *delveState) quit() { + s.do("q") +} + +func (s *delveState) do(ss string) { + expect("", s.ioState.writeRead(ss+"\n")) +} + +/* Gdb */ + +type gdbState struct { + cmd *exec.Cmd + tag string + args []string + *ioState + atLineRe *regexp.Regexp + funcFileLinePCre *regexp.Regexp + line string + file string + function string +} + +func newGdb(tag, executable string, args ...string) dbgr { + gdb := "gdb" + if runtime.GOOS == "darwin" { + gdb = "ggdb" // A possibility on a Mac + } + cmd := exec.Command(gdb, executable) + cmd.Env = replaceEnv(cmd.Env, "TERM", "dumb") + s := &gdbState{tag: tag, cmd: cmd, args: args} + s.atLineRe = regexp.MustCompile("(^|\n)([0-9]+)(.*)") + s.funcFileLinePCre = regexp.MustCompile( + "([^ ]+) [(][)][ \\t\\n]+at ([^:]+):([0-9]+)") + // runtime.main () at /Users/drchase/GoogleDrive/work/go/src/runtime/proc.go:201 + // function file line + // Thread 2 hit Breakpoint 1, main.main () at /Users/drchase/GoogleDrive/work/debug/hist.go:18 + s.ioState = newIoState(s.cmd) + return s +} + +func (s *gdbState) start() { + run := "run" + for _, a := range s.args { + run += " " + a // Can't quote args for gdb, it will pass them through including the quotes + } + if *dryrun { + fmt.Printf("%s\n", asCommandLine("", s.cmd)) + fmt.Printf("b main.main\n") + fmt.Printf("%s\n", run) + return + } + err := s.cmd.Start() + if err != nil { + line := asCommandLine("", s.cmd) + panic(fmt.Sprintf("There was an error [start] running '%s', %v\n", line, err)) + } + s.ioState.readExpecting(-1, 5000, "[(]gdb[)] ") + x := s.ioState.writeReadExpect("b main.main\n", "[(]gdb[)] ") + expect("Breakpoint [0-9]+ at", x) + s.stepnext(run) +} + +func (s *gdbState) stepnext(ss string) bool { + x := s.ioState.writeReadExpect(ss+"\n", "[(]gdb[)] ") + excerpts := s.atLineRe.FindStringSubmatch(x.o) + locations := s.funcFileLinePCre.FindStringSubmatch(x.o) + excerpt := "" + if len(excerpts) == 0 && len(locations) == 0 { + fmt.Printf("DID NOT MATCH %s", x.o) + return false + } + if len(excerpts) > 0 { + excerpt = excerpts[3] + } + if len(locations) > 0 { + if *verbose { + if s.file != locations[2] { + fmt.Printf("%s\n", locations[2]) + } + fmt.Printf(" %s\n", locations[3]) + } + s.line = locations[3] + s.file = locations[2] + s.function = locations[1] + s.ioState.history.add(s.file, s.line, excerpt) + } + if len(excerpts) > 0 { + if *verbose { + fmt.Printf(" %s\n", excerpts[2]) + } + s.line = excerpts[2] + s.ioState.history.add(s.file, s.line, excerpt) + } + + // Look for //gdb-=(v1,v2,v3) and print v1, v2, v3 + vars := varsToPrint(excerpt, "//gdb-"+s.tag+"=(") + for _, v := range vars { + slashIndex := strings.Index(v, "/") + substitutions := "" + if slashIndex != -1 { + substitutions = v[slashIndex:] + v = v[:slashIndex] + } + response := s.ioState.writeRead("p " + v + "\n").String() + // expect something like "$1 = ..." + dollar := strings.Index(response, "$") + cr := strings.Index(response, "\n") + if dollar == -1 { + if cr == -1 { + response = strings.TrimSpace(response) // discards trailing newline + response = strings.Replace(response, "\n", "
", -1) + s.ioState.history.addVar("$ Malformed response " + response) + continue + } + response = strings.TrimSpace(response[:cr]) + s.ioState.history.addVar("$ " + response) + continue + } + if cr == -1 { + cr = len(response) + } + response = strings.TrimSpace(response[dollar:cr]) + if strings.Contains(substitutions, "A") { + response = hexRe.ReplaceAllString(response, "") + } + if strings.Contains(substitutions, "N") { + response = numRe.ReplaceAllString(response, "") + } + if strings.Contains(substitutions, "S") { + response = stringRe.ReplaceAllString(response, "") + } + s.ioState.history.addVar(response) + } + return true +} + +func varsToPrint(line, lookfor string) []string { + var vars []string + if strings.Contains(line, lookfor) { + x := line[strings.Index(line, lookfor)+len(lookfor):] + end := strings.Index(x, ")") + if end == -1 { + panic(fmt.Sprintf("Saw variable list begin %s in %s but no closing ')'", lookfor, line)) + } + vars = strings.Split(x[:end], ",") + for i, y := range vars { + vars[i] = strings.TrimSpace(y) + } + } + return vars +} + +func (s *gdbState) quit() { + response := s.ioState.writeRead("q\n") + if strings.Contains(response.o, "Quit anyway? (y or n)") { + s.ioState.writeRead("Y\n") + } +} + +func (s *gdbState) do(ss string) { + expect("", s.ioState.writeRead(ss+"\n")) +} + +type ioState struct { + stdout io.ReadCloser + stderr io.ReadCloser + stdin io.WriteCloser + outChan chan string + errChan chan string + last tstring // Output of previous step + history *nextHist +} + +func newIoState(cmd *exec.Cmd) *ioState { + var err error + s := &ioState{} + s.history = &nextHist{} + s.history.f2i = make(map[string]uint8) + s.stdout, err = cmd.StdoutPipe() + line := asCommandLine("", cmd) + if err != nil { + panic(fmt.Sprintf("There was an error [stdoutpipe] running '%s', %v\n", line, err)) + } + s.stderr, err = cmd.StderrPipe() + if err != nil { + panic(fmt.Sprintf("There was an error [stdouterr] running '%s', %v\n", line, err)) + } + s.stdin, err = cmd.StdinPipe() + if err != nil { + panic(fmt.Sprintf("There was an error [stdinpipe] running '%s', %v\n", line, err)) + } + + s.outChan = make(chan string, 1) + s.errChan = make(chan string, 1) + go func() { + buffer := make([]byte, 4096) + for { + n, err := s.stdout.Read(buffer) + if n > 0 { + s.outChan <- string(buffer[0:n]) + } + if err == io.EOF || n == 0 { + break + } + if err != nil { + fmt.Printf("Saw an error forwarding stdout") + break + } + } + close(s.outChan) + s.stdout.Close() + }() + + go func() { + buffer := make([]byte, 4096) + for { + n, err := s.stderr.Read(buffer) + if n > 0 { + s.errChan <- string(buffer[0:n]) + } + if err == io.EOF || n == 0 { + break + } + if err != nil { + fmt.Printf("Saw an error forwarding stderr") + break + } + } + close(s.errChan) + s.stderr.Close() + }() + return s +} + +func (s *ioState) hist() *nextHist { + return s.history +} + +const ( + interlineDelay = 300 +) + +func (s *ioState) writeRead(ss string) tstring { + if *verbose { + fmt.Printf("=> %s", ss) + } + _, err := io.WriteString(s.stdin, ss) + if err != nil { + panic(fmt.Sprintf("There was an error writing '%s', %v\n", ss, err)) + } + return s.readWithDelay(-1, interlineDelay) +} + +func (s *ioState) writeReadExpect(ss, expect string) tstring { + if *verbose { + fmt.Printf("=> %s", ss) + } + _, err := io.WriteString(s.stdin, ss) + if err != nil { + panic(fmt.Sprintf("There was an error writing '%s', %v\n", ss, err)) + } + return s.readExpecting(-1, interlineDelay, expect) +} + +func (s *ioState) readWithDelay(millis, interlineTimeout int) tstring { + return s.readExpecting(millis, interlineTimeout, "") +} + +func (s *ioState) readExpecting(millis, interlineTimeout int, expected string) tstring { + timeout := time.Millisecond * time.Duration(millis) + interline := time.Millisecond * time.Duration(interlineTimeout) + s.last = tstring{} + var re *regexp.Regexp + if expected != "" { + re = regexp.MustCompile(expected) + } +loop: + for { + var timer <-chan time.Time + if timeout > 0 { + timer = time.After(timeout) + } + select { + case x, ok := <-s.outChan: + if !ok { + s.outChan = nil + } + s.last.o += x + case x, ok := <-s.errChan: + if !ok { + s.errChan = nil + } + s.last.e += x + case <-timer: + break loop + } + if re != nil { + if re.MatchString(s.last.o) { + break + } + if re.MatchString(s.last.e) { + break + } + } + timeout = interline + } + if *verbose { + fmt.Printf("<= %s%s", s.last.o, s.last.e) + } + return s.last +} + +// replaceEnv returns a new environment derived from env +// by removing any existing definition of ev and adding ev=evv. +func replaceEnv(env []string, ev string, evv string) []string { + evplus := ev + "=" + var found bool + for i, v := range env { + if strings.HasPrefix(v, evplus) { + found = true + env[i] = evplus + evv + } + } + if !found { + env = append(env, evplus+evv) + } + return env +} + +// asCommandLine renders cmd as something that could be copy-and-pasted into a command line +// If cwd is not empty and different from the command's directory, prepend an approprirate "cd" +func asCommandLine(cwd string, cmd *exec.Cmd) string { + s := "(" + if cmd.Dir != "" && cmd.Dir != cwd { + s += "cd" + escape(cmd.Dir) + ";" + } + for _, e := range cmd.Env { + if !strings.HasPrefix(e, "PATH=") && + !strings.HasPrefix(e, "HOME=") && + !strings.HasPrefix(e, "USER=") && + !strings.HasPrefix(e, "SHELL=") { + s += escape(e) + } + } + for _, a := range cmd.Args { + s += escape(a) + } + s += " )" + return s +} + +// escape inserts escapes appropriate for use in a shell command line +func escape(s string) string { + s = strings.Replace(s, "\\", "\\\\", -1) + s = strings.Replace(s, "'", "\\'", -1) + // Conservative guess at characters that will force quoting + if strings.ContainsAny(s, "\\ ;#*&$~?!|[]()<>{}`") { + s = " '" + s + "'" + } else { + s = " " + s + } + return s +} + +func expect(want string, got tstring) { + if want != "" { + match, err := regexp.MatchString(want, got.o) + if err != nil { + panic(fmt.Sprintf("Error for regexp %s, %v\n", want, err)) + } + if match { + return + } + match, err = regexp.MatchString(want, got.e) + if match { + return + } + fmt.Printf("EXPECTED '%s'\n GOT O='%s'\nAND E='%s'\n", want, got.o, got.e) + } +} diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 25d8f484ab..7faf2f13fe 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -488,7 +488,7 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos c = s.curBlock.NewValue1(pos, OpCopy, v.Type, s.regs[r2].c) } else if v.rematerializeable() { // Rematerialize instead of loading from the spill location. - c = v.copyIntoNoXPos(s.curBlock) + c = v.copyIntoWithXPos(s.curBlock, pos) } else { // Load v from its spill location. spill := s.makeSpill(v, s.curBlock) @@ -2000,7 +2000,7 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP // register to accomplish this. r := e.findRegFor(v.Type) e.erase(r) - x = v.copyIntoNoXPos(e.p) + x = v.copyIntoWithXPos(e.p, pos) e.set(r, vid, x, false, pos) // Make sure we spill with the size of the slot, not the // size of x (which might be wider due to our dropping diff --git a/src/cmd/compile/internal/ssa/testdata/hist-dbg.delve-nexts b/src/cmd/compile/internal/ssa/testdata/hist-dbg.delve-nexts new file mode 100644 index 0000000000..cf0d34eb91 --- /dev/null +++ b/src/cmd/compile/internal/ssa/testdata/hist-dbg.delve-nexts @@ -0,0 +1,383 @@ + ./testdata/hist.go +35: func main() { +36: hist := make([]int, 100) +37: var reader io.Reader = strings.NewReader(cannedInput) //gdb-dbg=(hist/A,cannedInput/A) +38: if len(os.Args) > 1 { +43: return +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +57: t := 0 +58: n := 0 +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +63: t += i * a +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +60: if a == 0 { +63: t += i * a +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +63: t += i * a +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +63: t += i * a +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +68: } + /usr/local/google/home/drchase/work/go/src/runtime/proc.go +201: if atomic.Load(&runningPanicDefers) != 0 { +210: if atomic.Load(&panicking) != 0 { +214: exit(0) diff --git a/src/cmd/compile/internal/ssa/testdata/hist-dbg.gdb-nexts b/src/cmd/compile/internal/ssa/testdata/hist-dbg.gdb-nexts new file mode 100644 index 0000000000..39ed076e3a --- /dev/null +++ b/src/cmd/compile/internal/ssa/testdata/hist-dbg.gdb-nexts @@ -0,0 +1,409 @@ + /usr/local/google/home/drchase/work/go/src/cmd/compile/internal/ssa/testdata/hist.go +35: func main() { +35: func main() { +36: hist := make([]int, 100) +37: var reader io.Reader = strings.NewReader(cannedInput) //gdb-dbg=(hist/A,cannedInput/A) +$1 = {array = , len = 100, cap = 100} +$2 = "1\n1\n1\n1\n2\n2\n2\n4\n4\n8\n" +38: if len(os.Args) > 1 { +43: return +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$3 = 1 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$4 = 1 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$5 = 1 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$6 = 1 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$7 = 2 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$8 = 2 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$9 = 2 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$10 = 4 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$11 = 4 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +48: s := scanner.Text() +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +$12 = 8 +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +57: t := 0 +58: n := 0 +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +63: t += i * a +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +$13 = 4 +$14 = 1 +$15 = 4 +59: for i, a := range hist { +60: if a == 0 { +63: t += i * a +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +$16 = 7 +$17 = 2 +$18 = 10 +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +63: t += i * a +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +$19 = 9 +$20 = 4 +$21 = 18 +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +63: t += i * a +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +$22 = 10 +$23 = 8 +$24 = 26 +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +60: if a == 0 { +61: continue +59: for i, a := range hist { +68: } + /usr/local/google/home/drchase/work/go/src/runtime/proc.go +201: if atomic.Load(&runningPanicDefers) != 0 { +201: if atomic.Load(&runningPanicDefers) != 0 { +210: if atomic.Load(&panicking) != 0 { +214: exit(0) diff --git a/src/cmd/compile/internal/ssa/testdata/hist-opt.delve-nexts b/src/cmd/compile/internal/ssa/testdata/hist-opt.delve-nexts new file mode 100644 index 0000000000..4e2584586d --- /dev/null +++ b/src/cmd/compile/internal/ssa/testdata/hist-opt.delve-nexts @@ -0,0 +1,248 @@ + ./testdata/hist.go +35: func main() { +36: hist := make([]int, 100) +37: var reader io.Reader = strings.NewReader(cannedInput) //gdb-dbg=(hist/A,cannedInput/A) +13: "strings" + /usr/local/google/home/drchase/work/go/src/strings/reader.go +150: func NewReader(s string) *Reader { return &Reader{s, 0, -1} } + ./testdata/hist.go +38: if len(os.Args) > 1 { +8: "bufio" + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +84: split: ScanLines, +74: MaxScanTokenSize = 64 * 1024 + ./testdata/hist.go +47: for scanner.Scan() { +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { + /usr/local/google/home/drchase/work/go/src/bufio/scan.go +107: return string(s.token) + ./testdata/hist.go +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +55: hist[int(i)]++ +47: for scanner.Scan() { +59: for i, a := range hist { +60: if a == 0 { +60: if a == 0 { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +60: if a == 0 { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +60: if a == 0 { +60: if a == 0 { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +68: } + /usr/local/google/home/drchase/work/go/src/runtime/proc.go +201: if atomic.Load(&runningPanicDefers) != 0 { +210: if atomic.Load(&panicking) != 0 { +214: exit(0) diff --git a/src/cmd/compile/internal/ssa/testdata/hist-opt.gdb-nexts b/src/cmd/compile/internal/ssa/testdata/hist-opt.gdb-nexts new file mode 100644 index 0000000000..4add645962 --- /dev/null +++ b/src/cmd/compile/internal/ssa/testdata/hist-opt.gdb-nexts @@ -0,0 +1,215 @@ + /usr/local/google/home/drchase/work/go/src/cmd/compile/internal/ssa/testdata/hist.go +35: func main() { +35: func main() { +36: hist := make([]int, 100) +37: var reader io.Reader = strings.NewReader(cannedInput) //gdb-dbg=(hist/A,cannedInput/A) +13: "strings" +150: func NewReader(s string) *Reader { return &Reader{s, 0, -1} } +38: if len(os.Args) > 1 { +8: "bufio" +84: split: ScanLines, +74: MaxScanTokenSize = 64 * 1024 +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +107: return string(s.token) +49: i, err := strconv.ParseInt(s, 10, 64) +50: if err != nil { //gdb-dbg=(i) +54: hist = ensure(int(i), hist) +55: hist[int(i)]++ +47: for scanner.Scan() { +59: for i, a := range hist { +60: if a == 0 { +60: if a == 0 { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +60: if a == 0 { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +60: if a == 0 { +60: if a == 0 { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +64: n += a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +63: t += i * a +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +59: for i, a := range hist { +65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +60: if a == 0 { +68: } + /usr/local/google/home/drchase/work/go/src/runtime/proc.go +201: if atomic.Load(&runningPanicDefers) != 0 { +201: if atomic.Load(&runningPanicDefers) != 0 { +210: if atomic.Load(&panicking) != 0 { +214: exit(0) diff --git a/src/cmd/compile/internal/ssa/testdata/hist.go b/src/cmd/compile/internal/ssa/testdata/hist.go new file mode 100644 index 0000000000..623e2f86f9 --- /dev/null +++ b/src/cmd/compile/internal/ssa/testdata/hist.go @@ -0,0 +1,68 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "strconv" + "strings" +) + +func ensure(n int, sl []int) []int { + for len(sl) <= n { + sl = append(sl, 0) + } + return sl +} + +var cannedInput string = `1 +1 +1 +1 +2 +2 +2 +4 +4 +8 +` + +func main() { + hist := make([]int, 100) + var reader io.Reader = strings.NewReader(cannedInput) //gdb-dbg=(hist/A,cannedInput/A) + if len(os.Args) > 1 { + var err error + reader, err = os.Open(os.Args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "There was an error opening %s: %v\n", os.Args[1], err) + return + } + } + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + s := scanner.Text() + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { //gdb-dbg=(i) + fmt.Fprintf(os.Stderr, "There was an error: %v\n", err) + return + } + hist = ensure(int(i), hist) + hist[int(i)]++ + } + t := 0 + n := 0 + for i, a := range hist { + if a == 0 { + continue + } + t += i * a + n += a + fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) + } + +} diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index fa6dcd4cd4..68d9565b2b 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -240,7 +240,13 @@ func (v *Value) copyInto(b *Block) *Value { // The copied value receives no source code position to avoid confusing changes // in debugger information (the intended user is the register allocator). func (v *Value) copyIntoNoXPos(b *Block) *Value { - c := b.NewValue0(src.NoXPos, v.Op, v.Type) // Lose the position, this causes line number churn otherwise. + return v.copyIntoWithXPos(b, src.NoXPos) +} + +// copyIntoWithXPos makes a new value identical to v and adds it to the end of b. +// The supplied position is used as the position of the new value. +func (v *Value) copyIntoWithXPos(b *Block, pos src.XPos) *Value { + c := b.NewValue0(pos, v.Op, v.Type) c.Aux = v.Aux c.AuxInt = v.AuxInt c.AddArgs(v.Args...)