aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa/block.go
diff options
context:
space:
mode:
authorMichael Munday <mike.munday@ibm.com>2019-08-12 20:19:58 +0100
committerMichael Munday <mike.munday@ibm.com>2019-10-02 09:56:36 +0000
commit9c2e7e8bed3368fd2b3903b47d686b5a900ebe04 (patch)
tree56cfd2bd0950274ebff578688af535ef69983039 /src/cmd/compile/internal/ssa/block.go
parent274f4cef9329262dcfd4a715ab6c2ebc908d6209 (diff)
downloadgo-9c2e7e8bed3368fd2b3903b47d686b5a900ebe04.tar.gz
go-9c2e7e8bed3368fd2b3903b47d686b5a900ebe04.zip
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>
Diffstat (limited to 'src/cmd/compile/internal/ssa/block.go')
-rw-r--r--src/cmd/compile/internal/ssa/block.go104
1 files changed, 86 insertions, 18 deletions
diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go
index 273e5f15d7..1ccea778c2 100644
--- a/src/cmd/compile/internal/ssa/block.go
+++ b/src/cmd/compile/internal/ssa/block.go
@@ -40,23 +40,28 @@ type Block struct {
// arguments by block id and have this field computed explicitly when needed?
Preds []Edge
- // A value that determines how the block is exited. Its value depends on the kind
- // of the block. For instance, a BlockIf has a boolean control value and BlockExit
- // has a memory control value.
- Control *Value
+ // A list of values that determine how the block is exited. The number
+ // and type of control values depends on the Kind of the block. For
+ // instance, a BlockIf has a single boolean control value and BlockExit
+ // has a single memory control value.
+ //
+ // The ControlValues() method may be used to get a slice with the non-nil
+ // control values that can be ranged over.
+ //
+ // Controls[1] must be nil if Controls[0] is nil.
+ Controls [2]*Value
// Auxiliary info for the block. Its value depends on the Kind.
Aux interface{}
// The unordered set of Values that define the operation of this block.
- // The list must include the control value, if any. (TODO: need this last condition?)
// After the scheduling pass, this list is ordered.
Values []*Value
// The containing function
Func *Func
- // Storage for Succs, Preds, and Values
+ // Storage for Succs, Preds and Values.
succstorage [2]Edge
predstorage [4]Edge
valstorage [9]*Value
@@ -96,12 +101,12 @@ func (e Edge) Index() int {
return e.i
}
-// kind control successors
+// kind controls successors
// ------------------------------------------
-// Exit return mem []
-// Plain nil [next]
-// If a boolean Value [then, else]
-// Defer mem [nopanic, panic] (control opcode should be OpStaticCall to runtime.deferproc)
+// Exit [return mem] []
+// Plain [] [next]
+// If [boolean Value] [then, else]
+// Defer [mem] [nopanic, panic] (control opcode should be OpStaticCall to runtime.deferproc)
type BlockKind int8
// short form print
@@ -115,8 +120,8 @@ func (b *Block) LongString() string {
if b.Aux != nil {
s += fmt.Sprintf(" %s", b.Aux)
}
- if b.Control != nil {
- s += fmt.Sprintf(" %s", b.Control)
+ for _, c := range b.ControlValues() {
+ s += fmt.Sprintf(" %s", c)
}
if len(b.Succs) > 0 {
s += " ->"
@@ -133,13 +138,76 @@ func (b *Block) LongString() string {
return s
}
+// NumControls returns the number of non-nil control values the
+// block has.
+func (b *Block) NumControls() int {
+ if b.Controls[0] == nil {
+ return 0
+ }
+ if b.Controls[1] == nil {
+ return 1
+ }
+ return 2
+}
+
+// ControlValues returns a slice containing the non-nil control
+// values of the block. The index of each control value will be
+// the same as it is in the Controls property and can be used
+// in ReplaceControl calls.
+func (b *Block) ControlValues() []*Value {
+ if b.Controls[0] == nil {
+ return b.Controls[:0]
+ }
+ if b.Controls[1] == nil {
+ return b.Controls[:1]
+ }
+ return b.Controls[:2]
+}
+
+// SetControl removes all existing control values and then adds
+// the control value provided. The number of control values after
+// a call to SetControl will always be 1.
func (b *Block) SetControl(v *Value) {
- if w := b.Control; w != nil {
- w.Uses--
+ b.ResetControls()
+ b.Controls[0] = v
+ v.Uses++
+}
+
+// ResetControls sets the number of controls for the block to 0.
+func (b *Block) ResetControls() {
+ if b.Controls[0] != nil {
+ b.Controls[0].Uses--
+ }
+ if b.Controls[1] != nil {
+ b.Controls[1].Uses--
+ }
+ b.Controls = [2]*Value{} // reset both controls to nil
+}
+
+// AddControl appends a control value to the existing list of control values.
+func (b *Block) AddControl(v *Value) {
+ i := b.NumControls()
+ b.Controls[i] = v // panics if array is full
+ v.Uses++
+}
+
+// ReplaceControl exchanges the existing control value at the index provided
+// for the new value. The index must refer to a valid control value.
+func (b *Block) ReplaceControl(i int, v *Value) {
+ b.Controls[i].Uses--
+ b.Controls[i] = v
+ v.Uses++
+}
+
+// CopyControls replaces the controls for this block with those from the
+// provided block. The provided block is not modified.
+func (b *Block) CopyControls(from *Block) {
+ if b == from {
+ return
}
- b.Control = v
- if v != nil {
- v.Uses++
+ b.ResetControls()
+ for _, c := range from.ControlValues() {
+ b.AddControl(c)
}
}