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>
This commit is contained in:
Michael Munday 2019-08-12 20:19:58 +01:00
parent 274f4cef93
commit 9c2e7e8bed
63 changed files with 6026 additions and 4579 deletions

View file

@ -18,8 +18,8 @@ import (
// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
flive := b.FlagsLiveAtEnd
if b.Control != nil && b.Control.Type.IsFlags() {
flive = true
for _, c := range b.ControlValues() {
flive = c.Type.IsFlags() || flive
}
for i := len(b.Values) - 1; i >= 0; i-- {
v := b.Values[i]
@ -1245,6 +1245,6 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
}
default:
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
b.Fatalf("branch not implemented: %s", b.LongString())
}
}

View file

@ -955,6 +955,6 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
}
default:
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
b.Fatalf("branch not implemented: %s", b.LongString())
}
}

View file

@ -1057,9 +1057,9 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.Br(obj.AJMP, b.Succs[0].Block())
}
}
if !b.Control.Type.IsFlags() {
if !b.Controls[0].Type.IsFlags() {
p.From.Type = obj.TYPE_REG
p.From.Reg = b.Control.Reg()
p.From.Reg = b.Controls[0].Reg()
}
case ssa.BlockARM64TBZ, ssa.BlockARM64TBNZ:
jmp := blockJump[b.Kind]
@ -1080,9 +1080,9 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
}
p.From.Offset = b.Aux.(int64)
p.From.Type = obj.TYPE_CONST
p.Reg = b.Control.Reg()
p.Reg = b.Controls[0].Reg()
default:
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
b.Fatalf("branch not implemented: %s", b.LongString())
}
}

View file

@ -670,7 +670,7 @@ func (lv *Liveness) markUnsafePoints() {
// single op that does the memory load from the flag
// address, so we look for that.
var load *ssa.Value
v := wbBlock.Control
v := wbBlock.Controls[0]
for {
if sym, ok := v.Aux.(*obj.LSym); ok && sym == writeBarrier {
load = v

View file

@ -855,11 +855,11 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.Br(obj.AJMP, b.Succs[0].Block())
}
}
if !b.Control.Type.IsFlags() {
if !b.Controls[0].Type.IsFlags() {
p.From.Type = obj.TYPE_REG
p.From.Reg = b.Control.Reg()
p.From.Reg = b.Controls[0].Reg()
}
default:
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
b.Fatalf("branch not implemented: %s", b.LongString())
}
}

View file

@ -829,11 +829,11 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.Br(obj.AJMP, b.Succs[0].Block())
}
}
if !b.Control.Type.IsFlags() {
if !b.Controls[0].Type.IsFlags() {
p.From.Type = obj.TYPE_REG
p.From.Reg = b.Control.Reg()
p.From.Reg = b.Controls[0].Reg()
}
default:
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
b.Fatalf("branch not implemented: %s", b.LongString())
}
}

View file

@ -1337,6 +1337,6 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
}
}
default:
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
b.Fatalf("branch not implemented: %s", b.LongString())
}
}

View file

@ -17,8 +17,8 @@ import (
// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
flive := b.FlagsLiveAtEnd
if b.Control != nil && b.Control.Type.IsFlags() {
flive = true
for _, c := range b.ControlValues() {
flive = c.Type.IsFlags() || flive
}
for i := len(b.Values) - 1; i >= 0; i-- {
v := b.Values[i]
@ -864,6 +864,6 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.Br(s390x.ABR, succs[1])
}
default:
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
b.Fatalf("branch not implemented: %s", b.LongString())
}
}

View file

@ -82,10 +82,10 @@ control value, which must return a memory state. This is necessary for functions
to return some values, for example - the caller needs some memory state to
depend on, to ensure that it receives those return values correctly.
The last important block kind we will mention is the `if` block. Its control
value must be a boolean value, and it has exactly two successor blocks. The
control flow is handed to the first successor if the bool is true, and to the
second otherwise.
The last important block kind we will mention is the `if` block. It has a single
control value that must be a boolean value, and it has exactly two successor
blocks. The control flow is handed to the first successor if the bool is true,
and to the second otherwise.
Here is a sample if-else control flow represented with basic blocks:

View file

@ -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
}
func (b *Block) SetControl(v *Value) {
if w := b.Control; w != nil {
w.Uses--
// NumControls returns the number of non-nil control values the
// block has.
func (b *Block) NumControls() int {
if b.Controls[0] == nil {
return 0
}
b.Control = v
if v != nil {
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) {
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.ResetControls()
for _, c := range from.ControlValues() {
b.AddControl(c)
}
}

View file

@ -160,13 +160,13 @@ func elimIf(f *Func, loadAddr *sparseSet, dom *Block) bool {
if swap {
v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
}
v.AddArg(dom.Control)
v.AddArg(dom.Controls[0])
}
// Put all of the instructions into 'dom'
// and update the CFG appropriately.
dom.Kind = post.Kind
dom.SetControl(post.Control)
dom.CopyControls(post)
dom.Aux = post.Aux
dom.Succs = append(dom.Succs[:0], post.Succs...)
for i := range dom.Succs {
@ -201,7 +201,7 @@ func clobberBlock(b *Block) {
b.Preds = nil
b.Succs = nil
b.Aux = nil
b.SetControl(nil)
b.ResetControls()
b.Likely = BranchUnknown
b.Kind = BlockInvalid
}
@ -259,13 +259,13 @@ func elimIfElse(f *Func, loadAddr *sparseSet, b *Block) bool {
if swap {
v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
}
v.AddArg(b.Control)
v.AddArg(b.Controls[0])
}
// Move the contents of all of these
// blocks into 'b' and update CFG edges accordingly
b.Kind = post.Kind
b.SetControl(post.Control)
b.CopyControls(post)
b.Aux = post.Aux
b.Succs = append(b.Succs[:0], post.Succs...)
for i := range b.Succs {

View file

@ -39,31 +39,31 @@ func checkFunc(f *Func) {
if len(b.Succs) != 0 {
f.Fatalf("exit block %s has successors", b)
}
if b.Control == nil {
if b.NumControls() != 1 {
f.Fatalf("exit block %s has no control value", b)
}
if !b.Control.Type.IsMemory() {
f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString())
if !b.Controls[0].Type.IsMemory() {
f.Fatalf("exit block %s has non-memory control value %s", b, b.Controls[0].LongString())
}
case BlockRet:
if len(b.Succs) != 0 {
f.Fatalf("ret block %s has successors", b)
}
if b.Control == nil {
if b.NumControls() != 1 {
f.Fatalf("ret block %s has nil control", b)
}
if !b.Control.Type.IsMemory() {
f.Fatalf("ret block %s has non-memory control value %s", b, b.Control.LongString())
if !b.Controls[0].Type.IsMemory() {
f.Fatalf("ret block %s has non-memory control value %s", b, b.Controls[0].LongString())
}
case BlockRetJmp:
if len(b.Succs) != 0 {
f.Fatalf("retjmp block %s len(Succs)==%d, want 0", b, len(b.Succs))
}
if b.Control == nil {
if b.NumControls() != 1 {
f.Fatalf("retjmp block %s has nil control", b)
}
if !b.Control.Type.IsMemory() {
f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Control.LongString())
if !b.Controls[0].Type.IsMemory() {
f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Controls[0].LongString())
}
if b.Aux == nil {
f.Fatalf("retjmp block %s has nil Aux field", b)
@ -72,34 +72,34 @@ func checkFunc(f *Func) {
if len(b.Succs) != 1 {
f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs))
}
if b.Control != nil {
f.Fatalf("plain block %s has non-nil control %s", b, b.Control.LongString())
if b.NumControls() != 0 {
f.Fatalf("plain block %s has non-nil control %s", b, b.Controls[0].LongString())
}
case BlockIf:
if len(b.Succs) != 2 {
f.Fatalf("if block %s len(Succs)==%d, want 2", b, len(b.Succs))
}
if b.Control == nil {
if b.NumControls() != 1 {
f.Fatalf("if block %s has no control value", b)
}
if !b.Control.Type.IsBoolean() {
f.Fatalf("if block %s has non-bool control value %s", b, b.Control.LongString())
if !b.Controls[0].Type.IsBoolean() {
f.Fatalf("if block %s has non-bool control value %s", b, b.Controls[0].LongString())
}
case BlockDefer:
if len(b.Succs) != 2 {
f.Fatalf("defer block %s len(Succs)==%d, want 2", b, len(b.Succs))
}
if b.Control == nil {
if b.NumControls() != 1 {
f.Fatalf("defer block %s has no control value", b)
}
if !b.Control.Type.IsMemory() {
f.Fatalf("defer block %s has non-memory control value %s", b, b.Control.LongString())
if !b.Controls[0].Type.IsMemory() {
f.Fatalf("defer block %s has non-memory control value %s", b, b.Controls[0].LongString())
}
case BlockFirst:
if len(b.Succs) != 2 {
f.Fatalf("plain/dead block %s len(Succs)==%d, want 2", b, len(b.Succs))
}
if b.Control != nil {
if b.NumControls() != 0 {
f.Fatalf("plain/dead block %s has a control value", b)
}
}
@ -263,8 +263,10 @@ func checkFunc(f *Func) {
}
}
}
if b.Control != nil && !valueMark[b.Control.ID] {
f.Fatalf("control value for %s is missing: %v", b, b.Control)
for _, c := range b.ControlValues() {
if !valueMark[c.ID] {
f.Fatalf("control value for %s is missing: %v", b, c)
}
}
}
for b := f.freeBlocks; b != nil; b = b.succstorage[0].b {
@ -296,8 +298,10 @@ func checkFunc(f *Func) {
}
}
}
if b.Control != nil && !domCheck(f, sdom, b.Control.Block, b) {
f.Fatalf("control value %s for %s doesn't dominate", b.Control, b)
for _, c := range b.ControlValues() {
if !domCheck(f, sdom, c.Block, b) {
f.Fatalf("control value %s for %s doesn't dominate", c, b)
}
}
}
}
@ -329,8 +333,8 @@ func checkFunc(f *Func) {
uses[a.ID]++
}
}
if b.Control != nil {
uses[b.Control.ID]++
for _, c := range b.ControlValues() {
uses[c.ID]++
}
}
for _, b := range f.Blocks {

View file

@ -17,8 +17,10 @@ func copyelim(f *Func) {
// Update block control values.
for _, b := range f.Blocks {
if v := b.Control; v != nil && v.Op == OpCopy {
b.SetControl(v.Args[0])
for i, v := range b.ControlValues() {
if v.Op == OpCopy {
b.ReplaceControl(i, v.Args[0])
}
}
}

View file

@ -248,14 +248,14 @@ func cse(f *Func) {
}
}
}
if v := b.Control; v != nil {
for i, v := range b.ControlValues() {
if x := rewrite[v.ID]; x != nil {
if v.Op == OpNilCheck {
// nilcheck pass will remove the nil checks and log
// them appropriately, so don't mess with them here.
continue
}
b.SetControl(x)
b.ReplaceControl(i, x)
}
}
}

View file

@ -110,13 +110,15 @@ func liveValues(f *Func, reachable []bool) (live []bool, liveOrderStmts []*Value
if !reachable[b.ID] {
continue
}
if v := b.Control; v != nil && !live[v.ID] {
for _, v := range b.ControlValues() {
if !live[v.ID] {
live[v.ID] = true
q = append(q, v)
if v.Pos.IsStmt() != src.PosNotStmt {
liveOrderStmts = append(liveOrderStmts, v)
}
}
}
for _, v := range b.Values {
if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects) && !live[v.ID] {
live[v.ID] = true
@ -252,7 +254,7 @@ func deadcode(f *Func) {
for i, b := range f.Blocks {
if !reachable[b.ID] {
// TODO what if control is statement boundary? Too late here.
b.SetControl(nil)
b.ResetControls()
}
for _, v := range b.Values {
if !live[v.ID] {

View file

@ -264,14 +264,13 @@ func elimDeadAutosGeneric(f *Func) {
changed = visit(v) || changed
}
// keep the auto if its address reaches a control value
if b.Control == nil {
continue
}
if n, ok := addr[b.Control]; ok && !used[n] {
for _, c := range b.ControlValues() {
if n, ok := addr[c]; ok && !used[n] {
used[n] = true
changed = true
}
}
}
if !changed {
break
}

View file

@ -18,9 +18,17 @@ func flagalloc(f *Func) {
// Walk values backwards to figure out what flag
// value we want in the flag register at the start
// of the block.
flag := end[b.ID]
if b.Control != nil && b.Control.Type.IsFlags() {
flag = b.Control
var flag *Value
for _, c := range b.ControlValues() {
if c.Type.IsFlags() {
if flag != nil {
panic("cannot have multiple controls using flags")
}
flag = c
}
}
if flag == nil {
flag = end[b.ID]
}
for j := len(b.Values) - 1; j >= 0; j-- {
v := b.Values[j]
@ -49,13 +57,15 @@ func flagalloc(f *Func) {
// we can leave in the flags register at the end of the block. (There
// is no place to put a flag regeneration instruction.)
for _, b := range f.Blocks {
v := b.Control
if v != nil && v.Type.IsFlags() && end[b.ID] != v {
end[b.ID] = nil
}
if b.Kind == BlockDefer {
// Defer blocks internally use/clobber the flags value.
end[b.ID] = nil
continue
}
for _, v := range b.ControlValues() {
if v.Type.IsFlags() && end[b.ID] != v {
end[b.ID] = nil
}
}
}
@ -85,9 +95,11 @@ func flagalloc(f *Func) {
flag = v
}
}
if v := b.Control; v != nil && v != flag && v.Type.IsFlags() {
for _, v := range b.ControlValues() {
if v != flag && v.Type.IsFlags() {
spill[v.ID] = true
}
}
if v := end[b.ID]; v != nil && v != flag {
spill[v.ID] = true
}
@ -149,12 +161,14 @@ func flagalloc(f *Func) {
flag = v
}
}
if v := b.Control; v != nil && v != flag && v.Type.IsFlags() {
for i, v := range b.ControlValues() {
if v != flag && v.Type.IsFlags() {
// Recalculate control value.
c := copyFlags(v, b)
b.SetControl(c)
b.ReplaceControl(i, c)
flag = v
}
}
if v := end[b.ID]; v != nil && v != flag {
// Need to reissue flag generator for use by
// subsequent blocks.

View file

@ -118,7 +118,7 @@ func fuseBlockIf(b *Block) bool {
}
b.Kind = BlockPlain
b.Likely = BranchUnknown
b.SetControl(nil)
b.ResetControls()
// Trash the empty blocks s0 and s1.
blocks := [...]*Block{s0, s1}

View file

@ -899,65 +899,65 @@
(SBBLcarrymask (FlagGT_UGT)) -> (MOVLconst [0])
// Absorb flag constants into branches.
(EQ (FlagEQ) yes no) -> (First nil yes no)
(EQ (FlagLT_ULT) yes no) -> (First nil no yes)
(EQ (FlagLT_UGT) yes no) -> (First nil no yes)
(EQ (FlagGT_ULT) yes no) -> (First nil no yes)
(EQ (FlagGT_UGT) yes no) -> (First nil no yes)
(EQ (FlagEQ) yes no) -> (First yes no)
(EQ (FlagLT_ULT) yes no) -> (First no yes)
(EQ (FlagLT_UGT) yes no) -> (First no yes)
(EQ (FlagGT_ULT) yes no) -> (First no yes)
(EQ (FlagGT_UGT) yes no) -> (First no yes)
(NE (FlagEQ) yes no) -> (First nil no yes)
(NE (FlagLT_ULT) yes no) -> (First nil yes no)
(NE (FlagLT_UGT) yes no) -> (First nil yes no)
(NE (FlagGT_ULT) yes no) -> (First nil yes no)
(NE (FlagGT_UGT) yes no) -> (First nil yes no)
(NE (FlagEQ) yes no) -> (First no yes)
(NE (FlagLT_ULT) yes no) -> (First yes no)
(NE (FlagLT_UGT) yes no) -> (First yes no)
(NE (FlagGT_ULT) yes no) -> (First yes no)
(NE (FlagGT_UGT) yes no) -> (First yes no)
(LT (FlagEQ) yes no) -> (First nil no yes)
(LT (FlagLT_ULT) yes no) -> (First nil yes no)
(LT (FlagLT_UGT) yes no) -> (First nil yes no)
(LT (FlagGT_ULT) yes no) -> (First nil no yes)
(LT (FlagGT_UGT) yes no) -> (First nil no yes)
(LT (FlagEQ) yes no) -> (First no yes)
(LT (FlagLT_ULT) yes no) -> (First yes no)
(LT (FlagLT_UGT) yes no) -> (First yes no)
(LT (FlagGT_ULT) yes no) -> (First no yes)
(LT (FlagGT_UGT) yes no) -> (First no yes)
(LE (FlagEQ) yes no) -> (First nil yes no)
(LE (FlagLT_ULT) yes no) -> (First nil yes no)
(LE (FlagLT_UGT) yes no) -> (First nil yes no)
(LE (FlagGT_ULT) yes no) -> (First nil no yes)
(LE (FlagGT_UGT) yes no) -> (First nil no yes)
(LE (FlagEQ) yes no) -> (First yes no)
(LE (FlagLT_ULT) yes no) -> (First yes no)
(LE (FlagLT_UGT) yes no) -> (First yes no)
(LE (FlagGT_ULT) yes no) -> (First no yes)
(LE (FlagGT_UGT) yes no) -> (First no yes)
(GT (FlagEQ) yes no) -> (First nil no yes)
(GT (FlagLT_ULT) yes no) -> (First nil no yes)
(GT (FlagLT_UGT) yes no) -> (First nil no yes)
(GT (FlagGT_ULT) yes no) -> (First nil yes no)
(GT (FlagGT_UGT) yes no) -> (First nil yes no)
(GT (FlagEQ) yes no) -> (First no yes)
(GT (FlagLT_ULT) yes no) -> (First no yes)
(GT (FlagLT_UGT) yes no) -> (First no yes)
(GT (FlagGT_ULT) yes no) -> (First yes no)
(GT (FlagGT_UGT) yes no) -> (First yes no)
(GE (FlagEQ) yes no) -> (First nil yes no)
(GE (FlagLT_ULT) yes no) -> (First nil no yes)
(GE (FlagLT_UGT) yes no) -> (First nil no yes)
(GE (FlagGT_ULT) yes no) -> (First nil yes no)
(GE (FlagGT_UGT) yes no) -> (First nil yes no)
(GE (FlagEQ) yes no) -> (First yes no)
(GE (FlagLT_ULT) yes no) -> (First no yes)
(GE (FlagLT_UGT) yes no) -> (First no yes)
(GE (FlagGT_ULT) yes no) -> (First yes no)
(GE (FlagGT_UGT) yes no) -> (First yes no)
(ULT (FlagEQ) yes no) -> (First nil no yes)
(ULT (FlagLT_ULT) yes no) -> (First nil yes no)
(ULT (FlagLT_UGT) yes no) -> (First nil no yes)
(ULT (FlagGT_ULT) yes no) -> (First nil yes no)
(ULT (FlagGT_UGT) yes no) -> (First nil no yes)
(ULT (FlagEQ) yes no) -> (First no yes)
(ULT (FlagLT_ULT) yes no) -> (First yes no)
(ULT (FlagLT_UGT) yes no) -> (First no yes)
(ULT (FlagGT_ULT) yes no) -> (First yes no)
(ULT (FlagGT_UGT) yes no) -> (First no yes)
(ULE (FlagEQ) yes no) -> (First nil yes no)
(ULE (FlagLT_ULT) yes no) -> (First nil yes no)
(ULE (FlagLT_UGT) yes no) -> (First nil no yes)
(ULE (FlagGT_ULT) yes no) -> (First nil yes no)
(ULE (FlagGT_UGT) yes no) -> (First nil no yes)
(ULE (FlagEQ) yes no) -> (First yes no)
(ULE (FlagLT_ULT) yes no) -> (First yes no)
(ULE (FlagLT_UGT) yes no) -> (First no yes)
(ULE (FlagGT_ULT) yes no) -> (First yes no)
(ULE (FlagGT_UGT) yes no) -> (First no yes)
(UGT (FlagEQ) yes no) -> (First nil no yes)
(UGT (FlagLT_ULT) yes no) -> (First nil no yes)
(UGT (FlagLT_UGT) yes no) -> (First nil yes no)
(UGT (FlagGT_ULT) yes no) -> (First nil no yes)
(UGT (FlagGT_UGT) yes no) -> (First nil yes no)
(UGT (FlagEQ) yes no) -> (First no yes)
(UGT (FlagLT_ULT) yes no) -> (First no yes)
(UGT (FlagLT_UGT) yes no) -> (First yes no)
(UGT (FlagGT_ULT) yes no) -> (First no yes)
(UGT (FlagGT_UGT) yes no) -> (First yes no)
(UGE (FlagEQ) yes no) -> (First nil yes no)
(UGE (FlagLT_ULT) yes no) -> (First nil no yes)
(UGE (FlagLT_UGT) yes no) -> (First nil yes no)
(UGE (FlagGT_ULT) yes no) -> (First nil no yes)
(UGE (FlagGT_UGT) yes no) -> (First nil yes no)
(UGE (FlagEQ) yes no) -> (First yes no)
(UGE (FlagLT_ULT) yes no) -> (First no yes)
(UGE (FlagLT_UGT) yes no) -> (First yes no)
(UGE (FlagGT_ULT) yes no) -> (First no yes)
(UGE (FlagGT_UGT) yes no) -> (First yes no)
// Absorb flag constants into SETxx ops.
(SETEQ (FlagEQ)) -> (MOVLconst [1])

View file

@ -564,22 +564,22 @@ func init() {
}
var _386blocks = []blockData{
{name: "EQ"},
{name: "NE"},
{name: "LT"},
{name: "LE"},
{name: "GT"},
{name: "GE"},
{name: "OS"},
{name: "OC"},
{name: "ULT"},
{name: "ULE"},
{name: "UGT"},
{name: "UGE"},
{name: "EQF"},
{name: "NEF"},
{name: "ORD"}, // FP, ordered comparison (parity zero)
{name: "NAN"}, // FP, unordered comparison (parity one)
{name: "EQ", controls: 1},
{name: "NE", controls: 1},
{name: "LT", controls: 1},
{name: "LE", controls: 1},
{name: "GT", controls: 1},
{name: "GE", controls: 1},
{name: "OS", controls: 1},
{name: "OC", controls: 1},
{name: "ULT", controls: 1},
{name: "ULE", controls: 1},
{name: "UGT", controls: 1},
{name: "UGE", controls: 1},
{name: "EQF", controls: 1},
{name: "NEF", controls: 1},
{name: "ORD", controls: 1}, // FP, ordered comparison (parity zero)
{name: "NAN", controls: 1}, // FP, unordered comparison (parity one)
}
archs = append(archs, arch{

View file

@ -1346,16 +1346,16 @@
(SBBLcarrymask (FlagGT_UGT)) -> (MOVLconst [0])
// Absorb flag constants into branches.
((EQ|LE|GE|ULE|UGE) (FlagEQ) yes no) -> (First nil yes no)
((NE|LT|GT|ULT|UGT) (FlagEQ) yes no) -> (First nil no yes)
((NE|LT|LE|ULT|ULE) (FlagLT_ULT) yes no) -> (First nil yes no)
((EQ|GT|GE|UGT|UGE) (FlagLT_ULT) yes no) -> (First nil no yes)
((NE|LT|LE|UGT|UGE) (FlagLT_UGT) yes no) -> (First nil yes no)
((EQ|GT|GE|ULT|ULE) (FlagLT_UGT) yes no) -> (First nil no yes)
((NE|GT|GE|ULT|ULE) (FlagGT_ULT) yes no) -> (First nil yes no)
((EQ|LT|LE|UGT|UGE) (FlagGT_ULT) yes no) -> (First nil no yes)
((NE|GT|GE|UGT|UGE) (FlagGT_UGT) yes no) -> (First nil yes no)
((EQ|LT|LE|ULT|ULE) (FlagGT_UGT) yes no) -> (First nil no yes)
((EQ|LE|GE|ULE|UGE) (FlagEQ) yes no) -> (First yes no)
((NE|LT|GT|ULT|UGT) (FlagEQ) yes no) -> (First no yes)
((NE|LT|LE|ULT|ULE) (FlagLT_ULT) yes no) -> (First yes no)
((EQ|GT|GE|UGT|UGE) (FlagLT_ULT) yes no) -> (First no yes)
((NE|LT|LE|UGT|UGE) (FlagLT_UGT) yes no) -> (First yes no)
((EQ|GT|GE|ULT|ULE) (FlagLT_UGT) yes no) -> (First no yes)
((NE|GT|GE|ULT|ULE) (FlagGT_ULT) yes no) -> (First yes no)
((EQ|LT|LE|UGT|UGE) (FlagGT_ULT) yes no) -> (First no yes)
((NE|GT|GE|UGT|UGE) (FlagGT_UGT) yes no) -> (First yes no)
((EQ|LT|LE|ULT|ULE) (FlagGT_UGT) yes no) -> (First no yes)
// Absorb flag constants into SETxx ops.
((SETEQ|SETLE|SETGE|SETBE|SETAE) (FlagEQ)) -> (MOVLconst [1])

View file

@ -788,22 +788,22 @@ func init() {
}
var AMD64blocks = []blockData{
{name: "EQ"},
{name: "NE"},
{name: "LT"},
{name: "LE"},
{name: "GT"},
{name: "GE"},
{name: "OS"},
{name: "OC"},
{name: "ULT"},
{name: "ULE"},
{name: "UGT"},
{name: "UGE"},
{name: "EQF"},
{name: "NEF"},
{name: "ORD"}, // FP, ordered comparison (parity zero)
{name: "NAN"}, // FP, unordered comparison (parity one)
{name: "EQ", controls: 1},
{name: "NE", controls: 1},
{name: "LT", controls: 1},
{name: "LE", controls: 1},
{name: "GT", controls: 1},
{name: "GE", controls: 1},
{name: "OS", controls: 1},
{name: "OC", controls: 1},
{name: "ULT", controls: 1},
{name: "ULE", controls: 1},
{name: "UGT", controls: 1},
{name: "UGE", controls: 1},
{name: "EQF", controls: 1},
{name: "NEF", controls: 1},
{name: "ORD", controls: 1}, // FP, ordered comparison (parity zero)
{name: "NAN", controls: 1}, // FP, unordered comparison (parity one)
}
archs = append(archs, arch{

View file

@ -647,65 +647,65 @@
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) -> (FlagLT_ULT)
// absorb flag constants into branches
(EQ (FlagEQ) yes no) -> (First nil yes no)
(EQ (FlagLT_ULT) yes no) -> (First nil no yes)
(EQ (FlagLT_UGT) yes no) -> (First nil no yes)
(EQ (FlagGT_ULT) yes no) -> (First nil no yes)
(EQ (FlagGT_UGT) yes no) -> (First nil no yes)
(EQ (FlagEQ) yes no) -> (First yes no)
(EQ (FlagLT_ULT) yes no) -> (First no yes)
(EQ (FlagLT_UGT) yes no) -> (First no yes)
(EQ (FlagGT_ULT) yes no) -> (First no yes)
(EQ (FlagGT_UGT) yes no) -> (First no yes)
(NE (FlagEQ) yes no) -> (First nil no yes)
(NE (FlagLT_ULT) yes no) -> (First nil yes no)
(NE (FlagLT_UGT) yes no) -> (First nil yes no)
(NE (FlagGT_ULT) yes no) -> (First nil yes no)
(NE (FlagGT_UGT) yes no) -> (First nil yes no)
(NE (FlagEQ) yes no) -> (First no yes)
(NE (FlagLT_ULT) yes no) -> (First yes no)
(NE (FlagLT_UGT) yes no) -> (First yes no)
(NE (FlagGT_ULT) yes no) -> (First yes no)
(NE (FlagGT_UGT) yes no) -> (First yes no)
(LT (FlagEQ) yes no) -> (First nil no yes)
(LT (FlagLT_ULT) yes no) -> (First nil yes no)
(LT (FlagLT_UGT) yes no) -> (First nil yes no)
(LT (FlagGT_ULT) yes no) -> (First nil no yes)
(LT (FlagGT_UGT) yes no) -> (First nil no yes)
(LT (FlagEQ) yes no) -> (First no yes)
(LT (FlagLT_ULT) yes no) -> (First yes no)
(LT (FlagLT_UGT) yes no) -> (First yes no)
(LT (FlagGT_ULT) yes no) -> (First no yes)
(LT (FlagGT_UGT) yes no) -> (First no yes)
(LE (FlagEQ) yes no) -> (First nil yes no)
(LE (FlagLT_ULT) yes no) -> (First nil yes no)
(LE (FlagLT_UGT) yes no) -> (First nil yes no)
(LE (FlagGT_ULT) yes no) -> (First nil no yes)
(LE (FlagGT_UGT) yes no) -> (First nil no yes)
(LE (FlagEQ) yes no) -> (First yes no)
(LE (FlagLT_ULT) yes no) -> (First yes no)
(LE (FlagLT_UGT) yes no) -> (First yes no)
(LE (FlagGT_ULT) yes no) -> (First no yes)
(LE (FlagGT_UGT) yes no) -> (First no yes)
(GT (FlagEQ) yes no) -> (First nil no yes)
(GT (FlagLT_ULT) yes no) -> (First nil no yes)
(GT (FlagLT_UGT) yes no) -> (First nil no yes)
(GT (FlagGT_ULT) yes no) -> (First nil yes no)
(GT (FlagGT_UGT) yes no) -> (First nil yes no)
(GT (FlagEQ) yes no) -> (First no yes)
(GT (FlagLT_ULT) yes no) -> (First no yes)
(GT (FlagLT_UGT) yes no) -> (First no yes)
(GT (FlagGT_ULT) yes no) -> (First yes no)
(GT (FlagGT_UGT) yes no) -> (First yes no)
(GE (FlagEQ) yes no) -> (First nil yes no)
(GE (FlagLT_ULT) yes no) -> (First nil no yes)
(GE (FlagLT_UGT) yes no) -> (First nil no yes)
(GE (FlagGT_ULT) yes no) -> (First nil yes no)
(GE (FlagGT_UGT) yes no) -> (First nil yes no)
(GE (FlagEQ) yes no) -> (First yes no)
(GE (FlagLT_ULT) yes no) -> (First no yes)
(GE (FlagLT_UGT) yes no) -> (First no yes)
(GE (FlagGT_ULT) yes no) -> (First yes no)
(GE (FlagGT_UGT) yes no) -> (First yes no)
(ULT (FlagEQ) yes no) -> (First nil no yes)
(ULT (FlagLT_ULT) yes no) -> (First nil yes no)
(ULT (FlagLT_UGT) yes no) -> (First nil no yes)
(ULT (FlagGT_ULT) yes no) -> (First nil yes no)
(ULT (FlagGT_UGT) yes no) -> (First nil no yes)
(ULT (FlagEQ) yes no) -> (First no yes)
(ULT (FlagLT_ULT) yes no) -> (First yes no)
(ULT (FlagLT_UGT) yes no) -> (First no yes)
(ULT (FlagGT_ULT) yes no) -> (First yes no)
(ULT (FlagGT_UGT) yes no) -> (First no yes)
(ULE (FlagEQ) yes no) -> (First nil yes no)
(ULE (FlagLT_ULT) yes no) -> (First nil yes no)
(ULE (FlagLT_UGT) yes no) -> (First nil no yes)
(ULE (FlagGT_ULT) yes no) -> (First nil yes no)
(ULE (FlagGT_UGT) yes no) -> (First nil no yes)
(ULE (FlagEQ) yes no) -> (First yes no)
(ULE (FlagLT_ULT) yes no) -> (First yes no)
(ULE (FlagLT_UGT) yes no) -> (First no yes)
(ULE (FlagGT_ULT) yes no) -> (First yes no)
(ULE (FlagGT_UGT) yes no) -> (First no yes)
(UGT (FlagEQ) yes no) -> (First nil no yes)
(UGT (FlagLT_ULT) yes no) -> (First nil no yes)
(UGT (FlagLT_UGT) yes no) -> (First nil yes no)
(UGT (FlagGT_ULT) yes no) -> (First nil no yes)
(UGT (FlagGT_UGT) yes no) -> (First nil yes no)
(UGT (FlagEQ) yes no) -> (First no yes)
(UGT (FlagLT_ULT) yes no) -> (First no yes)
(UGT (FlagLT_UGT) yes no) -> (First yes no)
(UGT (FlagGT_ULT) yes no) -> (First no yes)
(UGT (FlagGT_UGT) yes no) -> (First yes no)
(UGE (FlagEQ) yes no) -> (First nil yes no)
(UGE (FlagLT_ULT) yes no) -> (First nil no yes)
(UGE (FlagLT_UGT) yes no) -> (First nil yes no)
(UGE (FlagGT_ULT) yes no) -> (First nil no yes)
(UGE (FlagGT_UGT) yes no) -> (First nil yes no)
(UGE (FlagEQ) yes no) -> (First yes no)
(UGE (FlagLT_ULT) yes no) -> (First no yes)
(UGE (FlagLT_UGT) yes no) -> (First yes no)
(UGE (FlagGT_ULT) yes no) -> (First no yes)
(UGE (FlagGT_UGT) yes no) -> (First yes no)
// absorb InvertFlags into branches
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)

View file

@ -1481,74 +1481,74 @@
(CMPWconst (MOVHUreg _) [c]) && 0xffff < int32(c) -> (FlagLT_ULT)
// absorb flag constants into branches
(EQ (FlagEQ) yes no) -> (First nil yes no)
(EQ (FlagLT_ULT) yes no) -> (First nil no yes)
(EQ (FlagLT_UGT) yes no) -> (First nil no yes)
(EQ (FlagGT_ULT) yes no) -> (First nil no yes)
(EQ (FlagGT_UGT) yes no) -> (First nil no yes)
(EQ (FlagEQ) yes no) -> (First yes no)
(EQ (FlagLT_ULT) yes no) -> (First no yes)
(EQ (FlagLT_UGT) yes no) -> (First no yes)
(EQ (FlagGT_ULT) yes no) -> (First no yes)
(EQ (FlagGT_UGT) yes no) -> (First no yes)
(NE (FlagEQ) yes no) -> (First nil no yes)
(NE (FlagLT_ULT) yes no) -> (First nil yes no)
(NE (FlagLT_UGT) yes no) -> (First nil yes no)
(NE (FlagGT_ULT) yes no) -> (First nil yes no)
(NE (FlagGT_UGT) yes no) -> (First nil yes no)
(NE (FlagEQ) yes no) -> (First no yes)
(NE (FlagLT_ULT) yes no) -> (First yes no)
(NE (FlagLT_UGT) yes no) -> (First yes no)
(NE (FlagGT_ULT) yes no) -> (First yes no)
(NE (FlagGT_UGT) yes no) -> (First yes no)
(LT (FlagEQ) yes no) -> (First nil no yes)
(LT (FlagLT_ULT) yes no) -> (First nil yes no)
(LT (FlagLT_UGT) yes no) -> (First nil yes no)
(LT (FlagGT_ULT) yes no) -> (First nil no yes)
(LT (FlagGT_UGT) yes no) -> (First nil no yes)
(LT (FlagEQ) yes no) -> (First no yes)
(LT (FlagLT_ULT) yes no) -> (First yes no)
(LT (FlagLT_UGT) yes no) -> (First yes no)
(LT (FlagGT_ULT) yes no) -> (First no yes)
(LT (FlagGT_UGT) yes no) -> (First no yes)
(LE (FlagEQ) yes no) -> (First nil yes no)
(LE (FlagLT_ULT) yes no) -> (First nil yes no)
(LE (FlagLT_UGT) yes no) -> (First nil yes no)
(LE (FlagGT_ULT) yes no) -> (First nil no yes)
(LE (FlagGT_UGT) yes no) -> (First nil no yes)
(LE (FlagEQ) yes no) -> (First yes no)
(LE (FlagLT_ULT) yes no) -> (First yes no)
(LE (FlagLT_UGT) yes no) -> (First yes no)
(LE (FlagGT_ULT) yes no) -> (First no yes)
(LE (FlagGT_UGT) yes no) -> (First no yes)
(GT (FlagEQ) yes no) -> (First nil no yes)
(GT (FlagLT_ULT) yes no) -> (First nil no yes)
(GT (FlagLT_UGT) yes no) -> (First nil no yes)
(GT (FlagGT_ULT) yes no) -> (First nil yes no)
(GT (FlagGT_UGT) yes no) -> (First nil yes no)
(GT (FlagEQ) yes no) -> (First no yes)
(GT (FlagLT_ULT) yes no) -> (First no yes)
(GT (FlagLT_UGT) yes no) -> (First no yes)
(GT (FlagGT_ULT) yes no) -> (First yes no)
(GT (FlagGT_UGT) yes no) -> (First yes no)
(GE (FlagEQ) yes no) -> (First nil yes no)
(GE (FlagLT_ULT) yes no) -> (First nil no yes)
(GE (FlagLT_UGT) yes no) -> (First nil no yes)
(GE (FlagGT_ULT) yes no) -> (First nil yes no)
(GE (FlagGT_UGT) yes no) -> (First nil yes no)
(GE (FlagEQ) yes no) -> (First yes no)
(GE (FlagLT_ULT) yes no) -> (First no yes)
(GE (FlagLT_UGT) yes no) -> (First no yes)
(GE (FlagGT_ULT) yes no) -> (First yes no)
(GE (FlagGT_UGT) yes no) -> (First yes no)
(ULT (FlagEQ) yes no) -> (First nil no yes)
(ULT (FlagLT_ULT) yes no) -> (First nil yes no)
(ULT (FlagLT_UGT) yes no) -> (First nil no yes)
(ULT (FlagGT_ULT) yes no) -> (First nil yes no)
(ULT (FlagGT_UGT) yes no) -> (First nil no yes)
(ULT (FlagEQ) yes no) -> (First no yes)
(ULT (FlagLT_ULT) yes no) -> (First yes no)
(ULT (FlagLT_UGT) yes no) -> (First no yes)
(ULT (FlagGT_ULT) yes no) -> (First yes no)
(ULT (FlagGT_UGT) yes no) -> (First no yes)
(ULE (FlagEQ) yes no) -> (First nil yes no)
(ULE (FlagLT_ULT) yes no) -> (First nil yes no)
(ULE (FlagLT_UGT) yes no) -> (First nil no yes)
(ULE (FlagGT_ULT) yes no) -> (First nil yes no)
(ULE (FlagGT_UGT) yes no) -> (First nil no yes)
(ULE (FlagEQ) yes no) -> (First yes no)
(ULE (FlagLT_ULT) yes no) -> (First yes no)
(ULE (FlagLT_UGT) yes no) -> (First no yes)
(ULE (FlagGT_ULT) yes no) -> (First yes no)
(ULE (FlagGT_UGT) yes no) -> (First no yes)
(UGT (FlagEQ) yes no) -> (First nil no yes)
(UGT (FlagLT_ULT) yes no) -> (First nil no yes)
(UGT (FlagLT_UGT) yes no) -> (First nil yes no)
(UGT (FlagGT_ULT) yes no) -> (First nil no yes)
(UGT (FlagGT_UGT) yes no) -> (First nil yes no)
(UGT (FlagEQ) yes no) -> (First no yes)
(UGT (FlagLT_ULT) yes no) -> (First no yes)
(UGT (FlagLT_UGT) yes no) -> (First yes no)
(UGT (FlagGT_ULT) yes no) -> (First no yes)
(UGT (FlagGT_UGT) yes no) -> (First yes no)
(UGE (FlagEQ) yes no) -> (First nil yes no)
(UGE (FlagLT_ULT) yes no) -> (First nil no yes)
(UGE (FlagLT_UGT) yes no) -> (First nil yes no)
(UGE (FlagGT_ULT) yes no) -> (First nil no yes)
(UGE (FlagGT_UGT) yes no) -> (First nil yes no)
(UGE (FlagEQ) yes no) -> (First yes no)
(UGE (FlagLT_ULT) yes no) -> (First no yes)
(UGE (FlagLT_UGT) yes no) -> (First yes no)
(UGE (FlagGT_ULT) yes no) -> (First no yes)
(UGE (FlagGT_UGT) yes no) -> (First yes no)
(Z (MOVDconst [0]) yes no) -> (First nil yes no)
(Z (MOVDconst [c]) yes no) && c != 0 -> (First nil no yes)
(NZ (MOVDconst [0]) yes no) -> (First nil no yes)
(NZ (MOVDconst [c]) yes no) && c != 0 -> (First nil yes no)
(ZW (MOVDconst [c]) yes no) && int32(c) == 0 -> (First nil yes no)
(ZW (MOVDconst [c]) yes no) && int32(c) != 0 -> (First nil no yes)
(NZW (MOVDconst [c]) yes no) && int32(c) == 0 -> (First nil no yes)
(NZW (MOVDconst [c]) yes no) && int32(c) != 0 -> (First nil yes no)
(Z (MOVDconst [0]) yes no) -> (First yes no)
(Z (MOVDconst [c]) yes no) && c != 0 -> (First no yes)
(NZ (MOVDconst [0]) yes no) -> (First no yes)
(NZ (MOVDconst [c]) yes no) && c != 0 -> (First yes no)
(ZW (MOVDconst [c]) yes no) && int32(c) == 0 -> (First yes no)
(ZW (MOVDconst [c]) yes no) && int32(c) != 0 -> (First no yes)
(NZW (MOVDconst [c]) yes no) && int32(c) == 0 -> (First no yes)
(NZW (MOVDconst [c]) yes no) && int32(c) != 0 -> (First yes no)
// absorb InvertFlags into branches
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)

View file

@ -678,26 +678,26 @@ func init() {
}
blocks := []blockData{
{name: "EQ"},
{name: "NE"},
{name: "LT"},
{name: "LE"},
{name: "GT"},
{name: "GE"},
{name: "ULT"},
{name: "ULE"},
{name: "UGT"},
{name: "UGE"},
{name: "Z"}, // Control == 0 (take a register instead of flags)
{name: "NZ"}, // Control != 0
{name: "ZW"}, // Control == 0, 32-bit
{name: "NZW"}, // Control != 0, 32-bit
{name: "TBZ"}, // Control & (1 << Aux.(int64)) == 0
{name: "TBNZ"}, // Control & (1 << Aux.(int64)) != 0
{name: "FLT"},
{name: "FLE"},
{name: "FGT"},
{name: "FGE"},
{name: "EQ", controls: 1},
{name: "NE", controls: 1},
{name: "LT", controls: 1},
{name: "LE", controls: 1},
{name: "GT", controls: 1},
{name: "GE", controls: 1},
{name: "ULT", controls: 1},
{name: "ULE", controls: 1},
{name: "UGT", controls: 1},
{name: "UGE", controls: 1},
{name: "Z", controls: 1}, // Control == 0 (take a register instead of flags)
{name: "NZ", controls: 1}, // Control != 0
{name: "ZW", controls: 1}, // Control == 0, 32-bit
{name: "NZW", controls: 1}, // Control != 0, 32-bit
{name: "TBZ", controls: 1}, // Control & (1 << Aux.(int64)) == 0
{name: "TBNZ", controls: 1}, // Control & (1 << Aux.(int64)) != 0
{name: "FLT", controls: 1},
{name: "FLE", controls: 1},
{name: "FGT", controls: 1},
{name: "FGE", controls: 1},
}
archs = append(archs, arch{

View file

@ -568,16 +568,16 @@ func init() {
}
blocks := []blockData{
{name: "EQ"},
{name: "NE"},
{name: "LT"},
{name: "LE"},
{name: "GT"},
{name: "GE"},
{name: "ULT"},
{name: "ULE"},
{name: "UGT"},
{name: "UGE"},
{name: "EQ", controls: 1},
{name: "NE", controls: 1},
{name: "LT", controls: 1},
{name: "LE", controls: 1},
{name: "GT", controls: 1},
{name: "GE", controls: 1},
{name: "ULT", controls: 1},
{name: "ULE", controls: 1},
{name: "UGT", controls: 1},
{name: "UGE", controls: 1},
}
archs = append(archs, arch{

View file

@ -687,18 +687,18 @@
(SGTUconst [c] (SRLconst _ [d])) && uint32(d) <= 31 && 0xffffffff>>uint32(d) < uint32(c) -> (MOVWconst [1])
// absorb constants into branches
(EQ (MOVWconst [0]) yes no) -> (First nil yes no)
(EQ (MOVWconst [c]) yes no) && c != 0 -> (First nil no yes)
(NE (MOVWconst [0]) yes no) -> (First nil no yes)
(NE (MOVWconst [c]) yes no) && c != 0 -> (First nil yes no)
(LTZ (MOVWconst [c]) yes no) && int32(c) < 0 -> (First nil yes no)
(LTZ (MOVWconst [c]) yes no) && int32(c) >= 0 -> (First nil no yes)
(LEZ (MOVWconst [c]) yes no) && int32(c) <= 0 -> (First nil yes no)
(LEZ (MOVWconst [c]) yes no) && int32(c) > 0 -> (First nil no yes)
(GTZ (MOVWconst [c]) yes no) && int32(c) > 0 -> (First nil yes no)
(GTZ (MOVWconst [c]) yes no) && int32(c) <= 0 -> (First nil no yes)
(GEZ (MOVWconst [c]) yes no) && int32(c) >= 0 -> (First nil yes no)
(GEZ (MOVWconst [c]) yes no) && int32(c) < 0 -> (First nil no yes)
(EQ (MOVWconst [0]) yes no) -> (First yes no)
(EQ (MOVWconst [c]) yes no) && c != 0 -> (First no yes)
(NE (MOVWconst [0]) yes no) -> (First no yes)
(NE (MOVWconst [c]) yes no) && c != 0 -> (First yes no)
(LTZ (MOVWconst [c]) yes no) && int32(c) < 0 -> (First yes no)
(LTZ (MOVWconst [c]) yes no) && int32(c) >= 0 -> (First no yes)
(LEZ (MOVWconst [c]) yes no) && int32(c) <= 0 -> (First yes no)
(LEZ (MOVWconst [c]) yes no) && int32(c) > 0 -> (First no yes)
(GTZ (MOVWconst [c]) yes no) && int32(c) > 0 -> (First yes no)
(GTZ (MOVWconst [c]) yes no) && int32(c) <= 0 -> (First no yes)
(GEZ (MOVWconst [c]) yes no) && int32(c) >= 0 -> (First yes no)
(GEZ (MOVWconst [c]) yes no) && int32(c) < 0 -> (First no yes)
// conditional move
(CMOVZ _ f (MOVWconst [0])) -> f

View file

@ -694,15 +694,15 @@
(SGTUconst [c] (SRLVconst _ [d])) && 0 < d && d <= 63 && 0xffffffffffffffff>>uint64(d) < uint64(c) -> (MOVVconst [1])
// absorb constants into branches
(EQ (MOVVconst [0]) yes no) -> (First nil yes no)
(EQ (MOVVconst [c]) yes no) && c != 0 -> (First nil no yes)
(NE (MOVVconst [0]) yes no) -> (First nil no yes)
(NE (MOVVconst [c]) yes no) && c != 0 -> (First nil yes no)
(LTZ (MOVVconst [c]) yes no) && c < 0 -> (First nil yes no)
(LTZ (MOVVconst [c]) yes no) && c >= 0 -> (First nil no yes)
(LEZ (MOVVconst [c]) yes no) && c <= 0 -> (First nil yes no)
(LEZ (MOVVconst [c]) yes no) && c > 0 -> (First nil no yes)
(GTZ (MOVVconst [c]) yes no) && c > 0 -> (First nil yes no)
(GTZ (MOVVconst [c]) yes no) && c <= 0 -> (First nil no yes)
(GEZ (MOVVconst [c]) yes no) && c >= 0 -> (First nil yes no)
(GEZ (MOVVconst [c]) yes no) && c < 0 -> (First nil no yes)
(EQ (MOVVconst [0]) yes no) -> (First yes no)
(EQ (MOVVconst [c]) yes no) && c != 0 -> (First no yes)
(NE (MOVVconst [0]) yes no) -> (First no yes)
(NE (MOVVconst [c]) yes no) && c != 0 -> (First yes no)
(LTZ (MOVVconst [c]) yes no) && c < 0 -> (First yes no)
(LTZ (MOVVconst [c]) yes no) && c >= 0 -> (First no yes)
(LEZ (MOVVconst [c]) yes no) && c <= 0 -> (First yes no)
(LEZ (MOVVconst [c]) yes no) && c > 0 -> (First no yes)
(GTZ (MOVVconst [c]) yes no) && c > 0 -> (First yes no)
(GTZ (MOVVconst [c]) yes no) && c <= 0 -> (First no yes)
(GEZ (MOVVconst [c]) yes no) && c >= 0 -> (First yes no)
(GEZ (MOVVconst [c]) yes no) && c < 0 -> (First no yes)

View file

@ -453,14 +453,14 @@ func init() {
}
blocks := []blockData{
{name: "EQ"},
{name: "NE"},
{name: "LTZ"}, // < 0
{name: "LEZ"}, // <= 0
{name: "GTZ"}, // > 0
{name: "GEZ"}, // >= 0
{name: "FPT"}, // FP flag is true
{name: "FPF"}, // FP flag is false
{name: "EQ", controls: 1},
{name: "NE", controls: 1},
{name: "LTZ", controls: 1}, // < 0
{name: "LEZ", controls: 1}, // <= 0
{name: "GTZ", controls: 1}, // > 0
{name: "GEZ", controls: 1}, // >= 0
{name: "FPT", controls: 1}, // FP flag is true
{name: "FPF", controls: 1}, // FP flag is false
}
archs = append(archs, arch{

View file

@ -409,14 +409,14 @@ func init() {
}
blocks := []blockData{
{name: "EQ"},
{name: "NE"},
{name: "LTZ"}, // < 0
{name: "LEZ"}, // <= 0
{name: "GTZ"}, // > 0
{name: "GEZ"}, // >= 0
{name: "FPT"}, // FP flag is true
{name: "FPF"}, // FP flag is false
{name: "EQ", controls: 1},
{name: "NE", controls: 1},
{name: "LTZ", controls: 1}, // < 0
{name: "LEZ", controls: 1}, // <= 0
{name: "GTZ", controls: 1}, // > 0
{name: "GEZ", controls: 1}, // >= 0
{name: "FPT", controls: 1}, // FP flag is true
{name: "FPF", controls: 1}, // FP flag is false
}
archs = append(archs, arch{

View file

@ -447,29 +447,29 @@
(NE (CMPWconst [0] (ANDconst [c] x)) yes no) -> (NE (ANDCCconst [c] x) yes no)
// absorb flag constants into branches
(EQ (FlagEQ) yes no) -> (First nil yes no)
(EQ (FlagLT) yes no) -> (First nil no yes)
(EQ (FlagGT) yes no) -> (First nil no yes)
(EQ (FlagEQ) yes no) -> (First yes no)
(EQ (FlagLT) yes no) -> (First no yes)
(EQ (FlagGT) yes no) -> (First no yes)
(NE (FlagEQ) yes no) -> (First nil no yes)
(NE (FlagLT) yes no) -> (First nil yes no)
(NE (FlagGT) yes no) -> (First nil yes no)
(NE (FlagEQ) yes no) -> (First no yes)
(NE (FlagLT) yes no) -> (First yes no)
(NE (FlagGT) yes no) -> (First yes no)
(LT (FlagEQ) yes no) -> (First nil no yes)
(LT (FlagLT) yes no) -> (First nil yes no)
(LT (FlagGT) yes no) -> (First nil no yes)
(LT (FlagEQ) yes no) -> (First no yes)
(LT (FlagLT) yes no) -> (First yes no)
(LT (FlagGT) yes no) -> (First no yes)
(LE (FlagEQ) yes no) -> (First nil yes no)
(LE (FlagLT) yes no) -> (First nil yes no)
(LE (FlagGT) yes no) -> (First nil no yes)
(LE (FlagEQ) yes no) -> (First yes no)
(LE (FlagLT) yes no) -> (First yes no)
(LE (FlagGT) yes no) -> (First no yes)
(GT (FlagEQ) yes no) -> (First nil no yes)
(GT (FlagLT) yes no) -> (First nil no yes)
(GT (FlagGT) yes no) -> (First nil yes no)
(GT (FlagEQ) yes no) -> (First no yes)
(GT (FlagLT) yes no) -> (First no yes)
(GT (FlagGT) yes no) -> (First yes no)
(GE (FlagEQ) yes no) -> (First nil yes no)
(GE (FlagLT) yes no) -> (First nil no yes)
(GE (FlagGT) yes no) -> (First nil yes no)
(GE (FlagEQ) yes no) -> (First yes no)
(GE (FlagLT) yes no) -> (First no yes)
(GE (FlagGT) yes no) -> (First yes no)
// absorb InvertFlags into branches
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)

View file

@ -585,16 +585,16 @@ func init() {
}
blocks := []blockData{
{name: "EQ"},
{name: "NE"},
{name: "LT"},
{name: "LE"},
{name: "GT"},
{name: "GE"},
{name: "FLT"},
{name: "FLE"},
{name: "FGT"},
{name: "FGE"},
{name: "EQ", controls: 1},
{name: "NE", controls: 1},
{name: "LT", controls: 1},
{name: "LE", controls: 1},
{name: "GT", controls: 1},
{name: "GE", controls: 1},
{name: "FLT", controls: 1},
{name: "FLE", controls: 1},
{name: "FGT", controls: 1},
{name: "FGE", controls: 1},
}
archs = append(archs, arch{

View file

@ -976,15 +976,15 @@
(CMP(W|W|WU|WU)const (MOV(W|WZ|W|WZ)reg x) [c]) -> (CMP(W|W|WU|WU)const x [c])
// Absorb flag constants into branches.
(BRC {c} (FlagEQ) yes no) && c.(s390x.CCMask) & s390x.Equal != 0 -> (First nil yes no)
(BRC {c} (FlagLT) yes no) && c.(s390x.CCMask) & s390x.Less != 0 -> (First nil yes no)
(BRC {c} (FlagGT) yes no) && c.(s390x.CCMask) & s390x.Greater != 0 -> (First nil yes no)
(BRC {c} (FlagOV) yes no) && c.(s390x.CCMask) & s390x.Unordered != 0 -> (First nil yes no)
(BRC {c} (FlagEQ) yes no) && c.(s390x.CCMask) & s390x.Equal != 0 -> (First yes no)
(BRC {c} (FlagLT) yes no) && c.(s390x.CCMask) & s390x.Less != 0 -> (First yes no)
(BRC {c} (FlagGT) yes no) && c.(s390x.CCMask) & s390x.Greater != 0 -> (First yes no)
(BRC {c} (FlagOV) yes no) && c.(s390x.CCMask) & s390x.Unordered != 0 -> (First yes no)
(BRC {c} (FlagEQ) yes no) && c.(s390x.CCMask) & s390x.Equal == 0 -> (First nil no yes)
(BRC {c} (FlagLT) yes no) && c.(s390x.CCMask) & s390x.Less == 0 -> (First nil no yes)
(BRC {c} (FlagGT) yes no) && c.(s390x.CCMask) & s390x.Greater == 0 -> (First nil no yes)
(BRC {c} (FlagOV) yes no) && c.(s390x.CCMask) & s390x.Unordered == 0 -> (First nil no yes)
(BRC {c} (FlagEQ) yes no) && c.(s390x.CCMask) & s390x.Equal == 0 -> (First no yes)
(BRC {c} (FlagLT) yes no) && c.(s390x.CCMask) & s390x.Less == 0 -> (First no yes)
(BRC {c} (FlagGT) yes no) && c.(s390x.CCMask) & s390x.Greater == 0 -> (First no yes)
(BRC {c} (FlagOV) yes no) && c.(s390x.CCMask) & s390x.Unordered == 0 -> (First no yes)
// Absorb flag constants into SETxx ops.
(LOCGR {c} _ x (FlagEQ)) && c.(s390x.CCMask) & s390x.Equal != 0 -> x

View file

@ -708,7 +708,7 @@ func init() {
}
var S390Xblocks = []blockData{
{name: "BRC"}, // aux is condition code mask (s390x.CCMask)
{name: "BRC", controls: 1}, // aux is condition code mask (s390x.CCMask)
}
archs = append(archs, arch{

View file

@ -879,8 +879,8 @@
(NilCheck (GetG mem) mem) -> mem
(If (Not cond) yes no) -> (If cond no yes)
(If (ConstBool [c]) yes no) && c == 1 -> (First nil yes no)
(If (ConstBool [c]) yes no) && c == 0 -> (First nil no yes)
(If (ConstBool [c]) yes no) && c == 1 -> (First yes no)
(If (ConstBool [c]) yes no) && c == 0 -> (First no yes)
// Get rid of Convert ops for pointer arithmetic on unsafe.Pointer.
(Convert (Add(64|32) (Convert ptr mem) off) mem) -> (Add(64|32) ptr off)

View file

@ -557,24 +557,22 @@ var genericOps = []opData{
{name: "Clobber", argLength: 0, typ: "Void", aux: "SymOff", symEffect: "None"}, // write an invalid pointer value to the given pointer slot of a stack variable
}
// kind control successors implicit exit
// kind controls successors implicit exit
// ----------------------------------------------------------
// Exit return mem [] yes
// Ret return mem [] yes
// RetJmp return mem [] yes
// Plain nil [next]
// If a boolean Value [then, else]
// Call mem [next] yes (control opcode should be OpCall or OpStaticCall)
// Check void [next] yes (control opcode should be Op{Lowered}NilCheck)
// First nil [always,never]
// Exit [return mem] [] yes
// Ret [return mem] [] yes
// RetJmp [return mem] [] yes
// Plain [] [next]
// If [boolean Value] [then, else]
// First [] [always, never]
var genericBlocks = []blockData{
{name: "Plain"}, // a single successor
{name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1]
{name: "Defer"}, // 2 successors, Succs[0]=defer queued, Succs[1]=defer recovered. control is call op (of memory type)
{name: "Ret"}, // no successors, control value is memory result
{name: "RetJmp"}, // no successors, jumps to b.Aux.(*gc.Sym)
{name: "Exit"}, // no successors, control value generates a panic
{name: "If", controls: 1}, // if Controls[0] goto Succs[0] else goto Succs[1]
{name: "Defer", controls: 1}, // Succs[0]=defer queued, Succs[1]=defer recovered. Controls[0] is call op (of memory type)
{name: "Ret", controls: 1}, // no successors, Controls[0] value is memory result
{name: "RetJmp", controls: 1}, // no successors, Controls[0] value is memory result, jumps to b.Aux.(*gc.Sym)
{name: "Exit", controls: 1}, // no successors, Controls[0] value generates a panic
// transient block state used for dead code removal
{name: "First"}, // 2 successors, always takes the first one (second is dead)

View file

@ -68,7 +68,8 @@ type opData struct {
}
type blockData struct {
name string
name string // the suffix for this block ("EQ", "LT", etc.)
controls int // the number of control values this type of block requires
}
type regInfo struct {

View file

@ -238,7 +238,6 @@ func genRulesSuffix(arch arch, suff string) {
fn = &Func{kind: "Block"}
fn.add(declf("config", "b.Func.Config"))
fn.add(declf("typ", "&b.Func.Config.Types"))
fn.add(declf("v", "b.Control"))
sw = &Switch{expr: exprf("b.Kind")}
ops = ops[:0]
@ -247,9 +246,10 @@ func genRulesSuffix(arch arch, suff string) {
}
sort.Strings(ops)
for _, op := range ops {
swc := &Case{expr: exprf("%s", blockName(op, arch))}
name, data := getBlockInfo(op, arch)
swc := &Case{expr: exprf("%s", name)}
for _, rule := range blockrules[op] {
swc.add(genBlockRewrite(rule, arch))
swc.add(genBlockRewrite(rule, arch, data))
}
sw.add(swc)
}
@ -593,11 +593,7 @@ func fprint(w io.Writer, n Node) {
fmt.Fprintf(w, "// cond: %s\n", n.cond)
}
fmt.Fprintf(w, "// result: %s\n", n.result)
if n.checkOp != "" {
fmt.Fprintf(w, "for v.Op == %s {\n", n.checkOp)
} else {
fmt.Fprintf(w, "for {\n")
}
fmt.Fprintf(w, "for %s {\n", n.check)
for _, n := range n.list {
fprint(w, n)
}
@ -700,7 +696,7 @@ type (
RuleRewrite struct {
bodyBase
match, cond, result string // top comments
checkOp string
check string // top-level boolean expression
alloc int // for unique var names
loc string // file name & line number of the original rule
@ -750,18 +746,39 @@ func breakf(format string, a ...interface{}) *CondBreak {
return &CondBreak{exprf(format, a...)}
}
func genBlockRewrite(rule Rule, arch arch) *RuleRewrite {
func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
rr := &RuleRewrite{loc: rule.loc}
rr.match, rr.cond, rr.result = rule.parse()
_, _, _, aux, s := extract(rr.match) // remove parens, then split
// check match of control value
pos := ""
if s[0] != "nil" {
if strings.Contains(s[0], "(") {
pos, rr.checkOp = genMatch0(rr, arch, s[0], "v")
// check match of control values
if len(s) < data.controls {
log.Fatalf("incorrect number of arguments in %s, got %v wanted at least %v", rule, len(s), data.controls)
}
controls := s[:data.controls]
pos := make([]string, data.controls)
for i, arg := range controls {
if strings.Contains(arg, "(") {
// TODO: allow custom names?
cname := fmt.Sprintf("b.Controls[%v]", i)
vname := fmt.Sprintf("v_%v", i)
rr.add(declf(vname, cname))
p, op := genMatch0(rr, arch, arg, vname)
if op != "" {
check := fmt.Sprintf("%s.Op == %s", cname, op)
if rr.check == "" {
rr.check = check
} else {
rr.add(declf(s[0], "b.Control"))
rr.check = rr.check + " && " + check
}
}
if p == "" {
p = vname + ".Pos"
}
pos[i] = p
} else {
rr.add(declf(arg, "b.Controls[%v]", i))
pos[i] = arg + ".Pos"
}
}
if aux != "" {
@ -773,10 +790,14 @@ func genBlockRewrite(rule Rule, arch arch) *RuleRewrite {
// Rule matches. Generate result.
outop, _, _, aux, t := extract(rr.result) // remove parens, then split
newsuccs := t[1:]
_, outdata := getBlockInfo(outop, arch)
if len(t) < outdata.controls {
log.Fatalf("incorrect number of output arguments in %s, got %v wanted at least %v", rule, len(s), outdata.controls)
}
// Check if newsuccs is the same set as succs.
succs := s[1:]
succs := s[data.controls:]
newsuccs := t[outdata.controls:]
m := map[string]bool{}
for _, succ := range succs {
if m[succ] {
@ -794,15 +815,23 @@ func genBlockRewrite(rule Rule, arch arch) *RuleRewrite {
log.Fatalf("unmatched successors %v in %s", m, rule)
}
rr.add(stmtf("b.Kind = %s", blockName(outop, arch)))
if t[0] == "nil" {
rr.add(stmtf("b.SetControl(nil)"))
} else {
if pos == "" {
pos = "v.Pos"
blockName, _ := getBlockInfo(outop, arch)
rr.add(stmtf("b.Kind = %s", blockName))
rr.add(stmtf("b.ResetControls()"))
for i, control := range t[:outdata.controls] {
// Select a source position for any new control values.
// TODO: does it always make sense to use the source position
// of the original control values or should we be using the
// block's source position in some cases?
newpos := "b.Pos" // default to block's source position
if i < len(pos) && pos[i] != "" {
// Use the previous control value's source position.
newpos = pos[i]
}
v := genResult0(rr, arch, t[0], false, false, pos)
rr.add(stmtf("b.SetControl(%s)", v))
// Generate a new control value (or copy an existing value).
v := genResult0(rr, arch, control, false, false, newpos)
rr.add(stmtf("b.AddControl(%s)", v))
}
if aux != "" {
rr.add(stmtf("b.Aux = %s", aux))
@ -1164,13 +1193,19 @@ func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxi
return
}
func blockName(name string, arch arch) string {
func getBlockInfo(op string, arch arch) (name string, data blockData) {
for _, b := range genericBlocks {
if b.name == name {
return "Block" + name
if b.name == op {
return "Block" + op, b
}
}
return "Block" + arch.name + name
for _, b := range arch.blocks {
if b.name == op {
return "Block" + arch.name + op, b
}
}
log.Fatalf("could not find block data for %s", op)
panic("unreachable")
}
// typeName returns the string to use to generate a type.

View file

@ -846,8 +846,8 @@ func (b *Block) LongHTML() string {
if b.Aux != nil {
s += html.EscapeString(fmt.Sprintf(" {%v}", b.Aux))
}
if b.Control != nil {
s += fmt.Sprintf(" %s", b.Control.HTML())
for _, c := range b.ControlValues() {
s += fmt.Sprintf(" %s", c.HTML())
}
if len(b.Succs) > 0 {
s += " &#8594;" // right arrow

View file

@ -96,17 +96,18 @@ func findIndVar(f *Func) []indVar {
// Check thet the control if it either ind </<= max or max >/>= ind.
// TODO: Handle 32-bit comparisons.
// TODO: Handle unsigned comparisons?
switch b.Control.Op {
c := b.Controls[0]
switch c.Op {
case OpLeq64:
flags |= indVarMaxInc
fallthrough
case OpLess64:
ind, max = b.Control.Args[0], b.Control.Args[1]
ind, max = c.Args[0], c.Args[1]
case OpGeq64:
flags |= indVarMaxInc
fallthrough
case OpGreater64:
ind, max = b.Control.Args[1], b.Control.Args[0]
ind, max = c.Args[1], c.Args[0]
default:
continue
}
@ -207,7 +208,7 @@ func findIndVar(f *Func) []indVar {
}
// Handle induction variables of these forms.
// KNN is known-not-negative.
// SIGNED ARITHMETIC ONLY. (see switch on b.Control.Op above)
// SIGNED ARITHMETIC ONLY. (see switch on c above)
// Possibilities for KNN are len and cap; perhaps we can infer others.
// for i := 0; i <= KNN-k ; i += k
// for i := 0; i < KNN-(k-1); i += k

View file

@ -99,9 +99,8 @@ func nilcheckelim(f *Func) {
// First, see if we're dominated by an explicit nil check.
if len(b.Preds) == 1 {
p := b.Preds[0].b
if p.Kind == BlockIf && p.Control.Op == OpIsNonNil && p.Succs[0].b == b {
ptr := p.Control.Args[0]
if !nonNilValues[ptr.ID] {
if p.Kind == BlockIf && p.Controls[0].Op == OpIsNonNil && p.Succs[0].b == b {
if ptr := p.Controls[0].Args[0]; !nonNilValues[ptr.ID] {
nonNilValues[ptr.ID] = true
work = append(work, bp{op: ClearPtr, ptr: ptr})
}

View file

@ -59,7 +59,7 @@ func ptrn(n int) string { return "p" + strconv.Itoa(n) }
func booln(n int) string { return "c" + strconv.Itoa(n) }
func isNilCheck(b *Block) bool {
return b.Kind == BlockIf && b.Control.Op == OpIsNonNil
return b.Kind == BlockIf && b.Controls[0].Op == OpIsNonNil
}
// TestNilcheckSimple verifies that a second repeated nilcheck is removed.

View file

@ -79,7 +79,7 @@ func phiopt(f *Func) {
if v.Args[reverse].AuxInt != v.Args[1-reverse].AuxInt {
ops := [2]Op{OpNot, OpCopy}
v.reset(ops[v.Args[reverse].AuxInt])
v.AddArg(b0.Control)
v.AddArg(b0.Controls[0])
if f.pass.debug > 0 {
f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
}
@ -95,7 +95,7 @@ func phiopt(f *Func) {
if v.Args[reverse].Op == OpConstBool && v.Args[reverse].AuxInt == 1 {
if tmp := v.Args[1-reverse]; sdom.isAncestorEq(tmp.Block, b) {
v.reset(OpOrB)
v.SetArgs2(b0.Control, tmp)
v.SetArgs2(b0.Controls[0], tmp)
if f.pass.debug > 0 {
f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
}
@ -111,7 +111,7 @@ func phiopt(f *Func) {
if v.Args[1-reverse].Op == OpConstBool && v.Args[1-reverse].AuxInt == 0 {
if tmp := v.Args[reverse]; sdom.isAncestorEq(tmp.Block, b) {
v.reset(OpAndB)
v.SetArgs2(b0.Control, tmp)
v.SetArgs2(b0.Controls[0], tmp)
if f.pass.debug > 0 {
f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
}
@ -161,7 +161,7 @@ func phioptint(v *Value, b0 *Block, reverse int) {
v.Fatalf("bad int size %d", v.Type.Size())
}
a := b0.Control
a := b0.Controls[0]
if negate {
a = v.Block.NewValue1(v.Pos, OpNot, a.Type, a)
}

View file

@ -979,7 +979,7 @@ func addIndVarRestrictions(ft *factsTable, b *Block, iv indVar) {
// addBranchRestrictions updates the factsTables ft with the facts learned when
// branching from Block b in direction br.
func addBranchRestrictions(ft *factsTable, b *Block, br branch) {
c := b.Control
c := b.Controls[0]
switch br {
case negative:
addRestrictions(b, ft, boolean, nil, c, eq)
@ -988,14 +988,14 @@ func addBranchRestrictions(ft *factsTable, b *Block, br branch) {
default:
panic("unknown branch")
}
if tr, has := domainRelationTable[b.Control.Op]; has {
if tr, has := domainRelationTable[c.Op]; has {
// When we branched from parent we learned a new set of
// restrictions. Update the factsTable accordingly.
d := tr.d
if d == signed && ft.isNonNegative(c.Args[0]) && ft.isNonNegative(c.Args[1]) {
d |= unsigned
}
switch b.Control.Op {
switch c.Op {
case OpIsInBounds, OpIsSliceInBounds:
// 0 <= a0 < a1 (or 0 <= a0 <= a1)
//
@ -1096,6 +1096,7 @@ func addLocalInductiveFacts(ft *factsTable, b *Block) {
if pred.Kind != BlockIf {
continue
}
control := pred.Controls[0]
br := unknown
if pred.Succs[0].b == child {
@ -1108,7 +1109,7 @@ func addLocalInductiveFacts(ft *factsTable, b *Block) {
br = negative
}
tr, has := domainRelationTable[pred.Control.Op]
tr, has := domainRelationTable[control.Op]
if !has {
continue
}
@ -1121,10 +1122,10 @@ func addLocalInductiveFacts(ft *factsTable, b *Block) {
// Check for i2 < max or max > i2.
var max *Value
if r == lt && pred.Control.Args[0] == i2 {
max = pred.Control.Args[1]
} else if r == gt && pred.Control.Args[1] == i2 {
max = pred.Control.Args[0]
if r == lt && control.Args[0] == i2 {
max = control.Args[1]
} else if r == gt && control.Args[1] == i2 {
max = control.Args[0]
} else {
continue
}
@ -1288,7 +1289,7 @@ func removeBranch(b *Block, branch branch) {
if branch == positive {
verb = "Disproved"
}
c := b.Control
c := b.Controls[0]
if b.Func.pass.debug > 1 {
b.Func.Warnl(b.Pos, "%s %s (%s)", verb, c.Op, c)
} else {
@ -1296,7 +1297,7 @@ func removeBranch(b *Block, branch branch) {
}
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
if branch == positive {
b.swapSuccessors()
}

View file

@ -701,8 +701,10 @@ func (s *regAllocState) init(f *Func) {
for _, b := range f.Blocks {
// New block. Clear candidate set.
canLiveOnStack.clear()
if b.Control != nil && b.Control.Uses == 1 && !opcodeTable[b.Control.Op].generic {
canLiveOnStack.add(b.Control.ID)
for _, c := range b.ControlValues() {
if c.Uses == 1 && !opcodeTable[c.Op].generic {
canLiveOnStack.add(c.ID)
}
}
// Walking backwards.
for i := len(b.Values) - 1; i >= 0; i-- {
@ -856,10 +858,12 @@ func (s *regAllocState) regalloc(f *Func) {
s.addUse(e.ID, int32(len(b.Values))+e.dist, e.pos) // pseudo-uses from beyond end of block
regValLiveSet.add(e.ID)
}
if v := b.Control; v != nil && s.values[v.ID].needReg {
s.addUse(v.ID, int32(len(b.Values)), b.Pos) // pseudo-use by control value
for _, v := range b.ControlValues() {
if s.values[v.ID].needReg {
s.addUse(v.ID, int32(len(b.Values)), b.Pos) // pseudo-use by control values
regValLiveSet.add(v.ID)
}
}
for i := len(b.Values) - 1; i >= 0; i-- {
v := b.Values[i]
regValLiveSet.remove(v.ID)
@ -1503,21 +1507,32 @@ func (s *regAllocState) regalloc(f *Func) {
issueSpill:
}
// Load control value into reg.
if v := b.Control; v != nil && s.values[v.ID].needReg {
// Copy the control values - we need this so we can reduce the
// uses property of these values later.
controls := append(make([]*Value, 0, 2), b.ControlValues()...)
// Load control values into registers.
for i, v := range b.ControlValues() {
if !s.values[v.ID].needReg {
continue
}
if s.f.pass.debug > regDebug {
fmt.Printf(" processing control %s\n", v.LongString())
}
// We assume that a control input can be passed in any
// type-compatible register. If this turns out not to be true,
// we'll need to introduce a regspec for a block's control value.
b.Control = s.allocValToReg(v, s.compatRegs(v.Type), false, b.Pos)
if b.Control != v {
v.Uses--
b.Control.Uses++
b.ReplaceControl(i, s.allocValToReg(v, s.compatRegs(v.Type), false, b.Pos))
}
// Reduce the uses of the control values once registers have been loaded.
// This loop is equivalent to the advanceUses method.
for _, v := range controls {
vi := &s.values[v.ID]
if !vi.needReg {
continue
}
// Remove this use from the uses list.
vi := &s.values[v.ID]
u := vi.uses
vi.uses = u.next
if u.next == nil {
@ -2355,9 +2370,11 @@ func (s *regAllocState) computeLive() {
live.set(e.ID, e.dist+int32(len(b.Values)), e.pos)
}
// Mark control value as live
if b.Control != nil && s.values[b.Control.ID].needReg {
live.set(b.Control.ID, int32(len(b.Values)), b.Pos)
// Mark control values as live
for _, c := range b.ControlValues() {
if s.values[c.ID].needReg {
live.set(c.ID, int32(len(b.Values)), b.Pos)
}
}
// Propagate backwards to the start of the block

View file

@ -25,9 +25,10 @@ func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter) {
for {
change := false
for _, b := range f.Blocks {
if b.Control != nil && b.Control.Op == OpCopy {
for b.Control.Op == OpCopy {
b.SetControl(b.Control.Args[0])
for i, c := range b.ControlValues() {
for c.Op == OpCopy {
c = c.Args[0]
b.ReplaceControl(i, c)
}
}
if rb(b) {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -8995,182 +8995,207 @@ func rewriteValueMIPS_OpZeromask_0(v *Value) bool {
}
}
func rewriteBlockMIPS(b *Block) bool {
v := b.Control
switch b.Kind {
case BlockMIPSEQ:
// match: (EQ (FPFlagTrue cmp) yes no)
// result: (FPF cmp yes no)
for v.Op == OpMIPSFPFlagTrue {
cmp := v.Args[0]
for b.Controls[0].Op == OpMIPSFPFlagTrue {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
b.Kind = BlockMIPSFPF
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (FPFlagFalse cmp) yes no)
// result: (FPT cmp yes no)
for v.Op == OpMIPSFPFlagFalse {
cmp := v.Args[0]
for b.Controls[0].Op == OpMIPSFPFlagFalse {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
b.Kind = BlockMIPSFPT
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGT _ _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGT {
break
}
_ = cmp.Args[1]
b.Kind = BlockMIPSNE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGTU _ _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTU {
break
}
_ = cmp.Args[1]
b.Kind = BlockMIPSNE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGTconst _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTconst {
break
}
b.Kind = BlockMIPSNE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGTUconst _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTUconst {
break
}
b.Kind = BlockMIPSNE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGTzero _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTzero {
break
}
b.Kind = BlockMIPSNE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGTUzero _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTUzero {
break
}
b.Kind = BlockMIPSNE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (SGTUconst [1] x) yes no)
// result: (NE x yes no)
for v.Op == OpMIPSSGTUconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSSGTUconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
x := v.Args[0]
x := v_0.Args[0]
b.Kind = BlockMIPSNE
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (EQ (SGTUzero x) yes no)
// result: (EQ x yes no)
for v.Op == OpMIPSSGTUzero {
x := v.Args[0]
for b.Controls[0].Op == OpMIPSSGTUzero {
v_0 := b.Controls[0]
x := v_0.Args[0]
b.Kind = BlockMIPSEQ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (EQ (SGTconst [0] x) yes no)
// result: (GEZ x yes no)
for v.Op == OpMIPSSGTconst {
if v.AuxInt != 0 {
for b.Controls[0].Op == OpMIPSSGTconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
x := v.Args[0]
x := v_0.Args[0]
b.Kind = BlockMIPSGEZ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (EQ (SGTzero x) yes no)
// result: (LEZ x yes no)
for v.Op == OpMIPSSGTzero {
x := v.Args[0]
for b.Controls[0].Op == OpMIPSSGTzero {
v_0 := b.Controls[0]
x := v_0.Args[0]
b.Kind = BlockMIPSLEZ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (EQ (MOVWconst [0]) yes no)
// result: (First nil yes no)
for v.Op == OpMIPSMOVWconst {
if v.AuxInt != 0 {
// result: (First yes no)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (EQ (MOVWconst [c]) yes no)
// cond: c != 0
// result: (First nil no yes)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c != 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -9178,27 +9203,29 @@ func rewriteBlockMIPS(b *Block) bool {
case BlockMIPSGEZ:
// match: (GEZ (MOVWconst [c]) yes no)
// cond: int32(c) >= 0
// result: (First nil yes no)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(int32(c) >= 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (GEZ (MOVWconst [c]) yes no)
// cond: int32(c) < 0
// result: (First nil no yes)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(int32(c) < 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -9206,27 +9233,29 @@ func rewriteBlockMIPS(b *Block) bool {
case BlockMIPSGTZ:
// match: (GTZ (MOVWconst [c]) yes no)
// cond: int32(c) > 0
// result: (First nil yes no)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(int32(c) > 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (GTZ (MOVWconst [c]) yes no)
// cond: int32(c) <= 0
// result: (First nil no yes)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(int32(c) <= 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -9235,36 +9264,39 @@ func rewriteBlockMIPS(b *Block) bool {
// match: (If cond yes no)
// result: (NE cond yes no)
for {
cond := b.Control
cond := b.Controls[0]
b.Kind = BlockMIPSNE
b.SetControl(cond)
b.ResetControls()
b.AddControl(cond)
b.Aux = nil
return true
}
case BlockMIPSLEZ:
// match: (LEZ (MOVWconst [c]) yes no)
// cond: int32(c) <= 0
// result: (First nil yes no)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(int32(c) <= 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (LEZ (MOVWconst [c]) yes no)
// cond: int32(c) > 0
// result: (First nil no yes)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(int32(c) > 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -9272,27 +9304,29 @@ func rewriteBlockMIPS(b *Block) bool {
case BlockMIPSLTZ:
// match: (LTZ (MOVWconst [c]) yes no)
// cond: int32(c) < 0
// result: (First nil yes no)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(int32(c) < 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (LTZ (MOVWconst [c]) yes no)
// cond: int32(c) >= 0
// result: (First nil no yes)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(int32(c) >= 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -9300,178 +9334,204 @@ func rewriteBlockMIPS(b *Block) bool {
case BlockMIPSNE:
// match: (NE (FPFlagTrue cmp) yes no)
// result: (FPT cmp yes no)
for v.Op == OpMIPSFPFlagTrue {
cmp := v.Args[0]
for b.Controls[0].Op == OpMIPSFPFlagTrue {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
b.Kind = BlockMIPSFPT
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (FPFlagFalse cmp) yes no)
// result: (FPF cmp yes no)
for v.Op == OpMIPSFPFlagFalse {
cmp := v.Args[0]
for b.Controls[0].Op == OpMIPSFPFlagFalse {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
b.Kind = BlockMIPSFPF
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGT _ _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGT {
break
}
_ = cmp.Args[1]
b.Kind = BlockMIPSEQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGTU _ _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTU {
break
}
_ = cmp.Args[1]
b.Kind = BlockMIPSEQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGTconst _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTconst {
break
}
b.Kind = BlockMIPSEQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGTUconst _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTUconst {
break
}
b.Kind = BlockMIPSEQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGTzero _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTzero {
break
}
b.Kind = BlockMIPSEQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGTUzero _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPSXORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSXORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPSSGTUzero {
break
}
b.Kind = BlockMIPSEQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (SGTUconst [1] x) yes no)
// result: (EQ x yes no)
for v.Op == OpMIPSSGTUconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPSSGTUconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
x := v.Args[0]
x := v_0.Args[0]
b.Kind = BlockMIPSEQ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (NE (SGTUzero x) yes no)
// result: (NE x yes no)
for v.Op == OpMIPSSGTUzero {
x := v.Args[0]
for b.Controls[0].Op == OpMIPSSGTUzero {
v_0 := b.Controls[0]
x := v_0.Args[0]
b.Kind = BlockMIPSNE
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (NE (SGTconst [0] x) yes no)
// result: (LTZ x yes no)
for v.Op == OpMIPSSGTconst {
if v.AuxInt != 0 {
for b.Controls[0].Op == OpMIPSSGTconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
x := v.Args[0]
x := v_0.Args[0]
b.Kind = BlockMIPSLTZ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (NE (SGTzero x) yes no)
// result: (GTZ x yes no)
for v.Op == OpMIPSSGTzero {
x := v.Args[0]
for b.Controls[0].Op == OpMIPSSGTzero {
v_0 := b.Controls[0]
x := v_0.Args[0]
b.Kind = BlockMIPSGTZ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (NE (MOVWconst [0]) yes no)
// result: (First nil no yes)
for v.Op == OpMIPSMOVWconst {
if v.AuxInt != 0 {
// result: (First no yes)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
}
// match: (NE (MOVWconst [c]) yes no)
// cond: c != 0
// result: (First nil yes no)
for v.Op == OpMIPSMOVWconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPSMOVWconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c != 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}

View file

@ -9740,162 +9740,183 @@ func rewriteValueMIPS64_OpZeroExt8to64_0(v *Value) bool {
}
}
func rewriteBlockMIPS64(b *Block) bool {
v := b.Control
switch b.Kind {
case BlockMIPS64EQ:
// match: (EQ (FPFlagTrue cmp) yes no)
// result: (FPF cmp yes no)
for v.Op == OpMIPS64FPFlagTrue {
cmp := v.Args[0]
for b.Controls[0].Op == OpMIPS64FPFlagTrue {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
b.Kind = BlockMIPS64FPF
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (FPFlagFalse cmp) yes no)
// result: (FPT cmp yes no)
for v.Op == OpMIPS64FPFlagFalse {
cmp := v.Args[0]
for b.Controls[0].Op == OpMIPS64FPFlagFalse {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
b.Kind = BlockMIPS64FPT
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGT _ _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPS64XORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64XORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPS64SGT {
break
}
_ = cmp.Args[1]
b.Kind = BlockMIPS64NE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGTU _ _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPS64XORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64XORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPS64SGTU {
break
}
_ = cmp.Args[1]
b.Kind = BlockMIPS64NE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGTconst _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPS64XORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64XORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPS64SGTconst {
break
}
b.Kind = BlockMIPS64NE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (XORconst [1] cmp:(SGTUconst _)) yes no)
// result: (NE cmp yes no)
for v.Op == OpMIPS64XORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64XORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPS64SGTUconst {
break
}
b.Kind = BlockMIPS64NE
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (EQ (SGTUconst [1] x) yes no)
// result: (NE x yes no)
for v.Op == OpMIPS64SGTUconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64SGTUconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
x := v.Args[0]
x := v_0.Args[0]
b.Kind = BlockMIPS64NE
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (EQ (SGTU x (MOVVconst [0])) yes no)
// result: (EQ x yes no)
for v.Op == OpMIPS64SGTU {
_ = v.Args[1]
x := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpMIPS64MOVVconst || v_1.AuxInt != 0 {
for b.Controls[0].Op == OpMIPS64SGTU {
v_0 := b.Controls[0]
_ = v_0.Args[1]
x := v_0.Args[0]
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpMIPS64MOVVconst || v_0_1.AuxInt != 0 {
break
}
b.Kind = BlockMIPS64EQ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (EQ (SGTconst [0] x) yes no)
// result: (GEZ x yes no)
for v.Op == OpMIPS64SGTconst {
if v.AuxInt != 0 {
for b.Controls[0].Op == OpMIPS64SGTconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
x := v.Args[0]
x := v_0.Args[0]
b.Kind = BlockMIPS64GEZ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (EQ (SGT x (MOVVconst [0])) yes no)
// result: (LEZ x yes no)
for v.Op == OpMIPS64SGT {
_ = v.Args[1]
x := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpMIPS64MOVVconst || v_1.AuxInt != 0 {
for b.Controls[0].Op == OpMIPS64SGT {
v_0 := b.Controls[0]
_ = v_0.Args[1]
x := v_0.Args[0]
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpMIPS64MOVVconst || v_0_1.AuxInt != 0 {
break
}
b.Kind = BlockMIPS64LEZ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (EQ (MOVVconst [0]) yes no)
// result: (First nil yes no)
for v.Op == OpMIPS64MOVVconst {
if v.AuxInt != 0 {
// result: (First yes no)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (EQ (MOVVconst [c]) yes no)
// cond: c != 0
// result: (First nil no yes)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c != 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -9903,27 +9924,29 @@ func rewriteBlockMIPS64(b *Block) bool {
case BlockMIPS64GEZ:
// match: (GEZ (MOVVconst [c]) yes no)
// cond: c >= 0
// result: (First nil yes no)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c >= 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (GEZ (MOVVconst [c]) yes no)
// cond: c < 0
// result: (First nil no yes)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c < 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -9931,27 +9954,29 @@ func rewriteBlockMIPS64(b *Block) bool {
case BlockMIPS64GTZ:
// match: (GTZ (MOVVconst [c]) yes no)
// cond: c > 0
// result: (First nil yes no)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c > 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (GTZ (MOVVconst [c]) yes no)
// cond: c <= 0
// result: (First nil no yes)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c <= 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -9960,36 +9985,39 @@ func rewriteBlockMIPS64(b *Block) bool {
// match: (If cond yes no)
// result: (NE cond yes no)
for {
cond := b.Control
cond := b.Controls[0]
b.Kind = BlockMIPS64NE
b.SetControl(cond)
b.ResetControls()
b.AddControl(cond)
b.Aux = nil
return true
}
case BlockMIPS64LEZ:
// match: (LEZ (MOVVconst [c]) yes no)
// cond: c <= 0
// result: (First nil yes no)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c <= 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (LEZ (MOVVconst [c]) yes no)
// cond: c > 0
// result: (First nil no yes)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c > 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -9997,27 +10025,29 @@ func rewriteBlockMIPS64(b *Block) bool {
case BlockMIPS64LTZ:
// match: (LTZ (MOVVconst [c]) yes no)
// cond: c < 0
// result: (First nil yes no)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c < 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (LTZ (MOVVconst [c]) yes no)
// cond: c >= 0
// result: (First nil no yes)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c >= 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -10025,158 +10055,180 @@ func rewriteBlockMIPS64(b *Block) bool {
case BlockMIPS64NE:
// match: (NE (FPFlagTrue cmp) yes no)
// result: (FPT cmp yes no)
for v.Op == OpMIPS64FPFlagTrue {
cmp := v.Args[0]
for b.Controls[0].Op == OpMIPS64FPFlagTrue {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
b.Kind = BlockMIPS64FPT
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (FPFlagFalse cmp) yes no)
// result: (FPF cmp yes no)
for v.Op == OpMIPS64FPFlagFalse {
cmp := v.Args[0]
for b.Controls[0].Op == OpMIPS64FPFlagFalse {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
b.Kind = BlockMIPS64FPF
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGT _ _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPS64XORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64XORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPS64SGT {
break
}
_ = cmp.Args[1]
b.Kind = BlockMIPS64EQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGTU _ _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPS64XORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64XORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPS64SGTU {
break
}
_ = cmp.Args[1]
b.Kind = BlockMIPS64EQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGTconst _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPS64XORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64XORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPS64SGTconst {
break
}
b.Kind = BlockMIPS64EQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (XORconst [1] cmp:(SGTUconst _)) yes no)
// result: (EQ cmp yes no)
for v.Op == OpMIPS64XORconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64XORconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
cmp := v.Args[0]
cmp := v_0.Args[0]
if cmp.Op != OpMIPS64SGTUconst {
break
}
b.Kind = BlockMIPS64EQ
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = nil
return true
}
// match: (NE (SGTUconst [1] x) yes no)
// result: (EQ x yes no)
for v.Op == OpMIPS64SGTUconst {
if v.AuxInt != 1 {
for b.Controls[0].Op == OpMIPS64SGTUconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 1 {
break
}
x := v.Args[0]
x := v_0.Args[0]
b.Kind = BlockMIPS64EQ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (NE (SGTU x (MOVVconst [0])) yes no)
// result: (NE x yes no)
for v.Op == OpMIPS64SGTU {
_ = v.Args[1]
x := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpMIPS64MOVVconst || v_1.AuxInt != 0 {
for b.Controls[0].Op == OpMIPS64SGTU {
v_0 := b.Controls[0]
_ = v_0.Args[1]
x := v_0.Args[0]
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpMIPS64MOVVconst || v_0_1.AuxInt != 0 {
break
}
b.Kind = BlockMIPS64NE
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (NE (SGTconst [0] x) yes no)
// result: (LTZ x yes no)
for v.Op == OpMIPS64SGTconst {
if v.AuxInt != 0 {
for b.Controls[0].Op == OpMIPS64SGTconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
x := v.Args[0]
x := v_0.Args[0]
b.Kind = BlockMIPS64LTZ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (NE (SGT x (MOVVconst [0])) yes no)
// result: (GTZ x yes no)
for v.Op == OpMIPS64SGT {
_ = v.Args[1]
x := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpMIPS64MOVVconst || v_1.AuxInt != 0 {
for b.Controls[0].Op == OpMIPS64SGT {
v_0 := b.Controls[0]
_ = v_0.Args[1]
x := v_0.Args[0]
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpMIPS64MOVVconst || v_0_1.AuxInt != 0 {
break
}
b.Kind = BlockMIPS64GTZ
b.SetControl(x)
b.ResetControls()
b.AddControl(x)
b.Aux = nil
return true
}
// match: (NE (MOVVconst [0]) yes no)
// result: (First nil no yes)
for v.Op == OpMIPS64MOVVconst {
if v.AuxInt != 0 {
// result: (First no yes)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
}
// match: (NE (MOVVconst [c]) yes no)
// cond: c != 0
// result: (First nil yes no)
for v.Op == OpMIPS64MOVVconst {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpMIPS64MOVVconst {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c != 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}

File diff suppressed because it is too large Load diff

View file

@ -36449,37 +36449,38 @@ func rewriteValueS390X_OpZeroExt8to64_0(v *Value) bool {
}
func rewriteBlockS390X(b *Block) bool {
typ := &b.Func.Config.Types
v := b.Control
switch b.Kind {
case BlockS390XBRC:
// match: (BRC {c} (CMPWconst [0] (LOCGR {d} (MOVDconst [0]) (MOVDconst [x]) cmp)) yes no)
// cond: x != 0 && c.(s390x.CCMask) == s390x.Equal
// result: (BRC {d} cmp no yes)
for v.Op == OpS390XCMPWconst {
if v.AuxInt != 0 {
for b.Controls[0].Op == OpS390XCMPWconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpS390XLOCGR {
break
}
d := v_0.Aux
cmp := v_0.Args[2]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpS390XMOVDconst || v_0_0.AuxInt != 0 {
if v_0_0.Op != OpS390XLOCGR {
break
}
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpS390XMOVDconst {
d := v_0_0.Aux
cmp := v_0_0.Args[2]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpS390XMOVDconst || v_0_0_0.AuxInt != 0 {
break
}
x := v_0_1.AuxInt
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpS390XMOVDconst {
break
}
x := v_0_0_1.AuxInt
c := b.Aux
if !(x != 0 && c.(s390x.CCMask) == s390x.Equal) {
break
}
b.Kind = BlockS390XBRC
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = d
b.swapSuccessors()
return true
@ -36487,148 +36488,152 @@ func rewriteBlockS390X(b *Block) bool {
// match: (BRC {c} (CMPWconst [0] (LOCGR {d} (MOVDconst [0]) (MOVDconst [x]) cmp)) yes no)
// cond: x != 0 && c.(s390x.CCMask) == s390x.NotEqual
// result: (BRC {d} cmp yes no)
for v.Op == OpS390XCMPWconst {
if v.AuxInt != 0 {
for b.Controls[0].Op == OpS390XCMPWconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpS390XLOCGR {
break
}
d := v_0.Aux
cmp := v_0.Args[2]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpS390XMOVDconst || v_0_0.AuxInt != 0 {
if v_0_0.Op != OpS390XLOCGR {
break
}
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpS390XMOVDconst {
d := v_0_0.Aux
cmp := v_0_0.Args[2]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpS390XMOVDconst || v_0_0_0.AuxInt != 0 {
break
}
x := v_0_1.AuxInt
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpS390XMOVDconst {
break
}
x := v_0_0_1.AuxInt
c := b.Aux
if !(x != 0 && c.(s390x.CCMask) == s390x.NotEqual) {
break
}
b.Kind = BlockS390XBRC
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = d
return true
}
// match: (BRC {c} (InvertFlags cmp) yes no)
// result: (BRC {c.(s390x.CCMask).ReverseComparison()} cmp yes no)
for v.Op == OpS390XInvertFlags {
cmp := v.Args[0]
for b.Controls[0].Op == OpS390XInvertFlags {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
c := b.Aux
b.Kind = BlockS390XBRC
b.SetControl(cmp)
b.ResetControls()
b.AddControl(cmp)
b.Aux = c.(s390x.CCMask).ReverseComparison()
return true
}
// match: (BRC {c} (FlagEQ) yes no)
// cond: c.(s390x.CCMask) & s390x.Equal != 0
// result: (First nil yes no)
for v.Op == OpS390XFlagEQ {
// result: (First yes no)
for b.Controls[0].Op == OpS390XFlagEQ {
c := b.Aux
if !(c.(s390x.CCMask)&s390x.Equal != 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (BRC {c} (FlagLT) yes no)
// cond: c.(s390x.CCMask) & s390x.Less != 0
// result: (First nil yes no)
for v.Op == OpS390XFlagLT {
// result: (First yes no)
for b.Controls[0].Op == OpS390XFlagLT {
c := b.Aux
if !(c.(s390x.CCMask)&s390x.Less != 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (BRC {c} (FlagGT) yes no)
// cond: c.(s390x.CCMask) & s390x.Greater != 0
// result: (First nil yes no)
for v.Op == OpS390XFlagGT {
// result: (First yes no)
for b.Controls[0].Op == OpS390XFlagGT {
c := b.Aux
if !(c.(s390x.CCMask)&s390x.Greater != 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (BRC {c} (FlagOV) yes no)
// cond: c.(s390x.CCMask) & s390x.Unordered != 0
// result: (First nil yes no)
for v.Op == OpS390XFlagOV {
// result: (First yes no)
for b.Controls[0].Op == OpS390XFlagOV {
c := b.Aux
if !(c.(s390x.CCMask)&s390x.Unordered != 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (BRC {c} (FlagEQ) yes no)
// cond: c.(s390x.CCMask) & s390x.Equal == 0
// result: (First nil no yes)
for v.Op == OpS390XFlagEQ {
// result: (First no yes)
for b.Controls[0].Op == OpS390XFlagEQ {
c := b.Aux
if !(c.(s390x.CCMask)&s390x.Equal == 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
}
// match: (BRC {c} (FlagLT) yes no)
// cond: c.(s390x.CCMask) & s390x.Less == 0
// result: (First nil no yes)
for v.Op == OpS390XFlagLT {
// result: (First no yes)
for b.Controls[0].Op == OpS390XFlagLT {
c := b.Aux
if !(c.(s390x.CCMask)&s390x.Less == 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
}
// match: (BRC {c} (FlagGT) yes no)
// cond: c.(s390x.CCMask) & s390x.Greater == 0
// result: (First nil no yes)
for v.Op == OpS390XFlagGT {
// result: (First no yes)
for b.Controls[0].Op == OpS390XFlagGT {
c := b.Aux
if !(c.(s390x.CCMask)&s390x.Greater == 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
}
// match: (BRC {c} (FlagOV) yes no)
// cond: c.(s390x.CCMask) & s390x.Unordered == 0
// result: (First nil no yes)
for v.Op == OpS390XFlagOV {
// result: (First no yes)
for b.Controls[0].Op == OpS390XFlagOV {
c := b.Aux
if !(c.(s390x.CCMask)&s390x.Unordered == 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true
@ -36637,14 +36642,15 @@ func rewriteBlockS390X(b *Block) bool {
// match: (If cond yes no)
// result: (BRC {s390x.NotEqual} (CMPWconst [0] (MOVBZreg <typ.Bool> cond)) yes no)
for {
cond := b.Control
cond := b.Controls[0]
b.Kind = BlockS390XBRC
v0 := b.NewValue0(v.Pos, OpS390XCMPWconst, types.TypeFlags)
b.ResetControls()
v0 := b.NewValue0(cond.Pos, OpS390XCMPWconst, types.TypeFlags)
v0.AuxInt = 0
v1 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.Bool)
v1 := b.NewValue0(cond.Pos, OpS390XMOVBZreg, typ.Bool)
v1.AddArg(cond)
v0.AddArg(v1)
b.SetControl(v0)
b.AddControl(v0)
b.Aux = s390x.NotEqual
return true
}

View file

@ -47407,42 +47407,45 @@ func rewriteValuegeneric_OpZeroExt8to64_0(v *Value) bool {
return false
}
func rewriteBlockgeneric(b *Block) bool {
v := b.Control
switch b.Kind {
case BlockIf:
// match: (If (Not cond) yes no)
// result: (If cond no yes)
for v.Op == OpNot {
cond := v.Args[0]
for b.Controls[0].Op == OpNot {
v_0 := b.Controls[0]
cond := v_0.Args[0]
b.Kind = BlockIf
b.SetControl(cond)
b.ResetControls()
b.AddControl(cond)
b.Aux = nil
b.swapSuccessors()
return true
}
// match: (If (ConstBool [c]) yes no)
// cond: c == 1
// result: (First nil yes no)
for v.Op == OpConstBool {
c := v.AuxInt
// result: (First yes no)
for b.Controls[0].Op == OpConstBool {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c == 1) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
return true
}
// match: (If (ConstBool [c]) yes no)
// cond: c == 0
// result: (First nil no yes)
for v.Op == OpConstBool {
c := v.AuxInt
// result: (First no yes)
for b.Controls[0].Op == OpConstBool {
v_0 := b.Controls[0]
c := v_0.AuxInt
if !(c == 0) {
break
}
b.Kind = BlockFirst
b.SetControl(nil)
b.ResetControls()
b.Aux = nil
b.swapSuccessors()
return true

View file

@ -195,27 +195,31 @@ func schedule(f *Func) {
}
}
if b.Control != nil && b.Control.Op != OpPhi && b.Control.Op != OpArg {
// Force the control value to be scheduled at the end,
// unless it is a phi value (which must be first).
for _, c := range b.ControlValues() {
// Force the control values to be scheduled at the end,
// unless they are phi values (which must be first).
// OpArg also goes first -- if it is stack it register allocates
// to a LoadReg, if it is register it is from the beginning anyway.
score[b.Control.ID] = ScoreControl
if c.Op == OpPhi || c.Op == OpArg {
continue
}
score[c.ID] = ScoreControl
// Schedule values dependent on the control value at the end.
// Schedule values dependent on the control values at the end.
// This reduces the number of register spills. We don't find
// all values that depend on the control, just values with a
// all values that depend on the controls, just values with a
// direct dependency. This is cheaper and in testing there
// was no difference in the number of spills.
for _, v := range b.Values {
if v.Op != OpPhi {
for _, a := range v.Args {
if a == b.Control {
if a == c {
score[v.ID] = ScoreControl
}
}
}
}
}
// To put things into a priority queue

View file

@ -32,7 +32,7 @@ func shortcircuit(f *Func) {
if p.Kind != BlockIf {
continue
}
if p.Control != a {
if p.Controls[0] != a {
continue
}
if e.i == 0 {
@ -103,7 +103,7 @@ func shortcircuitBlock(b *Block) bool {
// Look for control values of the form Copy(Not(Copy(Phi(const, ...)))).
// Those must be the only values in the b, and they each must be used only by b.
// Track the negations so that we can swap successors as needed later.
v := b.Control
v := b.Controls[0]
nval := 1 // the control value
swap := false
for v.Uses == 1 && v.Block == b && (v.Op == OpCopy || v.Op == OpNot) {

View file

@ -23,7 +23,7 @@ func TestSizeof(t *testing.T) {
_64bit uintptr // size on 64bit platforms
}{
{Value{}, 72, 112},
{Block{}, 152, 288},
{Block{}, 156, 296},
{LocalSlot{}, 32, 48},
{valState{}, 28, 40},
}

View file

@ -87,7 +87,7 @@ func tighten(f *Func) {
}
}
}
if c := b.Control; c != nil {
for _, c := range b.ControlValues() {
if !canMove[c.ID] {
continue
}

View file

@ -47,7 +47,7 @@ type Value struct {
// Source position
Pos src.XPos
// Use count. Each appearance in Value.Args and Block.Control counts once.
// Use count. Each appearance in Value.Args and Block.Controls counts once.
Uses int32
// wasm: Value stays on the WebAssembly stack. This value will not get a "register" (WebAssembly variable)

View file

@ -182,7 +182,7 @@ func writebarrier(f *Func) {
b.Pos = pos
// set up control flow for end block
bEnd.SetControl(b.Control)
bEnd.CopyControls(b)
bEnd.Likely = b.Likely
for _, e := range b.Succs {
bEnd.Succs = append(bEnd.Succs, e)

View file

@ -78,20 +78,20 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
switch next {
case b.Succs[0].Block():
// if false, jump to b.Succs[1]
getValue32(s, b.Control)
getValue32(s, b.Controls[0])
s.Prog(wasm.AI32Eqz)
s.Prog(wasm.AIf)
s.Br(obj.AJMP, b.Succs[1].Block())
s.Prog(wasm.AEnd)
case b.Succs[1].Block():
// if true, jump to b.Succs[0]
getValue32(s, b.Control)
getValue32(s, b.Controls[0])
s.Prog(wasm.AIf)
s.Br(obj.AJMP, b.Succs[0].Block())
s.Prog(wasm.AEnd)
default:
// if true, jump to b.Succs[0], else jump to b.Succs[1]
getValue32(s, b.Control)
getValue32(s, b.Controls[0])
s.Prog(wasm.AIf)
s.Br(obj.AJMP, b.Succs[0].Block())
s.Prog(wasm.AEnd)

View file

@ -18,8 +18,8 @@ import (
// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
flive := b.FlagsLiveAtEnd
if b.Control != nil && b.Control.Type.IsFlags() {
flive = true
for _, c := range b.ControlValues() {
flive = c.Type.IsFlags() || flive
}
for i := len(b.Values) - 1; i >= 0; i-- {
v := b.Values[i]
@ -952,6 +952,6 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
}
}
default:
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
b.Fatalf("branch not implemented: %s", b.LongString())
}
}