go/src/cmd/compile/internal/ssa/value.go

492 lines
13 KiB
Go
Raw Normal View History

// Copyright 2015 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
import (
cmd/compile: change ssa.Type into *types.Type When package ssa was created, Type was in package gc. To avoid circular dependencies, we used an interface (ssa.Type) to represent type information in SSA. In the Go 1.9 cycle, gri extricated the Type type from package gc. As a result, we can now use it in package ssa. Now, instead of package types depending on package ssa, it is the other way. This is a more sensible dependency tree, and helps compiler performance a bit. Though this is a big CL, most of the changes are mechanical and uninteresting. Interesting bits: * Add new singleton globals to package types for the special SSA types Memory, Void, Invalid, Flags, and Int128. * Add two new Types, TSSA for the special types, and TTUPLE, for SSA tuple types. ssa.MakeTuple is now types.NewTuple. * Move type comparison result constants CMPlt, CMPeq, and CMPgt to package types. * We had picked the name "types" in our rules for the handy list of types provided by ssa.Config. That conflicted with the types package name, so change it to "typ". * Update the type comparison routine to handle tuples and special types inline. * Teach gc/fmt.go how to print special types. * We can now eliminate ElemTypes in favor of just Elem, and probably also some other duplicated Type methods designed to return ssa.Type instead of *types.Type. * The ssa tests were using their own dummy types, and they were not particularly careful about types in general. Of necessity, this CL switches them to use *types.Type; it does not make them more type-accurate. Unfortunately, using types.Type means initializing a bit of the types universe. This is prime for refactoring and improvement. This shrinks ssa.Value; it now fits in a smaller size class on 64 bit systems. This doesn't have a giant impact, though, since most Values are preallocated in a chunk. name old alloc/op new alloc/op delta Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8) Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10) GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10) Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10) GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9) Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8) Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10) XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10) [Geo mean] 40.5MB 40.3MB -0.68% name old allocs/op new allocs/op delta Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9) Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10) GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10) Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10) GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9) Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8) Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10) XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10) [Geo mean] 428k 428k -0.01% Removing all the interface calls helps non-trivially with CPU, though. name old time/op new time/op delta Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96) Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96) GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96) Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99) GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97) Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99) Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94) XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95) [Geo mean] 178ms 173ms -2.65% name old user-time/op new user-time/op delta Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99) Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95) GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99) Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96) GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100) Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92) Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100) XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97) [Geo mean] 220ms 213ms -2.76% Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1 Reviewed-on: https://go-review.googlesource.com/42145 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
"math"
"sort"
[dev.debug] cmd/compile: better DWARF with optimizations on Debuggers use DWARF information to find local variables on the stack and in registers. Prior to this CL, the DWARF information for functions claimed that all variables were on the stack at all times. That's incorrect when optimizations are enabled, and results in debuggers showing data that is out of date or complete gibberish. After this CL, the compiler is capable of representing variable locations more accurately, and attempts to do so. Due to limitations of the SSA backend, it's not possible to be completely correct. There are a number of problems in the current design. One of the easier to understand is that variable names currently must be attached to an SSA value, but not all assignments in the source code actually result in machine code. For example: type myint int var a int b := myint(int) and b := (*uint64)(unsafe.Pointer(a)) don't generate machine code because the underlying representation is the same, so the correct value of b will not be set when the user would expect. Generating the more precise debug information is behind a flag, dwarflocationlists. Because of the issues described above, setting the flag may not make the debugging experience much better, and may actually make it worse in cases where the variable actually is on the stack and the more complicated analysis doesn't realize it. A number of changes are included: - Add a new pseudo-instruction, RegKill, which indicates that the value in the register has been clobbered. - Adjust regalloc to emit RegKills in the right places. Significantly, this means that phis are mixed with StoreReg and RegKills after regalloc. - Track variable decomposition in ssa.LocalSlots. - After the SSA backend is done, analyze the result and build location lists for each LocalSlot. - After assembly is done, update the location lists with the assembled PC offsets, recompose variables, and build DWARF location lists. Emit the list as a new linker symbol, one per function. - In the linker, aggregate the location lists into a .debug_loc section. TODO: - currently disabled for non-X86/AMD64 because there are no data tables. go build -toolexec 'toolstash -cmp' -a std succeeds. With -dwarflocationlists false: before: f02812195637909ff675782c0b46836a8ff01976 after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec benchstat -geomean /tmp/220352263 /tmp/621364410 completed 15 of 15, estimated time remaining 0s (eta 3:52PM) name old time/op new time/op delta Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14) Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15) GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14) Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15) GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15) Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13) Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15) XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15) [Geo mean] 206ms 377ms +82.86% name old user-time/op new user-time/op delta Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15) Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14) GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15) Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15) GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15) Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13) Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15) XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15) [Geo mean] 317ms 583ms +83.72% name old alloc/op new alloc/op delta Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15) Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15) GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14) Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15) GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15) Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15) Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15) XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15) [Geo mean] 42.1MB 75.0MB +78.05% name old allocs/op new allocs/op delta Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15) Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14) GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14) Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15) GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15) Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15) Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15) XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15) [Geo mean] 439k 755k +72.01% name old text-bytes new text-bytes delta HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15) name old data-bytes new data-bytes delta HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal) name old bss-bytes new bss-bytes delta HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal) Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8 Reviewed-on: https://go-review.googlesource.com/41770 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
"strings"
)
// A Value represents a value in the SSA representation of the program.
// The ID and Type fields must not be modified. The remainder may be modified
// if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)).
type Value struct {
// A unique identifier for the value. For performance we allocate these IDs
// densely starting at 1. There is no guarantee that there won't be occasional holes, though.
ID ID
// The operation that computes this value. See op.go.
Op Op
// The type of this value. Normally this will be a Go type, but there
// are a few other pseudo-types, see ../types/type.go.
cmd/compile: change ssa.Type into *types.Type When package ssa was created, Type was in package gc. To avoid circular dependencies, we used an interface (ssa.Type) to represent type information in SSA. In the Go 1.9 cycle, gri extricated the Type type from package gc. As a result, we can now use it in package ssa. Now, instead of package types depending on package ssa, it is the other way. This is a more sensible dependency tree, and helps compiler performance a bit. Though this is a big CL, most of the changes are mechanical and uninteresting. Interesting bits: * Add new singleton globals to package types for the special SSA types Memory, Void, Invalid, Flags, and Int128. * Add two new Types, TSSA for the special types, and TTUPLE, for SSA tuple types. ssa.MakeTuple is now types.NewTuple. * Move type comparison result constants CMPlt, CMPeq, and CMPgt to package types. * We had picked the name "types" in our rules for the handy list of types provided by ssa.Config. That conflicted with the types package name, so change it to "typ". * Update the type comparison routine to handle tuples and special types inline. * Teach gc/fmt.go how to print special types. * We can now eliminate ElemTypes in favor of just Elem, and probably also some other duplicated Type methods designed to return ssa.Type instead of *types.Type. * The ssa tests were using their own dummy types, and they were not particularly careful about types in general. Of necessity, this CL switches them to use *types.Type; it does not make them more type-accurate. Unfortunately, using types.Type means initializing a bit of the types universe. This is prime for refactoring and improvement. This shrinks ssa.Value; it now fits in a smaller size class on 64 bit systems. This doesn't have a giant impact, though, since most Values are preallocated in a chunk. name old alloc/op new alloc/op delta Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8) Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10) GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10) Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10) GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9) Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8) Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10) XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10) [Geo mean] 40.5MB 40.3MB -0.68% name old allocs/op new allocs/op delta Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9) Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10) GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10) Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10) GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9) Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8) Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10) XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10) [Geo mean] 428k 428k -0.01% Removing all the interface calls helps non-trivially with CPU, though. name old time/op new time/op delta Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96) Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96) GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96) Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99) GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97) Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99) Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94) XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95) [Geo mean] 178ms 173ms -2.65% name old user-time/op new user-time/op delta Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99) Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95) GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99) Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96) GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100) Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92) Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100) XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97) [Geo mean] 220ms 213ms -2.76% Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1 Reviewed-on: https://go-review.googlesource.com/42145 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
Type *types.Type
// Auxiliary info for this value. The type of this information depends on the opcode and type.
// AuxInt is used for integer values, Aux is used for other values.
// Floats are stored in AuxInt using math.Float64bits(f).
// Unused portions of AuxInt are filled by sign-extending the used portion,
// even if the represented value is unsigned.
// Users of AuxInt which interpret AuxInt as unsigned (e.g. shifts) must be careful.
// Use Value.AuxUnsigned to get the zero-extended value of AuxInt.
AuxInt int64
Aux interface{}
// Arguments of this value
Args []*Value
// Containing basic block
Block *Block
// Source position
2016-12-15 17:17:01 -08:00
Pos src.XPos
cmd/compile: allow multiple SSA block control values Control values are used to choose which successor of a block is jumped to. Typically a control value takes the form of a 'flags' value that represents the result of a comparison. Some architectures however use a variable in a register as a control value. Up until now we have managed with a single control value per block. However some architectures (e.g. s390x and riscv64) have combined compare-and-branch instructions that take two variables in registers as parameters. To generate these instructions we need to support 2 control values per block. This CL allows up to 2 control values to be used in a block in order to support the addition of compare-and-branch instructions. I have implemented s390x compare-and-branch instructions in a different CL. Passes toolstash-check -all. Results of compilebench: name old time/op new time/op delta Template 208ms ± 1% 209ms ± 1% ~ (p=0.289 n=20+20) Unicode 83.7ms ± 1% 83.3ms ± 3% -0.49% (p=0.017 n=18+18) GoTypes 748ms ± 1% 748ms ± 0% ~ (p=0.460 n=20+18) Compiler 3.47s ± 1% 3.48s ± 1% ~ (p=0.070 n=19+18) SSA 11.5s ± 1% 11.7s ± 1% +1.64% (p=0.000 n=19+18) Flate 130ms ± 1% 130ms ± 1% ~ (p=0.588 n=19+20) GoParser 160ms ± 1% 161ms ± 1% ~ (p=0.211 n=20+20) Reflect 465ms ± 1% 467ms ± 1% +0.42% (p=0.007 n=20+20) Tar 184ms ± 1% 185ms ± 2% ~ (p=0.087 n=18+20) XML 253ms ± 1% 253ms ± 1% ~ (p=0.377 n=20+18) LinkCompiler 769ms ± 2% 774ms ± 2% ~ (p=0.070 n=19+19) ExternalLinkCompiler 3.59s ±11% 3.68s ± 6% ~ (p=0.072 n=20+20) LinkWithoutDebugCompiler 446ms ± 5% 454ms ± 3% +1.79% (p=0.002 n=19+20) StdCmd 26.0s ± 2% 26.0s ± 2% ~ (p=0.799 n=20+20) name old user-time/op new user-time/op delta Template 238ms ± 5% 240ms ± 5% ~ (p=0.142 n=20+20) Unicode 105ms ±11% 106ms ±10% ~ (p=0.512 n=20+20) GoTypes 876ms ± 2% 873ms ± 4% ~ (p=0.647 n=20+19) Compiler 4.17s ± 2% 4.19s ± 1% ~ (p=0.093 n=20+18) SSA 13.9s ± 1% 14.1s ± 1% +1.45% (p=0.000 n=18+18) Flate 145ms ±13% 146ms ± 5% ~ (p=0.851 n=20+18) GoParser 185ms ± 5% 188ms ± 7% ~ (p=0.174 n=20+20) Reflect 534ms ± 3% 538ms ± 2% ~ (p=0.105 n=20+18) Tar 215ms ± 4% 211ms ± 9% ~ (p=0.079 n=19+20) XML 295ms ± 6% 295ms ± 5% ~ (p=0.968 n=20+20) LinkCompiler 832ms ± 4% 837ms ± 7% ~ (p=0.707 n=17+20) ExternalLinkCompiler 1.58s ± 8% 1.60s ± 4% ~ (p=0.296 n=20+19) LinkWithoutDebugCompiler 478ms ±12% 489ms ±10% ~ (p=0.429 n=20+20) name old object-bytes new object-bytes delta Template 559kB ± 0% 559kB ± 0% ~ (all equal) Unicode 216kB ± 0% 216kB ± 0% ~ (all equal) GoTypes 2.03MB ± 0% 2.03MB ± 0% ~ (all equal) Compiler 8.07MB ± 0% 8.07MB ± 0% -0.06% (p=0.000 n=20+20) SSA 27.1MB ± 0% 27.3MB ± 0% +0.89% (p=0.000 n=20+20) Flate 343kB ± 0% 343kB ± 0% ~ (all equal) GoParser 441kB ± 0% 441kB ± 0% ~ (all equal) Reflect 1.36MB ± 0% 1.36MB ± 0% ~ (all equal) Tar 487kB ± 0% 487kB ± 0% ~ (all equal) XML 632kB ± 0% 632kB ± 0% ~ (all equal) name old export-bytes new export-bytes delta Template 18.5kB ± 0% 18.5kB ± 0% ~ (all equal) Unicode 7.92kB ± 0% 7.92kB ± 0% ~ (all equal) GoTypes 35.0kB ± 0% 35.0kB ± 0% ~ (all equal) Compiler 109kB ± 0% 110kB ± 0% +0.72% (p=0.000 n=20+20) SSA 137kB ± 0% 138kB ± 0% +0.58% (p=0.000 n=20+20) Flate 4.89kB ± 0% 4.89kB ± 0% ~ (all equal) GoParser 8.49kB ± 0% 8.49kB ± 0% ~ (all equal) Reflect 11.4kB ± 0% 11.4kB ± 0% ~ (all equal) Tar 10.5kB ± 0% 10.5kB ± 0% ~ (all equal) XML 16.7kB ± 0% 16.7kB ± 0% ~ (all equal) name old text-bytes new text-bytes delta HelloSize 761kB ± 0% 761kB ± 0% ~ (all equal) CmdGoSize 10.8MB ± 0% 10.8MB ± 0% ~ (all equal) name old data-bytes new data-bytes delta HelloSize 10.7kB ± 0% 10.7kB ± 0% ~ (all equal) CmdGoSize 312kB ± 0% 312kB ± 0% ~ (all equal) name old bss-bytes new bss-bytes delta HelloSize 122kB ± 0% 122kB ± 0% ~ (all equal) CmdGoSize 146kB ± 0% 146kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.13MB ± 0% 1.13MB ± 0% ~ (all equal) CmdGoSize 15.1MB ± 0% 15.1MB ± 0% ~ (all equal) Change-Id: I3cc2f9829a109543d9a68be4a21775d2d3e9801f Reviewed-on: https://go-review.googlesource.com/c/go/+/196557 Run-TryBot: Michael Munday <mike.munday@ibm.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Daniel Martí <mvdan@mvdan.cc> Reviewed-by: Keith Randall <khr@golang.org>
2019-08-12 20:19:58 +01:00
// Use count. Each appearance in Value.Args and Block.Controls counts once.
Uses int32
cmd/compile: add wasm stack optimization Go's SSA instructions only operate on registers. For example, an add instruction would read two registers, do the addition and then write to a register. WebAssembly's instructions, on the other hand, operate on the stack. The add instruction first pops two values from the stack, does the addition, then pushes the result to the stack. To fulfill Go's semantics, one needs to map Go's single add instruction to 4 WebAssembly instructions: - Push the value of local variable A to the stack - Push the value of local variable B to the stack - Do addition - Write value from stack to local variable C Now consider that B was set to the constant 42 before the addition: - Push constant 42 to the stack - Write value from stack to local variable B This works, but is inefficient. Instead, the stack is used directly by inlining instructions if possible. With inlining it becomes: - Push the value of local variable A to the stack (add) - Push constant 42 to the stack (constant) - Do addition (add) - Write value from stack to local variable C (add) Note that the two SSA instructions can not be generated sequentially anymore, because their WebAssembly instructions are interleaved. Design doc: https://docs.google.com/document/d/131vjr4DH6JFnb-blm_uRdaC0_Nv3OUwjEY5qVCxCup4 Updates #18892 Change-Id: Ie35e1c0bebf4985fddda0d6330eb2066f9ad6dec Reviewed-on: https://go-review.googlesource.com/103535 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
2018-03-09 00:14:58 +01:00
// wasm: Value stays on the WebAssembly stack. This value will not get a "register" (WebAssembly variable)
// nor a slot on Go stack, and the generation of this value is delayed to its use time.
OnWasmStack bool
// Is this value in the per-function constant cache? If so, remove from cache before changing it or recycling it.
InCache bool
// Storage for the first three args
argstorage [3]*Value
}
// Examples:
// Opcode aux args
// OpAdd nil 2
// OpConst string 0 string constant
// OpConst int64 0 int64 constant
// OpAddcq int64 1 amd64 op: v = arg[0] + constant
// short form print. Just v#.
func (v *Value) String() string {
if v == nil {
return "nil" // should never happen, but not panicking helps with debugging
}
return fmt.Sprintf("v%d", v.ID)
}
func (v *Value) AuxInt8() int8 {
if opcodeTable[v.Op].auxType != auxInt8 {
v.Fatalf("op %s doesn't have an int8 aux field", v.Op)
}
return int8(v.AuxInt)
}
func (v *Value) AuxInt16() int16 {
if opcodeTable[v.Op].auxType != auxInt16 {
v.Fatalf("op %s doesn't have an int16 aux field", v.Op)
}
return int16(v.AuxInt)
}
func (v *Value) AuxInt32() int32 {
if opcodeTable[v.Op].auxType != auxInt32 {
v.Fatalf("op %s doesn't have an int32 aux field", v.Op)
}
return int32(v.AuxInt)
}
// AuxUnsigned returns v.AuxInt as an unsigned value for OpConst*.
// v.AuxInt is always sign-extended to 64 bits, even if the
// represented value is unsigned. This undoes that sign extension.
func (v *Value) AuxUnsigned() uint64 {
c := v.AuxInt
switch v.Op {
case OpConst64:
return uint64(c)
case OpConst32:
return uint64(uint32(c))
case OpConst16:
return uint64(uint16(c))
case OpConst8:
return uint64(uint8(c))
}
v.Fatalf("op %s isn't OpConst*", v.Op)
return 0
}
func (v *Value) AuxFloat() float64 {
if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 {
v.Fatalf("op %s doesn't have a float aux field", v.Op)
}
return math.Float64frombits(uint64(v.AuxInt))
}
func (v *Value) AuxValAndOff() ValAndOff {
if opcodeTable[v.Op].auxType != auxSymValAndOff {
v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
}
return ValAndOff(v.AuxInt)
}
func (v *Value) AuxArm64BitField() arm64BitField {
if opcodeTable[v.Op].auxType != auxARM64BitField {
v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
}
return arm64BitField(v.AuxInt)
}
[dev.debug] cmd/compile: better DWARF with optimizations on Debuggers use DWARF information to find local variables on the stack and in registers. Prior to this CL, the DWARF information for functions claimed that all variables were on the stack at all times. That's incorrect when optimizations are enabled, and results in debuggers showing data that is out of date or complete gibberish. After this CL, the compiler is capable of representing variable locations more accurately, and attempts to do so. Due to limitations of the SSA backend, it's not possible to be completely correct. There are a number of problems in the current design. One of the easier to understand is that variable names currently must be attached to an SSA value, but not all assignments in the source code actually result in machine code. For example: type myint int var a int b := myint(int) and b := (*uint64)(unsafe.Pointer(a)) don't generate machine code because the underlying representation is the same, so the correct value of b will not be set when the user would expect. Generating the more precise debug information is behind a flag, dwarflocationlists. Because of the issues described above, setting the flag may not make the debugging experience much better, and may actually make it worse in cases where the variable actually is on the stack and the more complicated analysis doesn't realize it. A number of changes are included: - Add a new pseudo-instruction, RegKill, which indicates that the value in the register has been clobbered. - Adjust regalloc to emit RegKills in the right places. Significantly, this means that phis are mixed with StoreReg and RegKills after regalloc. - Track variable decomposition in ssa.LocalSlots. - After the SSA backend is done, analyze the result and build location lists for each LocalSlot. - After assembly is done, update the location lists with the assembled PC offsets, recompose variables, and build DWARF location lists. Emit the list as a new linker symbol, one per function. - In the linker, aggregate the location lists into a .debug_loc section. TODO: - currently disabled for non-X86/AMD64 because there are no data tables. go build -toolexec 'toolstash -cmp' -a std succeeds. With -dwarflocationlists false: before: f02812195637909ff675782c0b46836a8ff01976 after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec benchstat -geomean /tmp/220352263 /tmp/621364410 completed 15 of 15, estimated time remaining 0s (eta 3:52PM) name old time/op new time/op delta Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14) Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15) GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14) Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15) GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15) Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13) Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15) XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15) [Geo mean] 206ms 377ms +82.86% name old user-time/op new user-time/op delta Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15) Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14) GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15) Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15) GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15) Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13) Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15) XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15) [Geo mean] 317ms 583ms +83.72% name old alloc/op new alloc/op delta Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15) Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15) GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14) Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15) GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15) Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15) Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15) XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15) [Geo mean] 42.1MB 75.0MB +78.05% name old allocs/op new allocs/op delta Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15) Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14) GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14) Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15) GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15) Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15) Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15) XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15) [Geo mean] 439k 755k +72.01% name old text-bytes new text-bytes delta HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15) name old data-bytes new data-bytes delta HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal) name old bss-bytes new bss-bytes delta HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal) Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8 Reviewed-on: https://go-review.googlesource.com/41770 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
// long form print. v# = opcode <type> [aux] args [: reg] (names)
func (v *Value) LongString() string {
s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
s += " <" + v.Type.String() + ">"
s += v.auxString()
for _, a := range v.Args {
s += fmt.Sprintf(" %v", a)
}
cmd/compile: assign and preserve statement boundaries. A new pass run after ssa building (before any other optimization) identifies the "first" ssa node for each statement. Other "noise" nodes are tagged as being never appropriate for a statement boundary (e.g., VarKill, VarDef, Phi). Rewrite, deadcode, cse, and nilcheck are modified to move the statement boundaries forward whenever possible if a boundary-tagged ssa value is removed; never-boundary nodes are ignored in this search (some operations involving constants are also tagged as never-boundary and also ignored because they are likely to be moved or removed during optimization). Code generation treats all nodes except those explicitly marked as statement boundaries as "not statement" nodes, and floats statement boundaries to the beginning of each same-line run of instructions found within a basic block. Line number html conversion was modified to make statement boundary nodes a bit more obvious by prepending a "+". The code in fuse.go that glued together the value slices of two blocks produced a result that depended on the former capacities (not lengths) of the two slices. This causes differences in the 386 bootstrap, and also can sometimes put values into an order that does a worse job of preserving statement boundaries when values are removed. Portions of two delve tests that had caught problems were incorporated into ssa/debug_test.go. There are some opportunities to do better with optimized code, but the next-ing is not lying or overly jumpy. Over 4 CLs, compilebench geomean measured binary size increase of 3.5% and compile user time increase of 3.8% (this is after optimization to reuse a sparse map instead of creating multiple maps.) This CL worsens the optimized-debugging experience with Delve; we need to work with the delve team so that they can use the is_stmt marks that we're emitting now. The reference output changes from time to time depending on other changes in the compiler, sometimes better, sometimes worse. This CL now includes a test ensuring that 99+% of the lines in the Go command itself (a handy optimized binary) include is_stmt markers. Change-Id: I359c94e06843f1eb41f9da437bd614885aa9644a Reviewed-on: https://go-review.googlesource.com/102435 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
2018-03-23 22:46:06 -04:00
var r []Location
if v.Block != nil {
r = v.Block.Func.RegAlloc
}
if int(v.ID) < len(r) && r[v.ID] != nil {
s += " : " + r[v.ID].String()
}
[dev.debug] cmd/compile: better DWARF with optimizations on Debuggers use DWARF information to find local variables on the stack and in registers. Prior to this CL, the DWARF information for functions claimed that all variables were on the stack at all times. That's incorrect when optimizations are enabled, and results in debuggers showing data that is out of date or complete gibberish. After this CL, the compiler is capable of representing variable locations more accurately, and attempts to do so. Due to limitations of the SSA backend, it's not possible to be completely correct. There are a number of problems in the current design. One of the easier to understand is that variable names currently must be attached to an SSA value, but not all assignments in the source code actually result in machine code. For example: type myint int var a int b := myint(int) and b := (*uint64)(unsafe.Pointer(a)) don't generate machine code because the underlying representation is the same, so the correct value of b will not be set when the user would expect. Generating the more precise debug information is behind a flag, dwarflocationlists. Because of the issues described above, setting the flag may not make the debugging experience much better, and may actually make it worse in cases where the variable actually is on the stack and the more complicated analysis doesn't realize it. A number of changes are included: - Add a new pseudo-instruction, RegKill, which indicates that the value in the register has been clobbered. - Adjust regalloc to emit RegKills in the right places. Significantly, this means that phis are mixed with StoreReg and RegKills after regalloc. - Track variable decomposition in ssa.LocalSlots. - After the SSA backend is done, analyze the result and build location lists for each LocalSlot. - After assembly is done, update the location lists with the assembled PC offsets, recompose variables, and build DWARF location lists. Emit the list as a new linker symbol, one per function. - In the linker, aggregate the location lists into a .debug_loc section. TODO: - currently disabled for non-X86/AMD64 because there are no data tables. go build -toolexec 'toolstash -cmp' -a std succeeds. With -dwarflocationlists false: before: f02812195637909ff675782c0b46836a8ff01976 after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec benchstat -geomean /tmp/220352263 /tmp/621364410 completed 15 of 15, estimated time remaining 0s (eta 3:52PM) name old time/op new time/op delta Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14) Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15) GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14) Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15) GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15) Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13) Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15) XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15) [Geo mean] 206ms 377ms +82.86% name old user-time/op new user-time/op delta Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15) Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14) GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15) Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15) GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15) Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13) Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15) XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15) [Geo mean] 317ms 583ms +83.72% name old alloc/op new alloc/op delta Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15) Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15) GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14) Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15) GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15) Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15) Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15) XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15) [Geo mean] 42.1MB 75.0MB +78.05% name old allocs/op new allocs/op delta Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15) Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14) GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14) Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15) GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15) Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15) Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15) XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15) [Geo mean] 439k 755k +72.01% name old text-bytes new text-bytes delta HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15) name old data-bytes new data-bytes delta HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal) name old bss-bytes new bss-bytes delta HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal) Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8 Reviewed-on: https://go-review.googlesource.com/41770 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
var names []string
cmd/compile: assign and preserve statement boundaries. A new pass run after ssa building (before any other optimization) identifies the "first" ssa node for each statement. Other "noise" nodes are tagged as being never appropriate for a statement boundary (e.g., VarKill, VarDef, Phi). Rewrite, deadcode, cse, and nilcheck are modified to move the statement boundaries forward whenever possible if a boundary-tagged ssa value is removed; never-boundary nodes are ignored in this search (some operations involving constants are also tagged as never-boundary and also ignored because they are likely to be moved or removed during optimization). Code generation treats all nodes except those explicitly marked as statement boundaries as "not statement" nodes, and floats statement boundaries to the beginning of each same-line run of instructions found within a basic block. Line number html conversion was modified to make statement boundary nodes a bit more obvious by prepending a "+". The code in fuse.go that glued together the value slices of two blocks produced a result that depended on the former capacities (not lengths) of the two slices. This causes differences in the 386 bootstrap, and also can sometimes put values into an order that does a worse job of preserving statement boundaries when values are removed. Portions of two delve tests that had caught problems were incorporated into ssa/debug_test.go. There are some opportunities to do better with optimized code, but the next-ing is not lying or overly jumpy. Over 4 CLs, compilebench geomean measured binary size increase of 3.5% and compile user time increase of 3.8% (this is after optimization to reuse a sparse map instead of creating multiple maps.) This CL worsens the optimized-debugging experience with Delve; we need to work with the delve team so that they can use the is_stmt marks that we're emitting now. The reference output changes from time to time depending on other changes in the compiler, sometimes better, sometimes worse. This CL now includes a test ensuring that 99+% of the lines in the Go command itself (a handy optimized binary) include is_stmt markers. Change-Id: I359c94e06843f1eb41f9da437bd614885aa9644a Reviewed-on: https://go-review.googlesource.com/102435 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
2018-03-23 22:46:06 -04:00
if v.Block != nil {
for name, values := range v.Block.Func.NamedValues {
for _, value := range values {
if value == v {
names = append(names, name.String())
break // drop duplicates.
}
[dev.debug] cmd/compile: better DWARF with optimizations on Debuggers use DWARF information to find local variables on the stack and in registers. Prior to this CL, the DWARF information for functions claimed that all variables were on the stack at all times. That's incorrect when optimizations are enabled, and results in debuggers showing data that is out of date or complete gibberish. After this CL, the compiler is capable of representing variable locations more accurately, and attempts to do so. Due to limitations of the SSA backend, it's not possible to be completely correct. There are a number of problems in the current design. One of the easier to understand is that variable names currently must be attached to an SSA value, but not all assignments in the source code actually result in machine code. For example: type myint int var a int b := myint(int) and b := (*uint64)(unsafe.Pointer(a)) don't generate machine code because the underlying representation is the same, so the correct value of b will not be set when the user would expect. Generating the more precise debug information is behind a flag, dwarflocationlists. Because of the issues described above, setting the flag may not make the debugging experience much better, and may actually make it worse in cases where the variable actually is on the stack and the more complicated analysis doesn't realize it. A number of changes are included: - Add a new pseudo-instruction, RegKill, which indicates that the value in the register has been clobbered. - Adjust regalloc to emit RegKills in the right places. Significantly, this means that phis are mixed with StoreReg and RegKills after regalloc. - Track variable decomposition in ssa.LocalSlots. - After the SSA backend is done, analyze the result and build location lists for each LocalSlot. - After assembly is done, update the location lists with the assembled PC offsets, recompose variables, and build DWARF location lists. Emit the list as a new linker symbol, one per function. - In the linker, aggregate the location lists into a .debug_loc section. TODO: - currently disabled for non-X86/AMD64 because there are no data tables. go build -toolexec 'toolstash -cmp' -a std succeeds. With -dwarflocationlists false: before: f02812195637909ff675782c0b46836a8ff01976 after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec benchstat -geomean /tmp/220352263 /tmp/621364410 completed 15 of 15, estimated time remaining 0s (eta 3:52PM) name old time/op new time/op delta Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14) Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15) GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14) Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15) GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15) Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13) Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15) XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15) [Geo mean] 206ms 377ms +82.86% name old user-time/op new user-time/op delta Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15) Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14) GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15) Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15) GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15) Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13) Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15) XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15) [Geo mean] 317ms 583ms +83.72% name old alloc/op new alloc/op delta Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15) Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15) GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14) Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15) GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15) Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15) Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15) XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15) [Geo mean] 42.1MB 75.0MB +78.05% name old allocs/op new allocs/op delta Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15) Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14) GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14) Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15) GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15) Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15) Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15) XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15) [Geo mean] 439k 755k +72.01% name old text-bytes new text-bytes delta HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15) name old data-bytes new data-bytes delta HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal) name old bss-bytes new bss-bytes delta HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal) Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8 Reviewed-on: https://go-review.googlesource.com/41770 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
}
}
}
if len(names) != 0 {
sort.Strings(names) // Otherwise a source of variation in debugging output.
[dev.debug] cmd/compile: better DWARF with optimizations on Debuggers use DWARF information to find local variables on the stack and in registers. Prior to this CL, the DWARF information for functions claimed that all variables were on the stack at all times. That's incorrect when optimizations are enabled, and results in debuggers showing data that is out of date or complete gibberish. After this CL, the compiler is capable of representing variable locations more accurately, and attempts to do so. Due to limitations of the SSA backend, it's not possible to be completely correct. There are a number of problems in the current design. One of the easier to understand is that variable names currently must be attached to an SSA value, but not all assignments in the source code actually result in machine code. For example: type myint int var a int b := myint(int) and b := (*uint64)(unsafe.Pointer(a)) don't generate machine code because the underlying representation is the same, so the correct value of b will not be set when the user would expect. Generating the more precise debug information is behind a flag, dwarflocationlists. Because of the issues described above, setting the flag may not make the debugging experience much better, and may actually make it worse in cases where the variable actually is on the stack and the more complicated analysis doesn't realize it. A number of changes are included: - Add a new pseudo-instruction, RegKill, which indicates that the value in the register has been clobbered. - Adjust regalloc to emit RegKills in the right places. Significantly, this means that phis are mixed with StoreReg and RegKills after regalloc. - Track variable decomposition in ssa.LocalSlots. - After the SSA backend is done, analyze the result and build location lists for each LocalSlot. - After assembly is done, update the location lists with the assembled PC offsets, recompose variables, and build DWARF location lists. Emit the list as a new linker symbol, one per function. - In the linker, aggregate the location lists into a .debug_loc section. TODO: - currently disabled for non-X86/AMD64 because there are no data tables. go build -toolexec 'toolstash -cmp' -a std succeeds. With -dwarflocationlists false: before: f02812195637909ff675782c0b46836a8ff01976 after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec benchstat -geomean /tmp/220352263 /tmp/621364410 completed 15 of 15, estimated time remaining 0s (eta 3:52PM) name old time/op new time/op delta Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14) Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15) GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14) Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15) GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15) Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13) Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15) XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15) [Geo mean] 206ms 377ms +82.86% name old user-time/op new user-time/op delta Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15) Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14) GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15) Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15) GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15) Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13) Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15) XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15) [Geo mean] 317ms 583ms +83.72% name old alloc/op new alloc/op delta Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15) Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15) GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14) Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15) GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15) Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15) Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15) XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15) [Geo mean] 42.1MB 75.0MB +78.05% name old allocs/op new allocs/op delta Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15) Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14) GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14) Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15) GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15) Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15) Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15) XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15) [Geo mean] 439k 755k +72.01% name old text-bytes new text-bytes delta HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15) name old data-bytes new data-bytes delta HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal) name old bss-bytes new bss-bytes delta HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal) name old exe-bytes new exe-bytes delta HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal) Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8 Reviewed-on: https://go-review.googlesource.com/41770 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
s += " (" + strings.Join(names, ", ") + ")"
}
return s
}
func (v *Value) auxString() string {
switch opcodeTable[v.Op].auxType {
case auxBool:
if v.AuxInt == 0 {
return " [false]"
} else {
return " [true]"
}
case auxInt8:
return fmt.Sprintf(" [%d]", v.AuxInt8())
case auxInt16:
return fmt.Sprintf(" [%d]", v.AuxInt16())
case auxInt32:
return fmt.Sprintf(" [%d]", v.AuxInt32())
case auxInt64, auxInt128:
return fmt.Sprintf(" [%d]", v.AuxInt)
case auxARM64BitField:
lsb := v.AuxArm64BitField().getARM64BFlsb()
width := v.AuxArm64BitField().getARM64BFwidth()
return fmt.Sprintf(" [lsb=%d,width=%d]", lsb, width)
case auxFloat32, auxFloat64:
return fmt.Sprintf(" [%g]", v.AuxFloat())
case auxString:
return fmt.Sprintf(" {%q}", v.Aux)
case auxSym, auxCall, auxTyp:
if v.Aux != nil {
return fmt.Sprintf(" {%v}", v.Aux)
}
case auxSymOff, auxCallOff, auxTypSize:
s := ""
if v.Aux != nil {
s = fmt.Sprintf(" {%v}", v.Aux)
}
if v.AuxInt != 0 {
s += fmt.Sprintf(" [%v]", v.AuxInt)
}
return s
case auxSymValAndOff:
s := ""
if v.Aux != nil {
s = fmt.Sprintf(" {%v}", v.Aux)
}
return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
cmd/compile/internal/ssa: emit csel on arm64 Introduce a new SSA pass to generate CondSelect intstrutions, and add CondSelect lowering rules for arm64. In order to make the CSEL instruction easier to optimize, and to simplify the introduction of CSNEG, CSINC, and CSINV in the future, modify the CSEL instruction to accept a condition code in the aux field. Notably, this change makes the go1 Gzip benchmark more than 10% faster. Benchmarks on a Cavium ThunderX: name old time/op new time/op delta BinaryTree17-96 15.9s ± 6% 16.0s ± 4% ~ (p=0.968 n=10+9) Fannkuch11-96 7.17s ± 0% 7.00s ± 0% -2.43% (p=0.000 n=8+9) FmtFprintfEmpty-96 208ns ± 1% 207ns ± 0% ~ (p=0.152 n=10+8) FmtFprintfString-96 379ns ± 0% 375ns ± 0% -0.95% (p=0.000 n=10+9) FmtFprintfInt-96 385ns ± 0% 383ns ± 0% -0.52% (p=0.000 n=9+10) FmtFprintfIntInt-96 591ns ± 0% 586ns ± 0% -0.85% (p=0.006 n=7+9) FmtFprintfPrefixedInt-96 656ns ± 0% 667ns ± 0% +1.71% (p=0.000 n=10+10) FmtFprintfFloat-96 967ns ± 0% 984ns ± 0% +1.78% (p=0.000 n=10+10) FmtManyArgs-96 2.35µs ± 0% 2.25µs ± 0% -4.63% (p=0.000 n=9+8) GobDecode-96 31.0ms ± 0% 30.8ms ± 0% -0.36% (p=0.006 n=9+9) GobEncode-96 24.4ms ± 0% 24.5ms ± 0% +0.30% (p=0.000 n=9+9) Gzip-96 1.60s ± 0% 1.43s ± 0% -10.58% (p=0.000 n=9+10) Gunzip-96 167ms ± 0% 169ms ± 0% +0.83% (p=0.000 n=8+9) HTTPClientServer-96 311µs ± 1% 308µs ± 0% -0.75% (p=0.000 n=10+10) JSONEncode-96 65.0ms ± 0% 64.8ms ± 0% -0.25% (p=0.000 n=9+8) JSONDecode-96 262ms ± 1% 261ms ± 1% ~ (p=0.579 n=10+10) Mandelbrot200-96 18.0ms ± 0% 18.1ms ± 0% +0.17% (p=0.000 n=8+10) GoParse-96 14.0ms ± 0% 14.1ms ± 1% +0.42% (p=0.003 n=9+10) RegexpMatchEasy0_32-96 644ns ± 2% 645ns ± 2% ~ (p=0.836 n=10+10) RegexpMatchEasy0_1K-96 3.70µs ± 0% 3.49µs ± 0% -5.58% (p=0.000 n=10+10) RegexpMatchEasy1_32-96 662ns ± 2% 657ns ± 2% ~ (p=0.137 n=10+10) RegexpMatchEasy1_1K-96 4.47µs ± 0% 4.31µs ± 0% -3.48% (p=0.000 n=10+10) RegexpMatchMedium_32-96 844ns ± 2% 849ns ± 1% ~ (p=0.208 n=10+10) RegexpMatchMedium_1K-96 179µs ± 0% 182µs ± 0% +1.20% (p=0.000 n=10+10) RegexpMatchHard_32-96 10.0µs ± 0% 10.1µs ± 0% +0.48% (p=0.000 n=10+9) RegexpMatchHard_1K-96 297µs ± 0% 297µs ± 0% -0.14% (p=0.000 n=10+10) Revcomp-96 3.08s ± 0% 3.13s ± 0% +1.56% (p=0.000 n=9+9) Template-96 276ms ± 2% 275ms ± 1% ~ (p=0.393 n=10+10) TimeParse-96 1.37µs ± 0% 1.36µs ± 0% -0.53% (p=0.000 n=10+7) TimeFormat-96 1.40µs ± 0% 1.42µs ± 0% +0.97% (p=0.000 n=10+10) [Geo mean] 264µs 262µs -0.77% Change-Id: Ie54eee4b3092af53e6da3baa6d1755098f57f3a2 Reviewed-on: https://go-review.googlesource.com/55670 Run-TryBot: Philip Hofer <phofer@umich.edu> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Keith Randall <khr@golang.org>
2017-08-13 22:36:47 +00:00
case auxCCop:
return fmt.Sprintf(" {%s}", Op(v.AuxInt))
case auxS390XCCMask, auxS390XRotateParams:
return fmt.Sprintf(" {%v}", v.Aux)
case auxFlagConstant:
return fmt.Sprintf("[%s]", flagConstant(v.AuxInt))
}
return ""
}
// If/when midstack inlining is enabled (-l=4), the compiler gets both larger and slower.
// Not-inlining this method is a help (*Value.reset and *Block.NewValue0 are similar).
//go:noinline
func (v *Value) AddArg(w *Value) {
if v.Args == nil {
v.resetArgs() // use argstorage
}
v.Args = append(v.Args, w)
w.Uses++
}
cmd/compile: add specialized AddArgN functions for rewrite rules This shrinks the compiler without impacting performance. (The performance-sensitive part of rewrite rules is the non-match case.) Passes toolstash-check -all. Executable size: file before after Δ % compile 20356168 20163960 -192208 -0.944% total 115599376 115407168 -192208 -0.166% Text size: file before after Δ % cmd/compile/internal/ssa.s 3928309 3778774 -149535 -3.807% total 18862943 18713408 -149535 -0.793% Memory allocated compiling package SSA: SSA 12.7M ± 0% 12.5M ± 0% -1.74% (p=0.008 n=5+5) Compiler speed impact: name old time/op new time/op delta Template 211ms ± 1% 211ms ± 2% ~ (p=0.832 n=49+49) Unicode 82.8ms ± 2% 83.2ms ± 2% +0.44% (p=0.022 n=46+49) GoTypes 726ms ± 1% 728ms ± 2% ~ (p=0.076 n=46+48) Compiler 3.39s ± 2% 3.40s ± 2% ~ (p=0.633 n=48+49) SSA 7.71s ± 1% 7.65s ± 1% -0.78% (p=0.000 n=45+44) Flate 134ms ± 1% 134ms ± 1% ~ (p=0.195 n=50+49) GoParser 167ms ± 1% 167ms ± 1% ~ (p=0.390 n=47+47) Reflect 453ms ± 3% 452ms ± 2% ~ (p=0.492 n=48+49) Tar 184ms ± 3% 184ms ± 2% ~ (p=0.862 n=50+48) XML 248ms ± 2% 248ms ± 2% ~ (p=0.096 n=49+47) [Geo mean] 415ms 415ms -0.03% name old user-time/op new user-time/op delta Template 273ms ± 1% 273ms ± 2% ~ (p=0.711 n=48+48) Unicode 117ms ± 6% 117ms ± 5% ~ (p=0.633 n=50+50) GoTypes 972ms ± 2% 974ms ± 1% +0.29% (p=0.016 n=47+49) Compiler 4.46s ± 6% 4.51s ± 6% ~ (p=0.093 n=50+50) SSA 10.4s ± 1% 10.3s ± 2% -0.94% (p=0.000 n=45+50) Flate 166ms ± 2% 167ms ± 2% ~ (p=0.148 n=49+48) GoParser 202ms ± 1% 202ms ± 2% -0.28% (p=0.014 n=47+49) Reflect 594ms ± 2% 594ms ± 2% ~ (p=0.717 n=48+49) Tar 224ms ± 2% 224ms ± 2% ~ (p=0.805 n=50+49) XML 311ms ± 1% 310ms ± 1% ~ (p=0.177 n=49+48) [Geo mean] 537ms 537ms +0.01% Change-Id: I562b9f349b34ddcff01771769e6dbbc80604da7a Reviewed-on: https://go-review.googlesource.com/c/go/+/221237 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2020-02-26 11:29:34 -08:00
//go:noinline
func (v *Value) AddArg2(w1, w2 *Value) {
if v.Args == nil {
v.resetArgs() // use argstorage
}
v.Args = append(v.Args, w1, w2)
w1.Uses++
w2.Uses++
}
//go:noinline
func (v *Value) AddArg3(w1, w2, w3 *Value) {
if v.Args == nil {
v.resetArgs() // use argstorage
}
v.Args = append(v.Args, w1, w2, w3)
w1.Uses++
w2.Uses++
w3.Uses++
}
//go:noinline
func (v *Value) AddArg4(w1, w2, w3, w4 *Value) {
v.Args = append(v.Args, w1, w2, w3, w4)
w1.Uses++
w2.Uses++
w3.Uses++
w4.Uses++
}
//go:noinline
func (v *Value) AddArg5(w1, w2, w3, w4, w5 *Value) {
v.Args = append(v.Args, w1, w2, w3, w4, w5)
w1.Uses++
w2.Uses++
w3.Uses++
w4.Uses++
w5.Uses++
}
//go:noinline
func (v *Value) AddArg6(w1, w2, w3, w4, w5, w6 *Value) {
v.Args = append(v.Args, w1, w2, w3, w4, w5, w6)
w1.Uses++
w2.Uses++
w3.Uses++
w4.Uses++
w5.Uses++
w6.Uses++
}
func (v *Value) AddArgs(a ...*Value) {
if v.Args == nil {
v.resetArgs() // use argstorage
}
v.Args = append(v.Args, a...)
for _, x := range a {
x.Uses++
}
}
func (v *Value) SetArg(i int, w *Value) {
v.Args[i].Uses--
v.Args[i] = w
w.Uses++
}
func (v *Value) RemoveArg(i int) {
v.Args[i].Uses--
copy(v.Args[i:], v.Args[i+1:])
v.Args[len(v.Args)-1] = nil // aid GC
v.Args = v.Args[:len(v.Args)-1]
}
func (v *Value) SetArgs1(a *Value) {
v.resetArgs()
v.AddArg(a)
}
cmd/compile: handle some additional phis in shortcircuit Prior to this change, the shortcircuit pass could only handle blocks containing only a single phi control value, possibly wrapped in some OpNot and OpCopy values. This change partially lifts this limitation. It handles some cases in which the block contains other phi values. This appears to happen most commonly in cases in which the conditionals being checked involve the memory state, in which case there is a phi memory value in the block. The general idea here is to use the information we have about the CFG to (1) move the other phi values into other blocks and/or (2) rewrite uses of the other phi values in other blocks. For example, consider this CFG: p q \ / b / \ t u And consider a phi value v in block b. We'll write v = Phi(p: x, q: y) to say that v has value x corresponding to inbound block p, and value y for block q. We will rewrite this CFG to: p q | / | b |/ \ t u What should we do with v? Any uses of v in u can be replaced with y. Why? If we are in block u, we came from b, and before that from q. If prior to b we came from p, then we would have gone to t, not u. Since we came from q, we know that v took the value y. Uses of v in t are a bit more complicated. It is going to end up being a phi value: Phi(p: ?, b: ?). Suppose, after the rewrite, we came from block p. Then, before the rewrite, we would have gone to b, where v would have the value x. So we have Phi(p: x, b: ?). Suppose, after the rewrite, we came from block b. Then we must have come from block q. If we come from block q, v has value y. So we have Phi(p: x, b: y). Uses of v in t can thus be replaced with a new phi value, with the same values as v, but with altered predecessors. Similar reasoning can be employed to rewrite or replace other uses of v elsewhere in the CFG, so that v itself can be eliminated, and the CFG rewrite can proceed. This change sets up the infrastructure for such optimizations and adds a few cheap ones. All optimizations in this change depend only on the shape of the CFG; future changes may also depend on where v's uses are. That analysis is more powerful but more expensive, and should be done incrementally. The use of closures here is perhaps a bit unusual, but during development it proved critical to having readable code. We must decide early on whether we can safely do the CFG modifications, and then later fix up the phis if so. Safely storing state and decisions across these two phases is hard to do readably. Closures solve the problem neatly. I manually instrumented the code paths in shortcircuitPhiPlan. During make.bash there are nearly 6000 invocations. The least-visited code path gets run 85 times, so all the code in this CL is reasonably well-exercised. Here is a concrete example of code improved by this change: func f(e interface{}) int { if x, ok := e.(int); ok { return x } return 0 } Omitting PCDATA, FUNCDATA, and the like, it used to compile to: "".f STEXT nosplit size=50 args=0x18 locals=0x0 0x0000 00000 (x.go:4) LEAQ type.int(SB), AX 0x0007 00007 (x.go:4) MOVQ "".e+8(SP), CX 0x000c 00012 (x.go:4) CMPQ AX, CX 0x000f 00015 (x.go:4) JNE 43 0x0011 00017 (x.go:4) MOVQ "".e+16(SP), AX 0x0016 00022 (x.go:4) MOVQ (AX), AX 0x0019 00025 (x.go:4) JNE 33 0x001b 00027 (x.go:5) MOVQ AX, "".~r1+24(SP) 0x0020 00032 (x.go:5) RET 0x0021 00033 (x.go:7) MOVQ $0, "".~r1+24(SP) 0x002a 00042 (x.go:7) RET 0x002b 00043 (x.go:7) MOVL $0, AX 0x0030 00048 (x.go:4) JMP 25 Afterwards, it compiles to: "".f STEXT nosplit size=41 args=0x18 locals=0x0 0x0000 00000 (x.go:4) LEAQ type.int(SB), AX 0x0007 00007 (x.go:4) MOVQ "".e+8(SP), CX 0x000c 00012 (x.go:4) CMPQ AX, CX 0x000f 00015 (x.go:4) JNE 31 0x0011 00017 (x.go:4) MOVQ "".e+16(SP), AX 0x0016 00022 (x.go:4) MOVQ (AX), AX 0x0019 00025 (x.go:5) MOVQ AX, "".~r1+24(SP) 0x001e 00030 (x.go:5) RET 0x001f 00031 (x.go:7) MOVQ $0, "".~r1+24(SP) 0x0028 00040 (x.go:7) RET Note that there is now only a single JNE and a single RET $0 path. Updates #37608 Has a minor good effect on compilation speed and memory use. Provides widespread improvements to generated code. The rare, minor regressions I have investigated are due to register allocation fluctuations. file before after Δ % addr2line 4376080 4371984 -4096 -0.094% api 5945400 5933112 -12288 -0.207% asm 5034312 5030216 -4096 -0.081% buildid 2844952 2840856 -4096 -0.144% cgo 4812872 4804680 -8192 -0.170% compile 19622064 19610368 -11696 -0.060% cover 5236648 5232552 -4096 -0.078% dist 3658312 3654216 -4096 -0.112% doc 4653512 4649416 -4096 -0.088% fix 3370072 3365976 -4096 -0.122% link 6671864 6667768 -4096 -0.061% pprof 14781652 14761172 -20480 -0.139% trace 11639684 11627396 -12288 -0.106% vet 8252280 8231800 -20480 -0.248% total 115052984 114934792 -118192 -0.103% file before after Δ % internal/cpu.s 3298 3296 -2 -0.061% internal/bytealg.s 1730 1737 +7 +0.405% cmd/vendor/golang.org/x/mod/semver.s 7332 7283 -49 -0.668% image/color.s 8248 8156 -92 -1.115% math.s 35966 35956 -10 -0.028% math/cmplx.s 6596 6575 -21 -0.318% runtime.s 480566 480053 -513 -0.107% sync.s 16408 16385 -23 -0.140% math/rand.s 10447 10406 -41 -0.392% internal/reflectlite.s 28408 28366 -42 -0.148% errors.s 2736 2701 -35 -1.279% sort.s 17031 17036 +5 +0.029% io.s 16993 16964 -29 -0.171% container/heap.s 2006 1997 -9 -0.449% text/tabwriter.s 9570 9552 -18 -0.188% bytes.s 31823 31594 -229 -0.720% strconv.s 52760 52717 -43 -0.082% vendor/golang.org/x/text/transform.s 16713 16706 -7 -0.042% strings.s 42590 42563 -27 -0.063% bufio.s 22883 22785 -98 -0.428% encoding/base32.s 9586 9531 -55 -0.574% syscall.s 82237 82243 +6 +0.007% image.s 37465 37452 -13 -0.035% regexp/syntax.s 82827 82769 -58 -0.070% image/draw.s 18698 18584 -114 -0.610% image/jpeg.s 36560 36549 -11 -0.030% time.s 82557 82526 -31 -0.038% context.s 10863 10820 -43 -0.396% regexp.s 64114 64049 -65 -0.101% os.s 51751 51524 -227 -0.439% reflect.s 168240 168049 -191 -0.114% cmd/go/internal/lockedfile/internal/filelock.s 2317 2290 -27 -1.165% path/filepath.s 17831 17766 -65 -0.365% io/ioutil.s 6994 6990 -4 -0.057% encoding/binary.s 30791 30726 -65 -0.211% cmd/vendor/golang.org/x/sys/unix.s 78055 78033 -22 -0.028% encoding/pem.s 9280 9247 -33 -0.356% crypto/cipher.s 20376 20374 -2 -0.010% os/exec.s 29229 29140 -89 -0.304% internal/goroot.s 4588 4579 -9 -0.196% cmd/internal/browser.s 2246 2240 -6 -0.267% cmd/vendor/golang.org/x/crypto/ssh/terminal.s 27183 27149 -34 -0.125% fmt.s 76625 76484 -141 -0.184% encoding/hex.s 6154 6152 -2 -0.032% compress/lzw.s 7063 7059 -4 -0.057% database/sql/driver.s 18875 18862 -13 -0.069% debug/plan9obj.s 8268 8266 -2 -0.024% net/url.s 29724 29719 -5 -0.017% encoding/csv.s 12872 12856 -16 -0.124% debug/gosym.s 25303 25268 -35 -0.138% compress/flate.s 50952 51019 +67 +0.131% compress/zlib.s 7277 7266 -11 -0.151% archive/zip.s 42155 42111 -44 -0.104% debug/dwarf.s 107632 107541 -91 -0.085% database/sql.s 98373 98028 -345 -0.351% os/user.s 14722 14708 -14 -0.095% encoding/json.s 105836 105711 -125 -0.118% debug/macho.s 32598 32560 -38 -0.117% encoding/gob.s 136478 135755 -723 -0.530% debug/pe.s 31160 30869 -291 -0.934% debug/elf.s 63495 63302 -193 -0.304% vendor/golang.org/x/text/unicode/bidi.s 27220 27217 -3 -0.011% vendor/golang.org/x/text/secure/bidirule.s 3363 3352 -11 -0.327% go/token.s 12036 12035 -1 -0.008% flag.s 22277 22256 -21 -0.094% mime.s 39696 39509 -187 -0.471% go/scanner.s 19033 19020 -13 -0.068% archive/tar.s 70936 70581 -355 -0.500% internal/xcoff.s 22823 22820 -3 -0.013% text/scanner.s 11631 11629 -2 -0.017% encoding/xml.s 110534 110408 -126 -0.114% math/big.s 183636 183545 -91 -0.050% image/gif.s 27376 27343 -33 -0.121% crypto/dsa.s 6029 5969 -60 -0.995% image/png.s 42947 42939 -8 -0.019% crypto/rand.s 6866 6854 -12 -0.175% vendor/golang.org/x/text/unicode/norm.s 66394 66354 -40 -0.060% runtime/trace.s 2603 2521 -82 -3.150% crypto/ed25519.s 6321 6300 -21 -0.332% text/template/parse.s 93910 93844 -66 -0.070% crypto/rsa.s 31460 31369 -91 -0.289% encoding/asn1.s 57021 57023 +2 +0.004% crypto/elliptic.s 51382 51363 -19 -0.037% crypto/x509/pkix.s 10386 10342 -44 -0.424% vendor/golang.org/x/net/idna.s 24482 24466 -16 -0.065% vendor/golang.org/x/crypto/cryptobyte.s 33479 33280 -199 -0.594% crypto/ecdsa.s 11936 11883 -53 -0.444% go/constant.s 43670 42663 -1007 -2.306% go/ast.s 80383 80191 -192 -0.239% testing.s 68069 68057 -12 -0.018% runtime/pprof.s 59613 59603 -10 -0.017% testing/iotest.s 4895 4891 -4 -0.082% internal/trace.s 78136 78089 -47 -0.060% cmd/internal/goobj2.s 13158 13154 -4 -0.030% cmd/internal/src.s 17661 17657 -4 -0.023% go/parser.s 79046 78880 -166 -0.210% cmd/internal/objabi.s 16367 16343 -24 -0.147% text/template.s 94899 94486 -413 -0.435% go/printer.s 77267 76992 -275 -0.356% cmd/internal/goobj.s 25988 25947 -41 -0.158% runtime/pprof/internal/profile.s 102066 101933 -133 -0.130% go/format.s 5419 5371 -48 -0.886% cmd/vendor/golang.org/x/arch/ppc64/ppc64asm.s 37181 37149 -32 -0.086% go/doc.s 74533 74132 -401 -0.538% html/template.s 88743 88389 -354 -0.399% cmd/asm/internal/lex.s 24881 24872 -9 -0.036% cmd/internal/buildid.s 18263 18256 -7 -0.038% cmd/vendor/golang.org/x/arch/x86/x86asm.s 80036 79980 -56 -0.070% go/build.s 68905 68737 -168 -0.244% cmd/cover.s 46070 45950 -120 -0.260% cmd/internal/obj.s 117001 116991 -10 -0.009% cmd/doc.s 62700 62419 -281 -0.448% cmd/internal/obj/arm.s 66745 66687 -58 -0.087% cmd/compile/internal/syntax.s 145406 145062 -344 -0.237% cmd/internal/obj/wasm.s 44049 44027 -22 -0.050% net.s 291835 291020 -815 -0.279% cmd/dist.s 209020 208807 -213 -0.102% cmd/cgo.s 241564 241102 -462 -0.191% vendor/golang.org/x/net/http/httpproxy.s 9407 9399 -8 -0.085% log/syslog.s 7921 7909 -12 -0.151% go/types.s 319325 317513 -1812 -0.567% vendor/golang.org/x/net/http/httpguts.s 3834 3825 -9 -0.235% mime/multipart.s 21414 21343 -71 -0.332% cmd/internal/obj/ppc64.s 119949 119938 -11 -0.009% cmd/compile/internal/logopt.s 10158 10118 -40 -0.394% vendor/golang.org/x/net/nettest.s 28012 27991 -21 -0.075% go/internal/srcimporter.s 6405 6380 -25 -0.390% go/internal/gcimporter.s 34525 34493 -32 -0.093% net/mail.s 23937 23720 -217 -0.907% go/internal/gccgoimporter.s 56095 56038 -57 -0.102% cmd/compile/internal/types.s 47247 47207 -40 -0.085% cmd/api.s 39582 39558 -24 -0.061% cmd/go/internal/base.s 12572 12551 -21 -0.167% cmd/vendor/golang.org/x/xerrors.s 17846 17814 -32 -0.179% cmd/vendor/golang.org/x/mod/sumdb/note.s 18142 18070 -72 -0.397% cmd/go/internal/search.s 19994 19876 -118 -0.590% cmd/go/internal/imports.s 16457 16428 -29 -0.176% cmd/vendor/golang.org/x/mod/module.s 17838 17759 -79 -0.443% cmd/go/internal/cache.s 30551 30514 -37 -0.121% cmd/vendor/golang.org/x/mod/sumdb/tlog.s 36356 36321 -35 -0.096% cmd/internal/test2json.s 9452 9408 -44 -0.466% cmd/go/internal/mvs.s 25136 25092 -44 -0.175% cmd/go/internal/txtar.s 3488 3461 -27 -0.774% cmd/vendor/golang.org/x/mod/zip.s 18811 18800 -11 -0.058% cmd/go/internal/version.s 11213 11171 -42 -0.375% cmd/link/internal/benchmark.s 4941 4949 +8 +0.162% cmd/internal/obj/s390x.s 126865 126849 -16 -0.013% cmd/gofmt.s 30684 30596 -88 -0.287% cmd/fix.s 87450 86906 -544 -0.622% cmd/internal/obj/x86.s 88578 88556 -22 -0.025% cmd/vendor/golang.org/x/mod/modfile.s 72450 72363 -87 -0.120% cmd/oldlink/internal/loader.s 16743 16741 -2 -0.012% cmd/pack.s 14863 14861 -2 -0.013% cmd/go/internal/load.s 106742 106568 -174 -0.163% cmd/oldlink/internal/objfile.s 21787 21780 -7 -0.032% cmd/oldlink/internal/loadmacho.s 29309 29317 +8 +0.027% cmd/oldlink/internal/loadelf.s 35013 35021 +8 +0.023% cmd/asm/internal/asm.s 68550 68538 -12 -0.018% cmd/link/internal/loader.s 94765 94564 -201 -0.212% cmd/link/internal/loadelf.s 35663 35667 +4 +0.011% cmd/link/internal/loadmacho.s 29501 29509 +8 +0.027% cmd/vendor/golang.org/x/tools/go/analysis.s 4983 4976 -7 -0.140% cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags.s 16771 16709 -62 -0.370% cmd/vendor/golang.org/x/tools/go/types/objectpath.s 18481 18456 -25 -0.135% cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil.s 2100 2085 -15 -0.714% cmd/vendor/github.com/google/pprof/profile.s 150141 149620 -521 -0.347% cmd/vendor/github.com/google/pprof/internal/measurement.s 10420 10404 -16 -0.154% cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl.s 36814 36755 -59 -0.160% cmd/vendor/golang.org/x/tools/go/analysis/passes/bools.s 6688 6673 -15 -0.224% cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall.s 9856 9784 -72 -0.731% cmd/vendor/golang.org/x/tools/go/analysis/passes/composite.s 3011 2979 -32 -1.063% cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock.s 9737 9682 -55 -0.565% cmd/vendor/golang.org/x/tools/go/cfg.s 30738 30725 -13 -0.042% cmd/vendor/github.com/ianlancetaylor/demangle.s 175195 174513 -682 -0.389% cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse.s 3625 3520 -105 -2.897% cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure.s 2987 2971 -16 -0.536% cmd/vendor/golang.org/x/tools/go/analysis/passes/shift.s 4372 4340 -32 -0.732% cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods.s 8634 8611 -23 -0.266% cmd/vendor/golang.org/x/tools/go/analysis/passes/tests.s 6189 6164 -25 -0.404% cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag.s 8089 8073 -16 -0.198% cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr.s 2208 2177 -31 -1.404% cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable.s 8050 8047 -3 -0.037% cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult.s 3665 3629 -36 -0.982% cmd/vendor/golang.org/x/tools/go/ast/astutil.s 65773 65680 -93 -0.141% cmd/vendor/golang.org/x/tools/go/analysis/unitchecker.s 13328 13286 -42 -0.315% cmd/vendor/golang.org/x/tools/go/types/typeutil.s 12263 12162 -101 -0.824% cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas.s 1459 1421 -38 -2.605% cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow.s 5208 5191 -17 -0.326% cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal.s 1801 1782 -19 -1.055% cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel.s 9569 9528 -41 -0.428% cmd/go/internal/work.s 304928 304756 -172 -0.056% crypto/x509.s 147340 147139 -201 -0.136% cmd/vendor/golang.org/x/tools/go/analysis/passes/printf.s 34287 34019 -268 -0.782% crypto/tls.s 311603 310644 -959 -0.308% cmd/oldlink/internal/ld.s 533115 532651 -464 -0.087% cmd/oldlink/internal/wasm.s 16484 16458 -26 -0.158% cmd/oldlink/internal/x86.s 18832 18830 -2 -0.011% cmd/link/internal/ld.s 548200 547626 -574 -0.105% cmd/link/internal/wasm.s 16760 16734 -26 -0.155% cmd/link/internal/arm64.s 20850 20840 -10 -0.048% cmd/link/internal/x86.s 17437 17435 -2 -0.011% net/http.s 556647 555519 -1128 -0.203% net/http/cookiejar.s 15849 15833 -16 -0.101% expvar.s 9521 9508 -13 -0.137% net/http/httptest.s 16471 16452 -19 -0.115% cmd/vendor/github.com/google/pprof/internal/plugin.s 4266 4264 -2 -0.047% net/http/cgi.s 23448 23428 -20 -0.085% cmd/go/internal/web.s 16472 16428 -44 -0.267% net/http/httputil.s 39672 39670 -2 -0.005% net/rpc.s 33989 33965 -24 -0.071% net/http/fcgi.s 19167 19162 -5 -0.026% cmd/vendor/github.com/google/pprof/internal/symbolz.s 5861 5857 -4 -0.068% cmd/vendor/github.com/google/pprof/internal/binutils.s 35842 35823 -19 -0.053% cmd/vendor/github.com/google/pprof/internal/symbolizer.s 11449 11404 -45 -0.393% cmd/go/internal/get.s 62726 62582 -144 -0.230% cmd/vendor/github.com/google/pprof/internal/report.s 80032 80022 -10 -0.012% cmd/go/internal/modfetch/codehost.s 89005 88871 -134 -0.151% cmd/trace.s 116607 116496 -111 -0.095% cmd/vendor/github.com/google/pprof/internal/driver.s 143234 143207 -27 -0.019% cmd/vendor/github.com/google/pprof/driver.s 9000 8998 -2 -0.022% cmd/go/internal/modfetch.s 126300 125726 -574 -0.454% cmd/pprof.s 12317 12312 -5 -0.041% cmd/go/internal/modconv.s 17878 17861 -17 -0.095% cmd/go/internal/modload.s 150261 149763 -498 -0.331% cmd/go/internal/clean.s 11122 11091 -31 -0.279% cmd/go/internal/help.s 6523 6521 -2 -0.031% cmd/go/internal/generate.s 11627 11614 -13 -0.112% cmd/go/internal/envcmd.s 22034 21986 -48 -0.218% cmd/go/internal/modget.s 38478 38398 -80 -0.208% cmd/go/internal/modcmd.s 46430 46229 -201 -0.433% cmd/go/internal/test.s 64399 64374 -25 -0.039% cmd/compile/internal/ssa.s 3615264 3608276 -6988 -0.193% cmd/compile/internal/gc.s 1538865 1537625 -1240 -0.081% cmd/compile/internal/amd64.s 33593 33574 -19 -0.057% cmd/compile/internal/x86.s 30871 30852 -19 -0.062% total 19343565 19311284 -32281 -0.167% Change-Id: Ib030eb79458827a5a5b6d0d2f98765f8325a4d7e Reviewed-on: https://go-review.googlesource.com/c/go/+/222923 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2020-03-11 05:39:08 -07:00
func (v *Value) SetArgs2(a, b *Value) {
v.resetArgs()
v.AddArg(a)
v.AddArg(b)
}
cmd/compile: handle some additional phis in shortcircuit Prior to this change, the shortcircuit pass could only handle blocks containing only a single phi control value, possibly wrapped in some OpNot and OpCopy values. This change partially lifts this limitation. It handles some cases in which the block contains other phi values. This appears to happen most commonly in cases in which the conditionals being checked involve the memory state, in which case there is a phi memory value in the block. The general idea here is to use the information we have about the CFG to (1) move the other phi values into other blocks and/or (2) rewrite uses of the other phi values in other blocks. For example, consider this CFG: p q \ / b / \ t u And consider a phi value v in block b. We'll write v = Phi(p: x, q: y) to say that v has value x corresponding to inbound block p, and value y for block q. We will rewrite this CFG to: p q | / | b |/ \ t u What should we do with v? Any uses of v in u can be replaced with y. Why? If we are in block u, we came from b, and before that from q. If prior to b we came from p, then we would have gone to t, not u. Since we came from q, we know that v took the value y. Uses of v in t are a bit more complicated. It is going to end up being a phi value: Phi(p: ?, b: ?). Suppose, after the rewrite, we came from block p. Then, before the rewrite, we would have gone to b, where v would have the value x. So we have Phi(p: x, b: ?). Suppose, after the rewrite, we came from block b. Then we must have come from block q. If we come from block q, v has value y. So we have Phi(p: x, b: y). Uses of v in t can thus be replaced with a new phi value, with the same values as v, but with altered predecessors. Similar reasoning can be employed to rewrite or replace other uses of v elsewhere in the CFG, so that v itself can be eliminated, and the CFG rewrite can proceed. This change sets up the infrastructure for such optimizations and adds a few cheap ones. All optimizations in this change depend only on the shape of the CFG; future changes may also depend on where v's uses are. That analysis is more powerful but more expensive, and should be done incrementally. The use of closures here is perhaps a bit unusual, but during development it proved critical to having readable code. We must decide early on whether we can safely do the CFG modifications, and then later fix up the phis if so. Safely storing state and decisions across these two phases is hard to do readably. Closures solve the problem neatly. I manually instrumented the code paths in shortcircuitPhiPlan. During make.bash there are nearly 6000 invocations. The least-visited code path gets run 85 times, so all the code in this CL is reasonably well-exercised. Here is a concrete example of code improved by this change: func f(e interface{}) int { if x, ok := e.(int); ok { return x } return 0 } Omitting PCDATA, FUNCDATA, and the like, it used to compile to: "".f STEXT nosplit size=50 args=0x18 locals=0x0 0x0000 00000 (x.go:4) LEAQ type.int(SB), AX 0x0007 00007 (x.go:4) MOVQ "".e+8(SP), CX 0x000c 00012 (x.go:4) CMPQ AX, CX 0x000f 00015 (x.go:4) JNE 43 0x0011 00017 (x.go:4) MOVQ "".e+16(SP), AX 0x0016 00022 (x.go:4) MOVQ (AX), AX 0x0019 00025 (x.go:4) JNE 33 0x001b 00027 (x.go:5) MOVQ AX, "".~r1+24(SP) 0x0020 00032 (x.go:5) RET 0x0021 00033 (x.go:7) MOVQ $0, "".~r1+24(SP) 0x002a 00042 (x.go:7) RET 0x002b 00043 (x.go:7) MOVL $0, AX 0x0030 00048 (x.go:4) JMP 25 Afterwards, it compiles to: "".f STEXT nosplit size=41 args=0x18 locals=0x0 0x0000 00000 (x.go:4) LEAQ type.int(SB), AX 0x0007 00007 (x.go:4) MOVQ "".e+8(SP), CX 0x000c 00012 (x.go:4) CMPQ AX, CX 0x000f 00015 (x.go:4) JNE 31 0x0011 00017 (x.go:4) MOVQ "".e+16(SP), AX 0x0016 00022 (x.go:4) MOVQ (AX), AX 0x0019 00025 (x.go:5) MOVQ AX, "".~r1+24(SP) 0x001e 00030 (x.go:5) RET 0x001f 00031 (x.go:7) MOVQ $0, "".~r1+24(SP) 0x0028 00040 (x.go:7) RET Note that there is now only a single JNE and a single RET $0 path. Updates #37608 Has a minor good effect on compilation speed and memory use. Provides widespread improvements to generated code. The rare, minor regressions I have investigated are due to register allocation fluctuations. file before after Δ % addr2line 4376080 4371984 -4096 -0.094% api 5945400 5933112 -12288 -0.207% asm 5034312 5030216 -4096 -0.081% buildid 2844952 2840856 -4096 -0.144% cgo 4812872 4804680 -8192 -0.170% compile 19622064 19610368 -11696 -0.060% cover 5236648 5232552 -4096 -0.078% dist 3658312 3654216 -4096 -0.112% doc 4653512 4649416 -4096 -0.088% fix 3370072 3365976 -4096 -0.122% link 6671864 6667768 -4096 -0.061% pprof 14781652 14761172 -20480 -0.139% trace 11639684 11627396 -12288 -0.106% vet 8252280 8231800 -20480 -0.248% total 115052984 114934792 -118192 -0.103% file before after Δ % internal/cpu.s 3298 3296 -2 -0.061% internal/bytealg.s 1730 1737 +7 +0.405% cmd/vendor/golang.org/x/mod/semver.s 7332 7283 -49 -0.668% image/color.s 8248 8156 -92 -1.115% math.s 35966 35956 -10 -0.028% math/cmplx.s 6596 6575 -21 -0.318% runtime.s 480566 480053 -513 -0.107% sync.s 16408 16385 -23 -0.140% math/rand.s 10447 10406 -41 -0.392% internal/reflectlite.s 28408 28366 -42 -0.148% errors.s 2736 2701 -35 -1.279% sort.s 17031 17036 +5 +0.029% io.s 16993 16964 -29 -0.171% container/heap.s 2006 1997 -9 -0.449% text/tabwriter.s 9570 9552 -18 -0.188% bytes.s 31823 31594 -229 -0.720% strconv.s 52760 52717 -43 -0.082% vendor/golang.org/x/text/transform.s 16713 16706 -7 -0.042% strings.s 42590 42563 -27 -0.063% bufio.s 22883 22785 -98 -0.428% encoding/base32.s 9586 9531 -55 -0.574% syscall.s 82237 82243 +6 +0.007% image.s 37465 37452 -13 -0.035% regexp/syntax.s 82827 82769 -58 -0.070% image/draw.s 18698 18584 -114 -0.610% image/jpeg.s 36560 36549 -11 -0.030% time.s 82557 82526 -31 -0.038% context.s 10863 10820 -43 -0.396% regexp.s 64114 64049 -65 -0.101% os.s 51751 51524 -227 -0.439% reflect.s 168240 168049 -191 -0.114% cmd/go/internal/lockedfile/internal/filelock.s 2317 2290 -27 -1.165% path/filepath.s 17831 17766 -65 -0.365% io/ioutil.s 6994 6990 -4 -0.057% encoding/binary.s 30791 30726 -65 -0.211% cmd/vendor/golang.org/x/sys/unix.s 78055 78033 -22 -0.028% encoding/pem.s 9280 9247 -33 -0.356% crypto/cipher.s 20376 20374 -2 -0.010% os/exec.s 29229 29140 -89 -0.304% internal/goroot.s 4588 4579 -9 -0.196% cmd/internal/browser.s 2246 2240 -6 -0.267% cmd/vendor/golang.org/x/crypto/ssh/terminal.s 27183 27149 -34 -0.125% fmt.s 76625 76484 -141 -0.184% encoding/hex.s 6154 6152 -2 -0.032% compress/lzw.s 7063 7059 -4 -0.057% database/sql/driver.s 18875 18862 -13 -0.069% debug/plan9obj.s 8268 8266 -2 -0.024% net/url.s 29724 29719 -5 -0.017% encoding/csv.s 12872 12856 -16 -0.124% debug/gosym.s 25303 25268 -35 -0.138% compress/flate.s 50952 51019 +67 +0.131% compress/zlib.s 7277 7266 -11 -0.151% archive/zip.s 42155 42111 -44 -0.104% debug/dwarf.s 107632 107541 -91 -0.085% database/sql.s 98373 98028 -345 -0.351% os/user.s 14722 14708 -14 -0.095% encoding/json.s 105836 105711 -125 -0.118% debug/macho.s 32598 32560 -38 -0.117% encoding/gob.s 136478 135755 -723 -0.530% debug/pe.s 31160 30869 -291 -0.934% debug/elf.s 63495 63302 -193 -0.304% vendor/golang.org/x/text/unicode/bidi.s 27220 27217 -3 -0.011% vendor/golang.org/x/text/secure/bidirule.s 3363 3352 -11 -0.327% go/token.s 12036 12035 -1 -0.008% flag.s 22277 22256 -21 -0.094% mime.s 39696 39509 -187 -0.471% go/scanner.s 19033 19020 -13 -0.068% archive/tar.s 70936 70581 -355 -0.500% internal/xcoff.s 22823 22820 -3 -0.013% text/scanner.s 11631 11629 -2 -0.017% encoding/xml.s 110534 110408 -126 -0.114% math/big.s 183636 183545 -91 -0.050% image/gif.s 27376 27343 -33 -0.121% crypto/dsa.s 6029 5969 -60 -0.995% image/png.s 42947 42939 -8 -0.019% crypto/rand.s 6866 6854 -12 -0.175% vendor/golang.org/x/text/unicode/norm.s 66394 66354 -40 -0.060% runtime/trace.s 2603 2521 -82 -3.150% crypto/ed25519.s 6321 6300 -21 -0.332% text/template/parse.s 93910 93844 -66 -0.070% crypto/rsa.s 31460 31369 -91 -0.289% encoding/asn1.s 57021 57023 +2 +0.004% crypto/elliptic.s 51382 51363 -19 -0.037% crypto/x509/pkix.s 10386 10342 -44 -0.424% vendor/golang.org/x/net/idna.s 24482 24466 -16 -0.065% vendor/golang.org/x/crypto/cryptobyte.s 33479 33280 -199 -0.594% crypto/ecdsa.s 11936 11883 -53 -0.444% go/constant.s 43670 42663 -1007 -2.306% go/ast.s 80383 80191 -192 -0.239% testing.s 68069 68057 -12 -0.018% runtime/pprof.s 59613 59603 -10 -0.017% testing/iotest.s 4895 4891 -4 -0.082% internal/trace.s 78136 78089 -47 -0.060% cmd/internal/goobj2.s 13158 13154 -4 -0.030% cmd/internal/src.s 17661 17657 -4 -0.023% go/parser.s 79046 78880 -166 -0.210% cmd/internal/objabi.s 16367 16343 -24 -0.147% text/template.s 94899 94486 -413 -0.435% go/printer.s 77267 76992 -275 -0.356% cmd/internal/goobj.s 25988 25947 -41 -0.158% runtime/pprof/internal/profile.s 102066 101933 -133 -0.130% go/format.s 5419 5371 -48 -0.886% cmd/vendor/golang.org/x/arch/ppc64/ppc64asm.s 37181 37149 -32 -0.086% go/doc.s 74533 74132 -401 -0.538% html/template.s 88743 88389 -354 -0.399% cmd/asm/internal/lex.s 24881 24872 -9 -0.036% cmd/internal/buildid.s 18263 18256 -7 -0.038% cmd/vendor/golang.org/x/arch/x86/x86asm.s 80036 79980 -56 -0.070% go/build.s 68905 68737 -168 -0.244% cmd/cover.s 46070 45950 -120 -0.260% cmd/internal/obj.s 117001 116991 -10 -0.009% cmd/doc.s 62700 62419 -281 -0.448% cmd/internal/obj/arm.s 66745 66687 -58 -0.087% cmd/compile/internal/syntax.s 145406 145062 -344 -0.237% cmd/internal/obj/wasm.s 44049 44027 -22 -0.050% net.s 291835 291020 -815 -0.279% cmd/dist.s 209020 208807 -213 -0.102% cmd/cgo.s 241564 241102 -462 -0.191% vendor/golang.org/x/net/http/httpproxy.s 9407 9399 -8 -0.085% log/syslog.s 7921 7909 -12 -0.151% go/types.s 319325 317513 -1812 -0.567% vendor/golang.org/x/net/http/httpguts.s 3834 3825 -9 -0.235% mime/multipart.s 21414 21343 -71 -0.332% cmd/internal/obj/ppc64.s 119949 119938 -11 -0.009% cmd/compile/internal/logopt.s 10158 10118 -40 -0.394% vendor/golang.org/x/net/nettest.s 28012 27991 -21 -0.075% go/internal/srcimporter.s 6405 6380 -25 -0.390% go/internal/gcimporter.s 34525 34493 -32 -0.093% net/mail.s 23937 23720 -217 -0.907% go/internal/gccgoimporter.s 56095 56038 -57 -0.102% cmd/compile/internal/types.s 47247 47207 -40 -0.085% cmd/api.s 39582 39558 -24 -0.061% cmd/go/internal/base.s 12572 12551 -21 -0.167% cmd/vendor/golang.org/x/xerrors.s 17846 17814 -32 -0.179% cmd/vendor/golang.org/x/mod/sumdb/note.s 18142 18070 -72 -0.397% cmd/go/internal/search.s 19994 19876 -118 -0.590% cmd/go/internal/imports.s 16457 16428 -29 -0.176% cmd/vendor/golang.org/x/mod/module.s 17838 17759 -79 -0.443% cmd/go/internal/cache.s 30551 30514 -37 -0.121% cmd/vendor/golang.org/x/mod/sumdb/tlog.s 36356 36321 -35 -0.096% cmd/internal/test2json.s 9452 9408 -44 -0.466% cmd/go/internal/mvs.s 25136 25092 -44 -0.175% cmd/go/internal/txtar.s 3488 3461 -27 -0.774% cmd/vendor/golang.org/x/mod/zip.s 18811 18800 -11 -0.058% cmd/go/internal/version.s 11213 11171 -42 -0.375% cmd/link/internal/benchmark.s 4941 4949 +8 +0.162% cmd/internal/obj/s390x.s 126865 126849 -16 -0.013% cmd/gofmt.s 30684 30596 -88 -0.287% cmd/fix.s 87450 86906 -544 -0.622% cmd/internal/obj/x86.s 88578 88556 -22 -0.025% cmd/vendor/golang.org/x/mod/modfile.s 72450 72363 -87 -0.120% cmd/oldlink/internal/loader.s 16743 16741 -2 -0.012% cmd/pack.s 14863 14861 -2 -0.013% cmd/go/internal/load.s 106742 106568 -174 -0.163% cmd/oldlink/internal/objfile.s 21787 21780 -7 -0.032% cmd/oldlink/internal/loadmacho.s 29309 29317 +8 +0.027% cmd/oldlink/internal/loadelf.s 35013 35021 +8 +0.023% cmd/asm/internal/asm.s 68550 68538 -12 -0.018% cmd/link/internal/loader.s 94765 94564 -201 -0.212% cmd/link/internal/loadelf.s 35663 35667 +4 +0.011% cmd/link/internal/loadmacho.s 29501 29509 +8 +0.027% cmd/vendor/golang.org/x/tools/go/analysis.s 4983 4976 -7 -0.140% cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags.s 16771 16709 -62 -0.370% cmd/vendor/golang.org/x/tools/go/types/objectpath.s 18481 18456 -25 -0.135% cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil.s 2100 2085 -15 -0.714% cmd/vendor/github.com/google/pprof/profile.s 150141 149620 -521 -0.347% cmd/vendor/github.com/google/pprof/internal/measurement.s 10420 10404 -16 -0.154% cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl.s 36814 36755 -59 -0.160% cmd/vendor/golang.org/x/tools/go/analysis/passes/bools.s 6688 6673 -15 -0.224% cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall.s 9856 9784 -72 -0.731% cmd/vendor/golang.org/x/tools/go/analysis/passes/composite.s 3011 2979 -32 -1.063% cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock.s 9737 9682 -55 -0.565% cmd/vendor/golang.org/x/tools/go/cfg.s 30738 30725 -13 -0.042% cmd/vendor/github.com/ianlancetaylor/demangle.s 175195 174513 -682 -0.389% cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse.s 3625 3520 -105 -2.897% cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure.s 2987 2971 -16 -0.536% cmd/vendor/golang.org/x/tools/go/analysis/passes/shift.s 4372 4340 -32 -0.732% cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods.s 8634 8611 -23 -0.266% cmd/vendor/golang.org/x/tools/go/analysis/passes/tests.s 6189 6164 -25 -0.404% cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag.s 8089 8073 -16 -0.198% cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr.s 2208 2177 -31 -1.404% cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable.s 8050 8047 -3 -0.037% cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult.s 3665 3629 -36 -0.982% cmd/vendor/golang.org/x/tools/go/ast/astutil.s 65773 65680 -93 -0.141% cmd/vendor/golang.org/x/tools/go/analysis/unitchecker.s 13328 13286 -42 -0.315% cmd/vendor/golang.org/x/tools/go/types/typeutil.s 12263 12162 -101 -0.824% cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas.s 1459 1421 -38 -2.605% cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow.s 5208 5191 -17 -0.326% cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal.s 1801 1782 -19 -1.055% cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel.s 9569 9528 -41 -0.428% cmd/go/internal/work.s 304928 304756 -172 -0.056% crypto/x509.s 147340 147139 -201 -0.136% cmd/vendor/golang.org/x/tools/go/analysis/passes/printf.s 34287 34019 -268 -0.782% crypto/tls.s 311603 310644 -959 -0.308% cmd/oldlink/internal/ld.s 533115 532651 -464 -0.087% cmd/oldlink/internal/wasm.s 16484 16458 -26 -0.158% cmd/oldlink/internal/x86.s 18832 18830 -2 -0.011% cmd/link/internal/ld.s 548200 547626 -574 -0.105% cmd/link/internal/wasm.s 16760 16734 -26 -0.155% cmd/link/internal/arm64.s 20850 20840 -10 -0.048% cmd/link/internal/x86.s 17437 17435 -2 -0.011% net/http.s 556647 555519 -1128 -0.203% net/http/cookiejar.s 15849 15833 -16 -0.101% expvar.s 9521 9508 -13 -0.137% net/http/httptest.s 16471 16452 -19 -0.115% cmd/vendor/github.com/google/pprof/internal/plugin.s 4266 4264 -2 -0.047% net/http/cgi.s 23448 23428 -20 -0.085% cmd/go/internal/web.s 16472 16428 -44 -0.267% net/http/httputil.s 39672 39670 -2 -0.005% net/rpc.s 33989 33965 -24 -0.071% net/http/fcgi.s 19167 19162 -5 -0.026% cmd/vendor/github.com/google/pprof/internal/symbolz.s 5861 5857 -4 -0.068% cmd/vendor/github.com/google/pprof/internal/binutils.s 35842 35823 -19 -0.053% cmd/vendor/github.com/google/pprof/internal/symbolizer.s 11449 11404 -45 -0.393% cmd/go/internal/get.s 62726 62582 -144 -0.230% cmd/vendor/github.com/google/pprof/internal/report.s 80032 80022 -10 -0.012% cmd/go/internal/modfetch/codehost.s 89005 88871 -134 -0.151% cmd/trace.s 116607 116496 -111 -0.095% cmd/vendor/github.com/google/pprof/internal/driver.s 143234 143207 -27 -0.019% cmd/vendor/github.com/google/pprof/driver.s 9000 8998 -2 -0.022% cmd/go/internal/modfetch.s 126300 125726 -574 -0.454% cmd/pprof.s 12317 12312 -5 -0.041% cmd/go/internal/modconv.s 17878 17861 -17 -0.095% cmd/go/internal/modload.s 150261 149763 -498 -0.331% cmd/go/internal/clean.s 11122 11091 -31 -0.279% cmd/go/internal/help.s 6523 6521 -2 -0.031% cmd/go/internal/generate.s 11627 11614 -13 -0.112% cmd/go/internal/envcmd.s 22034 21986 -48 -0.218% cmd/go/internal/modget.s 38478 38398 -80 -0.208% cmd/go/internal/modcmd.s 46430 46229 -201 -0.433% cmd/go/internal/test.s 64399 64374 -25 -0.039% cmd/compile/internal/ssa.s 3615264 3608276 -6988 -0.193% cmd/compile/internal/gc.s 1538865 1537625 -1240 -0.081% cmd/compile/internal/amd64.s 33593 33574 -19 -0.057% cmd/compile/internal/x86.s 30871 30852 -19 -0.062% total 19343565 19311284 -32281 -0.167% Change-Id: Ib030eb79458827a5a5b6d0d2f98765f8325a4d7e Reviewed-on: https://go-review.googlesource.com/c/go/+/222923 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2020-03-11 05:39:08 -07:00
func (v *Value) SetArgs3(a, b, c *Value) {
v.resetArgs()
v.AddArg(a)
v.AddArg(b)
v.AddArg(c)
}
func (v *Value) resetArgs() {
for _, a := range v.Args {
a.Uses--
}
v.argstorage[0] = nil
v.argstorage[1] = nil
v.argstorage[2] = nil
v.Args = v.argstorage[:0]
}
[dev.ssa] cmd/compile/ssa: separate logging, work in progress, and fatal errors The SSA implementation logs for three purposes: * debug logging * fatal errors * unimplemented features Separating these three uses lets us attempt an SSA implementation for all functions, not just _ssa functions. This turns the entire standard library into a compilation test, and makes it easy to figure out things like "how much coverage does SSA have now" and "what should we do next to get more coverage?". Functions called _ssa are still special. They log profusely by default and the output of the SSA implementation is used. For all other functions, logging is off, and the implementation is built and discarded, due to lack of support for the runtime. While we're here, fix a few minor bugs and add some extra Unimplementeds to allow all.bash to pass. As of now, SSA handles 20.79% of the functions in the standard library (689 of 3314). The top missing features are: 10.03% 2597 SSA unimplemented: zero for type error not implemented 7.79% 2016 SSA unimplemented: addr: bad op DOTPTR 7.33% 1898 SSA unimplemented: unhandled expr EQ 6.10% 1579 SSA unimplemented: unhandled expr OROR 4.91% 1271 SSA unimplemented: unhandled expr NE 4.49% 1163 SSA unimplemented: unhandled expr LROT 4.00% 1036 SSA unimplemented: unhandled expr LEN 3.56% 923 SSA unimplemented: unhandled stmt CALLFUNC 2.37% 615 SSA unimplemented: zero for type []byte not implemented 1.90% 492 SSA unimplemented: unhandled stmt CALLMETH 1.74% 450 SSA unimplemented: unhandled expr CALLINTER 1.74% 450 SSA unimplemented: unhandled expr DOT 1.71% 444 SSA unimplemented: unhandled expr ANDAND 1.65% 426 SSA unimplemented: unhandled expr CLOSUREVAR 1.54% 400 SSA unimplemented: unhandled expr CALLMETH 1.51% 390 SSA unimplemented: unhandled stmt SWITCH 1.47% 380 SSA unimplemented: unhandled expr CONV 1.33% 345 SSA unimplemented: addr: bad op * 1.30% 336 SSA unimplemented: unhandled OLITERAL 6 Change-Id: I4ca07951e276714dc13c31de28640aead17a1be7 Reviewed-on: https://go-review.googlesource.com/11160 Reviewed-by: Keith Randall <khr@golang.org>
2015-06-12 11:01:13 -07:00
// reset is called from most rewrite rules.
// Allowing it to be inlined increases the size
// of cmd/compile by almost 10%, and slows it down.
//go:noinline
func (v *Value) reset(op Op) {
if v.InCache {
v.Block.Func.unCache(v)
}
v.Op = op
v.resetArgs()
v.AuxInt = 0
v.Aux = nil
}
// copyOf is called from rewrite rules.
// It modifies v to be (Copy a).
//go:noinline
func (v *Value) copyOf(a *Value) {
if v.InCache {
v.Block.Func.unCache(v)
}
v.Op = OpCopy
v.resetArgs()
v.AddArg(a)
v.AuxInt = 0
v.Aux = nil
v.Type = a.Type
}
// copyInto makes a new value identical to v and adds it to the end of b.
// unlike copyIntoWithXPos this does not check for v.Pos being a statement.
func (v *Value) copyInto(b *Block) *Value {
cmd/compile: assign and preserve statement boundaries. A new pass run after ssa building (before any other optimization) identifies the "first" ssa node for each statement. Other "noise" nodes are tagged as being never appropriate for a statement boundary (e.g., VarKill, VarDef, Phi). Rewrite, deadcode, cse, and nilcheck are modified to move the statement boundaries forward whenever possible if a boundary-tagged ssa value is removed; never-boundary nodes are ignored in this search (some operations involving constants are also tagged as never-boundary and also ignored because they are likely to be moved or removed during optimization). Code generation treats all nodes except those explicitly marked as statement boundaries as "not statement" nodes, and floats statement boundaries to the beginning of each same-line run of instructions found within a basic block. Line number html conversion was modified to make statement boundary nodes a bit more obvious by prepending a "+". The code in fuse.go that glued together the value slices of two blocks produced a result that depended on the former capacities (not lengths) of the two slices. This causes differences in the 386 bootstrap, and also can sometimes put values into an order that does a worse job of preserving statement boundaries when values are removed. Portions of two delve tests that had caught problems were incorporated into ssa/debug_test.go. There are some opportunities to do better with optimized code, but the next-ing is not lying or overly jumpy. Over 4 CLs, compilebench geomean measured binary size increase of 3.5% and compile user time increase of 3.8% (this is after optimization to reuse a sparse map instead of creating multiple maps.) This CL worsens the optimized-debugging experience with Delve; we need to work with the delve team so that they can use the is_stmt marks that we're emitting now. The reference output changes from time to time depending on other changes in the compiler, sometimes better, sometimes worse. This CL now includes a test ensuring that 99+% of the lines in the Go command itself (a handy optimized binary) include is_stmt markers. Change-Id: I359c94e06843f1eb41f9da437bd614885aa9644a Reviewed-on: https://go-review.googlesource.com/102435 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
2018-03-23 22:46:06 -04:00
c := b.NewValue0(v.Pos.WithNotStmt(), v.Op, v.Type) // Lose the position, this causes line number churn otherwise.
c.Aux = v.Aux
c.AuxInt = v.AuxInt
c.AddArgs(v.Args...)
for _, a := range v.Args {
if a.Type.IsMemory() {
v.Fatalf("can't move a value with a memory arg %s", v.LongString())
}
}
return c
}
// 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.
// Because this is used for rematerialization, check for case that (rematerialized)
// input to value with position 'pos' carried a statement mark, and that the supplied
// position (of the instruction using the rematerialized value) is not marked, and
// preserve that mark if its line matches the supplied position.
func (v *Value) copyIntoWithXPos(b *Block, pos src.XPos) *Value {
if v.Pos.IsStmt() == src.PosIsStmt && pos.IsStmt() != src.PosIsStmt && v.Pos.SameFileAndLine(pos) {
pos = pos.WithIsStmt()
}
c := b.NewValue0(pos, v.Op, v.Type)
c.Aux = v.Aux
c.AuxInt = v.AuxInt
c.AddArgs(v.Args...)
for _, a := range v.Args {
if a.Type.IsMemory() {
v.Fatalf("can't move a value with a memory arg %s", v.LongString())
}
}
return c
}
func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) }
func (v *Value) Log() bool { return v.Block.Log() }
func (v *Value) Fatalf(msg string, args ...interface{}) {
v.Block.Func.fe.Fatalf(v.Pos, msg, args...)
}
// isGenericIntConst reports whether v is a generic integer constant.
func (v *Value) isGenericIntConst() bool {
return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8)
}
// Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering.
func (v *Value) Reg() int16 {
reg := v.Block.Func.RegAlloc[v.ID]
if reg == nil {
v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
}
return reg.(*Register).objNum
}
// Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering.
func (v *Value) Reg0() int16 {
reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0]
if reg == nil {
v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func)
}
return reg.(*Register).objNum
}
// Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering.
func (v *Value) Reg1() int16 {
reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1]
if reg == nil {
v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func)
}
return reg.(*Register).objNum
}
func (v *Value) RegName() string {
reg := v.Block.Func.RegAlloc[v.ID]
if reg == nil {
v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
}
return reg.(*Register).name
}
// MemoryArg returns the memory argument for the Value.
// The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part).
// Otherwise, nil is returned.
func (v *Value) MemoryArg() *Value {
if v.Op == OpPhi {
v.Fatalf("MemoryArg on Phi")
}
na := len(v.Args)
if na == 0 {
return nil
}
if m := v.Args[na-1]; m.Type.IsMemory() {
return m
}
return nil
}
// LackingPos indicates whether v is a value that is unlikely to have a correct
// position assigned to it. Ignoring such values leads to more user-friendly positions
// assigned to nearby values and the blocks containing them.
func (v *Value) LackingPos() bool {
// The exact definition of LackingPos is somewhat heuristically defined and may change
// in the future, for example if some of these operations are generated more carefully
// with respect to their source position.
return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi ||
(v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem
}
// removeable reports whether the value v can be removed from the SSA graph entirely
// if its use count drops to 0.
func (v *Value) removeable() bool {
if v.Type.IsVoid() {
// Void ops, like nil pointer checks, must stay.
return false
}
if v.Type.IsMemory() {
// All memory ops aren't needed here, but we do need
// to keep calls at least (because they might have
// syncronization operations we can't see).
return false
}
if v.Op.HasSideEffects() {
// These are mostly synchronization operations.
return false
}
return true
}