From a9cec30fdcc549282e0a5d520edb2eaf60f3061a Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 28 May 2015 16:45:33 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: Implement block rewriting rules Change-Id: I47e5349e34fc18118c4d35bf433f875b958cc3e5 Reviewed-on: https://go-review.googlesource.com/10495 Reviewed-by: Alan Donovan --- src/cmd/compile/internal/ssa/deadcode.go | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index a805861489..ba5d8758d9 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -14,30 +14,10 @@ func deadcode(f *Func) { reachable[f.Entry.ID] = true p := []*Block{f.Entry} // stack-like worklist for len(p) > 0 { - // pop a reachable block + // Pop a reachable block b := p[len(p)-1] p = p[:len(p)-1] - - // constant-fold conditionals - // TODO: rewrite rules instead? - if b.Kind == BlockIf && b.Control.Op == OpConst { - cond := b.Control.Aux.(bool) - var c *Block - if cond { - // then branch is always taken - c = b.Succs[1] - } else { - // else branch is always taken - c = b.Succs[0] - b.Succs[0] = b.Succs[1] - } - b.Succs[1] = nil // aid GC - b.Succs = b.Succs[:1] - removePredecessor(b, c) - b.Kind = BlockPlain - b.Control = nil - } - + // Mark successors as reachable for _, c := range b.Succs { if !reachable[c.ID] { reachable[c.ID] = true -- cgit v1.3 From e00d60901a225b2b08bb52126704cb3422a569f4 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Tue, 2 Jun 2015 09:16:22 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: minor fixes * Improve some docs and logging. * Set correct type and len for indexing into strings. Fixes #11029. Change-Id: Ib22c45908e41ba3752010d2f5759e37e3921a48e Reviewed-on: https://go-review.googlesource.com/10635 Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/ssa.go | 19 ++++++++++++++----- src/cmd/compile/internal/ssa/deadcode.go | 2 +- src/cmd/compile/internal/ssa/rewrite.go | 4 ++-- 3 files changed, 17 insertions(+), 8 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 3c95266bdc..fd1c30edee 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -327,11 +327,20 @@ func (s *state) expr(n *Node) *ssa.Value { return s.curBlock.NewValue2(ssa.OpLoad, n.Type, nil, p, s.mem()) case OINDEX: - if n.Left.Type.Bound >= 0 { // array + if n.Left.Type.Bound >= 0 { // array or string a := s.expr(n.Left) i := s.expr(n.Right) - s.boundsCheck(i, s.f.ConstInt(s.config.Uintptr, n.Left.Type.Bound)) - return s.curBlock.NewValue2(ssa.OpArrayIndex, n.Left.Type.Type, nil, a, i) + var elemtype *Type + var len *ssa.Value + if n.Left.Type.IsString() { + len = s.curBlock.NewValue1(ssa.OpStringLen, s.config.Uintptr, nil, a) + elemtype = Types[TUINT8] + } else { + len = s.f.ConstInt(s.config.Uintptr, n.Left.Type.Bound) + elemtype = n.Left.Type.Type + } + s.boundsCheck(i, len) + return s.curBlock.NewValue2(ssa.OpArrayIndex, elemtype, nil, a, i) } else { // slice p := s.addr(n) return s.curBlock.NewValue2(ssa.OpLoad, n.Left.Type.Type, nil, p, s.mem()) @@ -367,7 +376,7 @@ func (s *state) expr(n *Node) *ssa.Value { } } -// expr converts the address of the expression n to SSA, adds it to s and returns the SSA result. +// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result. func (s *state) addr(n *Node) *ssa.Value { switch n.Op { case ONAME: @@ -402,7 +411,7 @@ func (s *state) addr(n *Node) *ssa.Value { return s.curBlock.NewValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), nil, p, i) } default: - log.Fatalf("addr: bad op %v", n.Op) + log.Fatalf("addr: bad op %v", Oconv(int(n.Op), 0)) return nil } } diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index ba5d8758d9..1a5589cd0a 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -82,7 +82,7 @@ func deadcode(f *Func) { i++ } else { if len(b.Values) > 0 { - panic("live value in unreachable block") + log.Panicf("live values in unreachable block %v: %v", b, b.Values) } f.bid.put(b.ID) } diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 6b76e55e2a..fd0fc7e1a7 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -12,10 +12,10 @@ func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) var curv *Value defer func() { if curb != nil { - log.Printf("panic during rewrite of %s\n", curb.LongString()) + log.Printf("panic during rewrite of block %s\n", curb.LongString()) } if curv != nil { - log.Printf("panic during rewrite of %s\n", curv.LongString()) + log.Printf("panic during rewrite of value %s\n", curv.LongString()) panic("rewrite failed") // TODO(khr): print source location also } -- cgit v1.3 From 8c6abfeacb27f1bcce8fb01f7da95950590943e3 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 12 Jun 2015 11:01:13 -0700 Subject: [dev.ssa] cmd/compile/ssa: separate logging, work in progress, and fatal errors The SSA implementation logs for three purposes: * debug logging * fatal errors * unimplemented features Separating these three uses lets us attempt an SSA implementation for all functions, not just _ssa functions. This turns the entire standard library into a compilation test, and makes it easy to figure out things like "how much coverage does SSA have now" and "what should we do next to get more coverage?". Functions called _ssa are still special. They log profusely by default and the output of the SSA implementation is used. For all other functions, logging is off, and the implementation is built and discarded, due to lack of support for the runtime. While we're here, fix a few minor bugs and add some extra Unimplementeds to allow all.bash to pass. As of now, SSA handles 20.79% of the functions in the standard library (689 of 3314). The top missing features are: 10.03% 2597 SSA unimplemented: zero for type error not implemented 7.79% 2016 SSA unimplemented: addr: bad op DOTPTR 7.33% 1898 SSA unimplemented: unhandled expr EQ 6.10% 1579 SSA unimplemented: unhandled expr OROR 4.91% 1271 SSA unimplemented: unhandled expr NE 4.49% 1163 SSA unimplemented: unhandled expr LROT 4.00% 1036 SSA unimplemented: unhandled expr LEN 3.56% 923 SSA unimplemented: unhandled stmt CALLFUNC 2.37% 615 SSA unimplemented: zero for type []byte not implemented 1.90% 492 SSA unimplemented: unhandled stmt CALLMETH 1.74% 450 SSA unimplemented: unhandled expr CALLINTER 1.74% 450 SSA unimplemented: unhandled expr DOT 1.71% 444 SSA unimplemented: unhandled expr ANDAND 1.65% 426 SSA unimplemented: unhandled expr CLOSUREVAR 1.54% 400 SSA unimplemented: unhandled expr CALLMETH 1.51% 390 SSA unimplemented: unhandled stmt SWITCH 1.47% 380 SSA unimplemented: unhandled expr CONV 1.33% 345 SSA unimplemented: addr: bad op * 1.30% 336 SSA unimplemented: unhandled OLITERAL 6 Change-Id: I4ca07951e276714dc13c31de28640aead17a1be7 Reviewed-on: https://go-review.googlesource.com/11160 Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/pgen.go | 13 +-- src/cmd/compile/internal/gc/ssa.go | 126 ++++++++++++++++++++----- src/cmd/compile/internal/ssa/TODO | 1 - src/cmd/compile/internal/ssa/block.go | 4 + src/cmd/compile/internal/ssa/check.go | 44 +++++---- src/cmd/compile/internal/ssa/compile.go | 13 +-- src/cmd/compile/internal/ssa/config.go | 18 +++- src/cmd/compile/internal/ssa/deadcode.go | 6 +- src/cmd/compile/internal/ssa/deadcode_test.go | 6 +- src/cmd/compile/internal/ssa/deadstore.go | 6 +- src/cmd/compile/internal/ssa/deadstore_test.go | 6 +- src/cmd/compile/internal/ssa/dom.go | 6 +- src/cmd/compile/internal/ssa/export_test.go | 12 ++- src/cmd/compile/internal/ssa/func.go | 8 +- src/cmd/compile/internal/ssa/func_test.go | 14 +-- src/cmd/compile/internal/ssa/gen/generic.rules | 2 +- src/cmd/compile/internal/ssa/layout.go | 4 +- src/cmd/compile/internal/ssa/lower.go | 4 +- src/cmd/compile/internal/ssa/print.go | 3 +- src/cmd/compile/internal/ssa/regalloc.go | 10 +- src/cmd/compile/internal/ssa/rewrite.go | 11 +-- src/cmd/compile/internal/ssa/rewritegeneric.go | 10 +- src/cmd/compile/internal/ssa/schedule_test.go | 2 +- src/cmd/compile/internal/ssa/shift_test.go | 2 +- src/cmd/compile/internal/ssa/stackalloc.go | 8 +- src/cmd/compile/internal/ssa/value.go | 4 + 26 files changed, 211 insertions(+), 132 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index e6b670f7a2..6a6c213b84 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -355,6 +355,7 @@ func compile(fn *Node) { var gcargs *Sym var gclocals *Sym var ssafn *ssa.Func + var usessa bool if fn.Nbody == nil { if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") { Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name) @@ -406,13 +407,9 @@ func compile(fn *Node) { goto ret } - // Build an SSA backend function - { - name := Curfn.Func.Nname.Sym.Name - if len(name) > 4 && name[len(name)-4:] == "_ssa" { - ssafn = buildssa(Curfn) - } - } + // Build an SSA backend function. + // TODO: get rid of usessa. + ssafn, usessa = buildssa(Curfn) continpc = nil breakpc = nil @@ -475,7 +472,7 @@ func compile(fn *Node) { } } - if ssafn != nil { + if ssafn != nil && usessa { genssa(ssafn, ptxt, gcargs, gclocals) return } diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index f2dbabe6ad..1218a23488 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -5,26 +5,48 @@ package gc import ( - "log" + "fmt" "cmd/compile/internal/ssa" "cmd/internal/obj" "cmd/internal/obj/x86" // TODO: remove ) -func buildssa(fn *Node) *ssa.Func { - dumplist("buildssa-enter", fn.Func.Enter) - dumplist("buildssa-body", fn.Nbody) +// buildssa builds an SSA function +// and reports whether it should be used. +// Once the SSA implementation is complete, +// it will never return nil, and the bool can be removed. +func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { + name := fn.Func.Nname.Sym.Name + usessa = len(name) > 4 && name[len(name)-4:] == "_ssa" + + if usessa { + dumplist("buildssa-enter", fn.Func.Enter) + dumplist("buildssa-body", fn.Nbody) + } var s state - s.pushLine(fn.Lineno) defer s.popLine() // TODO(khr): build config just once at the start of the compiler binary - s.config = ssa.NewConfig(Thearch.Thestring, ssaExport{}) + + var e ssaExport + e.log = usessa + s.config = ssa.NewConfig(Thearch.Thestring, &e) s.f = s.config.NewFunc() - s.f.Name = fn.Func.Nname.Sym.Name + s.f.Name = name + + // If SSA support for the function is incomplete, + // assume that any panics are due to violated + // invariants. Swallow them silently. + defer func() { + if err := recover(); err != nil { + if !e.unimplemented { + panic(err) + } + } + }() // We construct SSA using an algorithm similar to // Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau @@ -67,7 +89,15 @@ func buildssa(fn *Node) *ssa.Func { // Main call to ssa package to compile function ssa.Compile(s.f) - return s.f + // Calculate stats about what percentage of functions SSA handles. + if false { + fmt.Printf("SSA implemented: %t\n", !e.unimplemented) + } + + if e.unimplemented { + return nil, false + } + return s.f, usessa // TODO: return s.f, true once runtime support is in (gc maps, write barriers, etc.) } type state struct { @@ -105,10 +135,13 @@ type state struct { line []int32 } +func (s *state) Fatal(msg string, args ...interface{}) { s.config.Fatal(msg, args...) } +func (s *state) Unimplemented(msg string, args ...interface{}) { s.config.Unimplemented(msg, args...) } + // startBlock sets the current block we're generating code in to b. func (s *state) startBlock(b *ssa.Block) { if s.curBlock != nil { - log.Fatalf("starting block %v when block %v has not ended", b, s.curBlock) + s.Fatal("starting block %v when block %v has not ended", b, s.curBlock) } s.curBlock = b s.vars = map[string]*ssa.Value{} @@ -230,7 +263,7 @@ func (s *state) stmt(n *Node) { return } if compiling_runtime != 0 { - log.Fatalf("%v escapes to heap, not allowed in runtime.", n) + Fatal("%v escapes to heap, not allowed in runtime.", n) } // TODO: the old pass hides the details of PHEAP @@ -260,6 +293,9 @@ func (s *state) stmt(n *Node) { // next we work on the label's target block s.startBlock(t) } + if n.Op == OGOTO && s.curBlock == nil { + s.Unimplemented("goto at start of function; see test/goto.go") + } case OAS, OASWB: s.assign(n.Op, n.Left, n.Right) @@ -317,6 +353,9 @@ func (s *state) stmt(n *Node) { // generate code to test condition // TODO(khr): Left == nil exception + if n.Left == nil { + s.Unimplemented("cond n.Left == nil: %v", n) + } s.startBlock(bCond) cond := s.expr(n.Left) b = s.endBlock() @@ -342,7 +381,7 @@ func (s *state) stmt(n *Node) { // TODO(khr): ??? anything to do here? Only for addrtaken variables? // Maybe just link it in the store chain? default: - log.Fatalf("unhandled stmt %s", opnames[n.Op]) + s.Unimplemented("unhandled stmt %s", opnames[n.Op]) } } @@ -370,7 +409,7 @@ func (s *state) expr(n *Node) *ssa.Value { case CTSTR: return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U) default: - log.Fatalf("unhandled OLITERAL %v", n.Val().Ctype()) + s.Unimplemented("unhandled OLITERAL %v", n.Val().Ctype()) return nil } case OCONVNOP: @@ -474,7 +513,7 @@ func (s *state) expr(n *Node) *ssa.Value { a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp) return s.newValue2(ssa.OpLoad, fp.Type, a, call) default: - log.Fatalf("unhandled expr %s", opnames[n.Op]) + s.Unimplemented("unhandled expr %s", opnames[n.Op]) return nil } } @@ -494,7 +533,7 @@ func (s *state) assign(op uint8, left *Node, right *Node) { case t.IsBoolean(): val = s.entryNewValue0A(ssa.OpConst, left.Type, false) // TODO: store bools as 0/1 in AuxInt? default: - log.Fatalf("zero for type %v not implemented", t) + s.Unimplemented("zero for type %v not implemented", t) } } else { val = s.expr(right) @@ -524,7 +563,7 @@ func (s *state) addr(n *Node) *ssa.Value { return s.expr(n.Name.Heapaddr) default: // TODO: address of locals - log.Fatalf("variable address of %v not implemented", n) + s.Unimplemented("variable address of %v not implemented", n) return nil } case OINDREG: @@ -547,7 +586,7 @@ func (s *state) addr(n *Node) *ssa.Value { return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i) } default: - log.Fatalf("addr: bad op %v", Oconv(int(n.Op), 0)) + s.Unimplemented("addr: bad op %v", Oconv(int(n.Op), 0)) return nil } } @@ -556,7 +595,7 @@ func (s *state) addr(n *Node) *ssa.Value { // n must be an ONAME. func canSSA(n *Node) bool { if n.Op != ONAME { - log.Fatalf("canSSA passed a non-ONAME %s %v", Oconv(int(n.Op), 0), n) + Fatal("canSSA passed a non-ONAME %s %v", Oconv(int(n.Op), 0), n) } if n.Addrtaken { return false @@ -610,7 +649,7 @@ func (s *state) boundsCheck(idx, len *ssa.Value) { // variable returns the value of a variable at the current location. func (s *state) variable(name string, t ssa.Type) *ssa.Value { if s.curBlock == nil { - log.Fatalf("nil curblock!") + s.Fatal("nil curblock!") } v := s.vars[name] if v == nil { @@ -662,6 +701,10 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name string) *ssa.Va for _, p := range b.Preds { vals = append(vals, s.lookupVarOutgoing(p, t, name)) } + if len(vals) == 0 { + s.Unimplemented("TODO: Handle fixedbugs/bug076.go") + return nil + } v0 := vals[0] for i := 1; i < len(vals); i++ { if vals[i] != v0 { @@ -822,11 +865,14 @@ func genValue(v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) case ssa.OpAMD64MULQconst: + v.Unimplemented("IMULQ doasm") + return // TODO: this isn't right. doasm fails on it. I don't think obj // has ever been taught to compile imul $c, r1, r2. p := Prog(x86.AIMULQ) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt + p.From3 = new(obj.Addr) p.From3.Type = obj.TYPE_REG p.From3.Reg = regnum(v.Args[0]) p.To.Type = obj.TYPE_REG @@ -854,7 +900,7 @@ func genValue(v *ssa.Value) { r := regnum(v) if x != r { if r == x86.REG_CX { - log.Fatalf("can't implement %s, target and shift both in CX", v.LongString()) + v.Fatal("can't implement %s, target and shift both in CX", v.LongString()) } p := Prog(x86.AMOVQ) p.From.Type = obj.TYPE_REG @@ -1003,12 +1049,12 @@ func genValue(v *ssa.Value) { loc := f.RegAlloc[v.ID] for _, a := range v.Args { if f.RegAlloc[a.ID] != loc { // TODO: .Equal() instead? - log.Fatalf("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID]) + v.Fatal("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID]) } } case ssa.OpConst: if v.Block.Func.RegAlloc[v.ID] != nil { - log.Fatalf("const value %v shouldn't have a location", v) + v.Fatal("const value %v shouldn't have a location", v) } case ssa.OpArg: // memory arg needs no code @@ -1033,7 +1079,7 @@ func genValue(v *ssa.Value) { case ssa.OpFP, ssa.OpSP: // nothing to do default: - log.Fatalf("value %s not implemented", v.LongString()) + v.Unimplemented("value %s not implemented", v.LongString()) } } @@ -1141,7 +1187,7 @@ func genBlock(b, next *ssa.Block, branches []branch) []branch { } default: - log.Fatalf("branch %s not implemented", b.LongString()) + b.Unimplemented("branch %s not implemented", b.LongString()) } return branches } @@ -1183,10 +1229,40 @@ func localOffset(v *ssa.Value) int64 { } // ssaExport exports a bunch of compiler services for the ssa backend. -type ssaExport struct{} +type ssaExport struct { + log bool + unimplemented bool +} // StringSym returns a symbol (a *Sym wrapped in an interface) which // is a global string constant containing s. -func (serv ssaExport) StringSym(s string) interface{} { +func (*ssaExport) StringSym(s string) interface{} { return stringsym(s) } + +// Log logs a message from the compiler. +func (e *ssaExport) Log(msg string, args ...interface{}) { + // If e was marked as unimplemented, anything could happen. Ignore. + if e.log && !e.unimplemented { + fmt.Printf(msg, args...) + } +} + +// Fatal reports a compiler error and exits. +func (e *ssaExport) Fatal(msg string, args ...interface{}) { + // If e was marked as unimplemented, anything could happen. Ignore. + if !e.unimplemented { + Fatal(msg, args...) + } +} + +// Unimplemented reports that the function cannot be compiled. +// It will be removed once SSA work is complete. +func (e *ssaExport) Unimplemented(msg string, args ...interface{}) { + const alwaysLog = false // enable to calculate top unimplemented features + if !e.unimplemented && (e.log || alwaysLog) { + // first implementation failure, print explanation + fmt.Printf("SSA unimplemented: "+msg+"\n", args...) + } + e.unimplemented = true +} diff --git a/src/cmd/compile/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO index e9b7553534..64b581fac0 100644 --- a/src/cmd/compile/internal/ssa/TODO +++ b/src/cmd/compile/internal/ssa/TODO @@ -42,7 +42,6 @@ Common-Subexpression Elimination - Can we move control values out of their basic block? Other - - Use gc.Fatal for errors. Add a callback to Frontend? - Write barriers - For testing, do something more sophisticated than checkOpcodeCounts. Michael Matloob suggests using a similar diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go index db16fb4a53..e0d5c1a55e 100644 --- a/src/cmd/compile/internal/ssa/block.go +++ b/src/cmd/compile/internal/ssa/block.go @@ -69,3 +69,7 @@ func (b *Block) LongString() string { } return s } + +func (b *Block) Log(msg string, args ...interface{}) { b.Func.Log(msg, args...) } +func (b *Block) Fatal(msg string, args ...interface{}) { b.Func.Fatal(msg, args...) } +func (b *Block) Unimplemented(msg string, args ...interface{}) { b.Func.Unimplemented(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 667313ad9f..230d0ec111 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -4,8 +4,6 @@ package ssa -import "log" - // checkFunc checks invariants of f. func checkFunc(f *Func) { blockMark := make([]bool, f.NumBlocks()) @@ -13,17 +11,17 @@ func checkFunc(f *Func) { for _, b := range f.Blocks { if blockMark[b.ID] { - log.Panicf("block %s appears twice in %s!", b, f.Name) + f.Fatal("block %s appears twice in %s!", b, f.Name) } blockMark[b.ID] = true if b.Func != f { - log.Panicf("%s.Func=%s, want %s", b, b.Func.Name, f.Name) + f.Fatal("%s.Func=%s, want %s", b, b.Func.Name, f.Name) } for i, c := range b.Succs { for j, d := range b.Succs { if i != j && c == d { - log.Panicf("%s.Succs has duplicate block %s", b, c) + f.Fatal("%s.Succs has duplicate block %s", b, c) } } } @@ -46,64 +44,64 @@ func checkFunc(f *Func) { } } if !found { - log.Panicf("block %s is not a succ of its pred block %s", b, p) + f.Fatal("block %s is not a succ of its pred block %s", b, p) } } switch b.Kind { case BlockExit: if len(b.Succs) != 0 { - log.Panicf("exit block %s has successors", b) + f.Fatal("exit block %s has successors", b) } if b.Control == nil { - log.Panicf("exit block %s has no control value", b) + f.Fatal("exit block %s has no control value", b) } if !b.Control.Type.IsMemory() { - log.Panicf("exit block %s has non-memory control value %s", b, b.Control.LongString()) + f.Fatal("exit block %s has non-memory control value %s", b, b.Control.LongString()) } case BlockPlain: if len(b.Succs) != 1 { - log.Panicf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs)) + f.Fatal("plain block %s len(Succs)==%d, want 1", b, len(b.Succs)) } if b.Control != nil { - log.Panicf("plain block %s has non-nil control %s", b, b.Control.LongString()) + f.Fatal("plain block %s has non-nil control %s", b, b.Control.LongString()) } case BlockIf: if len(b.Succs) != 2 { - log.Panicf("if block %s len(Succs)==%d, want 2", b, len(b.Succs)) + f.Fatal("if block %s len(Succs)==%d, want 2", b, len(b.Succs)) } if b.Control == nil { - log.Panicf("if block %s has no control value", b) + f.Fatal("if block %s has no control value", b) } if !b.Control.Type.IsBoolean() { - log.Panicf("if block %s has non-bool control value %s", b, b.Control.LongString()) + f.Fatal("if block %s has non-bool control value %s", b, b.Control.LongString()) } case BlockCall: if len(b.Succs) != 2 { - log.Panicf("call block %s len(Succs)==%d, want 2", b, len(b.Succs)) + f.Fatal("call block %s len(Succs)==%d, want 2", b, len(b.Succs)) } if b.Control == nil { - log.Panicf("call block %s has no control value", b) + f.Fatal("call block %s has no control value", b) } if !b.Control.Type.IsMemory() { - log.Panicf("call block %s has non-memory control value %s", b, b.Control.LongString()) + f.Fatal("call block %s has non-memory control value %s", b, b.Control.LongString()) } if b.Succs[1].Kind != BlockExit { - log.Panicf("exception edge from call block %s does not go to exit but %s", b, b.Succs[1]) + f.Fatal("exception edge from call block %s does not go to exit but %s", b, b.Succs[1]) } } for _, v := range b.Values { if valueMark[v.ID] { - log.Panicf("value %s appears twice!", v.LongString()) + f.Fatal("value %s appears twice!", v.LongString()) } valueMark[v.ID] = true if v.Block != b { - log.Panicf("%s.block != %s", v, b) + f.Fatal("%s.block != %s", v, b) } if v.Op == OpPhi && len(v.Args) != len(b.Preds) { - log.Panicf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b) + f.Fatal("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b) } // TODO: check for cycles in values @@ -113,12 +111,12 @@ func checkFunc(f *Func) { for _, id := range f.bid.free { if blockMark[id] { - log.Panicf("used block b%d in free list", id) + f.Fatal("used block b%d in free list", id) } } for _, id := range f.vid.free { if valueMark[id] { - log.Panicf("used value v%d in free list", id) + f.Fatal("used value v%d in free list", id) } } } diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index 02c9b5a4a9..896be01b68 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -4,10 +4,7 @@ package ssa -import ( - "fmt" - "log" -) +import "log" // Compile is the main entry point for this package. // Compile modifies f so that on return: @@ -18,13 +15,13 @@ import ( func Compile(f *Func) { // TODO: debugging - set flags to control verbosity of compiler, // which phases to dump IR before/after, etc. - fmt.Printf("compiling %s\n", f.Name) + f.Log("compiling %s\n", f.Name) // hook to print function & phase if panic happens phaseName := "init" defer func() { if phaseName != "" { - fmt.Printf("panic during %s while compiling %s\n", phaseName, f.Name) + f.Fatal("panic during %s while compiling %s\n", phaseName, f.Name) } }() @@ -33,9 +30,9 @@ func Compile(f *Func) { checkFunc(f) for _, p := range passes { phaseName = p.name - fmt.Printf(" pass %s begin\n", p.name) + f.Log(" pass %s begin\n", p.name) p.fn(f) - fmt.Printf(" pass %s end\n", p.name) + f.Log(" pass %s end\n", p.name) printFunc(f) checkFunc(f) } diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index db2d80a7c4..60c1a5a50b 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -4,8 +4,6 @@ package ssa -import "log" - type Config struct { arch string // "amd64", etc. ptrSize int64 // 4 or 8 @@ -22,6 +20,16 @@ type Frontend interface { // Strings are laid out in read-only memory with one word of pointer, // one word of length, then the contents of the string. StringSym(string) interface{} // returns *gc.Sym + + // Log logs a message from the compiler. + Log(string, ...interface{}) + + // Fatal reports a compiler error and exits. + Fatal(string, ...interface{}) + + // Unimplemented reports that the function cannot be compiled. + // It will be removed once SSA work is complete. + Unimplemented(msg string, args ...interface{}) } // NewConfig returns a new configuration object for the given architecture. @@ -37,7 +45,7 @@ func NewConfig(arch string, fe Frontend) *Config { c.lowerBlock = rewriteBlockAMD64 c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support default: - log.Fatalf("arch %s not implemented", arch) + fe.Unimplemented("arch %s not implemented", arch) } // cache the intptr type in the config @@ -55,5 +63,9 @@ func (c *Config) NewFunc() *Func { return &Func{Config: c} } +func (c *Config) Log(msg string, args ...interface{}) { c.fe.Log(msg, args...) } +func (c *Config) Fatal(msg string, args ...interface{}) { c.fe.Fatal(msg, args...) } +func (c *Config) Unimplemented(msg string, args ...interface{}) { c.fe.Unimplemented(msg, args...) } + // TODO(khr): do we really need a separate Config, or can we just // store all its fields inside a Func? diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 1a5589cd0a..f4884520de 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -4,8 +4,6 @@ package ssa -import "log" - // deadcode removes dead code from f. func deadcode(f *Func) { @@ -82,7 +80,7 @@ func deadcode(f *Func) { i++ } else { if len(b.Values) > 0 { - log.Panicf("live values in unreachable block %v: %v", b, b.Values) + b.Fatal("live values in unreachable block %v: %v", b, b.Values) } f.bid.put(b.ID) } @@ -105,7 +103,7 @@ func removePredecessor(b, c *Block) { if n == 0 { // c is now dead - don't bother working on it if c.Preds[0] != b { - log.Panicf("%s.Preds[0]==%s, want %s", c, c.Preds[0], b) + b.Fatal("%s.Preds[0]==%s, want %s", c, c.Preds[0], b) } return } diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index edd38e1254..ff9e6800da 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -7,7 +7,7 @@ package ssa import "testing" func TestDeadLoop(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -37,7 +37,7 @@ func TestDeadLoop(t *testing.T) { } func TestDeadValue(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -60,7 +60,7 @@ func TestDeadValue(t *testing.T) { } func TestNeverTaken(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", Valu("cond", OpConst, TypeBool, 0, false), diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go index b02b35460a..e4d73e7226 100644 --- a/src/cmd/compile/internal/ssa/deadstore.go +++ b/src/cmd/compile/internal/ssa/deadstore.go @@ -4,8 +4,6 @@ package ssa -import "log" - // dse does dead-store elimination on the Function. // Dead stores are those which are unconditionally followed by // another store to the same location, with no intervening load. @@ -58,12 +56,12 @@ func dse(f *Func) { continue } if last != nil { - log.Fatalf("two final stores - simultaneous live stores", last, v) + b.Fatal("two final stores - simultaneous live stores", last, v) } last = v } if last == nil { - log.Fatalf("no last store found - cycle?") + b.Fatal("no last store found - cycle?") } // Walk backwards looking for dead stores. Keep track of shadowed addresses. diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go index 5143afb6cb..48ea066aa3 100644 --- a/src/cmd/compile/internal/ssa/deadstore_test.go +++ b/src/cmd/compile/internal/ssa/deadstore_test.go @@ -9,7 +9,7 @@ import ( ) func TestDeadStore(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", @@ -35,7 +35,7 @@ func TestDeadStore(t *testing.T) { } func TestDeadStorePhi(t *testing.T) { // make sure we don't get into an infinite loop with phi values. - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", @@ -60,7 +60,7 @@ func TestDeadStoreTypes(t *testing.T) { // stronger restriction, that one store can't shadow another unless the // types of the address fields are identical (where identicalness is // decided by the CSE pass). - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) t1 := &TypeImpl{Size_: 8, Ptr: true, Name: "t1"} t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"} fun := Fun(c, "entry", diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go index aaf3ab3da1..fac2798a60 100644 --- a/src/cmd/compile/internal/ssa/dom.go +++ b/src/cmd/compile/internal/ssa/dom.go @@ -7,8 +7,6 @@ package ssa // This file contains code to compute the dominator tree // of a control-flow graph. -import "log" - // postorder computes a postorder traversal ordering for the // basic blocks in f. Unreachable blocks will not appear. func postorder(f *Func) []*Block { @@ -47,7 +45,7 @@ func postorder(f *Func) []*Block { } } default: - log.Fatalf("bad stack state %v %d", b, mark[b.ID]) + b.Fatal("bad stack state %v %d", b, mark[b.ID]) } } return order @@ -73,7 +71,7 @@ func dominators(f *Func) []*Block { // Make the entry block a self-loop idom[f.Entry.ID] = f.Entry if postnum[f.Entry.ID] != len(post)-1 { - log.Fatalf("entry block %v not last in postorder", f.Entry) + f.Fatal("entry block %v not last in postorder", f.Entry) } // Compute relaxation of idom entries diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index 103945a73e..6b006e9238 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -4,13 +4,21 @@ package ssa +import "testing" + var CheckFunc = checkFunc var PrintFunc = printFunc var Opt = opt var Deadcode = deadcode -type DummyFrontend struct{} +type DummyFrontend struct { + t *testing.T +} -func (d DummyFrontend) StringSym(s string) interface{} { +func (DummyFrontend) StringSym(s string) interface{} { return nil } + +func (d DummyFrontend) Log(msg string, args ...interface{}) { d.t.Logf(msg, args...) } +func (d DummyFrontend) Fatal(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } +func (d DummyFrontend) Unimplemented(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index d73e0ea9e0..56bee1aa3f 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -4,8 +4,6 @@ package ssa -import "log" - // A Func represents a Go func declaration (or function literal) and // its body. This package compiles each Func independently. type Func struct { @@ -79,7 +77,7 @@ func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value { // Disallow int64 aux values. They should be in the auxint field instead. // Maybe we want to allow this at some point, but for now we disallow it // to prevent errors like using NewValue1A instead of NewValue1I. - log.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) + b.Fatal("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) } v := &Value{ ID: b.Func.vid.get(), @@ -209,3 +207,7 @@ func (f *Func) ConstInt(line int32, t Type, c int64) *Value { // TODO: cache? return f.Entry.NewValue0I(line, OpConst, t, c) } + +func (f *Func) Log(msg string, args ...interface{}) { f.Config.Log(msg, args...) } +func (f *Func) Fatal(msg string, args ...interface{}) { f.Config.Fatal(msg, args...) } +func (f *Func) Unimplemented(msg string, args ...interface{}) { f.Config.Unimplemented(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index 7cfc7324ac..b52d470e24 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -37,7 +37,7 @@ package ssa // the parser can be used instead of Fun. import ( - "log" + "fmt" "reflect" "testing" ) @@ -161,7 +161,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun { if c.control != "" { cval, ok := values[c.control] if !ok { - log.Panicf("control value for block %s missing", bloc.name) + f.Fatal("control value for block %s missing", bloc.name) } b.Control = cval } @@ -171,7 +171,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun { for _, arg := range valu.args { a, ok := values[arg] if !ok { - log.Panicf("arg %s missing for value %s in block %s", + b.Fatal("arg %s missing for value %s in block %s", arg, valu.name, bloc.name) } v.AddArg(a) @@ -197,7 +197,7 @@ func Bloc(name string, entries ...interface{}) bloc { case ctrl: // there should be exactly one Ctrl entry. if seenCtrl { - log.Panicf("already seen control for block %s", name) + panic(fmt.Sprintf("already seen control for block %s", name)) } b.control = v seenCtrl = true @@ -206,7 +206,7 @@ func Bloc(name string, entries ...interface{}) bloc { } } if !seenCtrl { - log.Panicf("block %s doesn't have control", b.name) + panic(fmt.Sprintf("block %s doesn't have control", b.name)) } return b } @@ -262,7 +262,7 @@ func addEdge(b, c *Block) { } func TestArgs(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", Valu("a", OpConst, TypeInt64, 14, nil), @@ -282,7 +282,7 @@ func TestArgs(t *testing.T) { } func TestEquiv(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) equivalentCases := []struct{ f, g fun }{ // simple case { diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index e0bba1706f..9d08a35f1f 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -32,7 +32,7 @@ // indexing operations // Note: bounds check has already been done -(ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex ptr idx) mem) +(ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex ptr idx) mem) (PtrIndex ptr idx) -> (Add ptr (Mul idx (Const [t.Elem().Size()]))) // big-object moves diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go index 7123397c4c..0a271b39ad 100644 --- a/src/cmd/compile/internal/ssa/layout.go +++ b/src/cmd/compile/internal/ssa/layout.go @@ -4,8 +4,6 @@ package ssa -import "log" - // layout orders basic blocks in f with the goal of minimizing control flow instructions. // After this phase returns, the order of f.Blocks matters and is the order // in which those blocks will appear in the assembly output. @@ -82,7 +80,7 @@ blockloop: continue blockloop } } - log.Panicf("no block available for layout") + b.Fatal("no block available for layout") } f.Blocks = order } diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index 2ca1db784e..768ac124be 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -4,8 +4,6 @@ package ssa -import "log" - // convert to machine-dependent ops func lower(f *Func) { // repeat rewrites until we find no more rewrites @@ -15,7 +13,7 @@ func lower(f *Func) { for _, b := range f.Blocks { for _, v := range b.Values { if opcodeTable[v.Op].generic && v.Op != OpFP && v.Op != OpSP && v.Op != OpArg && v.Op != OpCopy && v.Op != OpPhi { - log.Panicf("%s not lowered", v.LongString()) + f.Unimplemented("%s not lowered", v.LongString()) } } } diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go index b9a958c18e..c1b97d2b8f 100644 --- a/src/cmd/compile/internal/ssa/print.go +++ b/src/cmd/compile/internal/ssa/print.go @@ -8,11 +8,10 @@ import ( "bytes" "fmt" "io" - "os" ) func printFunc(f *Func) { - fprintFunc(os.Stdout, f) + f.Log("%s", f.String()) } func (f *Func) String() string { diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 6f7d619247..d1489b20f2 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -4,11 +4,7 @@ package ssa -import ( - "fmt" - "log" - "sort" -) +import "sort" func setloc(home []Location, v *Value, loc Location) []Location { for v.ID >= ID(len(home)) { @@ -353,7 +349,7 @@ func regalloc(f *Func) { if b.Kind == BlockCall { call = b.Control if call != b.Values[len(b.Values)-1] { - log.Fatalf("call not at end of block %b %v", b, call) + b.Fatal("call not at end of block %b %v", b, call) } b.Values = b.Values[:len(b.Values)-1] // TODO: do this for all control types? @@ -423,7 +419,7 @@ func live(f *Func) [][]ID { t := newSparseSet(f.NumValues()) for { for _, b := range f.Blocks { - fmt.Printf("live %s %v\n", b, live[b.ID]) + f.Log("live %s %v\n", b, live[b.ID]) } changed := false diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 77aa2b07b4..2bfd3813ed 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -4,7 +4,7 @@ package ssa -import "log" +import "fmt" func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) { // repeat rewrites until we find no more rewrites @@ -12,11 +12,10 @@ func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) var curv *Value defer func() { if curb != nil { - log.Printf("panic during rewrite of block %s\n", curb.LongString()) + curb.Fatal("panic during rewrite of block %s\n", curb.LongString()) } if curv != nil { - log.Printf("panic during rewrite of value %s\n", curv.LongString()) - panic("rewrite failed") + curv.Fatal("panic during rewrite of value %s\n", curv.LongString()) // TODO(khr): print source location also } }() @@ -90,12 +89,12 @@ func typeSize(t Type) int64 { return t.Size() } -// addOff adds two int64 offsets. Fails if wraparound happens. +// addOff adds two int64 offsets. Fails if wraparound happens. func addOff(x, y int64) int64 { z := x + y // x and y have same sign and z has a different sign => overflow if x^y >= 0 && x^z < 0 { - log.Panicf("offset overflow %d %d\n", x, y) + panic(fmt.Sprintf("offset overflow %d %d", x, y)) } return z } diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 0ecc436343..ac4f009881 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -34,10 +34,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpArrayIndex: // match: (ArrayIndex (Load ptr mem) idx) // cond: - // result: (Load (PtrIndex ptr idx) mem) + // result: (Load (PtrIndex ptr idx) mem) { if v.Args[0].Op != OpLoad { - goto end3809f4c52270a76313e4ea26e6f0b753 + goto end4894dd7b58383fee5f8a92be08437c33 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] @@ -47,15 +47,15 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v.Aux = nil v.resetArgs() v0 := v.Block.NewValue0(v.Line, OpPtrIndex, TypeInvalid) - v0.Type = ptr.Type.Elem().Elem().PtrTo() + v0.Type = v.Type.PtrTo() v0.AddArg(ptr) v0.AddArg(idx) v.AddArg(v0) v.AddArg(mem) return true } - goto end3809f4c52270a76313e4ea26e6f0b753 - end3809f4c52270a76313e4ea26e6f0b753: + goto end4894dd7b58383fee5f8a92be08437c33 + end4894dd7b58383fee5f8a92be08437c33: ; case OpConst: // match: (Const {s}) diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go index a7c33d9d59..a9432579f7 100644 --- a/src/cmd/compile/internal/ssa/schedule_test.go +++ b/src/cmd/compile/internal/ssa/schedule_test.go @@ -7,7 +7,7 @@ package ssa import "testing" func TestSchedule(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) cases := []fun{ Fun(c, "entry", Bloc("entry", diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index b4b4f47ff0..52ddbbe42d 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -9,7 +9,7 @@ import ( ) func TestShiftConstAMD64(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := makeConstShiftFunc(c, 18, OpLsh, TypeUInt64) checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0}) fun = makeConstShiftFunc(c, 66, OpLsh, TypeUInt64) diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 5db7316dca..452d0c75a1 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -4,8 +4,6 @@ package ssa -import "log" - // stackalloc allocates storage in the stack frame for // all Values that did not get a register. func stackalloc(f *Func) { @@ -79,7 +77,7 @@ func stackalloc(f *Func) { for _, v := range b.Values { if v.Op == OpFP { if fp != nil { - log.Panicf("multiple FP ops: %s %s", fp, v) + b.Fatal("multiple FP ops: %s %s", fp, v) } fp = v } @@ -99,12 +97,12 @@ func stackalloc(f *Func) { case OpAMD64LEAQ, OpAMD64MOVQload, OpAMD64MOVQstore, OpAMD64MOVLload, OpAMD64MOVLstore, OpAMD64MOVWload, OpAMD64MOVWstore, OpAMD64MOVBload, OpAMD64MOVBstore, OpAMD64MOVQloadidx8: if v.Op == OpAMD64MOVQloadidx8 && i == 1 { // Note: we could do it, but it is probably an error - log.Panicf("can't do FP->SP adjust on index slot of load %s", v.Op) + f.Fatal("can't do FP->SP adjust on index slot of load %s", v.Op) } // eg: (MOVQload [c] (FP) mem) -> (MOVQload [c+n] (SP) mem) v.AuxInt = addOff(v.AuxInt, n) default: - log.Panicf("can't do FP->SP adjust on %s", v.Op) + f.Unimplemented("can't do FP->SP adjust on %s", v.Op) // TODO: OpCopy -> ADDQ } } diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index 3ed1f3c2b9..bfba8dc369 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -106,3 +106,7 @@ func (v *Value) resetArgs() { v.argstorage[1] = nil v.Args = v.argstorage[:0] } + +func (v *Value) Log(msg string, args ...interface{}) { v.Block.Log(msg, args...) } +func (v *Value) Fatal(msg string, args ...interface{}) { v.Block.Fatal(msg, args...) } +func (v *Value) Unimplemented(msg string, args ...interface{}) { v.Block.Unimplemented(msg, args...) } -- cgit v1.3 From 37ddc270ca5360ccde000fd373d49b3450ee8e6e Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 24 Jun 2015 14:03:39 -0700 Subject: [dev.ssa] cmd/compile/ssa: add -f suffix to logging methods Requested in CL 11380. Change-Id: Icf0d23fb8d383c76272401e363cc9b2169d11403 Reviewed-on: https://go-review.googlesource.com/11450 Reviewed-by: Alan Donovan --- src/cmd/compile/internal/gc/ssa.go | 44 ++++++++++++++--------------- src/cmd/compile/internal/ssa/block.go | 6 ++-- src/cmd/compile/internal/ssa/check.go | 42 +++++++++++++-------------- src/cmd/compile/internal/ssa/compile.go | 8 +++--- src/cmd/compile/internal/ssa/config.go | 14 ++++----- src/cmd/compile/internal/ssa/deadcode.go | 4 +-- src/cmd/compile/internal/ssa/deadstore.go | 4 +-- src/cmd/compile/internal/ssa/dom.go | 4 +-- src/cmd/compile/internal/ssa/export_test.go | 6 ++-- src/cmd/compile/internal/ssa/func.go | 8 +++--- src/cmd/compile/internal/ssa/func_test.go | 4 +-- src/cmd/compile/internal/ssa/layout.go | 2 +- src/cmd/compile/internal/ssa/lower.go | 2 +- src/cmd/compile/internal/ssa/print.go | 2 +- src/cmd/compile/internal/ssa/regalloc.go | 4 +-- src/cmd/compile/internal/ssa/rewrite.go | 4 +-- src/cmd/compile/internal/ssa/stackalloc.go | 6 ++-- src/cmd/compile/internal/ssa/value.go | 6 ++-- 18 files changed, 85 insertions(+), 85 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 569b985052..0dd2e44ec5 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -135,13 +135,13 @@ type state struct { line []int32 } -func (s *state) Fatal(msg string, args ...interface{}) { s.config.Fatal(msg, args...) } -func (s *state) Unimplemented(msg string, args ...interface{}) { s.config.Unimplemented(msg, args...) } +func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(msg, args...) } +func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimplementedf(msg, args...) } // startBlock sets the current block we're generating code in to b. func (s *state) startBlock(b *ssa.Block) { if s.curBlock != nil { - s.Fatal("starting block %v when block %v has not ended", b, s.curBlock) + s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock) } s.curBlock = b s.vars = map[string]*ssa.Value{} @@ -294,7 +294,7 @@ func (s *state) stmt(n *Node) { s.startBlock(t) } if n.Op == OGOTO && s.curBlock == nil { - s.Unimplemented("goto at start of function; see test/goto.go") + s.Unimplementedf("goto at start of function; see test/goto.go") } case OAS, OASWB: @@ -354,7 +354,7 @@ func (s *state) stmt(n *Node) { // generate code to test condition // TODO(khr): Left == nil exception if n.Left == nil { - s.Unimplemented("cond n.Left == nil: %v", n) + s.Unimplementedf("cond n.Left == nil: %v", n) } s.startBlock(bCond) cond := s.expr(n.Left) @@ -381,7 +381,7 @@ func (s *state) stmt(n *Node) { // TODO(khr): ??? anything to do here? Only for addrtaken variables? // Maybe just link it in the store chain? default: - s.Unimplemented("unhandled stmt %s", opnames[n.Op]) + s.Unimplementedf("unhandled stmt %s", opnames[n.Op]) } } @@ -409,7 +409,7 @@ func (s *state) expr(n *Node) *ssa.Value { case CTSTR: return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U) default: - s.Unimplemented("unhandled OLITERAL %v", n.Val().Ctype()) + s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype()) return nil } case OCONVNOP: @@ -513,7 +513,7 @@ func (s *state) expr(n *Node) *ssa.Value { a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp) return s.newValue2(ssa.OpLoad, fp.Type, a, call) default: - s.Unimplemented("unhandled expr %s", opnames[n.Op]) + s.Unimplementedf("unhandled expr %s", opnames[n.Op]) return nil } } @@ -533,7 +533,7 @@ func (s *state) assign(op uint8, left *Node, right *Node) { case t.IsBoolean(): val = s.entryNewValue0A(ssa.OpConst, left.Type, false) // TODO: store bools as 0/1 in AuxInt? default: - s.Unimplemented("zero for type %v not implemented", t) + s.Unimplementedf("zero for type %v not implemented", t) } } else { val = s.expr(right) @@ -563,7 +563,7 @@ func (s *state) addr(n *Node) *ssa.Value { return s.expr(n.Name.Heapaddr) default: // TODO: address of locals - s.Unimplemented("variable address of %v not implemented", n) + s.Unimplementedf("variable address of %v not implemented", n) return nil } case OINDREG: @@ -586,7 +586,7 @@ func (s *state) addr(n *Node) *ssa.Value { return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i) } default: - s.Unimplemented("addr: bad op %v", Oconv(int(n.Op), 0)) + s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0)) return nil } } @@ -652,7 +652,7 @@ func (s *state) variable(name string, t ssa.Type) *ssa.Value { // Unimplemented instead of Fatal because fixedbugs/bug303.go // demonstrates a case in which this appears to happen legitimately. // TODO: decide on the correct behavior here. - s.Unimplemented("nil curblock adding variable %v (%v)", name, t) + s.Unimplementedf("nil curblock adding variable %v (%v)", name, t) } v := s.vars[name] if v == nil { @@ -705,7 +705,7 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name string) *ssa.Va vals = append(vals, s.lookupVarOutgoing(p, t, name)) } if len(vals) == 0 { - s.Unimplemented("TODO: Handle fixedbugs/bug076.go") + s.Unimplementedf("TODO: Handle fixedbugs/bug076.go") return nil } v0 := vals[0] @@ -868,7 +868,7 @@ func genValue(v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) case ssa.OpAMD64MULQconst: - v.Unimplemented("IMULQ doasm") + v.Unimplementedf("IMULQ doasm") return // TODO: this isn't right. doasm fails on it. I don't think obj // has ever been taught to compile imul $c, r1, r2. @@ -903,7 +903,7 @@ func genValue(v *ssa.Value) { r := regnum(v) if x != r { if r == x86.REG_CX { - v.Fatal("can't implement %s, target and shift both in CX", v.LongString()) + v.Fatalf("can't implement %s, target and shift both in CX", v.LongString()) } p := Prog(x86.AMOVQ) p.From.Type = obj.TYPE_REG @@ -1052,12 +1052,12 @@ func genValue(v *ssa.Value) { loc := f.RegAlloc[v.ID] for _, a := range v.Args { if f.RegAlloc[a.ID] != loc { // TODO: .Equal() instead? - v.Fatal("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID]) + v.Fatalf("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID]) } } case ssa.OpConst: if v.Block.Func.RegAlloc[v.ID] != nil { - v.Fatal("const value %v shouldn't have a location", v) + v.Fatalf("const value %v shouldn't have a location", v) } case ssa.OpArg: // memory arg needs no code @@ -1082,7 +1082,7 @@ func genValue(v *ssa.Value) { case ssa.OpFP, ssa.OpSP: // nothing to do default: - v.Unimplemented("value %s not implemented", v.LongString()) + v.Unimplementedf("value %s not implemented", v.LongString()) } } @@ -1190,7 +1190,7 @@ func genBlock(b, next *ssa.Block, branches []branch) []branch { } default: - b.Unimplemented("branch %s not implemented", b.LongString()) + b.Unimplementedf("branch %s not implemented", b.LongString()) } return branches } @@ -1244,7 +1244,7 @@ func (*ssaExport) StringSym(s string) interface{} { } // Log logs a message from the compiler. -func (e *ssaExport) Log(msg string, args ...interface{}) { +func (e *ssaExport) Logf(msg string, args ...interface{}) { // If e was marked as unimplemented, anything could happen. Ignore. if e.log && !e.unimplemented { fmt.Printf(msg, args...) @@ -1252,7 +1252,7 @@ func (e *ssaExport) Log(msg string, args ...interface{}) { } // Fatal reports a compiler error and exits. -func (e *ssaExport) Fatal(msg string, args ...interface{}) { +func (e *ssaExport) Fatalf(msg string, args ...interface{}) { // If e was marked as unimplemented, anything could happen. Ignore. if !e.unimplemented { Fatal(msg, args...) @@ -1261,7 +1261,7 @@ func (e *ssaExport) Fatal(msg string, args ...interface{}) { // Unimplemented reports that the function cannot be compiled. // It will be removed once SSA work is complete. -func (e *ssaExport) Unimplemented(msg string, args ...interface{}) { +func (e *ssaExport) Unimplementedf(msg string, args ...interface{}) { const alwaysLog = false // enable to calculate top unimplemented features if !e.unimplemented && (e.log || alwaysLog) { // first implementation failure, print explanation diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go index e0d5c1a55e..b788031fce 100644 --- a/src/cmd/compile/internal/ssa/block.go +++ b/src/cmd/compile/internal/ssa/block.go @@ -70,6 +70,6 @@ func (b *Block) LongString() string { return s } -func (b *Block) Log(msg string, args ...interface{}) { b.Func.Log(msg, args...) } -func (b *Block) Fatal(msg string, args ...interface{}) { b.Func.Fatal(msg, args...) } -func (b *Block) Unimplemented(msg string, args ...interface{}) { b.Func.Unimplemented(msg, args...) } +func (b *Block) Logf(msg string, args ...interface{}) { b.Func.Logf(msg, args...) } +func (b *Block) Fatalf(msg string, args ...interface{}) { b.Func.Fatalf(msg, args...) } +func (b *Block) Unimplementedf(msg string, args ...interface{}) { b.Func.Unimplementedf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 230d0ec111..672aeda96a 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -11,17 +11,17 @@ func checkFunc(f *Func) { for _, b := range f.Blocks { if blockMark[b.ID] { - f.Fatal("block %s appears twice in %s!", b, f.Name) + f.Fatalf("block %s appears twice in %s!", b, f.Name) } blockMark[b.ID] = true if b.Func != f { - f.Fatal("%s.Func=%s, want %s", b, b.Func.Name, f.Name) + f.Fatalf("%s.Func=%s, want %s", b, b.Func.Name, f.Name) } for i, c := range b.Succs { for j, d := range b.Succs { if i != j && c == d { - f.Fatal("%s.Succs has duplicate block %s", b, c) + f.Fatalf("%s.Succs has duplicate block %s", b, c) } } } @@ -44,64 +44,64 @@ func checkFunc(f *Func) { } } if !found { - f.Fatal("block %s is not a succ of its pred block %s", b, p) + f.Fatalf("block %s is not a succ of its pred block %s", b, p) } } switch b.Kind { case BlockExit: if len(b.Succs) != 0 { - f.Fatal("exit block %s has successors", b) + f.Fatalf("exit block %s has successors", b) } if b.Control == nil { - f.Fatal("exit block %s has no control value", b) + f.Fatalf("exit block %s has no control value", b) } if !b.Control.Type.IsMemory() { - f.Fatal("exit block %s has non-memory control value %s", b, b.Control.LongString()) + f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString()) } case BlockPlain: if len(b.Succs) != 1 { - f.Fatal("plain block %s len(Succs)==%d, want 1", b, len(b.Succs)) + f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs)) } if b.Control != nil { - f.Fatal("plain block %s has non-nil control %s", b, b.Control.LongString()) + f.Fatalf("plain block %s has non-nil control %s", b, b.Control.LongString()) } case BlockIf: if len(b.Succs) != 2 { - f.Fatal("if block %s len(Succs)==%d, want 2", b, len(b.Succs)) + f.Fatalf("if block %s len(Succs)==%d, want 2", b, len(b.Succs)) } if b.Control == nil { - f.Fatal("if block %s has no control value", b) + f.Fatalf("if block %s has no control value", b) } if !b.Control.Type.IsBoolean() { - f.Fatal("if block %s has non-bool control value %s", b, b.Control.LongString()) + f.Fatalf("if block %s has non-bool control value %s", b, b.Control.LongString()) } case BlockCall: if len(b.Succs) != 2 { - f.Fatal("call block %s len(Succs)==%d, want 2", b, len(b.Succs)) + f.Fatalf("call block %s len(Succs)==%d, want 2", b, len(b.Succs)) } if b.Control == nil { - f.Fatal("call block %s has no control value", b) + f.Fatalf("call block %s has no control value", b) } if !b.Control.Type.IsMemory() { - f.Fatal("call block %s has non-memory control value %s", b, b.Control.LongString()) + f.Fatalf("call block %s has non-memory control value %s", b, b.Control.LongString()) } if b.Succs[1].Kind != BlockExit { - f.Fatal("exception edge from call block %s does not go to exit but %s", b, b.Succs[1]) + f.Fatalf("exception edge from call block %s does not go to exit but %s", b, b.Succs[1]) } } for _, v := range b.Values { if valueMark[v.ID] { - f.Fatal("value %s appears twice!", v.LongString()) + f.Fatalf("value %s appears twice!", v.LongString()) } valueMark[v.ID] = true if v.Block != b { - f.Fatal("%s.block != %s", v, b) + f.Fatalf("%s.block != %s", v, b) } if v.Op == OpPhi && len(v.Args) != len(b.Preds) { - f.Fatal("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b) + f.Fatalf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b) } // TODO: check for cycles in values @@ -111,12 +111,12 @@ func checkFunc(f *Func) { for _, id := range f.bid.free { if blockMark[id] { - f.Fatal("used block b%d in free list", id) + f.Fatalf("used block b%d in free list", id) } } for _, id := range f.vid.free { if valueMark[id] { - f.Fatal("used value v%d in free list", id) + f.Fatalf("used value v%d in free list", id) } } } diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index 27cc0d0609..b02c10a745 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -15,13 +15,13 @@ import "log" func Compile(f *Func) { // TODO: debugging - set flags to control verbosity of compiler, // which phases to dump IR before/after, etc. - f.Log("compiling %s\n", f.Name) + f.Logf("compiling %s\n", f.Name) // hook to print function & phase if panic happens phaseName := "init" defer func() { if phaseName != "" { - f.Fatal("panic during %s while compiling %s\n", phaseName, f.Name) + f.Fatalf("panic during %s while compiling %s\n", phaseName, f.Name) } }() @@ -30,9 +30,9 @@ func Compile(f *Func) { checkFunc(f) for _, p := range passes { phaseName = p.name - f.Log(" pass %s begin\n", p.name) + f.Logf(" pass %s begin\n", p.name) p.fn(f) - f.Log(" pass %s end\n", p.name) + f.Logf(" pass %s end\n", p.name) printFunc(f) checkFunc(f) } diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 60c1a5a50b..53eb5e8eb5 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -22,14 +22,14 @@ type Frontend interface { StringSym(string) interface{} // returns *gc.Sym // Log logs a message from the compiler. - Log(string, ...interface{}) + Logf(string, ...interface{}) // Fatal reports a compiler error and exits. - Fatal(string, ...interface{}) + Fatalf(string, ...interface{}) // Unimplemented reports that the function cannot be compiled. // It will be removed once SSA work is complete. - Unimplemented(msg string, args ...interface{}) + Unimplementedf(msg string, args ...interface{}) } // NewConfig returns a new configuration object for the given architecture. @@ -45,7 +45,7 @@ func NewConfig(arch string, fe Frontend) *Config { c.lowerBlock = rewriteBlockAMD64 c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support default: - fe.Unimplemented("arch %s not implemented", arch) + fe.Unimplementedf("arch %s not implemented", arch) } // cache the intptr type in the config @@ -63,9 +63,9 @@ func (c *Config) NewFunc() *Func { return &Func{Config: c} } -func (c *Config) Log(msg string, args ...interface{}) { c.fe.Log(msg, args...) } -func (c *Config) Fatal(msg string, args ...interface{}) { c.fe.Fatal(msg, args...) } -func (c *Config) Unimplemented(msg string, args ...interface{}) { c.fe.Unimplemented(msg, args...) } +func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) } +func (c *Config) Fatalf(msg string, args ...interface{}) { c.fe.Fatalf(msg, args...) } +func (c *Config) Unimplementedf(msg string, args ...interface{}) { c.fe.Unimplementedf(msg, args...) } // TODO(khr): do we really need a separate Config, or can we just // store all its fields inside a Func? diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index f4884520de..48d6fd6938 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -80,7 +80,7 @@ func deadcode(f *Func) { i++ } else { if len(b.Values) > 0 { - b.Fatal("live values in unreachable block %v: %v", b, b.Values) + b.Fatalf("live values in unreachable block %v: %v", b, b.Values) } f.bid.put(b.ID) } @@ -103,7 +103,7 @@ func removePredecessor(b, c *Block) { if n == 0 { // c is now dead - don't bother working on it if c.Preds[0] != b { - b.Fatal("%s.Preds[0]==%s, want %s", c, c.Preds[0], b) + b.Fatalf("%s.Preds[0]==%s, want %s", c, c.Preds[0], b) } return } diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go index e4d73e7226..9d138e3ac1 100644 --- a/src/cmd/compile/internal/ssa/deadstore.go +++ b/src/cmd/compile/internal/ssa/deadstore.go @@ -56,12 +56,12 @@ func dse(f *Func) { continue } if last != nil { - b.Fatal("two final stores - simultaneous live stores", last, v) + b.Fatalf("two final stores - simultaneous live stores", last, v) } last = v } if last == nil { - b.Fatal("no last store found - cycle?") + b.Fatalf("no last store found - cycle?") } // Walk backwards looking for dead stores. Keep track of shadowed addresses. diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go index fac2798a60..343df76b22 100644 --- a/src/cmd/compile/internal/ssa/dom.go +++ b/src/cmd/compile/internal/ssa/dom.go @@ -45,7 +45,7 @@ func postorder(f *Func) []*Block { } } default: - b.Fatal("bad stack state %v %d", b, mark[b.ID]) + b.Fatalf("bad stack state %v %d", b, mark[b.ID]) } } return order @@ -71,7 +71,7 @@ func dominators(f *Func) []*Block { // Make the entry block a self-loop idom[f.Entry.ID] = f.Entry if postnum[f.Entry.ID] != len(post)-1 { - f.Fatal("entry block %v not last in postorder", f.Entry) + f.Fatalf("entry block %v not last in postorder", f.Entry) } // Compute relaxation of idom entries diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index 6b006e9238..f254e066ac 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -19,6 +19,6 @@ func (DummyFrontend) StringSym(s string) interface{} { return nil } -func (d DummyFrontend) Log(msg string, args ...interface{}) { d.t.Logf(msg, args...) } -func (d DummyFrontend) Fatal(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } -func (d DummyFrontend) Unimplemented(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } +func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) } +func (d DummyFrontend) Fatalf(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } +func (d DummyFrontend) Unimplementedf(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 56bee1aa3f..046c068eb9 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -77,7 +77,7 @@ func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value { // Disallow int64 aux values. They should be in the auxint field instead. // Maybe we want to allow this at some point, but for now we disallow it // to prevent errors like using NewValue1A instead of NewValue1I. - b.Fatal("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) + b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) } v := &Value{ ID: b.Func.vid.get(), @@ -208,6 +208,6 @@ func (f *Func) ConstInt(line int32, t Type, c int64) *Value { return f.Entry.NewValue0I(line, OpConst, t, c) } -func (f *Func) Log(msg string, args ...interface{}) { f.Config.Log(msg, args...) } -func (f *Func) Fatal(msg string, args ...interface{}) { f.Config.Fatal(msg, args...) } -func (f *Func) Unimplemented(msg string, args ...interface{}) { f.Config.Unimplemented(msg, args...) } +func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) } +func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(msg, args...) } +func (f *Func) Unimplementedf(msg string, args ...interface{}) { f.Config.Unimplementedf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index b52d470e24..a620e8f602 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -161,7 +161,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun { if c.control != "" { cval, ok := values[c.control] if !ok { - f.Fatal("control value for block %s missing", bloc.name) + f.Fatalf("control value for block %s missing", bloc.name) } b.Control = cval } @@ -171,7 +171,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun { for _, arg := range valu.args { a, ok := values[arg] if !ok { - b.Fatal("arg %s missing for value %s in block %s", + b.Fatalf("arg %s missing for value %s in block %s", arg, valu.name, bloc.name) } v.AddArg(a) diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go index 0a271b39ad..c2d72267b1 100644 --- a/src/cmd/compile/internal/ssa/layout.go +++ b/src/cmd/compile/internal/ssa/layout.go @@ -80,7 +80,7 @@ blockloop: continue blockloop } } - b.Fatal("no block available for layout") + b.Fatalf("no block available for layout") } f.Blocks = order } diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index 768ac124be..a72006ab2f 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -13,7 +13,7 @@ func lower(f *Func) { for _, b := range f.Blocks { for _, v := range b.Values { if opcodeTable[v.Op].generic && v.Op != OpFP && v.Op != OpSP && v.Op != OpArg && v.Op != OpCopy && v.Op != OpPhi { - f.Unimplemented("%s not lowered", v.LongString()) + f.Unimplementedf("%s not lowered", v.LongString()) } } } diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go index c1b97d2b8f..23fdbca7c4 100644 --- a/src/cmd/compile/internal/ssa/print.go +++ b/src/cmd/compile/internal/ssa/print.go @@ -11,7 +11,7 @@ import ( ) func printFunc(f *Func) { - f.Log("%s", f.String()) + f.Logf("%s", f.String()) } func (f *Func) String() string { diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index d1489b20f2..fde1cf457b 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -349,7 +349,7 @@ func regalloc(f *Func) { if b.Kind == BlockCall { call = b.Control if call != b.Values[len(b.Values)-1] { - b.Fatal("call not at end of block %b %v", b, call) + b.Fatalf("call not at end of block %b %v", b, call) } b.Values = b.Values[:len(b.Values)-1] // TODO: do this for all control types? @@ -419,7 +419,7 @@ func live(f *Func) [][]ID { t := newSparseSet(f.NumValues()) for { for _, b := range f.Blocks { - f.Log("live %s %v\n", b, live[b.ID]) + f.Logf("live %s %v\n", b, live[b.ID]) } changed := false diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 2bfd3813ed..0de8830fb2 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -12,10 +12,10 @@ func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) var curv *Value defer func() { if curb != nil { - curb.Fatal("panic during rewrite of block %s\n", curb.LongString()) + curb.Fatalf("panic during rewrite of block %s\n", curb.LongString()) } if curv != nil { - curv.Fatal("panic during rewrite of value %s\n", curv.LongString()) + curv.Fatalf("panic during rewrite of value %s\n", curv.LongString()) // TODO(khr): print source location also } }() diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 452d0c75a1..e39a3e7a59 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -77,7 +77,7 @@ func stackalloc(f *Func) { for _, v := range b.Values { if v.Op == OpFP { if fp != nil { - b.Fatal("multiple FP ops: %s %s", fp, v) + b.Fatalf("multiple FP ops: %s %s", fp, v) } fp = v } @@ -97,12 +97,12 @@ func stackalloc(f *Func) { case OpAMD64LEAQ, OpAMD64MOVQload, OpAMD64MOVQstore, OpAMD64MOVLload, OpAMD64MOVLstore, OpAMD64MOVWload, OpAMD64MOVWstore, OpAMD64MOVBload, OpAMD64MOVBstore, OpAMD64MOVQloadidx8: if v.Op == OpAMD64MOVQloadidx8 && i == 1 { // Note: we could do it, but it is probably an error - f.Fatal("can't do FP->SP adjust on index slot of load %s", v.Op) + f.Fatalf("can't do FP->SP adjust on index slot of load %s", v.Op) } // eg: (MOVQload [c] (FP) mem) -> (MOVQload [c+n] (SP) mem) v.AuxInt = addOff(v.AuxInt, n) default: - f.Unimplemented("can't do FP->SP adjust on %s", v.Op) + f.Unimplementedf("can't do FP->SP adjust on %s", v.Op) // TODO: OpCopy -> ADDQ } } diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index ef10fb20cd..9c7f148a79 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -111,6 +111,6 @@ func (v *Value) resetArgs() { v.Args = v.argstorage[:0] } -func (v *Value) Log(msg string, args ...interface{}) { v.Block.Log(msg, args...) } -func (v *Value) Fatal(msg string, args ...interface{}) { v.Block.Fatal(msg, args...) } -func (v *Value) Unimplemented(msg string, args ...interface{}) { v.Block.Unimplemented(msg, args...) } +func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) } +func (v *Value) Fatalf(msg string, args ...interface{}) { v.Block.Fatalf(msg, args...) } +func (v *Value) Unimplementedf(msg string, args ...interface{}) { v.Block.Unimplementedf(msg, args...) } -- cgit v1.3 From 7d10a2c04a28ac09448a3a890141a56870f86232 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 6 Jul 2015 14:13:17 -0700 Subject: [dev.ssa] cmd/compile/ssa: implement constant booleans The removal of if false { ... } blocks in the opt pass exposed that removePredecessor needed to do more cleaning, on pain of failing later consistency checks. Change-Id: I45d4ff7e1f7f1486fdd99f867867ce6ea006a288 Reviewed-on: https://go-review.googlesource.com/11879 Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/ssa.go | 2 +- src/cmd/compile/internal/ssa/deadcode.go | 69 +++++++++++++++----------- src/cmd/compile/internal/ssa/gen/rulegen.go | 2 +- src/cmd/compile/internal/ssa/nilcheck.go | 2 +- src/cmd/compile/internal/ssa/rewritegeneric.go | 4 +- 5 files changed, 46 insertions(+), 33 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 1be5f0cb85..866db610b8 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -464,7 +464,7 @@ func (s *state) expr(n *Node) *ssa.Value { switch n.Val().Ctype() { case CTINT: return s.constInt(n.Type, Mpgetfix(n.Val().U.(*Mpint))) - case CTSTR: + case CTSTR, CTBOOL: return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U) default: s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype()) diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 48d6fd6938..a5d0fe0f34 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -98,38 +98,51 @@ func deadcode(f *Func) { // There was an edge b->c. It has been removed from b's successors. // Fix up c to handle that fact. -func removePredecessor(b, c *Block) { - n := len(c.Preds) - 1 - if n == 0 { - // c is now dead - don't bother working on it - if c.Preds[0] != b { - b.Fatalf("%s.Preds[0]==%s, want %s", c, c.Preds[0], b) - } - return - } +func (f *Func) removePredecessor(b, c *Block) { + work := [][2]*Block{{b, c}} + + for len(work) > 0 { + b, c := work[0][0], work[0][1] + work = work[1:] + + n := len(c.Preds) - 1 - // find index of b in c's predecessor list - var i int - for j, p := range c.Preds { - if p == b { - i = j - break + // find index of b in c's predecessor list + var i int + for j, p := range c.Preds { + if p == b { + i = j + break + } } - } - c.Preds[i] = c.Preds[n] - c.Preds[n] = nil // aid GC - c.Preds = c.Preds[:n] - // rewrite phi ops to match the new predecessor list - for _, v := range c.Values { - if v.Op != OpPhi { - continue + c.Preds[i] = c.Preds[n] + c.Preds[n] = nil // aid GC + c.Preds = c.Preds[:n] + + // rewrite phi ops to match the new predecessor list + for _, v := range c.Values { + if v.Op != OpPhi { + continue + } + v.Args[i] = v.Args[n] + v.Args[n] = nil // aid GC + v.Args = v.Args[:n] + if n == 1 { + v.Op = OpCopy + } } - v.Args[i] = v.Args[n] - v.Args[n] = nil // aid GC - v.Args = v.Args[:n] - if n == 1 { - v.Op = OpCopy + + if n == 0 { + // c is now dead--recycle its values + for _, v := range c.Values { + f.vid.put(v.ID) + } + c.Values = nil + // Also kill any successors of c now, to spare later processing. + for _, succ := range c.Succs { + work = append(work, [2]*Block{c, succ}) + } } } } diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go index 1a4b2c1b85..46e0e507c4 100644 --- a/src/cmd/compile/internal/ssa/gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/gen/rulegen.go @@ -232,7 +232,7 @@ func genRules(arch arch) { // Modify predecessor lists for no-longer-reachable blocks for succ := range m { - fmt.Fprintf(w, "removePredecessor(b, %s)\n", succ) + fmt.Fprintf(w, "v.Block.Func.removePredecessor(b, %s)\n", succ) } fmt.Fprintf(w, "b.Kind = %s\n", blockName(t[0], arch)) diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go index 1265ee9971..d24340e630 100644 --- a/src/cmd/compile/internal/ssa/nilcheck.go +++ b/src/cmd/compile/internal/ssa/nilcheck.go @@ -46,7 +46,7 @@ func nilcheckelim(f *Func) { // and the fuse pass will join this block with its successor. b.Kind = BlockPlain b.Control = nil - removePredecessor(b, b.Succs[1]) + f.removePredecessor(b, b.Succs[1]) b.Succs = b.Succs[:1] } } diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index e2feeb53cc..78cb2c8ebb 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -403,7 +403,7 @@ func rewriteBlockgeneric(b *Block) bool { if !(c.(bool)) { goto end915e334b6388fed7d63e09aa69ecb05c } - removePredecessor(b, no) + v.Block.Func.removePredecessor(b, no) b.Kind = BlockPlain b.Control = nil b.Succs = b.Succs[:1] @@ -427,7 +427,7 @@ func rewriteBlockgeneric(b *Block) bool { if !(!c.(bool)) { goto end6452ee3a5bb02c708bddc3181c3ea3cb } - removePredecessor(b, yes) + v.Block.Func.removePredecessor(b, yes) b.Kind = BlockPlain b.Control = nil b.Succs = b.Succs[:1] -- cgit v1.3 From 9b048527db4122732795211291a02357d995c898 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 9 Jul 2015 21:24:12 -0600 Subject: [dev.ssa] cmd/compile/ssa: handle nested dead blocks removePredecessor can change which blocks are live. However, it cannot remove dead blocks from the function's slice of blocks because removePredecessor may have been called from within a function doing a walk of the blocks. CL 11879 did not handle this correctly and broke the build. To fix this, mark the block as dead but leave its actual removal for a deadcode pass. Blocks that are dead must have no successors, predecessors, values, or control values, so they will generally be ignored by other passes. To be safe, we add a deadcode pass after the opt pass, which is the only other pass that calls removePredecessor. Two alternatives that I considered and discarded: (1) Make all call sites aware of the fact that removePrecessor might make arbitrary changes to the list of blocks. This will needlessly complicate callers. (2) Handle the things that can go wrong in practice when we encounter a dead-but-not-removed block. CL 11930 takes this approach (and the tests are stolen from that CL). However, this is just patching over the problem. Change-Id: Icf0687b0a8148ce5e96b2988b668804411b05bd8 Reviewed-on: https://go-review.googlesource.com/12004 Reviewed-by: Todd Neal Reviewed-by: Michael Matloob --- src/cmd/compile/internal/ssa/check.go | 13 +++++++++ src/cmd/compile/internal/ssa/compile.go | 1 + src/cmd/compile/internal/ssa/deadcode.go | 8 ++++-- src/cmd/compile/internal/ssa/deadcode_test.go | 39 ++++++++++++++++++++++++++ src/cmd/compile/internal/ssa/gen/genericOps.go | 1 + src/cmd/compile/internal/ssa/opGen.go | 2 ++ src/cmd/compile/internal/ssa/rewrite.go | 3 ++ 7 files changed, 64 insertions(+), 3 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index a27e1bc653..4fe59e08d1 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -59,6 +59,19 @@ func checkFunc(f *Func) { if !b.Control.Type.IsMemory() { f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString()) } + case BlockDead: + if len(b.Succs) != 0 { + f.Fatalf("dead block %s has successors", b) + } + if len(b.Preds) != 0 { + f.Fatalf("dead block %s has predecessors", b) + } + if len(b.Values) != 0 { + f.Fatalf("dead block %s has values", b) + } + if b.Control != nil { + f.Fatalf("dead block %s has a control value", b) + } case BlockPlain: if len(b.Succs) != 1 { f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs)) diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index b02c10a745..4a6c2a9404 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -51,6 +51,7 @@ var passes = [...]pass{ {"phielim", phielim}, {"copyelim", copyelim}, {"opt", opt}, + {"opt deadcode", deadcode}, // remove any blocks orphaned during opt {"generic cse", cse}, {"nilcheckelim", nilcheckelim}, {"generic deadcode", deadcode}, diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index a5d0fe0f34..2be7b8ebaf 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -96,7 +96,7 @@ func deadcode(f *Func) { // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? } -// There was an edge b->c. It has been removed from b's successors. +// There was an edge b->c. c has been removed from b's successors. // Fix up c to handle that fact. func (f *Func) removePredecessor(b, c *Block) { work := [][2]*Block{{b, c}} @@ -105,8 +105,6 @@ func (f *Func) removePredecessor(b, c *Block) { b, c := work[0][0], work[0][1] work = work[1:] - n := len(c.Preds) - 1 - // find index of b in c's predecessor list var i int for j, p := range c.Preds { @@ -116,6 +114,7 @@ func (f *Func) removePredecessor(b, c *Block) { } } + n := len(c.Preds) - 1 c.Preds[i] = c.Preds[n] c.Preds[n] = nil // aid GC c.Preds = c.Preds[:n] @@ -143,6 +142,9 @@ func (f *Func) removePredecessor(b, c *Block) { for _, succ := range c.Succs { work = append(work, [2]*Block{c, succ}) } + c.Succs = nil + c.Kind = BlockDead + c.Control = nil } } } diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index ff9e6800da..c63b8e4106 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -93,3 +93,42 @@ func TestNeverTaken(t *testing.T) { } } + +func TestNestedDeadBlocks(t *testing.T) { + c := NewConfig("amd64", DummyFrontend{t}) + fun := Fun(c, "entry", + Bloc("entry", + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("cond", OpConst, TypeBool, 0, false), + If("cond", "b2", "b4")), + Bloc("b2", + If("cond", "b3", "b4")), + Bloc("b3", + If("cond", "b3", "b4")), + Bloc("b4", + If("cond", "b3", "exit")), + Bloc("exit", + Exit("mem"))) + + CheckFunc(fun.f) + Opt(fun.f) + CheckFunc(fun.f) + Deadcode(fun.f) + CheckFunc(fun.f) + if fun.blocks["entry"].Kind != BlockPlain { + t.Errorf("if(false) not simplified") + } + for _, b := range fun.f.Blocks { + if b == fun.blocks["b2"] { + t.Errorf("b2 block still present") + } + if b == fun.blocks["b3"] { + t.Errorf("b3 block still present") + } + for _, v := range b.Values { + if v == fun.values["cond"] { + t.Errorf("constant condition still present") + } + } + } +} diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index a6e6c93fc5..c410cc4f02 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -105,6 +105,7 @@ var genericOps = []opData{ var genericBlocks = []blockData{ {name: "Exit"}, // no successors. There should only be 1 of these. + {name: "Dead"}, // no successors; determined to be dead but not yet removed {name: "Plain"}, // a single successor {name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1] {name: "Call"}, // 2 successors, normal return and panic diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index a6fb0b06e2..3769cfeb86 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -19,6 +19,7 @@ const ( BlockAMD64UGE BlockExit + BlockDead BlockPlain BlockIf BlockCall @@ -39,6 +40,7 @@ var blockString = [...]string{ BlockAMD64UGE: "UGE", BlockExit: "Exit", + BlockDead: "Dead", BlockPlain: "Plain", BlockIf: "If", BlockCall: "Call", diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index b2c45969e4..306fe1274e 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -23,6 +23,9 @@ func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) for { change := false for _, b := range f.Blocks { + if b.Kind == BlockDead { + continue + } if b.Control != nil && b.Control.Op == OpCopy { for b.Control.Op == OpCopy { b.Control = b.Control.Args[0] -- cgit v1.3 From 050ce4390aa16b03e7272e22e79de165589319b5 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 11 Jul 2015 14:41:22 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: Phi inputs from dead blocks are not live Fixes #11676 Change-Id: I941f951633c89bb1454ce6d1d1b4124d46a7d9dd Reviewed-on: https://go-review.googlesource.com/12091 Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/ssa/deadcode.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 2be7b8ebaf..1b1ae27e58 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -44,7 +44,10 @@ func deadcode(f *Func) { // pop a reachable value v := q[len(q)-1] q = q[:len(q)-1] - for _, x := range v.Args { + for i, x := range v.Args { + if v.Op == OpPhi && !reachable[v.Block.Preds[i].ID] { + continue + } if !live[x.ID] { live[x.ID] = true q = append(q, x) // push -- cgit v1.3 From accf9b5951f14a7a62cfe9ec5c59d6dc880c1bba Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 11 Jul 2015 15:43:35 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: comment why replacing phi with copy is ok Change-Id: I3e2e8862f2fde4349923016b97e8330b0d494e0e Reviewed-on: https://go-review.googlesource.com/12092 Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/ssa/deadcode.go | 33 +++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 1b1ae27e58..04e5b71ceb 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -132,9 +132,40 @@ func (f *Func) removePredecessor(b, c *Block) { v.Args = v.Args[:n] if n == 1 { v.Op = OpCopy + // Note: this is trickier than it looks. Replacing + // a Phi with a Copy can in general cause problems because + // Phi and Copy don't have exactly the same semantics. + // Phi arguments always come from a predecessor block, + // whereas copies don't. This matters in loops like: + // 1: x = (Phi y) + // y = (Add x 1) + // goto 1 + // If we replace Phi->Copy, we get + // 1: x = (Copy y) + // y = (Add x 1) + // goto 1 + // (Phi y) refers to the *previous* value of y, whereas + // (Copy y) refers to the *current* value of y. + // The modified code has a cycle and the scheduler + // will barf on it. + // + // Fortunately, this situation can only happen for dead + // code loops. So although the value graph is transiently + // bad, we'll throw away the bad part by the end of + // the next deadcode phase. + // Proof: If we have a potential bad cycle, we have a + // situation like this: + // x = (Phi z) + // y = (op1 x ...) + // z = (op2 y ...) + // Where opX are not Phi ops. But such a situation + // implies a cycle in the dominator graph. In the + // example, x.Block dominates y.Block, y.Block dominates + // z.Block, and z.Block dominates x.Block (treating + // "dominates" as reflexive). Cycles in the dominator + // graph can only happen in an unreachable cycle. } } - if n == 0 { // c is now dead--recycle its values for _, v := range c.Values { -- cgit v1.3 From cfd8dfaa10ab387c6b9c9e620aadab5852a4c76e Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 4 Aug 2015 21:59:15 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: more checks on ssa structure Make sure all referenced Blocks and Values are really there. Fix deadcode to generate SSA graphs that pass this new test. Change-Id: Ib002ce20e33490eb8c919bd189d209f769d61517 Reviewed-on: https://go-review.googlesource.com/13147 Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/ssa/check.go | 29 ++++++++++++++++++++++++++--- src/cmd/compile/internal/ssa/deadcode.go | 16 ++++++++++++++-- 2 files changed, 40 insertions(+), 5 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 1f6ffc0129..668828fcd1 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -137,13 +137,36 @@ func checkFunc(f *Func) { } } + // Check to make sure all Blocks referenced are in the function. + if !blockMark[f.Entry.ID] { + f.Fatalf("entry block %v is missing", f.Entry) + } for _, b := range f.Blocks { - if b.Control != nil { - if !valueMark[b.Control.ID] { - f.Fatalf("control value for %s is missing: %v", b, b.Control) + for _, c := range b.Preds { + if !blockMark[c.ID] { + f.Fatalf("predecessor block %v for %v is missing", c, b) + } + } + for _, c := range b.Succs { + if !blockMark[c.ID] { + f.Fatalf("successor block %v for %v is missing", c, b) } } } + + // Check to make sure all Values referenced are in the function. + for _, b := range f.Blocks { + for _, v := range b.Values { + for i, a := range v.Args { + if !valueMark[a.ID] { + f.Fatalf("%v, arg %d of %v, is missing", a, i, v) + } + } + } + if b.Control != nil && !valueMark[b.Control.ID] { + f.Fatalf("control value for %s is missing: %v", b, b.Control) + } + } for _, id := range f.bid.free { if blockMark[id] { f.Fatalf("used block b%d in free list", id) diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 04e5b71ceb..426e6865c0 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -6,7 +6,6 @@ package ssa // deadcode removes dead code from f. func deadcode(f *Func) { - // Find all reachable basic blocks. reachable := make([]bool, f.NumBlocks()) reachable[f.Entry.ID] = true @@ -85,6 +84,11 @@ func deadcode(f *Func) { if len(b.Values) > 0 { b.Fatalf("live values in unreachable block %v: %v", b, b.Values) } + s := b.Succs + b.Succs = nil + for _, c := range s { + f.removePredecessor(b, c) + } f.bid.put(b.ID) } } @@ -108,14 +112,22 @@ func (f *Func) removePredecessor(b, c *Block) { b, c := work[0][0], work[0][1] work = work[1:] - // find index of b in c's predecessor list + // Find index of b in c's predecessor list + // TODO: This could conceivably cause O(n^2) work. Imagine a very + // wide phi in (for example) the return block. If we determine that + // lots of panics won't happen, we remove each edge at a cost of O(n) each. var i int + found := false for j, p := range c.Preds { if p == b { i = j + found = true break } } + if !found { + f.Fatalf("can't find predecessor %v of %v\n", b, c) + } n := len(c.Preds) - 1 c.Preds[i] = c.Preds[n] -- cgit v1.3 From 35fb514596b970a73be972fa917fa23ca74f7be6 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 10 Aug 2015 12:15:52 -0700 Subject: [dev.ssa] cmd/compile: add HTML SSA printer This is an initial implementation. There are many rough edges and TODOs, which will hopefully be polished out with use. Fixes #12071. Change-Id: I1d6fd5a343063b5200623bceef2c2cfcc885794e Reviewed-on: https://go-review.googlesource.com/13472 Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/ssa.go | 40 +++ src/cmd/compile/internal/ssa/compile.go | 3 + src/cmd/compile/internal/ssa/config.go | 16 +- src/cmd/compile/internal/ssa/deadcode.go | 17 +- src/cmd/compile/internal/ssa/html.go | 461 +++++++++++++++++++++++++++++++ src/cmd/compile/internal/ssa/print.go | 90 ++++-- src/cmd/internal/obj/obj.go | 25 +- 7 files changed, 607 insertions(+), 45 deletions(-) create mode 100644 src/cmd/compile/internal/ssa/html.go (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index c8ec01f5b6..882efc0dae 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -5,7 +5,9 @@ package gc import ( + "bytes" "fmt" + "html" "os" "strings" @@ -40,6 +42,18 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { s.f = s.config.NewFunc() s.f.Name = name + if name == os.Getenv("GOSSAFUNC") { + // TODO: tempfile? it is handy to have the location + // of this file be stable, so you can just reload in the browser. + s.config.HTML = ssa.NewHTMLWriter("ssa.html", &s, name) + // TODO: generate and print a mapping from nodes to values and blocks + } + defer func() { + if !usessa { + s.config.HTML.Close() + } + }() + // If SSA support for the function is incomplete, // assume that any panics are due to violated // invariants. Swallow them silently. @@ -1811,6 +1825,30 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { } f.Logf("%s\t%s\n", s, p) } + if f.Config.HTML != nil { + saved := ptxt.Ctxt.LineHist.PrintFilenameOnly + ptxt.Ctxt.LineHist.PrintFilenameOnly = true + var buf bytes.Buffer + buf.WriteString("") + buf.WriteString("
") + for p := ptxt; p != nil; p = p.Link { + buf.WriteString("
") + if v, ok := valueProgs[p]; ok { + buf.WriteString(v.HTML()) + } else if b, ok := blockProgs[p]; ok { + buf.WriteString(b.HTML()) + } + buf.WriteString("
") + buf.WriteString("
") + buf.WriteString(html.EscapeString(p.String())) + buf.WriteString("
") + buf.WriteString("") + } + buf.WriteString("
") + buf.WriteString("
") + f.Config.HTML.WriteColumn("genssa", buf.String()) + ptxt.Ctxt.LineHist.PrintFilenameOnly = saved + } } // Emit static data @@ -1834,6 +1872,8 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { ggloblsym(gcargs, 4, obj.RODATA|obj.DUPOK) duint32(gclocals, 0, 0) ggloblsym(gclocals, 4, obj.RODATA|obj.DUPOK) + + f.Config.HTML.Close() } func genValue(v *ssa.Value) { diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index 7ab8ddf3dc..e85fb10e00 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -34,13 +34,16 @@ func Compile(f *Func) { // Run all the passes printFunc(f) + f.Config.HTML.WriteFunc("start", f) checkFunc(f) for _, p := range passes { phaseName = p.name f.Logf(" pass %s begin\n", p.name) + // TODO: capture logging during this pass, add it to the HTML p.fn(f) f.Logf(" pass %s end\n", p.name) printFunc(f) + f.Config.HTML.WriteFunc("after "+phaseName, f) checkFunc(f) } diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 8aea59d13c..ad6441117c 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -11,6 +11,7 @@ type Config struct { lowerBlock func(*Block) bool // lowering function lowerValue func(*Value, *Config) bool // lowering function fe Frontend // callbacks into compiler frontend + HTML *HTMLWriter // html writer, for debugging // TODO: more stuff. Compiler flags of interest, ... } @@ -31,12 +32,7 @@ type TypeSource interface { TypeBytePtr() Type // TODO: use unsafe.Pointer instead? } -type Frontend interface { - TypeSource - - // StringData returns a symbol pointing to the given string's contents. - StringData(string) interface{} // returns *gc.Sym - +type Logger interface { // Log logs a message from the compiler. Logf(string, ...interface{}) @@ -48,6 +44,14 @@ type Frontend interface { Unimplementedf(msg string, args ...interface{}) } +type Frontend interface { + TypeSource + Logger + + // StringData returns a symbol pointing to the given string's contents. + StringData(string) interface{} // returns *gc.Sym +} + // NewConfig returns a new configuration object for the given architecture. func NewConfig(arch string, fe Frontend) *Config { c := &Config{arch: arch, fe: fe} diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 426e6865c0..109b3dd09f 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -4,10 +4,10 @@ package ssa -// deadcode removes dead code from f. -func deadcode(f *Func) { +// findlive returns the reachable blocks and live values in f. +func findlive(f *Func) (reachable []bool, live []bool) { // Find all reachable basic blocks. - reachable := make([]bool, f.NumBlocks()) + reachable = make([]bool, f.NumBlocks()) reachable[f.Entry.ID] = true p := []*Block{f.Entry} // stack-like worklist for len(p) > 0 { @@ -24,8 +24,8 @@ func deadcode(f *Func) { } // Find all live values - live := make([]bool, f.NumValues()) // flag to set for each live value - var q []*Value // stack-like worklist of unscanned values + live = make([]bool, f.NumValues()) // flag to set for each live value + var q []*Value // stack-like worklist of unscanned values // Starting set: all control values of reachable blocks are live. for _, b := range f.Blocks { @@ -54,6 +54,13 @@ func deadcode(f *Func) { } } + return reachable, live +} + +// deadcode removes dead code from f. +func deadcode(f *Func) { + reachable, live := findlive(f) + // Remove dead values from blocks' value list. Return dead // value ids to the allocator. for _, b := range f.Blocks { diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go new file mode 100644 index 0000000000..581331a215 --- /dev/null +++ b/src/cmd/compile/internal/ssa/html.go @@ -0,0 +1,461 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssa + +import ( + "bytes" + "fmt" + "html" + "io" + "os" +) + +type HTMLWriter struct { + Logger + *os.File +} + +func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter { + out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + logger.Fatalf("%v", err) + } + html := HTMLWriter{File: out, Logger: logger} + html.start(funcname) + return &html +} + +func (w *HTMLWriter) start(name string) { + if w == nil { + return + } + w.WriteString("") + w.WriteString(` + + + + +`) + // TODO: Add javascript click handlers for blocks + // to outline that block across all phases + w.WriteString("") + w.WriteString("

") + w.WriteString(html.EscapeString(name)) + w.WriteString("

") + w.WriteString(` +help +
+ +

+Click on a value or block to toggle highlighting of that value/block and its uses. +Values and blocks are highlighted by ID, which may vary across passes. +(TODO: Fix this.) +

+ +

+Faded out values and blocks are dead code that has not been eliminated. +

+ +

+Values printed in italics have a dependency cycle. +

+ +
+`) + w.WriteString("") + w.WriteString("") +} + +func (w *HTMLWriter) Close() { + if w == nil { + return + } + w.WriteString("") + w.WriteString("
") + w.WriteString("") + w.WriteString("") + w.File.Close() +} + +// WriteFunc writes f in a column headed by title. +func (w *HTMLWriter) WriteFunc(title string, f *Func) { + if w == nil { + return // avoid generating HTML just to discard it + } + w.WriteColumn(title, f.HTML()) + // TODO: Add visual representation of f's CFG. +} + +// WriteColumn writes raw HTML in a column headed by title. +// It is intended for pre- and post-compilation log output. +func (w *HTMLWriter) WriteColumn(title string, html string) { + if w == nil { + return + } + w.WriteString("") + w.WriteString("

" + title + "

") + w.WriteString(html) + w.WriteString("") +} + +func (w *HTMLWriter) Printf(msg string, v ...interface{}) { + if _, err := fmt.Fprintf(w.File, msg, v...); err != nil { + w.Fatalf("%v", err) + } +} + +func (w *HTMLWriter) WriteString(s string) { + if _, err := w.File.WriteString(s); err != nil { + w.Fatalf("%v", err) + } +} + +func (v *Value) HTML() string { + // TODO: Using the value ID as the class ignores the fact + // that value IDs get recycled and that some values + // are transmuted into other values. + return fmt.Sprintf("%[1]s", v.String()) +} + +func (v *Value) LongHTML() string { + // TODO: Any intra-value formatting? + // I'm wary of adding too much visual noise, + // but a little bit might be valuable. + // We already have visual noise in the form of punctuation + // maybe we could replace some of that with formatting. + s := fmt.Sprintf("", v.String()) + s += fmt.Sprintf("%s = %s", v.HTML(), v.Op.String()) + s += " <" + html.EscapeString(v.Type.String()) + ">" + if v.AuxInt != 0 { + s += fmt.Sprintf(" [%d]", v.AuxInt) + } + if v.Aux != nil { + if _, ok := v.Aux.(string); ok { + s += html.EscapeString(fmt.Sprintf(" {%q}", v.Aux)) + } else { + s += html.EscapeString(fmt.Sprintf(" {%v}", v.Aux)) + } + } + for _, a := range v.Args { + s += fmt.Sprintf(" %s", a.HTML()) + } + r := v.Block.Func.RegAlloc + if r != nil && r[v.ID] != nil { + s += " : " + r[v.ID].Name() + } + + s += "" + return s +} + +func (b *Block) HTML() string { + // TODO: Using the value ID as the class ignores the fact + // that value IDs get recycled and that some values + // are transmuted into other values. + return fmt.Sprintf("%[1]s", html.EscapeString(b.String())) +} + +func (b *Block) LongHTML() string { + // TODO: improve this for HTML? + s := b.Kind.String() + if b.Control != nil { + s += fmt.Sprintf(" %s", b.Control.HTML()) + } + if len(b.Succs) > 0 { + s += " →" // right arrow + for _, c := range b.Succs { + s += " " + c.HTML() + } + } + return s +} + +func (f *Func) HTML() string { + var buf bytes.Buffer + fmt.Fprint(&buf, "") + p := htmlFuncPrinter{w: &buf} + fprintFunc(p, f) + + // fprintFunc(&buf, f) // TODO: HTML, not text,
for line breaks, etc. + fmt.Fprint(&buf, "
") + return buf.String() +} + +type htmlFuncPrinter struct { + w io.Writer +} + +func (p htmlFuncPrinter) header(f *Func) {} + +func (p htmlFuncPrinter) startBlock(b *Block, reachable bool) { + // TODO: Make blocks collapsable? + var dead string + if !reachable { + dead = "dead-block" + } + fmt.Fprintf(p.w, "
    ", b, dead) + fmt.Fprintf(p.w, "
  • %s:", b.HTML()) + if len(b.Preds) > 0 { + io.WriteString(p.w, " ←") // left arrow + for _, pred := range b.Preds { + fmt.Fprintf(p.w, " %s", pred.HTML()) + } + } + io.WriteString(p.w, "
  • ") + if len(b.Values) > 0 { // start list of values + io.WriteString(p.w, "
  • ") + io.WriteString(p.w, "
      ") + } +} + +func (p htmlFuncPrinter) endBlock(b *Block) { + if len(b.Values) > 0 { // end list of values + io.WriteString(p.w, "
    ") + io.WriteString(p.w, "
  • ") + } + io.WriteString(p.w, "
  • ") + fmt.Fprint(p.w, b.LongHTML()) + io.WriteString(p.w, "
  • ") + io.WriteString(p.w, "
") + // io.WriteString(p.w, "") +} + +func (p htmlFuncPrinter) value(v *Value, live bool) { + var dead string + if !live { + dead = "dead-value" + } + fmt.Fprintf(p.w, "
  • ", dead) + fmt.Fprint(p.w, v.LongHTML()) + io.WriteString(p.w, "
  • ") +} + +func (p htmlFuncPrinter) startDepCycle() { + fmt.Fprintln(p.w, "") +} + +func (p htmlFuncPrinter) endDepCycle() { + fmt.Fprintln(p.w, "") +} diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go index 2f9db4438f..192dc83b39 100644 --- a/src/cmd/compile/internal/ssa/print.go +++ b/src/cmd/compile/internal/ssa/print.go @@ -16,33 +16,77 @@ func printFunc(f *Func) { func (f *Func) String() string { var buf bytes.Buffer - fprintFunc(&buf, f) + p := stringFuncPrinter{w: &buf} + fprintFunc(p, f) return buf.String() } -func fprintFunc(w io.Writer, f *Func) { - fmt.Fprint(w, f.Name) - fmt.Fprint(w, " ") - fmt.Fprintln(w, f.Type) +type funcPrinter interface { + header(f *Func) + startBlock(b *Block, reachable bool) + endBlock(b *Block) + value(v *Value, live bool) + startDepCycle() + endDepCycle() +} + +type stringFuncPrinter struct { + w io.Writer +} + +func (p stringFuncPrinter) header(f *Func) { + fmt.Fprint(p.w, f.Name) + fmt.Fprint(p.w, " ") + fmt.Fprintln(p.w, f.Type) +} + +func (p stringFuncPrinter) startBlock(b *Block, reachable bool) { + fmt.Fprintf(p.w, " b%d:", b.ID) + if len(b.Preds) > 0 { + io.WriteString(p.w, " <-") + for _, pred := range b.Preds { + fmt.Fprintf(p.w, " b%d", pred.ID) + } + } + if !reachable { + fmt.Fprint(p.w, " DEAD") + } + io.WriteString(p.w, "\n") +} + +func (p stringFuncPrinter) endBlock(b *Block) { + fmt.Fprintln(p.w, " "+b.LongString()) +} + +func (p stringFuncPrinter) value(v *Value, live bool) { + fmt.Fprint(p.w, " ") + fmt.Fprint(p.w, v.LongString()) + if !live { + fmt.Fprint(p.w, " DEAD") + } + fmt.Fprintln(p.w) +} + +func (p stringFuncPrinter) startDepCycle() { + fmt.Fprintln(p.w, "dependency cycle!") +} + +func (p stringFuncPrinter) endDepCycle() {} + +func fprintFunc(p funcPrinter, f *Func) { + reachable, live := findlive(f) + p.header(f) printed := make([]bool, f.NumValues()) for _, b := range f.Blocks { - fmt.Fprintf(w, " b%d:", b.ID) - if len(b.Preds) > 0 { - io.WriteString(w, " <-") - for _, pred := range b.Preds { - fmt.Fprintf(w, " b%d", pred.ID) - } - } - io.WriteString(w, "\n") + p.startBlock(b, reachable[b.ID]) if f.scheduled { // Order of Values has been decided - print in that order. for _, v := range b.Values { - fmt.Fprint(w, " ") - fmt.Fprintln(w, v.LongString()) + p.value(v, live[v.ID]) printed[v.ID] = true } - fmt.Fprintln(w, " "+b.LongString()) + p.endBlock(b) continue } @@ -52,8 +96,7 @@ func fprintFunc(w io.Writer, f *Func) { if v.Op != OpPhi { continue } - fmt.Fprint(w, " ") - fmt.Fprintln(w, v.LongString()) + p.value(v, live[v.ID]) printed[v.ID] = true n++ } @@ -73,25 +116,24 @@ func fprintFunc(w io.Writer, f *Func) { continue outer } } - fmt.Fprint(w, " ") - fmt.Fprintln(w, v.LongString()) + p.value(v, live[v.ID]) printed[v.ID] = true n++ } if m == n { - fmt.Fprintln(w, "dependency cycle!") + p.startDepCycle() for _, v := range b.Values { if printed[v.ID] { continue } - fmt.Fprint(w, " ") - fmt.Fprintln(w, v.LongString()) + p.value(v, live[v.ID]) printed[v.ID] = true n++ } + p.endDepCycle() } } - fmt.Fprintln(w, " "+b.LongString()) + p.endBlock(b) } } diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go index af3290d3a5..6229bbb288 100644 --- a/src/cmd/internal/obj/obj.go +++ b/src/cmd/internal/obj/obj.go @@ -25,12 +25,13 @@ import ( // together, so that given (only) calls Push(10, "x.go", 1) and Pop(15), // virtual line 12 corresponds to x.go line 3. type LineHist struct { - Top *LineStack // current top of stack - Ranges []LineRange // ranges for lookup - Dir string // directory to qualify relative paths - TrimPathPrefix string // remove leading TrimPath from recorded file names - GOROOT string // current GOROOT - GOROOT_FINAL string // target GOROOT + Top *LineStack // current top of stack + Ranges []LineRange // ranges for lookup + Dir string // directory to qualify relative paths + TrimPathPrefix string // remove leading TrimPath from recorded file names + PrintFilenameOnly bool // ignore path when pretty-printing a line; internal use only + GOROOT string // current GOROOT + GOROOT_FINAL string // target GOROOT } // A LineStack is an entry in the recorded line history. @@ -221,20 +222,24 @@ func (h *LineHist) LineString(lineno int) string { return "" } - text := fmt.Sprintf("%s:%d", stk.File, stk.fileLineAt(lineno)) + filename := stk.File + if h.PrintFilenameOnly { + filename = filepath.Base(filename) + } + text := fmt.Sprintf("%s:%d", filename, stk.fileLineAt(lineno)) if stk.Directive && stk.Parent != nil { stk = stk.Parent - text += fmt.Sprintf("[%s:%d]", stk.File, stk.fileLineAt(lineno)) + text += fmt.Sprintf("[%s:%d]", filename, stk.fileLineAt(lineno)) } const showFullStack = false // was used by old C compilers if showFullStack { for stk.Parent != nil { lineno = stk.Lineno - 1 stk = stk.Parent - text += fmt.Sprintf(" %s:%d", stk.File, stk.fileLineAt(lineno)) + text += fmt.Sprintf(" %s:%d", filename, stk.fileLineAt(lineno)) if stk.Directive && stk.Parent != nil { stk = stk.Parent - text += fmt.Sprintf("[%s:%d]", stk.File, stk.fileLineAt(lineno)) + text += fmt.Sprintf("[%s:%d]", filename, stk.fileLineAt(lineno)) } } } -- cgit v1.3 From 0b46b42943ee9d7ad4e9a19772d22468718173c9 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 11 Aug 2015 12:51:33 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: New register allocator Implement a global (whole function) register allocator. This replaces the local (per basic block) register allocator. Clobbering of registers by instructions is handled properly. A separate change will add the correct clobbers to all the instructions. Change-Id: I38ce4dc7dccb8303c1c0e0295fe70247b0a3f2ea Reviewed-on: https://go-review.googlesource.com/13622 Reviewed-by: Josh Bleecher Snyder Reviewed-by: Todd Neal --- src/cmd/compile/internal/gc/ssa.go | 12 +- .../compile/internal/gc/testdata/regalloc_ssa.go | 57 ++ src/cmd/compile/internal/ssa/deadcode.go | 8 + src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 34 +- src/cmd/compile/internal/ssa/gen/main.go | 42 +- src/cmd/compile/internal/ssa/html.go | 2 +- src/cmd/compile/internal/ssa/op.go | 7 +- src/cmd/compile/internal/ssa/opGen.go | 909 ++++++++-------- src/cmd/compile/internal/ssa/regalloc.go | 1081 ++++++++++++++------ src/cmd/compile/internal/ssa/stackalloc.go | 18 +- src/cmd/compile/internal/ssa/tighten.go | 7 - src/cmd/compile/internal/ssa/value.go | 4 +- 12 files changed, 1439 insertions(+), 742 deletions(-) create mode 100644 src/cmd/compile/internal/gc/testdata/regalloc_ssa.go (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 4e115a0fcd..ef90ed40e7 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -2277,7 +2277,10 @@ func genValue(v *ssa.Value) { p.To.Reg = x86.REG_SP p.To.Offset = localOffset(v) case ssa.OpPhi: - // just check to make sure regalloc did it right + // just check to make sure regalloc and stackalloc did it right + if v.Type.IsMemory() { + return + } f := v.Block.Func loc := f.RegAlloc[v.ID] for _, a := range v.Args { @@ -2376,13 +2379,16 @@ func genValue(v *ssa.Value) { case ssa.OpAMD64InvertFlags: v.Fatalf("InvertFlags should never make it to codegen %v", v) case ssa.OpAMD64REPSTOSQ: + p := Prog(x86.AXORL) // TODO: lift out zeroing into its own instruction? + p.From.Type = obj.TYPE_REG + p.From.Reg = x86.REG_AX + p.To.Type = obj.TYPE_REG + p.To.Reg = x86.REG_AX Prog(x86.AREP) Prog(x86.ASTOSQ) - v.Unimplementedf("REPSTOSQ clobbers not implemented: %s", v.LongString()) case ssa.OpAMD64REPMOVSB: Prog(x86.AREP) Prog(x86.AMOVSB) - v.Unimplementedf("REPMOVSB clobbers not implemented: %s", v.LongString()) default: v.Unimplementedf("genValue not implemented: %s", v.LongString()) } diff --git a/src/cmd/compile/internal/gc/testdata/regalloc_ssa.go b/src/cmd/compile/internal/gc/testdata/regalloc_ssa.go new file mode 100644 index 0000000000..f752692952 --- /dev/null +++ b/src/cmd/compile/internal/gc/testdata/regalloc_ssa.go @@ -0,0 +1,57 @@ +// run + +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Tests phi implementation + +package main + +func phiOverwrite_ssa() int { + var n int + for i := 0; i < 10; i++ { + if i == 6 { + break + } + n = i + } + return n +} + +func phiOverwrite() { + want := 5 + got := phiOverwrite_ssa() + if got != want { + println("phiOverwrite_ssa()=", want, ", got", got) + failed = true + } +} + +func phiOverwriteBig_ssa() int { + var a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int + a = 1 + for idx := 0; idx < 26; idx++ { + a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z = b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a + } + return a*1 + b*2 + c*3 + d*4 + e*5 + f*6 + g*7 + h*8 + i*9 + j*10 + k*11 + l*12 + m*13 + n*14 + o*15 + p*16 + q*17 + r*18 + s*19 + t*20 + u*21 + v*22 + w*23 + x*24 + y*25 + z*26 +} + +func phiOverwriteBig() { + want := 1 + got := phiOverwriteBig_ssa() + if got != want { + println("phiOverwriteBig_ssa()=", want, ", got", got) + failed = true + } +} + +var failed = false + +func main() { + phiOverwrite() + phiOverwriteBig() + if failed { + panic("failed") + } +} diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 109b3dd09f..8c306c8412 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -59,6 +59,14 @@ func findlive(f *Func) (reachable []bool, live []bool) { // deadcode removes dead code from f. func deadcode(f *Func) { + // deadcode after regalloc is forbidden for now. Regalloc + // doesn't quite generate legal SSA which will lead to some + // required moves being eliminated. See the comment at the + // top of regalloc.go for details. + if f.RegAlloc != nil { + f.Fatalf("deadcode after regalloc") + } + reachable, live := findlive(f) // Remove dead values from blocks' value list. Return dead diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 8bdcfaaac7..5aa5e60e33 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -72,13 +72,14 @@ func init() { // Common individual register masks var ( - cx = buildReg("CX") - x15 = buildReg("X15") - gp = buildReg("AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15") - fp = buildReg("X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15") - gpsp = gp | buildReg("SP") - gpspsb = gpsp | buildReg("SB") - flags = buildReg("FLAGS") + cx = buildReg("CX") + x15 = buildReg("X15") + gp = buildReg("AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15") + fp = buildReg("X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15") + gpsp = gp | buildReg("SP") + gpspsb = gpsp | buildReg("SB") + flags = buildReg("FLAGS") + callerSave = gp | fp | flags ) // Common slices of register masks @@ -90,16 +91,16 @@ func init() { // Common regInfo var ( - gp01 = regInfo{inputs: []regMask{}, outputs: gponly} - gp11 = regInfo{inputs: []regMask{gpsp}, outputs: gponly} - gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly} - gp21 = regInfo{inputs: []regMask{gpsp, gpsp}, outputs: gponly} - gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly} - gp21shift = regInfo{inputs: []regMask{gpsp, cx}, outputs: []regMask{gp &^ cx}} + gp01 = regInfo{inputs: []regMask{}, outputs: gponly, clobbers: flags} + gp11 = regInfo{inputs: []regMask{gpsp}, outputs: gponly, clobbers: flags} + gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly, clobbers: flags} + gp21 = regInfo{inputs: []regMask{gpsp, gpsp}, outputs: gponly, clobbers: flags} + gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly, clobbers: flags} + gp21shift = regInfo{inputs: []regMask{gpsp, cx}, outputs: []regMask{gp &^ cx}, clobbers: flags} gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}, outputs: flagsonly} gp1flags = regInfo{inputs: []regMask{gpsp}, outputs: flagsonly} - flagsgp = regInfo{inputs: flagsonly, outputs: gponly} + flagsgp = regInfo{inputs: flagsonly, outputs: gponly, clobbers: flags} gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly} gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly} @@ -122,6 +123,7 @@ func init() { fpstore = regInfo{inputs: []regMask{gpspsb, fp, 0}} fpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, fp, 0}} ) + // TODO: most ops clobber flags // Suffixes encode the bit width of various instructions. // Q = 64 bit, L = 32 bit, W = 16 bit, B = 8 bit @@ -318,8 +320,8 @@ func init() { {name: "REPSTOSQ", reg: regInfo{[]regMask{buildReg("DI"), buildReg("CX")}, buildReg("DI AX CX"), nil}}, // store arg1 8-byte words containing zero into arg0 using STOSQ. arg2=mem. //TODO: set register clobber to everything? - {name: "CALLstatic"}, // call static function aux.(*gc.Sym). arg0=mem, returns mem - {name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, 0, nil}}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem returns mem + {name: "CALLstatic", reg: regInfo{clobbers: callerSave}}, // call static function aux.(*gc.Sym). arg0=mem, returns mem + {name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, callerSave, nil}}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem returns mem {name: "REPMOVSB", reg: regInfo{[]regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")}, buildReg("DI SI CX"), nil}}, // move arg2 bytes from arg1 to arg0. arg3=mem, returns memory diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go index 97ac802cbd..6620c0a1d0 100644 --- a/src/cmd/compile/internal/ssa/gen/main.go +++ b/src/cmd/compile/internal/ssa/gen/main.go @@ -15,6 +15,7 @@ import ( "io/ioutil" "log" "regexp" + "sort" ) type arch struct { @@ -125,11 +126,22 @@ func genOp() { fmt.Fprintf(w, "asm: x86.A%s,\n", v.asm) } fmt.Fprintln(w, "reg:regInfo{") - // reg inputs - if len(v.reg.inputs) > 0 { - fmt.Fprintln(w, "inputs: []regMask{") - for _, r := range v.reg.inputs { - fmt.Fprintf(w, "%d,%s\n", r, a.regMaskComment(r)) + + // Compute input allocation order. We allocate from the + // most to the least constrained input. This order guarantees + // that we will always be able to find a register. + var s []intPair + for i, r := range v.reg.inputs { + if r != 0 { + s = append(s, intPair{countRegs(r), i}) + } + } + if len(s) > 0 { + sort.Sort(byKey(s)) + fmt.Fprintln(w, "inputs: []inputInfo{") + for _, p := range s { + r := v.reg.inputs[p.val] + fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r)) } fmt.Fprintln(w, "},") } @@ -205,3 +217,23 @@ func genLower() { genRules(a) } } + +// countRegs returns the number of set bits in the register mask. +func countRegs(r regMask) int { + n := 0 + for r != 0 { + n += int(r & 1) + r >>= 1 + } + return n +} + +// for sorting a pair of integers by key +type intPair struct { + key, val int +} +type byKey []intPair + +func (a byKey) Len() int { return len(a) } +func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key } diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index 848e016129..5c23320680 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -362,7 +362,7 @@ func (v *Value) LongHTML() string { s += fmt.Sprintf(" %s", a.HTML()) } r := v.Block.Func.RegAlloc - if r != nil && r[v.ID] != nil { + if int(v.ID) < len(r) && r[v.ID] != nil { s += " : " + r[v.ID].Name() } diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 4ca8c770cb..356084fb02 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -19,8 +19,13 @@ type opInfo struct { generic bool // this is a generic (arch-independent) opcode } +type inputInfo struct { + idx int // index in Args array + regs regMask // allowed input registers +} + type regInfo struct { - inputs []regMask + inputs []inputInfo // ordered in register allocation order clobbers regMask outputs []regMask // NOTE: values can only have 1 output for now. } diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 2155cd318e..cbabbfade5 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -425,9 +425,9 @@ var opcodeTable = [...]opInfo{ name: "ADDSS", asm: x86.AADDSS, reg: regInfo{ - inputs: []regMask{ - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + inputs: []inputInfo{ + {0, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + {1, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 }, outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -438,9 +438,9 @@ var opcodeTable = [...]opInfo{ name: "ADDSD", asm: x86.AADDSD, reg: regInfo{ - inputs: []regMask{ - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + inputs: []inputInfo{ + {0, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + {1, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 }, outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -451,9 +451,9 @@ var opcodeTable = [...]opInfo{ name: "SUBSS", asm: x86.ASUBSS, reg: regInfo{ - inputs: []regMask{ - 2147418112, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 - 2147418112, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 + inputs: []inputInfo{ + {0, 2147418112}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 + {1, 2147418112}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 }, clobbers: 2147483648, // .X15 outputs: []regMask{ @@ -465,9 +465,9 @@ var opcodeTable = [...]opInfo{ name: "SUBSD", asm: x86.ASUBSD, reg: regInfo{ - inputs: []regMask{ - 2147418112, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 - 2147418112, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 + inputs: []inputInfo{ + {0, 2147418112}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 + {1, 2147418112}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 }, clobbers: 2147483648, // .X15 outputs: []regMask{ @@ -479,9 +479,9 @@ var opcodeTable = [...]opInfo{ name: "MULSS", asm: x86.AMULSS, reg: regInfo{ - inputs: []regMask{ - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + inputs: []inputInfo{ + {0, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + {1, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 }, outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -492,9 +492,9 @@ var opcodeTable = [...]opInfo{ name: "MULSD", asm: x86.AMULSD, reg: regInfo{ - inputs: []regMask{ - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + inputs: []inputInfo{ + {0, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + {1, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 }, outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -505,9 +505,9 @@ var opcodeTable = [...]opInfo{ name: "DIVSS", asm: x86.ADIVSS, reg: regInfo{ - inputs: []regMask{ - 2147418112, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 - 2147418112, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 + inputs: []inputInfo{ + {0, 2147418112}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 + {1, 2147418112}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 }, clobbers: 2147483648, // .X15 outputs: []regMask{ @@ -519,9 +519,9 @@ var opcodeTable = [...]opInfo{ name: "DIVSD", asm: x86.ADIVSD, reg: regInfo{ - inputs: []regMask{ - 2147418112, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 - 2147418112, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 + inputs: []inputInfo{ + {0, 2147418112}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 + {1, 2147418112}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 }, clobbers: 2147483648, // .X15 outputs: []regMask{ @@ -533,9 +533,8 @@ var opcodeTable = [...]opInfo{ name: "MOVSSload", asm: x86.AMOVSS, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 0, + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -546,9 +545,8 @@ var opcodeTable = [...]opInfo{ name: "MOVSDload", asm: x86.AMOVSD, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 0, + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -577,10 +575,9 @@ var opcodeTable = [...]opInfo{ name: "MOVSSloadidx4", asm: x86.AMOVSS, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -591,10 +588,9 @@ var opcodeTable = [...]opInfo{ name: "MOVSDloadidx8", asm: x86.AMOVSD, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -605,10 +601,9 @@ var opcodeTable = [...]opInfo{ name: "MOVSSstore", asm: x86.AMOVSS, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 - 0, + inputs: []inputInfo{ + {1, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, @@ -616,10 +611,9 @@ var opcodeTable = [...]opInfo{ name: "MOVSDstore", asm: x86.AMOVSD, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 - 0, + inputs: []inputInfo{ + {1, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, @@ -627,11 +621,10 @@ var opcodeTable = [...]opInfo{ name: "MOVSSstoreidx4", asm: x86.AMOVSS, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {2, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, @@ -639,11 +632,10 @@ var opcodeTable = [...]opInfo{ name: "MOVSDstoreidx8", asm: x86.AMOVSD, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {2, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, @@ -651,10 +643,11 @@ var opcodeTable = [...]opInfo{ name: "ADDQ", asm: x86.AADDQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -664,10 +657,11 @@ var opcodeTable = [...]opInfo{ name: "ADDL", asm: x86.AADDL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -677,10 +671,11 @@ var opcodeTable = [...]opInfo{ name: "ADDW", asm: x86.AADDW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -690,10 +685,11 @@ var opcodeTable = [...]opInfo{ name: "ADDB", asm: x86.AADDB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -703,9 +699,10 @@ var opcodeTable = [...]opInfo{ name: "ADDQconst", asm: x86.AADDQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -715,9 +712,10 @@ var opcodeTable = [...]opInfo{ name: "ADDLconst", asm: x86.AADDL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -727,9 +725,10 @@ var opcodeTable = [...]opInfo{ name: "ADDWconst", asm: x86.AADDW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -739,9 +738,10 @@ var opcodeTable = [...]opInfo{ name: "ADDBconst", asm: x86.AADDB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -751,10 +751,11 @@ var opcodeTable = [...]opInfo{ name: "SUBQ", asm: x86.ASUBQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -764,10 +765,11 @@ var opcodeTable = [...]opInfo{ name: "SUBL", asm: x86.ASUBL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -777,10 +779,11 @@ var opcodeTable = [...]opInfo{ name: "SUBW", asm: x86.ASUBW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -790,10 +793,11 @@ var opcodeTable = [...]opInfo{ name: "SUBB", asm: x86.ASUBB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -803,9 +807,10 @@ var opcodeTable = [...]opInfo{ name: "SUBQconst", asm: x86.ASUBQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -815,9 +820,10 @@ var opcodeTable = [...]opInfo{ name: "SUBLconst", asm: x86.ASUBL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -827,9 +833,10 @@ var opcodeTable = [...]opInfo{ name: "SUBWconst", asm: x86.ASUBW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -839,9 +846,10 @@ var opcodeTable = [...]opInfo{ name: "SUBBconst", asm: x86.ASUBB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -851,10 +859,11 @@ var opcodeTable = [...]opInfo{ name: "MULQ", asm: x86.AIMULQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -864,10 +873,11 @@ var opcodeTable = [...]opInfo{ name: "MULL", asm: x86.AIMULL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -877,10 +887,11 @@ var opcodeTable = [...]opInfo{ name: "MULW", asm: x86.AIMULW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -890,10 +901,11 @@ var opcodeTable = [...]opInfo{ name: "MULB", asm: x86.AIMULW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -903,9 +915,10 @@ var opcodeTable = [...]opInfo{ name: "MULQconst", asm: x86.AIMULQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -915,9 +928,10 @@ var opcodeTable = [...]opInfo{ name: "MULLconst", asm: x86.AIMULL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -927,9 +941,10 @@ var opcodeTable = [...]opInfo{ name: "MULWconst", asm: x86.AIMULW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -939,9 +954,10 @@ var opcodeTable = [...]opInfo{ name: "MULBconst", asm: x86.AIMULW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -951,10 +967,11 @@ var opcodeTable = [...]opInfo{ name: "ANDQ", asm: x86.AANDQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -964,10 +981,11 @@ var opcodeTable = [...]opInfo{ name: "ANDL", asm: x86.AANDL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -977,10 +995,11 @@ var opcodeTable = [...]opInfo{ name: "ANDW", asm: x86.AANDW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -990,10 +1009,11 @@ var opcodeTable = [...]opInfo{ name: "ANDB", asm: x86.AANDB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1003,9 +1023,10 @@ var opcodeTable = [...]opInfo{ name: "ANDQconst", asm: x86.AANDQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1015,9 +1036,10 @@ var opcodeTable = [...]opInfo{ name: "ANDLconst", asm: x86.AANDL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1027,9 +1049,10 @@ var opcodeTable = [...]opInfo{ name: "ANDWconst", asm: x86.AANDW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1039,9 +1062,10 @@ var opcodeTable = [...]opInfo{ name: "ANDBconst", asm: x86.AANDB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1051,10 +1075,11 @@ var opcodeTable = [...]opInfo{ name: "ORQ", asm: x86.AORQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1064,10 +1089,11 @@ var opcodeTable = [...]opInfo{ name: "ORL", asm: x86.AORL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1077,10 +1103,11 @@ var opcodeTable = [...]opInfo{ name: "ORW", asm: x86.AORW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1090,10 +1117,11 @@ var opcodeTable = [...]opInfo{ name: "ORB", asm: x86.AORB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1103,9 +1131,10 @@ var opcodeTable = [...]opInfo{ name: "ORQconst", asm: x86.AORQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1115,9 +1144,10 @@ var opcodeTable = [...]opInfo{ name: "ORLconst", asm: x86.AORL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1127,9 +1157,10 @@ var opcodeTable = [...]opInfo{ name: "ORWconst", asm: x86.AORW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1139,9 +1170,10 @@ var opcodeTable = [...]opInfo{ name: "ORBconst", asm: x86.AORB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1151,10 +1183,11 @@ var opcodeTable = [...]opInfo{ name: "XORQ", asm: x86.AXORQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1164,10 +1197,11 @@ var opcodeTable = [...]opInfo{ name: "XORL", asm: x86.AXORL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1177,10 +1211,11 @@ var opcodeTable = [...]opInfo{ name: "XORW", asm: x86.AXORW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1190,10 +1225,11 @@ var opcodeTable = [...]opInfo{ name: "XORB", asm: x86.AXORB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1203,9 +1239,10 @@ var opcodeTable = [...]opInfo{ name: "XORQconst", asm: x86.AXORQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1215,9 +1252,10 @@ var opcodeTable = [...]opInfo{ name: "XORLconst", asm: x86.AXORL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1227,9 +1265,10 @@ var opcodeTable = [...]opInfo{ name: "XORWconst", asm: x86.AXORW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1239,9 +1278,10 @@ var opcodeTable = [...]opInfo{ name: "XORBconst", asm: x86.AXORB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1251,9 +1291,9 @@ var opcodeTable = [...]opInfo{ name: "CMPQ", asm: x86.ACMPQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1264,9 +1304,9 @@ var opcodeTable = [...]opInfo{ name: "CMPL", asm: x86.ACMPL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1277,9 +1317,9 @@ var opcodeTable = [...]opInfo{ name: "CMPW", asm: x86.ACMPW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1290,9 +1330,9 @@ var opcodeTable = [...]opInfo{ name: "CMPB", asm: x86.ACMPB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1303,8 +1343,8 @@ var opcodeTable = [...]opInfo{ name: "CMPQconst", asm: x86.ACMPQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1315,8 +1355,8 @@ var opcodeTable = [...]opInfo{ name: "CMPLconst", asm: x86.ACMPL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1327,8 +1367,8 @@ var opcodeTable = [...]opInfo{ name: "CMPWconst", asm: x86.ACMPW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1339,8 +1379,8 @@ var opcodeTable = [...]opInfo{ name: "CMPBconst", asm: x86.ACMPB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1351,9 +1391,9 @@ var opcodeTable = [...]opInfo{ name: "TESTQ", asm: x86.ATESTQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1364,9 +1404,9 @@ var opcodeTable = [...]opInfo{ name: "TESTL", asm: x86.ATESTL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1377,9 +1417,9 @@ var opcodeTable = [...]opInfo{ name: "TESTW", asm: x86.ATESTW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1390,9 +1430,9 @@ var opcodeTable = [...]opInfo{ name: "TESTB", asm: x86.ATESTB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1403,8 +1443,8 @@ var opcodeTable = [...]opInfo{ name: "TESTQconst", asm: x86.ATESTQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1415,8 +1455,8 @@ var opcodeTable = [...]opInfo{ name: "TESTLconst", asm: x86.ATESTL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1427,8 +1467,8 @@ var opcodeTable = [...]opInfo{ name: "TESTWconst", asm: x86.ATESTW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1439,8 +1479,8 @@ var opcodeTable = [...]opInfo{ name: "TESTBconst", asm: x86.ATESTB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, outputs: []regMask{ 8589934592, // .FLAGS @@ -1451,10 +1491,11 @@ var opcodeTable = [...]opInfo{ name: "SHLQ", asm: x86.ASHLQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1464,10 +1505,11 @@ var opcodeTable = [...]opInfo{ name: "SHLL", asm: x86.ASHLL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1477,10 +1519,11 @@ var opcodeTable = [...]opInfo{ name: "SHLW", asm: x86.ASHLW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1490,10 +1533,11 @@ var opcodeTable = [...]opInfo{ name: "SHLB", asm: x86.ASHLB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1503,9 +1547,10 @@ var opcodeTable = [...]opInfo{ name: "SHLQconst", asm: x86.ASHLQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1515,9 +1560,10 @@ var opcodeTable = [...]opInfo{ name: "SHLLconst", asm: x86.ASHLL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1527,9 +1573,10 @@ var opcodeTable = [...]opInfo{ name: "SHLWconst", asm: x86.ASHLW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1539,9 +1586,10 @@ var opcodeTable = [...]opInfo{ name: "SHLBconst", asm: x86.ASHLB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1551,10 +1599,11 @@ var opcodeTable = [...]opInfo{ name: "SHRQ", asm: x86.ASHRQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1564,10 +1613,11 @@ var opcodeTable = [...]opInfo{ name: "SHRL", asm: x86.ASHRL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1577,10 +1627,11 @@ var opcodeTable = [...]opInfo{ name: "SHRW", asm: x86.ASHRW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1590,10 +1641,11 @@ var opcodeTable = [...]opInfo{ name: "SHRB", asm: x86.ASHRB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1603,9 +1655,10 @@ var opcodeTable = [...]opInfo{ name: "SHRQconst", asm: x86.ASHRQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1615,9 +1668,10 @@ var opcodeTable = [...]opInfo{ name: "SHRLconst", asm: x86.ASHRL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1627,9 +1681,10 @@ var opcodeTable = [...]opInfo{ name: "SHRWconst", asm: x86.ASHRW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1639,9 +1694,10 @@ var opcodeTable = [...]opInfo{ name: "SHRBconst", asm: x86.ASHRB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1651,10 +1707,11 @@ var opcodeTable = [...]opInfo{ name: "SARQ", asm: x86.ASARQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1664,10 +1721,11 @@ var opcodeTable = [...]opInfo{ name: "SARL", asm: x86.ASARL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1677,10 +1735,11 @@ var opcodeTable = [...]opInfo{ name: "SARW", asm: x86.ASARW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1690,10 +1749,11 @@ var opcodeTable = [...]opInfo{ name: "SARB", asm: x86.ASARB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 2, // .CX + inputs: []inputInfo{ + {1, 2}, // .CX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65517, // .AX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1703,9 +1763,10 @@ var opcodeTable = [...]opInfo{ name: "SARQconst", asm: x86.ASARQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1715,9 +1776,10 @@ var opcodeTable = [...]opInfo{ name: "SARLconst", asm: x86.ASARL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1727,9 +1789,10 @@ var opcodeTable = [...]opInfo{ name: "SARWconst", asm: x86.ASARW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1739,9 +1802,10 @@ var opcodeTable = [...]opInfo{ name: "SARBconst", asm: x86.ASARB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1751,9 +1815,10 @@ var opcodeTable = [...]opInfo{ name: "ROLQconst", asm: x86.AROLQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1763,9 +1828,10 @@ var opcodeTable = [...]opInfo{ name: "ROLLconst", asm: x86.AROLL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1775,9 +1841,10 @@ var opcodeTable = [...]opInfo{ name: "ROLWconst", asm: x86.AROLW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1787,9 +1854,10 @@ var opcodeTable = [...]opInfo{ name: "ROLBconst", asm: x86.AROLB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1799,9 +1867,10 @@ var opcodeTable = [...]opInfo{ name: "NEGQ", asm: x86.ANEGQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1811,9 +1880,10 @@ var opcodeTable = [...]opInfo{ name: "NEGL", asm: x86.ANEGL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1823,9 +1893,10 @@ var opcodeTable = [...]opInfo{ name: "NEGW", asm: x86.ANEGW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1835,9 +1906,10 @@ var opcodeTable = [...]opInfo{ name: "NEGB", asm: x86.ANEGB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1847,9 +1919,10 @@ var opcodeTable = [...]opInfo{ name: "NOTQ", asm: x86.ANOTQ, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1859,9 +1932,10 @@ var opcodeTable = [...]opInfo{ name: "NOTL", asm: x86.ANOTL, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1871,9 +1945,10 @@ var opcodeTable = [...]opInfo{ name: "NOTW", asm: x86.ANOTW, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1883,9 +1958,10 @@ var opcodeTable = [...]opInfo{ name: "NOTB", asm: x86.ANOTB, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1895,9 +1971,10 @@ var opcodeTable = [...]opInfo{ name: "SBBQcarrymask", asm: x86.ASBBQ, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1907,9 +1984,10 @@ var opcodeTable = [...]opInfo{ name: "SBBLcarrymask", asm: x86.ASBBL, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1919,9 +1997,10 @@ var opcodeTable = [...]opInfo{ name: "SETEQ", asm: x86.ASETEQ, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1931,9 +2010,10 @@ var opcodeTable = [...]opInfo{ name: "SETNE", asm: x86.ASETNE, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1943,9 +2023,10 @@ var opcodeTable = [...]opInfo{ name: "SETL", asm: x86.ASETLT, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1955,9 +2036,10 @@ var opcodeTable = [...]opInfo{ name: "SETLE", asm: x86.ASETLE, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1967,9 +2049,10 @@ var opcodeTable = [...]opInfo{ name: "SETG", asm: x86.ASETGT, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1979,9 +2062,10 @@ var opcodeTable = [...]opInfo{ name: "SETGE", asm: x86.ASETGE, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -1991,9 +2075,10 @@ var opcodeTable = [...]opInfo{ name: "SETB", asm: x86.ASETCS, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2003,9 +2088,10 @@ var opcodeTable = [...]opInfo{ name: "SETBE", asm: x86.ASETLS, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2015,9 +2101,10 @@ var opcodeTable = [...]opInfo{ name: "SETA", asm: x86.ASETHI, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2027,9 +2114,10 @@ var opcodeTable = [...]opInfo{ name: "SETAE", asm: x86.ASETCC, reg: regInfo{ - inputs: []regMask{ - 8589934592, // .FLAGS + inputs: []inputInfo{ + {0, 8589934592}, // .FLAGS }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2039,9 +2127,10 @@ var opcodeTable = [...]opInfo{ name: "MOVBQSX", asm: x86.AMOVBQSX, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2051,9 +2140,10 @@ var opcodeTable = [...]opInfo{ name: "MOVBQZX", asm: x86.AMOVBQZX, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2063,9 +2153,10 @@ var opcodeTable = [...]opInfo{ name: "MOVWQSX", asm: x86.AMOVWQSX, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2075,9 +2166,10 @@ var opcodeTable = [...]opInfo{ name: "MOVWQZX", asm: x86.AMOVWQZX, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2087,9 +2179,10 @@ var opcodeTable = [...]opInfo{ name: "MOVLQSX", asm: x86.AMOVLQSX, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2099,9 +2192,10 @@ var opcodeTable = [...]opInfo{ name: "MOVLQZX", asm: x86.AMOVLQZX, reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2111,6 +2205,7 @@ var opcodeTable = [...]opInfo{ name: "MOVBconst", asm: x86.AMOVB, reg: regInfo{ + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2120,6 +2215,7 @@ var opcodeTable = [...]opInfo{ name: "MOVWconst", asm: x86.AMOVW, reg: regInfo{ + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2129,6 +2225,7 @@ var opcodeTable = [...]opInfo{ name: "MOVLconst", asm: x86.AMOVL, reg: regInfo{ + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2138,6 +2235,7 @@ var opcodeTable = [...]opInfo{ name: "MOVQconst", asm: x86.AMOVQ, reg: regInfo{ + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2146,9 +2244,10 @@ var opcodeTable = [...]opInfo{ { name: "LEAQ", reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2157,10 +2256,11 @@ var opcodeTable = [...]opInfo{ { name: "LEAQ1", reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2169,10 +2269,11 @@ var opcodeTable = [...]opInfo{ { name: "LEAQ2", reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2181,10 +2282,11 @@ var opcodeTable = [...]opInfo{ { name: "LEAQ4", reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2193,10 +2295,11 @@ var opcodeTable = [...]opInfo{ { name: "LEAQ8", reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, @@ -2206,9 +2309,8 @@ var opcodeTable = [...]opInfo{ name: "MOVBload", asm: x86.AMOVB, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 0, + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2219,9 +2321,8 @@ var opcodeTable = [...]opInfo{ name: "MOVBQSXload", asm: x86.AMOVBQSX, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 0, + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2232,9 +2333,8 @@ var opcodeTable = [...]opInfo{ name: "MOVBQZXload", asm: x86.AMOVBQZX, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 0, + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2245,9 +2345,8 @@ var opcodeTable = [...]opInfo{ name: "MOVWload", asm: x86.AMOVW, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 0, + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2258,9 +2357,8 @@ var opcodeTable = [...]opInfo{ name: "MOVLload", asm: x86.AMOVL, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 0, + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2271,9 +2369,8 @@ var opcodeTable = [...]opInfo{ name: "MOVQload", asm: x86.AMOVQ, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 0, + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2284,10 +2381,9 @@ var opcodeTable = [...]opInfo{ name: "MOVQloadidx8", asm: x86.AMOVQ, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2298,10 +2394,9 @@ var opcodeTable = [...]opInfo{ name: "MOVBstore", asm: x86.AMOVB, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, @@ -2309,10 +2404,9 @@ var opcodeTable = [...]opInfo{ name: "MOVWstore", asm: x86.AMOVW, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, @@ -2320,10 +2414,9 @@ var opcodeTable = [...]opInfo{ name: "MOVLstore", asm: x86.AMOVL, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, @@ -2331,10 +2424,9 @@ var opcodeTable = [...]opInfo{ name: "MOVQstore", asm: x86.AMOVQ, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, @@ -2342,54 +2434,54 @@ var opcodeTable = [...]opInfo{ name: "MOVQstoreidx8", asm: x86.AMOVQ, reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 0, + inputs: []inputInfo{ + {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {2, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, { name: "MOVXzero", reg: regInfo{ - inputs: []regMask{ - 4295032831, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB - 0, + inputs: []inputInfo{ + {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB }, }, }, { name: "REPSTOSQ", reg: regInfo{ - inputs: []regMask{ - 128, // .DI - 2, // .CX + inputs: []inputInfo{ + {0, 128}, // .DI + {1, 2}, // .CX }, clobbers: 131, // .AX .CX .DI }, }, { name: "CALLstatic", - reg: regInfo{}, + reg: regInfo{ + clobbers: 12884901871, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 .FLAGS + }, }, { name: "CALLclosure", reg: regInfo{ - inputs: []regMask{ - 65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 - 4, // .DX - 0, + inputs: []inputInfo{ + {1, 4}, // .DX + {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, + clobbers: 12884901871, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 .FLAGS }, }, { name: "REPMOVSB", reg: regInfo{ - inputs: []regMask{ - 128, // .DI - 64, // .SI - 2, // .CX + inputs: []inputInfo{ + {0, 128}, // .DI + {1, 64}, // .SI + {2, 2}, // .CX }, clobbers: 194, // .CX .SI .DI }, @@ -2405,6 +2497,7 @@ var opcodeTable = [...]opInfo{ { name: "LoweredGetG", reg: regInfo{ + clobbers: 8589934592, // .FLAGS outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 }, diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index b8a2f24c33..d593faf95b 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -2,22 +2,132 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Register allocation. +// +// We use a version of a linear scan register allocator. We treat the +// whole function as a single long basic block and run through +// it using a greedy register allocator. Then all merge edges +// (those targeting a block with len(Preds)>1) are processed to +// shuffle data into the place that the target of the edge expects. +// +// The greedy allocator moves values into registers just before they +// are used, spills registers only when necessary, and spills the +// value whose next use is farthest in the future. +// +// The register allocator requires that a block is not scheduled until +// at least one of its predecessors have been scheduled. The most recent +// such predecessor provides the starting register state for a block. +// +// It also requires that there are no critical edges (critical = +// comes from a block with >1 successor and goes to a block with >1 +// predecessor). This makes it easy to add fixup code on merge edges - +// the source of a merge edge has only one successor, so we can add +// fixup code to the end of that block. + +// Spilling +// +// For every value, we generate a spill immediately after the value itself. +// x = Op y z : AX +// x2 = StoreReg x +// While AX still holds x, any uses of x will use that value. When AX is needed +// for another value, we simply reuse AX. Spill code has already been generated +// so there is no code generated at "spill" time. When x is referenced +// subsequently, we issue a load to restore x to a register using x2 as +// its argument: +// x3 = Restore x2 : CX +// x3 can then be used wherever x is referenced again. +// If the spill (x2) is never used, it will be removed at the end of regalloc. +// +// Phi values are special, as always. We define two kinds of phis, those +// where the merge happens in a register (a "register" phi) and those where +// the merge happens in a stack location (a "stack" phi). +// +// A register phi must have the phi and all of its inputs allocated to the +// same register. Register phis are spilled similarly to regular ops: +// b1: y = ... : AX b2: z = ... : AX +// goto b3 goto b3 +// b3: x = phi(y, z) : AX +// x2 = StoreReg x +// +// A stack phi must have the phi and all of its inputs allocated to the same +// stack location. Stack phis start out life already spilled - each phi +// input must be a store (using StoreReg) at the end of the corresponding +// predecessor block. +// b1: y = ... : AX b2: z = ... : BX +// y2 = StoreReg y z2 = StoreReg z +// goto b3 goto b3 +// b3: x = phi(y2, z2) +// The stack allocator knows that StoreReg args of stack-allocated phis +// must be allocated to the same stack slot as the phi that uses them. +// x is now a spilled value and a restore must appear before its first use. + +// TODO + +// Use an affinity graph to mark two values which should use the +// same register. This affinity graph will be used to prefer certain +// registers for allocation. This affinity helps eliminate moves that +// are required for phi implementations and helps generate allocations +// for 2-register architectures. + +// Note: regalloc generates a not-quite-SSA output. If we have: +// +// b1: x = ... : AX +// x2 = StoreReg x +// ... AX gets reused for something else ... +// if ... goto b3 else b4 +// +// b3: x3 = LoadReg x2 : BX b4: x4 = LoadReg x2 : CX +// ... use x3 ... ... use x4 ... +// +// b2: ... use x3 ... +// +// If b3 is the primary predecessor of b2, then we use x3 in b2 and +// add a x4:CX->BX copy at the end of b4. +// But the definition of x3 doesn't dominate b2. We should really +// insert a dummy phi at the start of b2 (x5=phi(x3,x4):BX) to keep +// SSA form. For now, we ignore this problem as remaining in strict +// SSA form isn't needed after regalloc. We'll just leave the use +// of x3 not dominated by the definition of x3, and the CX->BX copy +// will have no use (so don't run deadcode after regalloc!). +// TODO: maybe we should introduce these extra phis? + package ssa -import "sort" +import ( + "fmt" + "unsafe" +) -func setloc(home []Location, v *Value, loc Location) []Location { - for v.ID >= ID(len(home)) { - home = append(home, nil) - } - home[v.ID] = loc - return home +const regDebug = false + +// regalloc performs register allocation on f. It sets f.RegAlloc +// to the resulting allocation. +func regalloc(f *Func) { + var s regAllocState + s.init(f) + s.regalloc(f) } -type register uint +type register uint8 + +const noRegister register = 255 type regMask uint64 +func (m regMask) String() string { + s := "" + for r := register(0); r < numRegs; r++ { + if m>>r&1 == 0 { + continue + } + if s != "" { + s += " " + } + s += fmt.Sprintf("r%d", r) + } + return s +} + // TODO: make arch-dependent var numRegs register = 64 @@ -84,343 +194,719 @@ func pickReg(r regMask) register { } } -// regalloc performs register allocation on f. It sets f.RegAlloc -// to the resulting allocation. -func regalloc(f *Func) { - // For now, a very simple allocator. Everything has a home - // location on the stack (TBD as a subsequent stackalloc pass). - // Values live in the home locations at basic block boundaries. - // We use a simple greedy allocator within a basic block. - home := make([]Location, f.NumValues()) +// A use is a record of a position (2*pc for value uses, odd numbers for other uses) +// and a value ID that is used at that position. +type use struct { + idx int32 + vid ID +} - addPhiCopies(f) // add copies of phi inputs in preceeding blocks +type valState struct { + regs regMask // the set of registers holding a Value (usually just one) + uses []int32 // sorted list of places where Value is used + usestorage [2]int32 + spill *Value // spilled copy of the Value + spill2 *Value // special alternate spill location used for phi resolution + spillUsed bool + spill2used bool +} - // Compute live values at the end of each block. - live := live(f) - lastUse := make([]int, f.NumValues()) +type regState struct { + v *Value // Original (preregalloc) Value stored in this register. + c *Value // A Value equal to v which is currently in register. Might be v or a copy of it. + // If a register is unused, v==c==nil +} - var oldSched []*Value +type regAllocState struct { + f *Func + + // for each block, its primary predecessor. + // A predecessor of b is primary if it is the closest + // predecessor that appears before b in the layout order. + // We record the index in the Preds list where the primary predecessor sits. + primary []int32 + + // live values on each edge. live[b.ID][idx] is a list of value IDs + // which are live on b's idx'th successor edge. + live [][][]ID + + // current state of each (preregalloc) Value + values []valState + + // current state of each register + regs []regState + + // registers that contain values which can't be kicked out + nospill regMask + + // mask of registers currently in use + used regMask + + // An ordered list (by idx) of all uses in the function + uses []use - // Hack to find sp and sb Values and assign them a register. - // TODO: make not so hacky; update the tighten pass when this is done - var sp, sb *Value - for _, v := range f.Entry.Values { - switch v.Op { - case OpSP: - sp = v - home = setloc(home, v, ®isters[4]) // TODO: arch-dependent - case OpSB: - sb = v - home = setloc(home, v, ®isters[32]) // TODO: arch-dependent + // Home locations (registers) for Values + home []Location + + // current block we're working on + curBlock *Block +} + +// freeReg frees up register r. Any current user of r is kicked out. +func (s *regAllocState) freeReg(r register) { + v := s.regs[r].v + if v == nil { + s.f.Fatalf("tried to free an already free register %d\n", r) + } + + // Mark r as unused. + if regDebug { + fmt.Printf("freeReg %d (dump %s/%s)\n", r, v, s.regs[r].c) + } + s.regs[r] = regState{} + s.values[v.ID].regs &^= regMask(1) << r + s.used &^= regMask(1) << r +} + +// freeRegs frees up all registers listed in m. +func (s *regAllocState) freeRegs(m regMask) { + for m&s.used != 0 { + s.freeReg(pickReg(m & s.used)) + } +} + +func (s *regAllocState) setHome(v *Value, r register) { + // Remember assignment. + for int(v.ID) >= len(s.home) { + s.home = append(s.home, nil) + s.home = s.home[:cap(s.home)] + } + s.home[v.ID] = ®isters[r] +} +func (s *regAllocState) getHome(v *Value) register { + if int(v.ID) >= len(s.home) || s.home[v.ID] == nil { + return noRegister + } + return register(s.home[v.ID].(*Register).Num) +} + +// assignReg assigns register r to hold c, a copy of v. +// r must be unused. +func (s *regAllocState) assignReg(r register, v *Value, c *Value) { + if regDebug { + fmt.Printf("assignReg %d %s/%s\n", r, v, c) + } + if s.regs[r].v != nil { + s.f.Fatalf("tried to assign register %d to %s/%s but it is already used by %s", r, v, c, s.regs[r].v) + } + + // Update state. + s.regs[r] = regState{v, c} + s.values[v.ID].regs |= regMask(1) << r + s.used |= regMask(1) << r + s.setHome(c, r) +} + +// allocReg picks an unused register from regmask. If there is no unused register, +// a Value will be kicked out of a register to make room. +func (s *regAllocState) allocReg(mask regMask) register { + // Pick a register to use. + mask &^= s.nospill + if mask == 0 { + s.f.Fatalf("no register available") + } + + var r register + if unused := mask & ^s.used; unused != 0 { + // Pick an unused register. + return pickReg(unused) + // TODO: use affinity graph to pick a good register + } + // Pick a value to spill. Spill the value with the + // farthest-in-the-future use. + // TODO: Prefer registers with already spilled Values? + // TODO: Modify preference using affinity graph. + mask &^= 1<<4 | 1<<32 // don't spill SP or SB + maxuse := int32(-1) + for t := register(0); t < numRegs; t++ { + if mask>>t&1 == 0 { + continue + } + v := s.regs[t].v + if len(s.values[v.ID].uses) == 0 { + // This can happen when fixing up merge blocks at the end. + // We've already run through the use lists so they are empty. + // Any register would be ok at this point. + r = t + maxuse = 0 + break } + if n := s.values[v.ID].uses[0]; n > maxuse { + r = t + maxuse = n + } + } + if maxuse == -1 { + s.f.Unimplementedf("couldn't find register to spill") + } + s.freeReg(r) + return r +} + +// allocValToReg allocates v to a register selected from regMask and +// returns the register copy of v. Any previous user is kicked out and spilled +// (if necessary). Load code is added at the current pc. If nospill is set the +// allocated register is marked nospill so the assignment cannot be +// undone until the caller allows it by clearing nospill. Returns a +// *Value which is either v or a copy of v allocated to the chosen register. +func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool) *Value { + vi := &s.values[v.ID] + + // Check if v is already in a requested register. + if mask&vi.regs != 0 { + r := pickReg(mask & vi.regs) + if s.regs[r].v != v || s.regs[r].c == nil { + panic("bad register state") + } + if nospill { + s.nospill |= regMask(1) << r + } + return s.regs[r].c + } + + // SP and SB are allocated specially. No regular value should + // be allocated to them. + mask &^= 1<<4 | 1<<32 + + // Allocate a register. + r := s.allocReg(mask) + + // Allocate v to the new register. + var c *Value + if vi.regs != 0 { + // Copy from a register that v is already in. + r2 := pickReg(vi.regs) + if s.regs[r2].v != v { + panic("bad register state") + } + c = s.curBlock.NewValue1(v.Line, OpCopy, v.Type, s.regs[r2].c) + } else { + // Load v from its spill location. + // TODO: rematerialize if we can. + if vi.spill2 != nil { + c = s.curBlock.NewValue1(v.Line, OpLoadReg, v.Type, vi.spill2) + vi.spill2used = true + } else { + c = s.curBlock.NewValue1(v.Line, OpLoadReg, v.Type, vi.spill) + vi.spillUsed = true + } + if v.Type.IsFlags() { + v.Unimplementedf("spill of flags not implemented yet") + } + } + s.assignReg(r, v, c) + if nospill { + s.nospill |= regMask(1) << r + } + return c +} + +func (s *regAllocState) init(f *Func) { + if numRegs > noRegister || numRegs > register(unsafe.Sizeof(regMask(0))*8) { + panic("too many registers") + } + + s.f = f + s.regs = make([]regState, numRegs) + s.values = make([]valState, f.NumValues()) + for i := range s.values { + s.values[i].uses = s.values[i].usestorage[:0] } + s.live = f.live() - // Register allocate each block separately. All live values will live - // in home locations (stack slots) between blocks. + // Compute block order. This array allows us to distinguish forward edges + // from backward edges and compute how far they go. + blockOrder := make([]int32, f.NumBlocks()) + for i, b := range f.Blocks { + blockOrder[b.ID] = int32(i) + } + + // Compute primary predecessors. + s.primary = make([]int32, f.NumBlocks()) for _, b := range f.Blocks { + best := -1 + for i, p := range b.Preds { + if blockOrder[p.ID] >= blockOrder[b.ID] { + continue // backward edge + } + if best == -1 || blockOrder[p.ID] > blockOrder[b.Preds[best].ID] { + best = i + } + } + s.primary[b.ID] = int32(best) + } - // Compute the index of the last use of each Value in the Block. - // Scheduling has already happened, so Values are totally ordered. - // lastUse[x] = max(i) where b.Value[i] uses Value x. - for i, v := range b.Values { - lastUse[v.ID] = -1 - for _, w := range v.Args { - // could condition this store on w.Block == b, but no need - lastUse[w.ID] = i + // Compute uses. We assign a PC to each Value in the program, in f.Blocks + // and then b.Values order. Uses are recorded using this numbering. + // Uses by Values are recorded as 2*PC. Special uses (block control values, + // pseudo-uses for backedges) are recorded as 2*(last PC in block)+1. + var pc int32 + for _, b := range f.Blocks { + // uses in regular Values + for _, v := range b.Values { + for _, a := range v.Args { + s.values[a.ID].uses = append(s.values[a.ID].uses, pc*2) + s.uses = append(s.uses, use{pc * 2, a.ID}) } + pc++ } - // Values which are live at block exit have a lastUse of len(b.Values). + // use as a block control value + endIdx := pc*2 - 1 if b.Control != nil { - lastUse[b.Control.ID] = len(b.Values) + s.values[b.Control.ID].uses = append(s.values[b.Control.ID].uses, endIdx) + s.uses = append(s.uses, use{endIdx, b.Control.ID}) } - // Values live after block exit have a lastUse of len(b.Values)+1. - for _, vid := range live[b.ID] { - lastUse[vid] = len(b.Values) + 1 + // uses by backedges + // Backedges are treated as uses so that the uses span the entire live + // range of the value. + for i, c := range b.Succs { + if blockOrder[c.ID] > blockOrder[b.ID] { + continue // forward edge + } + for _, vid := range s.live[b.ID][i] { + s.values[vid].uses = append(s.values[vid].uses, endIdx) + s.uses = append(s.uses, use{endIdx, vid}) + } } + } + if pc*2 < 0 { + f.Fatalf("pc too large: function too big") + } +} - // For each register, store which value it contains - type regInfo struct { - v *Value // stack-homed original value (or nil if empty) - c *Value // the register copy of v - dirty bool // if the stack-homed copy is out of date +// clearUses drops any uses <= useIdx. Any values which have no future +// uses are dropped from registers. +func (s *regAllocState) clearUses(useIdx int32) { + for len(s.uses) > 0 && s.uses[0].idx <= useIdx { + idx := s.uses[0].idx + vid := s.uses[0].vid + s.uses = s.uses[1:] + + vi := &s.values[vid] + if vi.uses[0] != idx { + s.f.Fatalf("use mismatch for v%d\n", vid) } - regs := make([]regInfo, numRegs) + vi.uses = vi.uses[1:] + if len(vi.uses) != 0 { + continue + } + // Value is dead, free all registers that hold it (except SP & SB). + s.freeRegs(vi.regs &^ (1<<4 | 1<<32)) + } +} - // TODO: hack: initialize fixed registers - regs[4] = regInfo{sp, sp, false} - regs[32] = regInfo{sb, sb, false} +// Sets the state of the registers to that encoded in state. +func (s *regAllocState) setState(state []regState) { + s.freeRegs(s.used) + for r, x := range state { + if x.c == nil { + continue + } + s.assignReg(register(r), x.v, x.c) + } +} - var used regMask // has a 1 for each non-nil entry in regs - var dirty regMask // has a 1 for each dirty entry in regs +func (s *regAllocState) regalloc(f *Func) { + liveset := newSparseSet(f.NumValues()) + argset := newSparseSet(f.NumValues()) + var oldSched []*Value + var phis []*Value + var stackPhis []*Value + var regPhis []*Value + + if f.Entry != f.Blocks[0] { + f.Fatalf("entry block must be first") + } + + var phiRegs []register + + // For each merge block, we record the starting register state (after phi ops) + // for that merge block. Indexed by blockid/regnum. + startRegs := make([][]*Value, f.NumBlocks()) + // end state of registers for each block, idexed by blockid/regnum. + endRegs := make([][]regState, f.NumBlocks()) + var pc int32 + for _, b := range f.Blocks { + s.curBlock = b - oldSched = append(oldSched[:0], b.Values...) + // Make a copy of the block schedule so we can generate a new one in place. + // We make a separate copy for phis and regular values. + nphi := 0 + for _, v := range b.Values { + if v.Op != OpPhi { + break + } + nphi++ + } + phis = append(phis[:0], b.Values[:nphi]...) + oldSched = append(oldSched[:0], b.Values[nphi:]...) b.Values = b.Values[:0] - for idx, v := range oldSched { - // For each instruction, do: - // set up inputs to v in registers - // pick output register - // run insn - // mark output register as dirty - // Note that v represents the Value at "home" (on the stack), and c - // is its register equivalent. There are two ways to establish c: - // - use of v. c will be a load from v's home. - // - definition of v. c will be identical to v but will live in - // a register. v will be modified into a spill of c. - regspec := opcodeTable[v.Op].reg - if v.Op == OpCopy { - // TODO: make this less of a hack - regspec = opcodeTable[OpAMD64ADDQconst].reg + // Initialize start state of block. + if b == f.Entry { + // Regalloc state is empty to start. + if nphi > 0 { + f.Fatalf("phis in entry block") } - inputs := regspec.inputs - outputs := regspec.outputs - if len(inputs) == 0 && len(outputs) == 0 { - // No register allocation required (or none specified yet) + } else if len(b.Preds) == 1 { + // Start regalloc state with the end state of the previous block. + s.setState(endRegs[b.Preds[0].ID]) + if nphi > 0 { + f.Fatalf("phis in single-predecessor block") + } + } else { + // This is the complicated case. We have more than one predecessor, + // which means we may have Phi ops. + + // Copy phi ops into new schedule. + b.Values = append(b.Values, phis...) + + // Start with the final register state of the primary predecessor + idx := s.primary[b.ID] + if idx < 0 { + f.Fatalf("block with no primary predecessor %s", b) + } + p := b.Preds[idx] + s.setState(endRegs[p.ID]) + + // Drop anything not live on the c->b edge. + var idx2 int + for idx2 = 0; idx2 < len(p.Succs); idx2++ { + if p.Succs[idx2] == b { + break + } + } + liveset.clear() + liveset.addAll(s.live[p.ID][idx2]) + for r := register(0); r < numRegs; r++ { + v := s.regs[r].v + if v == nil { + continue + } + if !liveset.contains(v.ID) { + s.freeReg(r) + } + } + + // Decide on registers for phi ops. Use the registers determined + // by the primary predecessor if we can. + // TODO: pick best of (already processed) predecessors? + // Majority vote? Deepest nesting level? + phiRegs = phiRegs[:0] + var used regMask + for _, v := range phis { + if v.Type.IsMemory() { + phiRegs = append(phiRegs, noRegister) + continue + } + regs := s.values[v.Args[idx].ID].regs + m := regs &^ used + var r register + if m != 0 { + r = pickReg(m) + used |= regMask(1) << r + } else { + r = noRegister + } + phiRegs = append(phiRegs, r) + } + // Change register user from phi input to phi. Add phi spill code. + for i, v := range phis { + if v.Type.IsMemory() { + continue + } + r := phiRegs[i] + if r == noRegister { + // stack-based phi + // Spills will be inserted in all the predecessors below. + s.values[v.ID].spill = v // v starts life spilled + s.values[v.ID].spillUsed = true // use is guaranteed + continue + } + // register-based phi + // Transfer ownership of register from input arg to phi. + s.freeReg(r) + s.assignReg(r, v, v) + // Spill the phi in case we need to restore it later. + spill := b.NewValue1(v.Line, OpStoreReg, v.Type, v) + s.values[v.ID].spill = spill + s.values[v.ID].spillUsed = false + } + + // Save the starting state for use by incoming edges below. + startRegs[b.ID] = make([]*Value, numRegs) + for r := register(0); r < numRegs; r++ { + startRegs[b.ID][r] = s.regs[r].v + } + } + + // Process all the non-phi values. + pc += int32(nphi) + for _, v := range oldSched { + if v.Op == OpPhi { + f.Fatalf("phi %s not at start of block", v) + } + if v.Op == OpSP { + s.assignReg(4, v, v) // TODO: arch-dependent b.Values = append(b.Values, v) + pc++ continue } - if v.Op == OpCopy && v.Type.IsMemory() { + if v.Op == OpSB { + s.assignReg(32, v, v) // TODO: arch-dependent b.Values = append(b.Values, v) + pc++ continue } - - // Compute a good input ordering. Start with the most constrained input. - order := make([]intPair, len(inputs)) - for i, input := range inputs { - order[i] = intPair{countRegs(input), i} + s.clearUses(pc*2 - 1) + regspec := opcodeTable[v.Op].reg + if regDebug { + fmt.Printf("%d: working on %s %s %v\n", pc, v, v.LongString(), regspec) + } + if len(regspec.inputs) == 0 && len(regspec.outputs) == 0 { + // No register allocation required (or none specified yet) + s.freeRegs(regspec.clobbers) + b.Values = append(b.Values, v) + pc++ + continue } - sort.Sort(byKey(order)) - // nospill contains registers that we can't spill because - // we already set them up for use by the current instruction. - var nospill regMask - nospill |= 0x100000010 // SP & SB can't be spilled (TODO: arch-specific) + // TODO: If value is rematerializeable, don't issue it here. + // Instead, rely on argument loading code to put it in a register when needed. - // Move inputs into registers - for _, o := range order { - w := v.Args[o.val] - mask := inputs[o.val] - if mask == 0 { - // Input doesn't need a register - continue - } - // TODO: 2-address overwrite instructions + // Move arguments to registers + for _, i := range regspec.inputs { + a := v.Args[i.idx] + v.Args[i.idx] = s.allocValToReg(a, i.regs, true) + } - // Find registers that w is already in - var wreg regMask - for r := register(0); r < numRegs; r++ { - if regs[r].v == w { - wreg |= regMask(1) << r - } - } + // Now that all args are in regs, we're ready to issue the value itself. + // Before we pick a register for the value, allow input registers + // to be deallocated. We do this here so that the output can use the + // same register as a dying input. + s.nospill = 0 + s.clearUses(pc * 2) + + // Dump any registers which will be clobbered + s.freeRegs(regspec.clobbers) + + // Pick register for output. + var r register + var mask regMask + if len(regspec.outputs) > 0 { + mask = regspec.outputs[0] + } + if mask != 0 { + r = s.allocReg(mask) + s.assignReg(r, v, v) + } - var r register - if mask&wreg != 0 { - // w is already in an allowed register. We're done. - r = pickReg(mask & wreg) - } else { - // Pick a register for w - // Priorities (in order) - // - an unused register - // - a clean register - // - a dirty register - // TODO: for used registers, pick the one whose next use is the - // farthest in the future. - mask &^= nospill - if mask & ^dirty != 0 { - mask &^= dirty - } - if mask & ^used != 0 { - mask &^= used - } - r = pickReg(mask) - - // Kick out whomever is using this register. - if regs[r].v != nil { - x := regs[r].v - c := regs[r].c - if regs[r].dirty && lastUse[x.ID] >= idx { - // Write x back to home. Its value is currently held in c. - x.Op = OpStoreReg - x.Aux = nil - x.resetArgs() - x.AddArg(c) - b.Values = append(b.Values, x) - regs[r].dirty = false - dirty &^= regMask(1) << r - } - regs[r].v = nil - regs[r].c = nil - used &^= regMask(1) << r - } + // Issue the Value itself. + b.Values = append(b.Values, v) - // Load w into this register - var c *Value - if len(w.Args) == 0 { - // Materialize w - if w.Op == OpSB { - c = w - } else if w.Op == OpSP { - c = b.NewValue1(w.Line, OpCopy, w.Type, w) - } else { - c = b.NewValue0IA(w.Line, w.Op, w.Type, w.AuxInt, w.Aux) - } - } else if len(w.Args) == 1 && (w.Args[0].Op == OpSP || w.Args[0].Op == OpSB) { - // Materialize offsets from SP/SB - c = b.NewValue1IA(w.Line, w.Op, w.Type, w.AuxInt, w.Aux, w.Args[0]) - } else if wreg != 0 { - // Copy from another register. - // Typically just an optimization, but this is - // required if w is dirty. - s := pickReg(wreg) - // inv: s != r - c = b.NewValue1(w.Line, OpCopy, w.Type, regs[s].c) - } else { - // Load from home location - c = b.NewValue1(w.Line, OpLoadReg, w.Type, w) - } - home = setloc(home, c, ®isters[r]) - // Remember what we did - regs[r].v = w - regs[r].c = c - regs[r].dirty = false - used |= regMask(1) << r - } + // Issue a spill for this value. We issue spills unconditionally, + // then at the end of regalloc delete the ones we never use. + spill := b.NewValue1(v.Line, OpStoreReg, v.Type, v) + s.values[v.ID].spill = spill + s.values[v.ID].spillUsed = false - // Replace w with its in-register copy. - v.SetArg(o.val, regs[r].c) + // Increment pc for next Value. + pc++ + } - // Remember not to undo this register assignment until after - // the instruction is issued. - nospill |= regMask(1) << r - } + // Load control value into reg + if b.Control != nil && !b.Control.Type.IsMemory() { + // TODO: regspec for block control values, instead of using + // register set from the control op's output. + s.allocValToReg(b.Control, opcodeTable[b.Control.Op].reg.outputs[0], false) + } - // TODO: do any clobbering + // Record endRegs + endRegs[b.ID] = make([]regState, numRegs) + copy(endRegs[b.ID], s.regs) - // pick a register for v itself. - if len(outputs) > 1 { - panic("can't do multi-output yet") + // Allow control Values and Values live only on backedges to be dropped. + s.clearUses(pc*2 - 1) + } + + // Process merge block input edges. They are the tricky ones. + dst := make([]*Value, numRegs) + for _, b := range f.Blocks { + if len(b.Preds) <= 1 { + continue + } + for i, p := range b.Preds { + if regDebug { + fmt.Printf("processing %s->%s\n", p, b) } - if len(outputs) == 0 || outputs[0] == 0 { - // output doesn't need a register - b.Values = append(b.Values, v) - } else { - mask := outputs[0] - if mask & ^dirty != 0 { - mask &^= dirty + + // Find phis, separate them into stack & register classes. + stackPhis = stackPhis[:0] + regPhis = regPhis[:0] + for _, v := range b.Values { + if v.Op != OpPhi { + break } - if mask & ^used != 0 { - mask &^= used + if v.Type.IsMemory() { + continue } - r := pickReg(mask) - - // Kick out whomever is using this register. - if regs[r].v != nil { - x := regs[r].v - c := regs[r].c - if regs[r].dirty && lastUse[x.ID] >= idx { - // Write x back to home. Its value is currently held in c. - x.Op = OpStoreReg - x.Aux = nil - x.resetArgs() - x.AddArg(c) - b.Values = append(b.Values, x) - regs[r].dirty = false - dirty &^= regMask(1) << r - } - regs[r].v = nil - regs[r].c = nil - used &^= regMask(1) << r + if s.getHome(v) != noRegister { + regPhis = append(regPhis, v) + } else { + stackPhis = append(stackPhis, v) } - - // Reissue v with new op, with r as its home. - c := b.NewValue0IA(v.Line, v.Op, v.Type, v.AuxInt, v.Aux) - c.AddArgs(v.Args...) - home = setloc(home, c, ®isters[r]) - - // Remember what we did - regs[r].v = v - regs[r].c = c - regs[r].dirty = true - used |= regMask(1) << r - dirty |= regMask(1) << r } - } - // If the block ends in a call, we must put the call after the spill code. - var call *Value - if b.Kind == BlockCall { - call = b.Control - if call != b.Values[len(b.Values)-1] { - b.Fatalf("call not at end of block %v %v", b, call) + // Start with the state that exists at the end of the + // predecessor block. We'll be adding instructions here + // to shuffle registers & stack phis into the right spot. + s.setState(endRegs[p.ID]) + s.curBlock = p + + // Handle stack-based phi ops first. We need to handle them + // first because we need a register with which to copy them. + + // We must be careful not to overwrite any stack phis which are + // themselves args of other phis. For example: + // v1 = phi(v2, v3) : 8(SP) + // v2 = phi(v4, v5) : 16(SP) + // Here we must not write v2 until v2 is read and written to v1. + // The situation could be even more complicated, with cycles, etc. + // So in the interest of being simple, we find all the phis which + // are arguments of other phis and copy their values to a temporary + // location first. This temporary location is called "spill2" and + // represents a higher-priority but temporary spill location for the value. + // Note this is not a problem for register-based phis because + // if needed we will use the spilled location as the source, and + // the spill location is not clobbered by the code generated here. + argset.clear() + for _, v := range stackPhis { + argset.add(v.Args[i].ID) } - b.Values = b.Values[:len(b.Values)-1] - // TODO: do this for all control types? - } - - // at the end of the block, spill any remaining dirty, live values - for r := register(0); r < numRegs; r++ { - if !regs[r].dirty { - continue + for _, v := range regPhis { + argset.add(v.Args[i].ID) } - v := regs[r].v - c := regs[r].c - if lastUse[v.ID] <= len(oldSched) { - if v == v.Block.Control { - // link control value to register version - v.Block.Control = c + for _, v := range stackPhis { + if !argset.contains(v.ID) { + continue } - continue // not live after block + // This stack-based phi is the argument of some other + // phi in this block. We must make a copy of its + // value so that we don't clobber it prematurely. + c := s.allocValToReg(v, s.values[v.ID].regs|1<<0, false) + d := p.NewValue1(v.Line, OpStoreReg, v.Type, c) + s.values[v.ID].spill2 = d } - // change v to be a copy of c - v.Op = OpStoreReg - v.Aux = nil - v.resetArgs() - v.AddArg(c) - b.Values = append(b.Values, v) + // Assign to stack-based phis. We do stack phis first because + // we might need a register to do the assignment. + for _, v := range stackPhis { + // Load phi arg into a register, then store it with a StoreReg. + // If already in a register, use that. If not, use register 0. + // TODO: choose a better default register (set of reg by type?). + c := s.allocValToReg(v.Args[i], s.values[v.Args[i].ID].regs|1<<0, false) + v.Args[i] = p.NewValue1(v.Line, OpStoreReg, v.Type, c) + } + // Figure out what value goes in each register. + for r := register(0); r < numRegs; r++ { + dst[r] = startRegs[b.ID][r] + } + // Handle register-based phi ops. + for _, v := range regPhis { + r := s.getHome(v) + if dst[r] != v { + f.Fatalf("dst not right") + } + v.Args[i] = s.allocValToReg(v.Args[i], regMask(1)<CX and CX->DX, do the latter first. Now if we do the + // former first then the latter must be a restore instead of a register move. + + // Erase any spills we never used + for i := range s.values { + vi := s.values[i] + if vi.spillUsed { + continue + } + spill := vi.spill + if spill == nil { + // Constants, SP, SB, ... + continue } + spill.Op = OpInvalid + spill.Type = TypeInvalid + spill.resetArgs() } - f.RegAlloc = home - deadcode(f) // remove values that had all of their uses rematerialized. TODO: separate pass? -} - -// addPhiCopies adds copies of phi inputs in the blocks -// immediately preceding the phi's block. -func addPhiCopies(f *Func) { for _, b := range f.Blocks { - phis := true // all phis should appear first; confirm that as we go + i := 0 for _, v := range b.Values { - switch { - case v.Op == OpPhi && !phis: - f.Fatalf("phi var %v not at beginning of block %v:\n%s\n", v, v.Block, f) - break - case v.Op != OpPhi: - phis = false + if v.Op == OpInvalid { continue - case v.Type.IsMemory(): // TODO: only "regallocable" types - continue - } - for i, w := range v.Args { - c := b.Preds[i] - cpy := c.NewValue1(w.Line, OpCopy, v.Type, w) - v.Args[i] = cpy } + b.Values[i] = v + i++ } + b.Values = b.Values[:i] + // TODO: zero b.Values[i:], recycle Values + // Not important now because this is the last phase that manipulates Values } + + // Set final regalloc result. + f.RegAlloc = s.home } -// live returns a map from block ID to a list of value IDs live at the end of that block +// live returns a map from block ID and successor edge index to a list +// of value IDs live on that edge. // TODO: this could be quadratic if lots of variables are live across lots of // basic blocks. Figure out a way to make this function (or, more precisely, the user // of this function) require only linear size & time. -func live(f *Func) [][]ID { - live := make([][]ID, f.NumBlocks()) +func (f *Func) live() [][][]ID { + live := make([][][]ID, f.NumBlocks()) + for _, b := range f.Blocks { + live[b.ID] = make([][]ID, len(b.Succs)) + } var phis []*Value s := newSparseSet(f.NumValues()) @@ -445,7 +931,11 @@ func live(f *Func) [][]ID { for _, b := range po { // Start with known live values at the end of the block s.clear() - s.addAll(live[b.ID]) + for i := 0; i < len(b.Succs); i++ { + s.addAll(live[b.ID][i]) + } + + // Mark control value as live if b.Control != nil { s.add(b.Control.ID) } @@ -467,19 +957,24 @@ func live(f *Func) [][]ID { // for each predecessor of b, expand its list of live-at-end values // invariant: s contains the values live at the start of b (excluding phi inputs) for i, p := range b.Preds { + // Find index of b in p's successors. + var j int + for j = 0; j < len(p.Succs); j++ { + if p.Succs[j] == b { + break + } + } t.clear() - t.addAll(live[p.ID]) + t.addAll(live[p.ID][j]) t.addAll(s.contents()) for _, v := range phis { t.add(v.Args[i].ID) } - if t.size() == len(live[p.ID]) { + if t.size() == len(live[p.ID][j]) { continue } // grow p's live set - c := make([]ID, t.size()) - copy(c, t.contents()) - live[p.ID] = c + live[p.ID][j] = append(live[p.ID][j][:0], t.contents()...) changed = true } } @@ -490,13 +985,3 @@ func live(f *Func) [][]ID { } return live } - -// for sorting a pair of integers by key -type intPair struct { - key, val int -} -type byKey []intPair - -func (a byKey) Len() int { return len(a) } -func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key } diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 064b84a804..626fb8f369 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -4,6 +4,15 @@ package ssa +// setloc sets the home location of v to loc. +func setloc(home []Location, v *Value, loc Location) []Location { + for v.ID >= ID(len(home)) { + home = append(home, nil) + } + home[v.ID] = loc + return home +} + // stackalloc allocates storage in the stack frame for // all Values that did not get a register. func stackalloc(f *Func) { @@ -26,7 +35,7 @@ func stackalloc(f *Func) { // so stackmap is smaller. // Assign stack locations to phis first, because we - // must also assign the same locations to the phi copies + // must also assign the same locations to the phi stores // introduced during regalloc. for _, b := range f.Blocks { for _, v := range b.Values { @@ -36,12 +45,19 @@ func stackalloc(f *Func) { if v.Type.IsMemory() { // TODO: only "regallocable" types continue } + if int(v.ID) < len(home) && home[v.ID] != nil { + continue // register-based phi + } + // stack-based phi n = align(n, v.Type.Alignment()) f.Logf("stackalloc: %d-%d for %v\n", n, n+v.Type.Size(), v) loc := &LocalSlot{n} n += v.Type.Size() home = setloc(home, v, loc) for _, w := range v.Args { + if w.Op != OpStoreReg { + f.Fatalf("stack-based phi must have StoreReg args") + } home = setloc(home, w, loc) } } diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go index 02b1f701f5..a43218095e 100644 --- a/src/cmd/compile/internal/ssa/tighten.go +++ b/src/cmd/compile/internal/ssa/tighten.go @@ -57,13 +57,6 @@ func tighten(f *Func) { if v.Op == OpPhi { continue } - if v.Op == OpSB || v.Op == OpSP { - // regalloc expects OpSP and OpSB values to be in the entry block, - // so don't move them. - // TODO: Handle this more gracefully in regalloc and - // remove this restriction. - continue - } if uses[v.ID] == 1 && !phi[v.ID] && home[v.ID] != b && len(v.Args) < 2 { // v is used in exactly one block, and it is not b. // Furthermore, it takes at most one input, diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index e6e23d5270..286edc0cda 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -11,7 +11,7 @@ import "fmt" // if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)). type Value struct { // A unique identifier for the value. For performance we allocate these IDs - // densely starting at 0. There is no guarantee that there won't be occasional holes, though. + // densely starting at 1. There is no guarantee that there won't be occasional holes, though. ID ID // The operation that computes this value. See op.go. @@ -69,7 +69,7 @@ func (v *Value) LongString() string { s += fmt.Sprintf(" %v", a) } r := v.Block.Func.RegAlloc - if r != nil && r[v.ID] != nil { + if int(v.ID) < len(r) && r[v.ID] != nil { s += " : " + r[v.ID].Name() } return s -- cgit v1.3 From 7393c24877407ff2d3d1fad761e5aebbf6671ac3 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 21 Aug 2015 10:15:15 -0700 Subject: [dev.ssa] cmd/compile: everything is live and reachable after regalloc This CL makes function printing and HTML generation accurate after regalloc. Prior to this CL, text and HTML function outputs showed live values and blocks as dead. Change-Id: I70669cd8641af841447fc5d2ecbd754b281356f0 Reviewed-on: https://go-review.googlesource.com/13812 Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/deadcode.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 8c306c8412..5ff082baff 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -6,6 +6,20 @@ package ssa // findlive returns the reachable blocks and live values in f. func findlive(f *Func) (reachable []bool, live []bool) { + // After regalloc, consider all blocks and values to be reachable and live. + // See the comment at the top of regalloc.go and in deadcode for details. + if f.RegAlloc != nil { + reachable = make([]bool, f.NumBlocks()) + for i := range reachable { + reachable[i] = true + } + live = make([]bool, f.NumValues()) + for i := range live { + live[i] = true + } + return reachable, live + } + // Find all reachable basic blocks. reachable = make([]bool, f.NumBlocks()) reachable[f.Entry.ID] = true -- cgit v1.3 From 186cf1b9ba1358344b8ce6f2fb4a62302b98ba90 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 28 Aug 2015 16:45:17 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: handle dead code a different way Instead of trying to delete dead code as soon as we find it, just mark it as dead using a PlainAndDead block kind. The deadcode pass will do the real removal. This way is somewhat more efficient because we don't need to mess with successor and predecessor lists of all the dead blocks. Fixes #12347 Change-Id: Ia42d6b5f9cdb3215a51737b3eb117c00bd439b13 Reviewed-on: https://go-review.googlesource.com/14033 Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/ssa/check.go | 7 + src/cmd/compile/internal/ssa/deadcode.go | 186 +++++++++++++------------ src/cmd/compile/internal/ssa/gen/generic.rules | 6 +- src/cmd/compile/internal/ssa/gen/genericOps.go | 2 +- src/cmd/compile/internal/ssa/gen/rulegen.go | 5 +- src/cmd/compile/internal/ssa/nilcheck.go | 8 +- src/cmd/compile/internal/ssa/opGen.go | 2 + src/cmd/compile/internal/ssa/rewritegeneric.go | 49 +++---- test/fixedbugs/issue12347.go | 16 +++ 9 files changed, 154 insertions(+), 127 deletions(-) create mode 100644 test/fixedbugs/issue12347.go (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index ad9222f3e2..0c2bc4c7f1 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -99,6 +99,13 @@ func checkFunc(f *Func) { if !b.Control.Type.IsMemory() { f.Fatalf("call block %s has non-memory control value %s", b, b.Control.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 { + f.Fatalf("plain/dead block %s has a control value", b) + } } if len(b.Succs) > 2 && b.Likely != BranchUnknown { f.Fatalf("likeliness prediction %d for block %s with %d successors: %s", b.Likely, b, len(b.Succs)) diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 5ff082baff..be25eddb47 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -29,7 +29,11 @@ func findlive(f *Func) (reachable []bool, live []bool) { b := p[len(p)-1] p = p[:len(p)-1] // Mark successors as reachable - for _, c := range b.Succs { + s := b.Succs + if b.Kind == BlockFirst { + s = s[:1] + } + for _, c := range s { if !reachable[c.ID] { reachable[c.ID] = true p = append(p, c) // push @@ -103,6 +107,37 @@ func deadcode(f *Func) { b.Values = b.Values[:i] } + // Get rid of edges from dead to live code. + for _, b := range f.Blocks { + if reachable[b.ID] { + continue + } + for _, c := range b.Succs { + if reachable[c.ID] { + c.removePred(b) + } + } + } + + // Get rid of dead edges from live code. + for _, b := range f.Blocks { + if !reachable[b.ID] { + continue + } + if b.Kind != BlockFirst { + continue + } + c := b.Succs[1] + b.Succs[1] = nil + b.Succs = b.Succs[:1] + b.Kind = BlockPlain + + if reachable[c.ID] { + // Note: c must be reachable through some other edge. + c.removePred(b) + } + } + // Remove unreachable blocks. Return dead block ids to allocator. i := 0 for _, b := range f.Blocks { @@ -113,11 +148,10 @@ func deadcode(f *Func) { if len(b.Values) > 0 { b.Fatalf("live values in unreachable block %v: %v", b, b.Values) } - s := b.Succs + b.Preds = nil b.Succs = nil - for _, c := range s { - f.removePredecessor(b, c) - } + b.Control = nil + b.Kind = BlockDead f.bid.put(b.ID) } } @@ -132,94 +166,68 @@ func deadcode(f *Func) { // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? } -// There was an edge b->c. c has been removed from b's successors. -// Fix up c to handle that fact. -func (f *Func) removePredecessor(b, c *Block) { - work := [][2]*Block{{b, c}} - - for len(work) > 0 { - b, c := work[0][0], work[0][1] - work = work[1:] - - // Find index of b in c's predecessor list - // TODO: This could conceivably cause O(n^2) work. Imagine a very - // wide phi in (for example) the return block. If we determine that - // lots of panics won't happen, we remove each edge at a cost of O(n) each. - var i int - found := false - for j, p := range c.Preds { - if p == b { - i = j - found = true - break - } - } - if !found { - f.Fatalf("can't find predecessor %v of %v\n", b, c) +// removePred removes the predecessor p from b's predecessor list. +func (b *Block) removePred(p *Block) { + var i int + found := false + for j, q := range b.Preds { + if q == p { + i = j + found = true + break } + } + // TODO: the above loop could make the deadcode pass take quadratic time + if !found { + b.Fatalf("can't find predecessor %v of %v\n", p, b) + } - n := len(c.Preds) - 1 - c.Preds[i] = c.Preds[n] - c.Preds[n] = nil // aid GC - c.Preds = c.Preds[:n] + n := len(b.Preds) - 1 + b.Preds[i] = b.Preds[n] + b.Preds[n] = nil // aid GC + b.Preds = b.Preds[:n] - // rewrite phi ops to match the new predecessor list - for _, v := range c.Values { - if v.Op != OpPhi { - continue - } - v.Args[i] = v.Args[n] - v.Args[n] = nil // aid GC - v.Args = v.Args[:n] - if n == 1 { - v.Op = OpCopy - // Note: this is trickier than it looks. Replacing - // a Phi with a Copy can in general cause problems because - // Phi and Copy don't have exactly the same semantics. - // Phi arguments always come from a predecessor block, - // whereas copies don't. This matters in loops like: - // 1: x = (Phi y) - // y = (Add x 1) - // goto 1 - // If we replace Phi->Copy, we get - // 1: x = (Copy y) - // y = (Add x 1) - // goto 1 - // (Phi y) refers to the *previous* value of y, whereas - // (Copy y) refers to the *current* value of y. - // The modified code has a cycle and the scheduler - // will barf on it. - // - // Fortunately, this situation can only happen for dead - // code loops. So although the value graph is transiently - // bad, we'll throw away the bad part by the end of - // the next deadcode phase. - // Proof: If we have a potential bad cycle, we have a - // situation like this: - // x = (Phi z) - // y = (op1 x ...) - // z = (op2 y ...) - // Where opX are not Phi ops. But such a situation - // implies a cycle in the dominator graph. In the - // example, x.Block dominates y.Block, y.Block dominates - // z.Block, and z.Block dominates x.Block (treating - // "dominates" as reflexive). Cycles in the dominator - // graph can only happen in an unreachable cycle. - } + // rewrite phi ops to match the new predecessor list + for _, v := range b.Values { + if v.Op != OpPhi { + continue } - if n == 0 { - // c is now dead--recycle its values - for _, v := range c.Values { - f.vid.put(v.ID) - } - c.Values = nil - // Also kill any successors of c now, to spare later processing. - for _, succ := range c.Succs { - work = append(work, [2]*Block{c, succ}) - } - c.Succs = nil - c.Kind = BlockDead - c.Control = nil + v.Args[i] = v.Args[n] + v.Args[n] = nil // aid GC + v.Args = v.Args[:n] + if n == 1 { + v.Op = OpCopy + // Note: this is trickier than it looks. Replacing + // a Phi with a Copy can in general cause problems because + // Phi and Copy don't have exactly the same semantics. + // Phi arguments always come from a predecessor block, + // whereas copies don't. This matters in loops like: + // 1: x = (Phi y) + // y = (Add x 1) + // goto 1 + // If we replace Phi->Copy, we get + // 1: x = (Copy y) + // y = (Add x 1) + // goto 1 + // (Phi y) refers to the *previous* value of y, whereas + // (Copy y) refers to the *current* value of y. + // The modified code has a cycle and the scheduler + // will barf on it. + // + // Fortunately, this situation can only happen for dead + // code loops. We know the code we're working with is + // not dead, so we're ok. + // Proof: If we have a potential bad cycle, we have a + // situation like this: + // x = (Phi z) + // y = (op1 x ...) + // z = (op2 y ...) + // Where opX are not Phi ops. But such a situation + // implies a cycle in the dominator graph. In the + // example, x.Block dominates y.Block, y.Block dominates + // z.Block, and z.Block dominates x.Block (treating + // "dominates" as reflexive). Cycles in the dominator + // graph can only happen in an unreachable cycle. } } } diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index f77b31501d..5d870ab1cc 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -174,8 +174,8 @@ // big-object moves (TODO: remove?) (Store [size] dst (Load src mem) mem) && size > config.IntSize -> (Move [size] dst src mem) -(If (IsNonNil (GetG)) yes no) -> (Plain nil yes) +(If (IsNonNil (GetG)) yes no) -> (First nil yes no) (If (Not cond) yes no) -> (If cond no yes) -(If (ConstBool {c}) yes no) && c.(bool) -> (Plain nil yes) -(If (ConstBool {c}) yes no) && !c.(bool) -> (Plain nil no) +(If (ConstBool {c}) yes no) && c.(bool) -> (First nil yes no) +(If (ConstBool {c}) yes no) && !c.(bool) -> (First nil no yes) diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 62d34e74bb..2e3be0c0ce 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -373,7 +373,7 @@ var genericBlocks = []blockData{ {name: "Plain"}, // a single successor {name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1] {name: "Call"}, // 2 successors, normal return and panic - // TODO(khr): BlockPanic for the built-in panic call, has 1 edge to the exit block + {name: "First"}, // 2 successors, always takes the first one (second is dead) } func init() { diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go index 057e68601b..e5c61952f1 100644 --- a/src/cmd/compile/internal/ssa/gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/gen/rulegen.go @@ -236,7 +236,7 @@ func genRules(arch arch) { t := split(result[1 : len(result)-1]) // remove parens, then split newsuccs := t[2:] - // Check if newsuccs is a subset of succs. + // Check if newsuccs is the same set as succs. m := map[string]bool{} for _, succ := range succs { if m[succ] { @@ -250,6 +250,9 @@ func genRules(arch arch) { } delete(m, succ) } + if len(m) != 0 { + log.Fatalf("unmatched successors %v in %s", m, rule) + } // Modify predecessor lists for no-longer-reachable blocks for succ := range m { diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go index 4833ac472d..80b9e668d3 100644 --- a/src/cmd/compile/internal/ssa/nilcheck.go +++ b/src/cmd/compile/internal/ssa/nilcheck.go @@ -83,10 +83,8 @@ func nilcheckelim(f *Func) { // Eliminate the nil check. // The deadcode pass will remove vestigial values, // and the fuse pass will join this block with its successor. - node.block.Kind = BlockPlain + node.block.Kind = BlockFirst node.block.Control = nil - f.removePredecessor(node.block, node.block.Succs[1]) - node.block.Succs = node.block.Succs[:1] } else { // new nilcheck so add a ClearPtr node to clear the // ptr from the map of nil checks once we traverse @@ -173,10 +171,8 @@ func nilcheckelim0(f *Func) { // Eliminate the nil check. // The deadcode pass will remove vestigial values, // and the fuse pass will join this block with its successor. - b.Kind = BlockPlain + b.Kind = BlockFirst b.Control = nil - f.removePredecessor(b, b.Succs[1]) - b.Succs = b.Succs[:1] } } } diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 15689b2a85..51a998e352 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -27,6 +27,7 @@ const ( BlockPlain BlockIf BlockCall + BlockFirst ) var blockString = [...]string{ @@ -52,6 +53,7 @@ var blockString = [...]string{ BlockPlain: "Plain", BlockIf: "If", BlockCall: "Call", + BlockFirst: "First", } func (k BlockKind) String() string { return blockString[k] } diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index b14ed9c21e..3ec41181cc 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -1574,27 +1574,25 @@ func rewriteBlockgeneric(b *Block) bool { case BlockIf: // match: (If (IsNonNil (GetG)) yes no) // cond: - // result: (Plain nil yes) + // result: (First nil yes no) { v := b.Control if v.Op != OpIsNonNil { - goto end0f2bb0111a86be0436b44210dbd83a90 + goto endafdc4e2525f9933ab0ae7effc3559597 } if v.Args[0].Op != OpGetG { - goto end0f2bb0111a86be0436b44210dbd83a90 + goto endafdc4e2525f9933ab0ae7effc3559597 } yes := b.Succs[0] no := b.Succs[1] - b.Func.removePredecessor(b, no) - b.Kind = BlockPlain + b.Kind = BlockFirst b.Control = nil - b.Succs = b.Succs[:1] b.Succs[0] = yes - b.Likely = BranchUnknown + b.Succs[1] = no return true } - goto end0f2bb0111a86be0436b44210dbd83a90 - end0f2bb0111a86be0436b44210dbd83a90: + goto endafdc4e2525f9933ab0ae7effc3559597 + endafdc4e2525f9933ab0ae7effc3559597: ; // match: (If (Not cond) yes no) // cond: @@ -1619,53 +1617,50 @@ func rewriteBlockgeneric(b *Block) bool { ; // match: (If (ConstBool {c}) yes no) // cond: c.(bool) - // result: (Plain nil yes) + // result: (First nil yes no) { v := b.Control if v.Op != OpConstBool { - goto end9ff0273f9b1657f4afc287562ca889f0 + goto end7a20763049489cdb40bb1eaa57d113d8 } c := v.Aux yes := b.Succs[0] no := b.Succs[1] if !(c.(bool)) { - goto end9ff0273f9b1657f4afc287562ca889f0 + goto end7a20763049489cdb40bb1eaa57d113d8 } - b.Func.removePredecessor(b, no) - b.Kind = BlockPlain + b.Kind = BlockFirst b.Control = nil - b.Succs = b.Succs[:1] b.Succs[0] = yes - b.Likely = BranchUnknown + b.Succs[1] = no return true } - goto end9ff0273f9b1657f4afc287562ca889f0 - end9ff0273f9b1657f4afc287562ca889f0: + goto end7a20763049489cdb40bb1eaa57d113d8 + end7a20763049489cdb40bb1eaa57d113d8: ; // match: (If (ConstBool {c}) yes no) // cond: !c.(bool) - // result: (Plain nil no) + // result: (First nil no yes) { v := b.Control if v.Op != OpConstBool { - goto endf401a4553c3c7c6bed64801da7bba076 + goto end3ecbf5b2cc1f0a08444d8ab1871a829c } c := v.Aux yes := b.Succs[0] no := b.Succs[1] if !(!c.(bool)) { - goto endf401a4553c3c7c6bed64801da7bba076 + goto end3ecbf5b2cc1f0a08444d8ab1871a829c } - b.Func.removePredecessor(b, yes) - b.Kind = BlockPlain + b.Kind = BlockFirst b.Control = nil - b.Succs = b.Succs[:1] b.Succs[0] = no - b.Likely = BranchUnknown + b.Succs[1] = yes + b.Likely *= -1 return true } - goto endf401a4553c3c7c6bed64801da7bba076 - endf401a4553c3c7c6bed64801da7bba076: + goto end3ecbf5b2cc1f0a08444d8ab1871a829c + end3ecbf5b2cc1f0a08444d8ab1871a829c: } return false } diff --git a/test/fixedbugs/issue12347.go b/test/fixedbugs/issue12347.go new file mode 100644 index 0000000000..4bbe09c3e8 --- /dev/null +++ b/test/fixedbugs/issue12347.go @@ -0,0 +1,16 @@ +// compile + +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f_ssa(x int, p *int) { + if false { + y := x + 5 + for { + *p = y + } + } +} -- cgit v1.3 From c24681ae2e1c96bd67c149cffa8f5ed394e68453 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 22 Oct 2015 14:22:38 -0700 Subject: [dev.ssa] cmd/compile: remember names of values For debugging, spill values to named variables instead of autotmp_ variables if possible. We do this by keeping a name -> value map for each function, keep it up-to-date during deadcode elim, and use it to override spill decisions in stackalloc. It might even make stack frames a bit smaller, as it makes it easy to identify a set of spills which are likely not to interfere. This just works for one-word variables for now. Strings/slices will be a separate CL. Change-Id: Ie89eba8cab16bcd41b311c479ec46dd7e64cdb67 Reviewed-on: https://go-review.googlesource.com/16336 Run-TryBot: Keith Randall Reviewed-by: David Chase --- src/cmd/compile/internal/gc/closure.go | 1 + src/cmd/compile/internal/gc/ssa.go | 73 +++++++++++++++++++++-------- src/cmd/compile/internal/ssa/config.go | 16 ++++--- src/cmd/compile/internal/ssa/deadcode.go | 19 ++++++++ src/cmd/compile/internal/ssa/decompose.go | 4 +- src/cmd/compile/internal/ssa/export_test.go | 3 +- src/cmd/compile/internal/ssa/func.go | 7 +++ src/cmd/compile/internal/ssa/location.go | 6 +-- src/cmd/compile/internal/ssa/stackalloc.go | 63 +++++++++++++++++++++++-- src/cmd/compile/internal/ssa/value.go | 8 ++-- 10 files changed, 156 insertions(+), 44 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go index e7bece8bd9..8ebdd66553 100644 --- a/src/cmd/compile/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -604,6 +604,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node { ptr.Ullman = 1 ptr.Used = true ptr.Name.Curfn = xfunc + ptr.Xoffset = 0 xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr) var body *NodeList if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) { diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index f7100fefbe..c988465e9f 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -304,14 +304,14 @@ func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimp var ( // dummy node for the memory variable - memVar = Node{Op: ONAME, Sym: &Sym{Name: "mem"}} + memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}} // dummy nodes for temporary variables - ptrVar = Node{Op: ONAME, Sym: &Sym{Name: "ptr"}} - capVar = Node{Op: ONAME, Sym: &Sym{Name: "cap"}} - typVar = Node{Op: ONAME, Sym: &Sym{Name: "typ"}} - idataVar = Node{Op: ONAME, Sym: &Sym{Name: "idata"}} - okVar = Node{Op: ONAME, Sym: &Sym{Name: "ok"}} + ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}} + capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}} + typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}} + idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}} + okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}} ) // startBlock sets the current block we're generating code in to b. @@ -2021,6 +2021,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb bool) { if left.Op == ONAME && canSSA(left) { // Update variable assignment. s.vars[left] = right + s.addNamedValue(left, right) return } // not ssa-able. Treat as a store. @@ -2245,13 +2246,14 @@ func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} { // If bounded is true then this address does not require a nil check for its operand // even if that would otherwise be implied. func (s *state) addr(n *Node, bounded bool) *ssa.Value { + t := Ptrto(n.Type) switch n.Op { case ONAME: switch n.Class { case PEXTERN: // global variable aux := &ssa.ExternSymbol{n.Type, n.Sym} - v := s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb) + v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb) // TODO: Make OpAddr use AuxInt as well as Aux. if n.Xoffset != 0 { v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v) @@ -2277,12 +2279,12 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { // getting lucky. We might need a real dependency edge // between vardef and addr ops. aux := &ssa.AutoSymbol{Typ: n.Type, Node: n} - return s.newValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp) + return s.newValue1A(ssa.OpAddr, t, aux, s.sp) case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early. // ensure that we reuse symbols for out parameters so // that cse works on their addresses aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n}) - return s.newValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp) + return s.newValue1A(ssa.OpAddr, t, aux, s.sp) case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF: return s.expr(n.Name.Heapaddr) default: @@ -2296,18 +2298,18 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n) return nil } - return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp) + return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp) case OINDEX: if n.Left.Type.IsSlice() { a := s.expr(n.Left) i := s.expr(n.Right) i = s.extendIndex(i) - len := s.newValue1(ssa.OpSliceLen, Types[TUINTPTR], a) + len := s.newValue1(ssa.OpSliceLen, Types[TINT], a) if !n.Bounded { s.boundsCheck(i, len) } - p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a) - return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i) + p := s.newValue1(ssa.OpSlicePtr, t, a) + return s.newValue2(ssa.OpPtrIndex, t, p, i) } else { // array a := s.addr(n.Left, bounded) i := s.expr(n.Right) @@ -2326,15 +2328,15 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { return p case ODOT: p := s.addr(n.Left, bounded) - return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(Types[TUINTPTR], n.Xoffset)) + return s.newValue2(ssa.OpAddPtr, t, p, s.constIntPtr(Types[TUINTPTR], n.Xoffset)) case ODOTPTR: p := s.expr(n.Left) if !bounded { s.nilCheck(p) } - return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(Types[TUINTPTR], n.Xoffset)) + return s.newValue2(ssa.OpAddPtr, t, p, s.constIntPtr(Types[TUINTPTR], n.Xoffset)) case OCLOSUREVAR: - return s.newValue2(ssa.OpAddPtr, Ptrto(n.Type), + return s.newValue2(ssa.OpAddPtr, t, s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])), s.constIntPtr(Types[TUINTPTR], n.Xoffset)) case OPARAM: @@ -2347,11 +2349,10 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { original_p := *p original_p.Xoffset = n.Xoffset aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p} - return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp) + return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp) case OCONVNOP: addr := s.addr(n.Left, bounded) - to := Ptrto(n.Type) - return s.newValue1(ssa.OpCopy, to, addr) // ensure that addr has the right type + return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type default: s.Unimplementedf("unhandled addr %v", Oconv(int(n.Op), 0)) @@ -3155,6 +3156,7 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name *Node) *ssa.Val // need a phi value v := b.NewValue0(s.peekLine(), ssa.OpPhi, t) v.AddArgs(vals...) + s.addNamedValue(name, v) return v } } @@ -3182,6 +3184,33 @@ func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node) *ssa.Val // TODO: the above mutually recursive functions can lead to very deep stacks. Fix that. +func (s *state) addNamedValue(n *Node, v *ssa.Value) { + if n.Class == Pxxx { + // Don't track our dummy nodes (&memVar etc.). + return + } + if n.Sym == nil { + // TODO: What the heck is this? + return + } + if strings.HasPrefix(n.Sym.Name, "autotmp_") { + // Don't track autotmp_ variables. + return + } + if n.Class == PPARAM || n.Class == PPARAMOUT { + // TODO: Remove this + return + } + if n.Class == PAUTO && n.Xoffset != 0 { + s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset) + } + values, ok := s.f.NamedValues[n] + if !ok { + s.f.Names = append(s.f.Names, n) + } + s.f.NamedValues[n] = append(values, v) +} + // an unresolved branch type branch struct { p *obj.Prog // branch instruction @@ -4441,7 +4470,7 @@ func (*ssaExport) StringData(s string) interface{} { return &ssa.ExternSymbol{Typ: idealstring, Sym: data} } -func (e *ssaExport) Auto(t ssa.Type) fmt.Stringer { +func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode { n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here! return n @@ -4480,3 +4509,7 @@ func (e *ssaExport) Unimplementedf(msg string, args ...interface{}) { } e.unimplemented = true } + +func (n *Node) Typ() ssa.Type { + return n.Type +} diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index efb8b146a1..cfba10bc24 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -4,10 +4,7 @@ package ssa -import ( - "cmd/internal/obj" - "fmt" -) +import "cmd/internal/obj" type Config struct { arch string // "amd64", etc. @@ -63,7 +60,14 @@ type Frontend interface { // Auto returns a Node for an auto variable of the given type. // The SSA compiler uses this function to allocate space for spills. - Auto(Type) fmt.Stringer // returns *gc.Node + Auto(Type) GCNode +} + +// interface used to hold *gc.Node. We'd use *gc.Node directly but +// that would lead to an import cycle. +type GCNode interface { + Typ() Type + String() string } // NewConfig returns a new configuration object for the given architecture. @@ -93,7 +97,7 @@ func (c *Config) Frontend() Frontend { return c.fe } // NewFunc returns a new, empty function object func (c *Config) NewFunc() *Func { // TODO(khr): should this function take name, type, etc. as arguments? - return &Func{Config: c} + return &Func{Config: c, NamedValues: map[GCNode][]*Value{}} } func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index be25eddb47..3351589fda 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -162,6 +162,25 @@ func deadcode(f *Func) { } f.Blocks = f.Blocks[:i] + // Remove dead entries from namedValues map. + for name, values := range f.NamedValues { + i := 0 + for _, v := range values { + for v.Op == OpCopy { + v = v.Args[0] + } + if live[v.ID] { + values[i] = v + i++ + } + } + f.NamedValues[name] = values[:i] + tail := values[i:] + for j := range tail { + tail[j] = nil + } + } + // TODO: renumber Blocks and Values densely? // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? } diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go index 3ef20ef34f..2057d8ea5c 100644 --- a/src/cmd/compile/internal/ssa/decompose.go +++ b/src/cmd/compile/internal/ssa/decompose.go @@ -36,7 +36,7 @@ func decompose(f *Func) { func decomposeStringPhi(v *Value) { fe := v.Block.Func.Config.fe ptrType := fe.TypeBytePtr() - lenType := fe.TypeUintptr() + lenType := fe.TypeInt() ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType) len := v.Block.NewValue0(v.Line, OpPhi, lenType) @@ -55,7 +55,7 @@ func decomposeStringPhi(v *Value) { func decomposeSlicePhi(v *Value) { fe := v.Block.Func.Config.fe ptrType := fe.TypeBytePtr() - lenType := fe.TypeUintptr() + lenType := fe.TypeInt() ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType) len := v.Block.NewValue0(v.Line, OpPhi, lenType) diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index 76a05f91d9..d0ba7b1c09 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -6,7 +6,6 @@ package ssa import ( "cmd/internal/obj" - "fmt" "testing" ) @@ -29,7 +28,7 @@ type DummyFrontend struct { func (DummyFrontend) StringData(s string) interface{} { return nil } -func (DummyFrontend) Auto(t Type) fmt.Stringer { +func (DummyFrontend) Auto(t Type) GCNode { return nil } diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 1ea7c2e2de..772fffce33 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -25,6 +25,13 @@ type Func struct { // when register allocation is done, maps value ids to locations RegAlloc []Location + + // map from *gc.Node to set of Values that represent that Node. + // The Node must be an ONAME with PPARAM, PPARAMOUT, or PAUTO class. + NamedValues map[GCNode][]*Value + // Names is a copy of NamedValues.Keys. We keep a separate list + // of keys to make iteration order deterministic. + Names []GCNode } // NumBlocks returns an integer larger than the id of any Block in the Func. diff --git a/src/cmd/compile/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go index 9f445e5b5a..0f9fb33eeb 100644 --- a/src/cmd/compile/internal/ssa/location.go +++ b/src/cmd/compile/internal/ssa/location.go @@ -4,10 +4,6 @@ package ssa -import ( - "fmt" -) - // A place that an ssa variable can reside. type Location interface { Name() string // name to use in assembly templates: %rax, 16(%rsp), ... @@ -26,7 +22,7 @@ func (r *Register) Name() string { // A LocalSlot is a location in the stack frame. type LocalSlot struct { - N fmt.Stringer // a *gc.Node for an auto variable + N GCNode // a *gc.Node for an auto variable } func (s *LocalSlot) Name() string { diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 17d1f66cea..793162a797 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -36,7 +36,8 @@ func stackalloc(f *Func) { case v.Op == OpStoreReg, v.isStackPhi(): s.remove(v.ID) for _, id := range s.contents() { - if v.Type == types[id] { + if v.Type.Equal(types[id]) { + // Only need interferences between equivalent types. interfere[v.ID] = append(interfere[v.ID], id) interfere[id] = append(interfere[id], v.ID) } @@ -47,6 +48,18 @@ func stackalloc(f *Func) { } } + // Build map from values to their names, if any. + // A value may be associated with more than one name (e.g. after + // the assignment i=j). This step picks one name per value arbitrarily. + names := make([]GCNode, f.NumValues()) + for _, name := range f.Names { + // Note: not "range f.NamedValues" above, because + // that would be nondeterministic. + for _, v := range f.NamedValues[name] { + names[v.ID] = name + } + } + // Figure out which StoreReg ops are phi args. We don't pick slots for // phi args because a stack phi and its args must all use the same stack slot. phiArg := make([]bool, f.NumValues()) @@ -67,6 +80,7 @@ func stackalloc(f *Func) { // Each time we assign a stack slot to a value v, we remember // the slot we used via an index into locations[v.Type]. + // TODO: share slots among equivalent types. slots := make([]int, f.NumValues()) for i := f.NumValues() - 1; i >= 0; i-- { slots[i] = -1 @@ -82,6 +96,45 @@ func stackalloc(f *Func) { if phiArg[v.ID] { continue } + + // If this is a named value, try to use the name as + // the spill location. + var name GCNode + if v.Op == OpStoreReg { + name = names[v.Args[0].ID] + } else { + name = names[v.ID] + } + if name != nil && v.Type.Equal(name.Typ()) { + for _, id := range interfere[v.ID] { + h := f.getHome(id) + if h != nil && h.(*LocalSlot).N == name { + // A variable can interfere with itself. + // It is rare, but but it can happen. + goto noname + } + } + if v.Op == OpPhi { + for _, a := range v.Args { + for _, id := range interfere[a.ID] { + h := f.getHome(id) + if h != nil && h.(*LocalSlot).N == name { + goto noname + } + } + } + } + loc := &LocalSlot{name} + f.setHome(v, loc) + if v.Op == OpPhi { + for _, a := range v.Args { + f.setHome(a, loc) + } + } + continue + } + + noname: // Set of stack slots we could reuse. locs := locations[v.Type] // Mark all positions in locs used by interfering values. @@ -96,7 +149,7 @@ func stackalloc(f *Func) { } if v.Op == OpPhi { // Stack phi and args must get the same stack slot, so - // anything they interfere with is something v the phi + // anything the args interfere with is something the phi // interferes with. for _, a := range v.Args { for _, xid := range interfere[a.ID] { @@ -209,11 +262,11 @@ func (f *Func) liveSpills() [][][]ID { return live } -func (f *Func) getHome(v *Value) Location { - if int(v.ID) >= len(f.RegAlloc) { +func (f *Func) getHome(vid ID) Location { + if int(vid) >= len(f.RegAlloc) { return nil } - return f.RegAlloc[v.ID] + return f.RegAlloc[vid] } func (f *Func) setHome(v *Value, loc Location) { diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index a5915da025..661a05989a 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -142,15 +142,15 @@ type ExternSymbol struct { // ArgSymbol is an aux value that encodes an argument or result // variable's constant offset from FP (FP = SP + framesize). type ArgSymbol struct { - Typ Type // Go type - Node fmt.Stringer // A *gc.Node referring to the argument/result variable. + Typ Type // Go type + Node GCNode // A *gc.Node referring to the argument/result variable. } // AutoSymbol is an aux value that encodes a local variable's // constant offset from SP. type AutoSymbol struct { - Typ Type // Go type - Node fmt.Stringer // A *gc.Node referring to a local (auto) variable. + Typ Type // Go type + Node GCNode // A *gc.Node referring to a local (auto) variable. } func (s *ExternSymbol) String() string { -- cgit v1.3 From 02f4d0a130ba95d7a03418c3ef308d7d21b34af3 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 2 Nov 2015 08:10:26 -0800 Subject: [dev.ssa] cmd/compile: start arguments as spilled Declare a function's arguments as having already been spilled so their use just requires a restore. Allow spill locations to be portions of larger objects the stack. Required to load portions of compound input arguments. Rename the memory input to InputMem. Use Arg for the pre-spilled argument values. Change-Id: I8fe2a03ffbba1022d98bfae2052b376b96d32dda Reviewed-on: https://go-review.googlesource.com/16536 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: David Chase --- src/cmd/compile/internal/gc/pgen.go | 3 + src/cmd/compile/internal/gc/ssa.go | 54 +++++-- src/cmd/compile/internal/ssa/compile.go | 2 +- src/cmd/compile/internal/ssa/config.go | 2 +- src/cmd/compile/internal/ssa/deadcode.go | 34 ++-- src/cmd/compile/internal/ssa/deadcode_test.go | 8 +- src/cmd/compile/internal/ssa/deadstore_test.go | 6 +- src/cmd/compile/internal/ssa/decompose.go | 69 ++++++++- src/cmd/compile/internal/ssa/dom_test.go | 26 ++-- src/cmd/compile/internal/ssa/func.go | 7 +- src/cmd/compile/internal/ssa/func_test.go | 32 ++-- src/cmd/compile/internal/ssa/gen/generic.rules | 45 ++++-- src/cmd/compile/internal/ssa/gen/genericOps.go | 3 +- src/cmd/compile/internal/ssa/html.go | 4 + src/cmd/compile/internal/ssa/location.go | 14 +- src/cmd/compile/internal/ssa/lower.go | 2 +- src/cmd/compile/internal/ssa/nilcheck_test.go | 20 +-- src/cmd/compile/internal/ssa/opGen.go | 5 + src/cmd/compile/internal/ssa/print.go | 8 + src/cmd/compile/internal/ssa/regalloc.go | 10 ++ src/cmd/compile/internal/ssa/regalloc_test.go | 2 +- src/cmd/compile/internal/ssa/rewritegeneric.go | 206 +++++++++++++++++++++---- src/cmd/compile/internal/ssa/schedule_test.go | 2 +- src/cmd/compile/internal/ssa/shift_test.go | 2 +- src/cmd/compile/internal/ssa/stackalloc.go | 34 ++-- src/cmd/compile/internal/ssa/tighten.go | 4 +- src/runtime/runtime-gdb_test.go | 7 - 27 files changed, 470 insertions(+), 141 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index 87e99df2e6..c8f2059543 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -484,6 +484,9 @@ func compile(fn *Node) { if ssafn != nil && usessa { genssa(ssafn, ptxt, gcargs, gclocals) + if Curfn.Func.Endlineno != 0 { + lineno = Curfn.Func.Endlineno + } return } Genlist(Curfn.Func.Enter) diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 5a8e43dedb..2c935b7247 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -97,7 +97,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { // Allocate starting values s.labels = map[string]*ssaLabel{} s.labeledNodes = map[*Node]*ssaLabel{} - s.startmem = s.entryNewValue0(ssa.OpArg, ssa.TypeMem) + s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem) s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR]) @@ -3168,6 +3168,12 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name *Node) *ssa.Val if name == &memVar { return s.startmem } + if canSSA(name) { + v := s.entryNewValue0A(ssa.OpArg, t, name) + // v starts with AuxInt == 0. + s.addNamedValue(name, v) + return v + } // variable is live at the entry block. Load it. addr := s.decladdrs[name] if addr == nil { @@ -3239,18 +3245,21 @@ func (s *state) addNamedValue(n *Node, v *ssa.Value) { // Don't track autotmp_ variables. return } - if n.Class == PPARAM || n.Class == PPARAMOUT { - // TODO: Remove this + if n.Class == PAUTO && (v.Type.IsString() || v.Type.IsSlice() || v.Type.IsInterface()) { + // TODO: can't handle auto compound objects with pointers yet. + // The live variable analysis barfs because we don't put VARDEF + // pseudos in the right place when we spill to these nodes. return } if n.Class == PAUTO && n.Xoffset != 0 { s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset) } - values, ok := s.f.NamedValues[n] + loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0} + values, ok := s.f.NamedValues[loc] if !ok { - s.f.Names = append(s.f.Names, n) + s.f.Names = append(s.f.Names, loc) } - s.f.NamedValues[n] = append(values, v) + s.f.NamedValues[loc] = append(values, v) } // an unresolved branch @@ -3873,11 +3882,17 @@ func (s *genState) genValue(v *ssa.Value) { return } p := Prog(movSizeByType(v.Type)) - n := autoVar(v.Args[0]) + n, off := autoVar(v.Args[0]) p.From.Type = obj.TYPE_MEM - p.From.Name = obj.NAME_AUTO p.From.Node = n p.From.Sym = Linksym(n.Sym) + p.From.Offset = off + if n.Class == PPARAM { + p.From.Name = obj.NAME_PARAM + p.From.Offset += n.Xoffset + } else { + p.From.Name = obj.NAME_AUTO + } p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) @@ -3889,11 +3904,17 @@ func (s *genState) genValue(v *ssa.Value) { p := Prog(movSizeByType(v.Type)) p.From.Type = obj.TYPE_REG p.From.Reg = regnum(v.Args[0]) - n := autoVar(v) + n, off := autoVar(v) p.To.Type = obj.TYPE_MEM - p.To.Name = obj.NAME_AUTO p.To.Node = n p.To.Sym = Linksym(n.Sym) + p.To.Offset = off + if n.Class == PPARAM { + p.To.Name = obj.NAME_PARAM + p.To.Offset += n.Xoffset + } else { + p.To.Name = obj.NAME_AUTO + } case ssa.OpPhi: // just check to make sure regalloc and stackalloc did it right if v.Type.IsMemory() { @@ -3912,9 +3933,10 @@ func (s *genState) genValue(v *ssa.Value) { v.Fatalf("const value %v shouldn't have a location", v) } - case ssa.OpArg: + case ssa.OpInitMem: // memory arg needs no code - // TODO: check that only mem arg goes here. + case ssa.OpArg: + // input args need no code case ssa.OpAMD64LoweredGetClosurePtr: // Output is hardwired to DX only, // and DX contains the closure pointer on @@ -4476,9 +4498,11 @@ func regnum(v *ssa.Value) int16 { return ssaRegToReg[reg.(*ssa.Register).Num] } -// autoVar returns a *Node representing the auto variable assigned to v. -func autoVar(v *ssa.Value) *Node { - return v.Block.Func.RegAlloc[v.ID].(*ssa.LocalSlot).N.(*Node) +// autoVar returns a *Node and int64 representing the auto variable and offset within it +// where v should be spilled. +func autoVar(v *ssa.Value) (*Node, int64) { + loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot) + return loc.N.(*Node), loc.Off } // ssaExport exports a bunch of compiler services for the ssa backend. diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index af672eea99..01238f24ca 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -83,8 +83,8 @@ type pass struct { var passes = [...]pass{ {"phielim", phielim}, {"copyelim", copyelim}, - {"decompose", decompose}, {"early deadcode", deadcode}, // remove generated dead code to avoid doing pointless work during opt + {"decompose", decompose}, {"opt", opt}, {"opt deadcode", deadcode}, // remove any blocks orphaned during opt {"generic cse", cse}, diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 014c960267..6d3a949a6a 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -103,7 +103,7 @@ func (c *Config) Frontend() Frontend { return c.fe } // NewFunc returns a new, empty function object func (c *Config) NewFunc() *Func { // TODO(khr): should this function take name, type, etc. as arguments? - return &Func{Config: c, NamedValues: map[GCNode][]*Value{}} + return &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}} } func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 3351589fda..e9d6525701 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -162,24 +162,38 @@ func deadcode(f *Func) { } f.Blocks = f.Blocks[:i] - // Remove dead entries from namedValues map. - for name, values := range f.NamedValues { - i := 0 + // Remove dead & duplicate entries from namedValues map. + s := newSparseSet(f.NumValues()) + i = 0 + for _, name := range f.Names { + j := 0 + s.clear() + values := f.NamedValues[name] for _, v := range values { for v.Op == OpCopy { v = v.Args[0] } - if live[v.ID] { - values[i] = v - i++ + if live[v.ID] && !s.contains(v.ID) { + values[j] = v + j++ + s.add(v.ID) } } - f.NamedValues[name] = values[:i] - tail := values[i:] - for j := range tail { - tail[j] = nil + if j == 0 { + delete(f.NamedValues, name) + } else { + f.Names[i] = name + i++ + for k := len(values) - 1; k >= j; k-- { + values[k] = nil + } + f.NamedValues[name] = values[:j] } } + for k := len(f.Names) - 1; k >= i; k-- { + f.Names[k] = LocalSlot{} + } + f.Names = f.Names[:i] // TODO: renumber Blocks and Values densely? // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index 7f491c77f9..c59d77ea60 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -10,7 +10,7 @@ func TestDeadLoop(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem")), @@ -40,7 +40,7 @@ func TestDeadValue(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("deadval", OpConst64, TypeInt64, 37, nil), Goto("exit")), Bloc("exit", @@ -64,7 +64,7 @@ func TestNeverTaken(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("cond", OpConstBool, TypeBool, 0, nil), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), If("cond", "then", "else")), Bloc("then", Goto("exit")), @@ -98,7 +98,7 @@ func TestNestedDeadBlocks(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("cond", OpConstBool, TypeBool, 0, nil), If("cond", "b2", "b4")), Bloc("b2", diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go index 159ac4e439..4514c99004 100644 --- a/src/cmd/compile/internal/ssa/deadstore_test.go +++ b/src/cmd/compile/internal/ssa/deadstore_test.go @@ -12,7 +12,7 @@ func TestDeadStore(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpArg, TypeMem, 0, ".mem"), + Valu("start", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr1", OpAddr, ptrType, 0, nil, "sb"), @@ -47,7 +47,7 @@ func TestDeadStorePhi(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpArg, TypeMem, 0, ".mem"), + Valu("start", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr", OpAddr, ptrType, 0, nil, "sb"), @@ -74,7 +74,7 @@ func TestDeadStoreTypes(t *testing.T) { t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"} fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpArg, TypeMem, 0, ".mem"), + Valu("start", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr1", OpAddr, t1, 0, nil, "sb"), diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go index 2057d8ea5c..c8a1df281a 100644 --- a/src/cmd/compile/internal/ssa/decompose.go +++ b/src/cmd/compile/internal/ssa/decompose.go @@ -29,8 +29,75 @@ func decompose(f *Func) { } } } - // TODO: decompose complex? // TODO: decompose 64-bit ops on 32-bit archs? + + // Split up named values into their components. + // NOTE: the component values we are making are dead at this point. + // We must do the opt pass before any deadcode elimination or we will + // lose the name->value correspondence. + for _, name := range f.Names { + t := name.Type + switch { + case t.IsComplex(): + var elemType Type + if t.Size() == 16 { + elemType = f.Config.fe.TypeFloat64() + } else { + elemType = f.Config.fe.TypeFloat32() + } + rName := LocalSlot{name.N, elemType, name.Off} + iName := LocalSlot{name.N, elemType, name.Off + elemType.Size()} + f.Names = append(f.Names, rName, iName) + for _, v := range f.NamedValues[name] { + r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v) + i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v) + f.NamedValues[rName] = append(f.NamedValues[rName], r) + f.NamedValues[iName] = append(f.NamedValues[iName], i) + } + case t.IsString(): + ptrType := f.Config.fe.TypeBytePtr() + lenType := f.Config.fe.TypeInt() + ptrName := LocalSlot{name.N, ptrType, name.Off} + lenName := LocalSlot{name.N, lenType, name.Off + f.Config.PtrSize} + f.Names = append(f.Names, ptrName, lenName) + for _, v := range f.NamedValues[name] { + ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v) + len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v) + f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr) + f.NamedValues[lenName] = append(f.NamedValues[lenName], len) + } + case t.IsSlice(): + ptrType := f.Config.fe.TypeBytePtr() + lenType := f.Config.fe.TypeInt() + ptrName := LocalSlot{name.N, ptrType, name.Off} + lenName := LocalSlot{name.N, lenType, name.Off + f.Config.PtrSize} + capName := LocalSlot{name.N, lenType, name.Off + 2*f.Config.PtrSize} + f.Names = append(f.Names, ptrName, lenName, capName) + for _, v := range f.NamedValues[name] { + ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v) + len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v) + cap := v.Block.NewValue1(v.Line, OpSliceCap, lenType, v) + f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr) + f.NamedValues[lenName] = append(f.NamedValues[lenName], len) + f.NamedValues[capName] = append(f.NamedValues[capName], cap) + } + case t.IsInterface(): + ptrType := f.Config.fe.TypeBytePtr() + typeName := LocalSlot{name.N, ptrType, name.Off} + dataName := LocalSlot{name.N, ptrType, name.Off + f.Config.PtrSize} + f.Names = append(f.Names, typeName, dataName) + for _, v := range f.NamedValues[name] { + typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v) + data := v.Block.NewValue1(v.Line, OpIData, ptrType, v) + f.NamedValues[typeName] = append(f.NamedValues[typeName], typ) + f.NamedValues[dataName] = append(f.NamedValues[dataName], data) + } + //case t.IsStruct(): + // TODO + case t.Size() > f.Config.IntSize: + f.Unimplementedf("undecomposed type %s", t) + } + } } func decomposeStringPhi(v *Value) { diff --git a/src/cmd/compile/internal/ssa/dom_test.go b/src/cmd/compile/internal/ssa/dom_test.go index eff7205fa3..84e0093799 100644 --- a/src/cmd/compile/internal/ssa/dom_test.go +++ b/src/cmd/compile/internal/ssa/dom_test.go @@ -20,7 +20,7 @@ func genLinear(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto(blockn(0)), ), ) @@ -43,7 +43,7 @@ func genFwdBack(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -73,7 +73,7 @@ func genManyPred(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -111,7 +111,7 @@ func genMaxPred(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -136,7 +136,7 @@ func genMaxPredValue(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -223,7 +223,7 @@ func TestDominatorsSingleBlock(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Exit("mem"))) doms := map[string]string{} @@ -238,7 +238,7 @@ func TestDominatorsSimple(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("a")), Bloc("a", Goto("b")), @@ -266,7 +266,7 @@ func TestDominatorsMultPredFwd(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", @@ -294,7 +294,7 @@ func TestDominatorsDeadCode(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 0, nil), If("p", "b3", "b5")), Bloc("b2", Exit("mem")), @@ -319,7 +319,7 @@ func TestDominatorsMultPredRev(t *testing.T) { Bloc("entry", Goto("first")), Bloc("first", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto("a")), Bloc("a", @@ -348,7 +348,7 @@ func TestDominatorsMultPred(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", @@ -376,7 +376,7 @@ func TestPostDominators(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", @@ -403,7 +403,7 @@ func TestInfiniteLoop(t *testing.T) { // note lack of an exit block fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto("a")), Bloc("a", diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index ce11b184f6..e5fbfdb5ff 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -26,12 +26,11 @@ type Func struct { // when register allocation is done, maps value ids to locations RegAlloc []Location - // map from *gc.Node to set of Values that represent that Node. - // The Node must be an ONAME with PPARAM, PPARAMOUT, or PAUTO class. - NamedValues map[GCNode][]*Value + // map from LocalSlot to set of Values that we want to store in that slot. + NamedValues map[LocalSlot][]*Value // Names is a copy of NamedValues.Keys. We keep a separate list // of keys to make iteration order deterministic. - Names []GCNode + Names []LocalSlot } // NumBlocks returns an integer larger than the id of any Block in the Func. diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index dc5d220db8..d35690a30c 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -18,7 +18,7 @@ // // fun := Fun("entry", // Bloc("entry", -// Valu("mem", OpArg, TypeMem, 0, ".mem"), +// Valu("mem", OpInitMem, TypeMem, 0, ".mem"), // Goto("exit")), // Bloc("exit", // Exit("mem")), @@ -263,7 +263,7 @@ func TestArgs(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))) @@ -286,7 +286,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -295,7 +295,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -307,7 +307,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -318,7 +318,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit"))), }, } @@ -335,26 +335,26 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Exit("mem"))), }, // value order changed { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("a", OpConst64, TypeInt64, 14, nil), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Exit("mem"))), @@ -363,12 +363,12 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 14, nil), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 26, nil), Exit("mem"))), }, @@ -376,12 +376,12 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 0, 14), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 0, 26), Exit("mem"))), }, @@ -389,14 +389,14 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 0, nil), Valu("b", OpConst64, TypeInt64, 14, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "b", "a"), diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index bb347aea8b..9c1da92b7e 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -188,12 +188,12 @@ (Load ptr mem) && t.IsString() -> (StringMake (Load ptr mem) - (Load - (OffPtr [config.PtrSize] ptr) + (Load + (OffPtr [config.PtrSize] ptr) mem)) (Store [2*config.PtrSize] dst (StringMake ptr len) mem) -> (Store [config.PtrSize] - (OffPtr [config.PtrSize] dst) + (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem)) @@ -215,18 +215,18 @@ (Load ptr mem) && t.IsSlice() -> (SliceMake (Load ptr mem) - (Load - (OffPtr [config.PtrSize] ptr) + (Load + (OffPtr [config.PtrSize] ptr) mem) - (Load - (OffPtr [2*config.PtrSize] ptr) + (Load + (OffPtr [2*config.PtrSize] ptr) mem)) (Store [3*config.PtrSize] dst (SliceMake ptr len cap) mem) -> (Store [config.PtrSize] - (OffPtr [2*config.PtrSize] dst) + (OffPtr [2*config.PtrSize] dst) cap (Store [config.PtrSize] - (OffPtr [config.PtrSize] dst) + (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem))) @@ -261,3 +261,30 @@ // Get rid of Convert ops for pointer arithmetic on unsafe.Pointer. (Convert (Add64 (Convert ptr) off)) -> (Add64 ptr off) + +// Decompose compound argument values +(Arg {n} [off]) && v.Type.IsString() -> + (StringMake + (Arg {n} [off]) + (Arg {n} [off+config.PtrSize])) + +(Arg {n} [off]) && v.Type.IsSlice() -> + (SliceMake + (Arg {n} [off]) + (Arg {n} [off+config.PtrSize]) + (Arg {n} [off+2*config.PtrSize])) + +(Arg {n} [off]) && v.Type.IsInterface() -> + (IMake + (Arg {n} [off]) + (Arg {n} [off+config.PtrSize])) + +(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 16 -> + (ComplexMake + (Arg {n} [off]) + (Arg {n} [off+8])) + +(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 8 -> + (ComplexMake + (Arg {n} [off]) + (Arg {n} [off+4])) diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 162ee0dab4..8eb10a7d9b 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -260,7 +260,8 @@ var genericOps = []opData{ // TODO: Const32F, ... // Constant-like things - {name: "Arg"}, // memory input to the function. + {name: "InitMem"}, // memory input to the function. + {name: "Arg"}, // argument to the function. aux=GCNode of arg, off = offset in that arg. // The address of a variable. arg0 is the base pointer (SB or SP, depending // on whether it is a global or stack variable). The Aux field identifies the diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index 68a432c676..9b8fc3750b 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -472,3 +472,7 @@ func (p htmlFuncPrinter) startDepCycle() { func (p htmlFuncPrinter) endDepCycle() { fmt.Fprintln(p.w, "") } + +func (p htmlFuncPrinter) named(n LocalSlot, vals []*Value) { + // TODO +} diff --git a/src/cmd/compile/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go index 0f9fb33eeb..85f525565b 100644 --- a/src/cmd/compile/internal/ssa/location.go +++ b/src/cmd/compile/internal/ssa/location.go @@ -4,6 +4,8 @@ package ssa +import "fmt" + // A place that an ssa variable can reside. type Location interface { Name() string // name to use in assembly templates: %rax, 16(%rsp), ... @@ -21,10 +23,16 @@ func (r *Register) Name() string { } // A LocalSlot is a location in the stack frame. +// It is (possibly a subpiece of) a PPARAM, PPARAMOUT, or PAUTO ONAME node. type LocalSlot struct { - N GCNode // a *gc.Node for an auto variable + N GCNode // an ONAME *gc.Node representing a variable on the stack + Type Type // type of slot + Off int64 // offset of slot in N } -func (s *LocalSlot) Name() string { - return s.N.String() +func (s LocalSlot) Name() string { + if s.Off == 0 { + return fmt.Sprintf("%s[%s]", s.N, s.Type) + } + return fmt.Sprintf("%s+%d[%s]", s.N, s.Off, s.Type) } diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index 9c28bd10a5..bf3c15f78b 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -21,7 +21,7 @@ func checkLower(f *Func) { continue // lowered } switch v.Op { - case OpSP, OpSB, OpArg, OpCopy, OpPhi, OpVarDef, OpVarKill: + case OpSP, OpSB, OpInitMem, OpArg, OpCopy, OpPhi, OpVarDef, OpVarKill: continue // ok not to lower } s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString() diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go index 8f32f32b1d..d4a55c0855 100644 --- a/src/cmd/compile/internal/ssa/nilcheck_test.go +++ b/src/cmd/compile/internal/ssa/nilcheck_test.go @@ -21,7 +21,7 @@ func benchmarkNilCheckDeep(b *testing.B, depth int) { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto(blockn(0)), ), @@ -67,7 +67,7 @@ func TestNilcheckSimple(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -104,7 +104,7 @@ func TestNilcheckDomOrder(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -140,7 +140,7 @@ func TestNilcheckAddr(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -173,7 +173,7 @@ func TestNilcheckAddPtr(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -207,7 +207,7 @@ func TestNilcheckPhi(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("sp", OpSP, TypeInvalid, 0, nil), Valu("baddr", OpAddr, TypeBool, 0, "b", "sp"), @@ -251,7 +251,7 @@ func TestNilcheckKeepRemove(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -299,7 +299,7 @@ func TestNilcheckInFalseBranch(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -350,7 +350,7 @@ func TestNilcheckUser(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -389,7 +389,7 @@ func TestNilcheckBug(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 400f59e174..d043e076ea 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -475,6 +475,7 @@ const ( OpConst64F OpConstInterface OpConstSlice + OpInitMem OpArg OpAddr OpSP @@ -3987,6 +3988,10 @@ var opcodeTable = [...]opInfo{ name: "ConstSlice", generic: true, }, + { + name: "InitMem", + generic: true, + }, { name: "Arg", generic: true, diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go index 192dc83b39..b61e6f1cc7 100644 --- a/src/cmd/compile/internal/ssa/print.go +++ b/src/cmd/compile/internal/ssa/print.go @@ -28,6 +28,7 @@ type funcPrinter interface { value(v *Value, live bool) startDepCycle() endDepCycle() + named(n LocalSlot, vals []*Value) } type stringFuncPrinter struct { @@ -73,6 +74,10 @@ func (p stringFuncPrinter) startDepCycle() { func (p stringFuncPrinter) endDepCycle() {} +func (p stringFuncPrinter) named(n LocalSlot, vals []*Value) { + fmt.Fprintf(p.w, "name %s: %v\n", n.Name(), vals) +} + func fprintFunc(p funcPrinter, f *Func) { reachable, live := findlive(f) p.header(f) @@ -136,4 +141,7 @@ func fprintFunc(p funcPrinter, f *Func) { p.endBlock(b) } + for name, vals := range f.NamedValues { + p.named(name, vals) + } } diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 89deb14a4a..a751d66988 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -759,6 +759,16 @@ func (s *regAllocState) regalloc(f *Func) { pc++ continue } + if v.Op == OpArg { + // Args are "pre-spilled" values. We don't allocate + // any register here. We just set up the spill pointer to + // point at itself and any later user will restore it to use it. + s.values[v.ID].spill = v + s.values[v.ID].spillUsed = true // use is guaranteed + b.Values = append(b.Values, v) + pc++ + continue + } s.clearUses(pc*2 - 1) regspec := opcodeTable[v.Op].reg if regDebug { diff --git a/src/cmd/compile/internal/ssa/regalloc_test.go b/src/cmd/compile/internal/ssa/regalloc_test.go index dcd253ea14..08260fbbbb 100644 --- a/src/cmd/compile/internal/ssa/regalloc_test.go +++ b/src/cmd/compile/internal/ssa/regalloc_test.go @@ -10,7 +10,7 @@ func TestLiveControlOps(t *testing.T) { c := testConfig(t) f := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("x", OpAMD64MOVBconst, TypeInt8, 0, 1), Valu("y", OpAMD64MOVBconst, TypeInt8, 0, 2), Valu("a", OpAMD64TESTB, TypeBool, 0, nil, "x", "y"), diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 2448b43547..c349603583 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -23,6 +23,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool { return rewriteValuegeneric_OpAnd64(v, config) case OpAnd8: return rewriteValuegeneric_OpAnd8(v, config) + case OpArg: + return rewriteValuegeneric_OpArg(v, config) case OpArrayIndex: return rewriteValuegeneric_OpArrayIndex(v, config) case OpCom16: @@ -402,6 +404,156 @@ endeaf127389bd0d4b0e0e297830f8f463b: ; return false } +func rewriteValuegeneric_OpArg(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (Arg {n} [off]) + // cond: v.Type.IsString() + // result: (StringMake (Arg {n} [off]) (Arg {n} [off+config.PtrSize])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsString()) { + goto end939d3f946bf61eb85b46b374e7afa9e9 + } + v.Op = OpStringMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeBytePtr() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeInt() + v1.Aux = n + v1.AuxInt = off + config.PtrSize + v.AddArg(v1) + return true + } + goto end939d3f946bf61eb85b46b374e7afa9e9 +end939d3f946bf61eb85b46b374e7afa9e9: + ; + // match: (Arg {n} [off]) + // cond: v.Type.IsSlice() + // result: (SliceMake (Arg {n} [off]) (Arg {n} [off+config.PtrSize]) (Arg {n} [off+2*config.PtrSize])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsSlice()) { + goto endab4b93ad3b1cf55e5bf25d1fd9cd498e + } + v.Op = OpSliceMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeBytePtr() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeInt() + v1.Aux = n + v1.AuxInt = off + config.PtrSize + v.AddArg(v1) + v2 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v2.Type = config.fe.TypeInt() + v2.Aux = n + v2.AuxInt = off + 2*config.PtrSize + v.AddArg(v2) + return true + } + goto endab4b93ad3b1cf55e5bf25d1fd9cd498e +endab4b93ad3b1cf55e5bf25d1fd9cd498e: + ; + // match: (Arg {n} [off]) + // cond: v.Type.IsInterface() + // result: (IMake (Arg {n} [off]) (Arg {n} [off+config.PtrSize])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsInterface()) { + goto end851de8e588a39e81b4e2aef06566bf3e + } + v.Op = OpIMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeBytePtr() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeBytePtr() + v1.Aux = n + v1.AuxInt = off + config.PtrSize + v.AddArg(v1) + return true + } + goto end851de8e588a39e81b4e2aef06566bf3e +end851de8e588a39e81b4e2aef06566bf3e: + ; + // match: (Arg {n} [off]) + // cond: v.Type.IsComplex() && v.Type.Size() == 16 + // result: (ComplexMake (Arg {n} [off]) (Arg {n} [off+8])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsComplex() && v.Type.Size() == 16) { + goto end0988fc6a62c810b2f4976cb6cf44387f + } + v.Op = OpComplexMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeFloat64() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeFloat64() + v1.Aux = n + v1.AuxInt = off + 8 + v.AddArg(v1) + return true + } + goto end0988fc6a62c810b2f4976cb6cf44387f +end0988fc6a62c810b2f4976cb6cf44387f: + ; + // match: (Arg {n} [off]) + // cond: v.Type.IsComplex() && v.Type.Size() == 8 + // result: (ComplexMake (Arg {n} [off]) (Arg {n} [off+4])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsComplex() && v.Type.Size() == 8) { + goto enda348e93e0036873dd7089a2939c22e3e + } + v.Op = OpComplexMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeFloat32() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeFloat32() + v1.Aux = n + v1.AuxInt = off + 4 + v.AddArg(v1) + return true + } + goto enda348e93e0036873dd7089a2939c22e3e +enda348e93e0036873dd7089a2939c22e3e: + ; + return false +} func rewriteValuegeneric_OpArrayIndex(v *Value, config *Config) bool { b := v.Block _ = b @@ -2115,13 +2267,13 @@ end1b106f89e0e3e26c613b957a7c98d8ad: ; // match: (Load ptr mem) // cond: t.IsString() - // result: (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) + // result: (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) { t := v.Type ptr := v.Args[0] mem := v.Args[1] if !(t.IsString()) { - goto end7c75255555bf9dd796298d9f6eaf9cf2 + goto enddd15a6f3d53a6ce7a19d4e181dd1c13a } v.Op = OpStringMake v.AuxInt = 0 @@ -2133,9 +2285,9 @@ end1b106f89e0e3e26c613b957a7c98d8ad: v0.AddArg(mem) v.AddArg(v0) v1 := b.NewValue0(v.Line, OpLoad, TypeInvalid) - v1.Type = config.fe.TypeUintptr() + v1.Type = config.fe.TypeInt() v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v2.Type = config.fe.TypeUintptr().PtrTo() + v2.Type = config.fe.TypeInt().PtrTo() v2.AuxInt = config.PtrSize v2.AddArg(ptr) v1.AddArg(v2) @@ -2143,18 +2295,18 @@ end1b106f89e0e3e26c613b957a7c98d8ad: v.AddArg(v1) return true } - goto end7c75255555bf9dd796298d9f6eaf9cf2 -end7c75255555bf9dd796298d9f6eaf9cf2: + goto enddd15a6f3d53a6ce7a19d4e181dd1c13a +enddd15a6f3d53a6ce7a19d4e181dd1c13a: ; // match: (Load ptr mem) // cond: t.IsSlice() - // result: (SliceMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem) (Load (OffPtr [2*config.PtrSize] ptr) mem)) + // result: (SliceMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem) (Load (OffPtr [2*config.PtrSize] ptr) mem)) { t := v.Type ptr := v.Args[0] mem := v.Args[1] if !(t.IsSlice()) { - goto end12c46556d962198680eb3238859e3016 + goto end65e8b0055aa7491b9b6066d9fe1b2c13 } v.Op = OpSliceMake v.AuxInt = 0 @@ -2166,18 +2318,18 @@ end7c75255555bf9dd796298d9f6eaf9cf2: v0.AddArg(mem) v.AddArg(v0) v1 := b.NewValue0(v.Line, OpLoad, TypeInvalid) - v1.Type = config.fe.TypeUintptr() + v1.Type = config.fe.TypeInt() v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v2.Type = config.fe.TypeUintptr().PtrTo() + v2.Type = config.fe.TypeInt().PtrTo() v2.AuxInt = config.PtrSize v2.AddArg(ptr) v1.AddArg(v2) v1.AddArg(mem) v.AddArg(v1) v3 := b.NewValue0(v.Line, OpLoad, TypeInvalid) - v3.Type = config.fe.TypeUintptr() + v3.Type = config.fe.TypeInt() v4 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v4.Type = config.fe.TypeUintptr().PtrTo() + v4.Type = config.fe.TypeInt().PtrTo() v4.AuxInt = 2 * config.PtrSize v4.AddArg(ptr) v3.AddArg(v4) @@ -2185,8 +2337,8 @@ end7c75255555bf9dd796298d9f6eaf9cf2: v.AddArg(v3) return true } - goto end12c46556d962198680eb3238859e3016 -end12c46556d962198680eb3238859e3016: + goto end65e8b0055aa7491b9b6066d9fe1b2c13 +end65e8b0055aa7491b9b6066d9fe1b2c13: ; // match: (Load ptr mem) // cond: t.IsInterface() @@ -2916,14 +3068,14 @@ end3851a482d7bd37a93c4d81581e85b3ab: ; // match: (Store [2*config.PtrSize] dst (StringMake ptr len) mem) // cond: - // result: (Store [config.PtrSize] (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem)) + // result: (Store [config.PtrSize] (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem)) { if v.AuxInt != 2*config.PtrSize { - goto end12abe4021d24e76ed56d64b18730bffb + goto endd3a6ecebdad5899570a79fe5c62f34f1 } dst := v.Args[0] if v.Args[1].Op != OpStringMake { - goto end12abe4021d24e76ed56d64b18730bffb + goto endd3a6ecebdad5899570a79fe5c62f34f1 } ptr := v.Args[1].Args[0] len := v.Args[1].Args[1] @@ -2934,7 +3086,7 @@ end3851a482d7bd37a93c4d81581e85b3ab: v.resetArgs() v.AuxInt = config.PtrSize v0 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v0.Type = config.fe.TypeUintptr().PtrTo() + v0.Type = config.fe.TypeInt().PtrTo() v0.AuxInt = config.PtrSize v0.AddArg(dst) v.AddArg(v0) @@ -2948,19 +3100,19 @@ end3851a482d7bd37a93c4d81581e85b3ab: v.AddArg(v1) return true } - goto end12abe4021d24e76ed56d64b18730bffb -end12abe4021d24e76ed56d64b18730bffb: + goto endd3a6ecebdad5899570a79fe5c62f34f1 +endd3a6ecebdad5899570a79fe5c62f34f1: ; // match: (Store [3*config.PtrSize] dst (SliceMake ptr len cap) mem) // cond: - // result: (Store [config.PtrSize] (OffPtr [2*config.PtrSize] dst) cap (Store [config.PtrSize] (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem))) + // result: (Store [config.PtrSize] (OffPtr [2*config.PtrSize] dst) cap (Store [config.PtrSize] (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem))) { if v.AuxInt != 3*config.PtrSize { - goto end7498d25e17db5398cf073a8590e35cc2 + goto endd5cc8c3dad7d24c845b0b88fc51487ae } dst := v.Args[0] if v.Args[1].Op != OpSliceMake { - goto end7498d25e17db5398cf073a8590e35cc2 + goto endd5cc8c3dad7d24c845b0b88fc51487ae } ptr := v.Args[1].Args[0] len := v.Args[1].Args[1] @@ -2972,7 +3124,7 @@ end12abe4021d24e76ed56d64b18730bffb: v.resetArgs() v.AuxInt = config.PtrSize v0 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v0.Type = config.fe.TypeUintptr().PtrTo() + v0.Type = config.fe.TypeInt().PtrTo() v0.AuxInt = 2 * config.PtrSize v0.AddArg(dst) v.AddArg(v0) @@ -2980,7 +3132,7 @@ end12abe4021d24e76ed56d64b18730bffb: v1 := b.NewValue0(v.Line, OpStore, TypeInvalid) v1.AuxInt = config.PtrSize v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v2.Type = config.fe.TypeUintptr().PtrTo() + v2.Type = config.fe.TypeInt().PtrTo() v2.AuxInt = config.PtrSize v2.AddArg(dst) v1.AddArg(v2) @@ -2996,8 +3148,8 @@ end12abe4021d24e76ed56d64b18730bffb: v.AddArg(v1) return true } - goto end7498d25e17db5398cf073a8590e35cc2 -end7498d25e17db5398cf073a8590e35cc2: + goto endd5cc8c3dad7d24c845b0b88fc51487ae +endd5cc8c3dad7d24c845b0b88fc51487ae: ; // match: (Store [2*config.PtrSize] dst (IMake itab data) mem) // cond: diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go index 7f62ab9e3b..30c029ef7c 100644 --- a/src/cmd/compile/internal/ssa/schedule_test.go +++ b/src/cmd/compile/internal/ssa/schedule_test.go @@ -11,7 +11,7 @@ func TestSchedule(t *testing.T) { cases := []fun{ Fun(c, "entry", Bloc("entry", - Valu("mem0", OpArg, TypeMem, 0, ".mem"), + Valu("mem0", OpInitMem, TypeMem, 0, ".mem"), Valu("ptr", OpConst64, TypeInt64, 0xABCD, nil), Valu("v", OpConst64, TypeInt64, 12, nil), Valu("mem1", OpStore, TypeMem, 8, nil, "ptr", "v", "mem0"), diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index 611b418b6d..9e7f0585a6 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -28,7 +28,7 @@ func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun { ptyp := &TypeImpl{Size_: 8, Ptr: true, Name: "ptr"} fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("SP", OpSP, TypeUInt64, 0, nil), Valu("argptr", OpOffPtr, ptyp, 8, nil, "SP"), Valu("resptr", OpOffPtr, ptyp, 16, nil, "SP"), diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 793162a797..3eb5c3cf4a 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -44,6 +44,13 @@ func stackalloc(f *Func) { } case v.Op == OpLoadReg: s.add(v.Args[0].ID) + case v.Op == OpArg: + // This is an input argument which is pre-spilled. It is kind of + // like a StoreReg, but we don't remove v.ID here because we want + // this value to appear live even before this point. Being live + // all the way to the start of the entry block prevents other + // values from being allocated to the same slot and clobbering + // the input value before we have a chance to load it. } } } @@ -51,7 +58,7 @@ func stackalloc(f *Func) { // Build map from values to their names, if any. // A value may be associated with more than one name (e.g. after // the assignment i=j). This step picks one name per value arbitrarily. - names := make([]GCNode, f.NumValues()) + names := make([]LocalSlot, f.NumValues()) for _, name := range f.Names { // Note: not "range f.NamedValues" above, because // that would be nondeterministic. @@ -74,9 +81,17 @@ func stackalloc(f *Func) { } } + // Allocate args to their assigned locations. + for _, v := range f.Entry.Values { + if v.Op != OpArg { + continue + } + f.setHome(v, LocalSlot{v.Aux.(GCNode), v.Type, v.AuxInt}) + } + // For each type, we keep track of all the stack slots we // have allocated for that type. - locations := map[Type][]*LocalSlot{} + locations := map[Type][]LocalSlot{} // Each time we assign a stack slot to a value v, we remember // the slot we used via an index into locations[v.Type]. @@ -99,16 +114,16 @@ func stackalloc(f *Func) { // If this is a named value, try to use the name as // the spill location. - var name GCNode + var name LocalSlot if v.Op == OpStoreReg { name = names[v.Args[0].ID] } else { name = names[v.ID] } - if name != nil && v.Type.Equal(name.Typ()) { + if name.N != nil && v.Type.Equal(name.Type) { for _, id := range interfere[v.ID] { h := f.getHome(id) - if h != nil && h.(*LocalSlot).N == name { + if h != nil && h.(LocalSlot) == name { // A variable can interfere with itself. // It is rare, but but it can happen. goto noname @@ -118,17 +133,16 @@ func stackalloc(f *Func) { for _, a := range v.Args { for _, id := range interfere[a.ID] { h := f.getHome(id) - if h != nil && h.(*LocalSlot).N == name { + if h != nil && h.(LocalSlot) == name { goto noname } } } } - loc := &LocalSlot{name} - f.setHome(v, loc) + f.setHome(v, name) if v.Op == OpPhi { for _, a := range v.Args { - f.setHome(a, loc) + f.setHome(a, name) } } continue @@ -169,7 +183,7 @@ func stackalloc(f *Func) { } // If there is no unused stack slot, allocate a new one. if i == len(locs) { - locs = append(locs, &LocalSlot{f.Config.fe.Auto(v.Type)}) + locs = append(locs, LocalSlot{N: f.Config.fe.Auto(v.Type), Type: v.Type, Off: 0}) locations[v.Type] = locs } // Use the stack variable at that index for v. diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go index 4fa26d2d18..6726c06e76 100644 --- a/src/cmd/compile/internal/ssa/tighten.go +++ b/src/cmd/compile/internal/ssa/tighten.go @@ -54,8 +54,8 @@ func tighten(f *Func) { for _, b := range f.Blocks { for i := 0; i < len(b.Values); i++ { v := b.Values[i] - if v.Op == OpPhi || v.Op == OpGetClosurePtr || v.Op == OpConvert { - // GetClosurePtr must stay in entry block. + if v.Op == OpPhi || v.Op == OpGetClosurePtr || v.Op == OpConvert || v.Op == OpArg { + // GetClosurePtr & Arg must stay in entry block. // OpConvert must not float over call sites. // TODO do we instead need a dependence edge of some sort for OpConvert? // Would memory do the trick, or do we need something else that relates diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 2843633ee1..48567f1b9c 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -94,9 +94,6 @@ func TestGdbPython(t *testing.T) { "-ex", "echo END\n", "-ex", "echo BEGIN print strvar\n", "-ex", "print strvar", - "-ex", "echo END\n", - "-ex", "echo BEGIN print ptrvar\n", - "-ex", "print ptrvar", "-ex", "echo END\n"} // without framepointer, gdb cannot backtrace our non-standard @@ -151,10 +148,6 @@ func TestGdbPython(t *testing.T) { t.Fatalf("print strvar failed: %s", bl) } - if bl := blocks["print ptrvar"]; !strVarRe.MatchString(bl) { - t.Fatalf("print ptrvar failed: %s", bl) - } - btGoroutineRe := regexp.MustCompile(`^#0\s+runtime.+at`) if bl := blocks["goroutine 2 bt"]; canBackTrace && !btGoroutineRe.MatchString(bl) { t.Fatalf("goroutine 2 bt failed: %s", bl) -- cgit v1.3 From 3425295e915bc16236f2c021317705aca34319af Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 5 Jan 2016 14:56:26 -0800 Subject: [dev.ssa] cmd/compile: clean up comparisons Add new constant-flags opcodes. These can be generated from comparisons that we know the result of, like x&31 < 32. Constant-fold the constant-flags opcodes into all flag users. Reorder some CMPxconst args so they read in the comparison direction. Reorg deadcode removal a bit - it needs to remove the OpCopy ops it generates when strength-reducing Phi ops. So it needs to splice out all the dead blocks and do a copy elimination before it computes live values. Change-Id: Ie922602033592ad8212efe4345394973d3b94d9f Reviewed-on: https://go-review.googlesource.com/18267 Run-TryBot: Keith Randall Reviewed-by: David Chase --- src/cmd/compile/internal/gc/ssa.go | 2 + src/cmd/compile/internal/ssa/copyelim.go | 14 + src/cmd/compile/internal/ssa/deadcode.go | 144 +- src/cmd/compile/internal/ssa/gen/AMD64.rules | 287 ++- src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 13 + src/cmd/compile/internal/ssa/lower.go | 2 +- src/cmd/compile/internal/ssa/opGen.go | 25 + src/cmd/compile/internal/ssa/rewriteAMD64.go | 3213 +++++++++++++++++++++----- 8 files changed, 3019 insertions(+), 681 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index eee3051c39..c41a66f1ae 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -4108,6 +4108,8 @@ func (s *genState) genValue(v *ssa.Value) { case ssa.OpAMD64InvertFlags: v.Fatalf("InvertFlags should never make it to codegen %v", v) + case ssa.OpAMD64FlagEQ, ssa.OpAMD64FlagLT_ULT, ssa.OpAMD64FlagLT_UGT, ssa.OpAMD64FlagGT_ULT, ssa.OpAMD64FlagGT_UGT: + v.Fatalf("Flag* ops should never make it to codegen %v", v) case ssa.OpAMD64REPSTOSQ: Prog(x86.AREP) Prog(x86.ASTOSQ) diff --git a/src/cmd/compile/internal/ssa/copyelim.go b/src/cmd/compile/internal/ssa/copyelim.go index 10c2dcc440..067d5e2606 100644 --- a/src/cmd/compile/internal/ssa/copyelim.go +++ b/src/cmd/compile/internal/ssa/copyelim.go @@ -26,4 +26,18 @@ func copyelim(f *Func) { b.Control = v } } + + // Update named values. + for _, name := range f.Names { + values := f.NamedValues[name] + for i, v := range values { + x := v + for x.Op == OpCopy { + x = x.Args[0] + } + if x != v { + values[i] = v + } + } + } } diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index e9d6525701..429708213f 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -6,22 +6,14 @@ package ssa // findlive returns the reachable blocks and live values in f. func findlive(f *Func) (reachable []bool, live []bool) { - // After regalloc, consider all blocks and values to be reachable and live. - // See the comment at the top of regalloc.go and in deadcode for details. - if f.RegAlloc != nil { - reachable = make([]bool, f.NumBlocks()) - for i := range reachable { - reachable[i] = true - } - live = make([]bool, f.NumValues()) - for i := range live { - live[i] = true - } - return reachable, live - } + reachable = reachableBlocks(f) + live = liveValues(f, reachable) + return +} - // Find all reachable basic blocks. - reachable = make([]bool, f.NumBlocks()) +// reachableBlocks returns the reachable blocks in f. +func reachableBlocks(f *Func) []bool { + reachable := make([]bool, f.NumBlocks()) reachable[f.Entry.ID] = true p := []*Block{f.Entry} // stack-like worklist for len(p) > 0 { @@ -40,10 +32,25 @@ func findlive(f *Func) (reachable []bool, live []bool) { } } } + return reachable +} + +// liveValues returns the live values in f. +// reachable is a map from block ID to whether the block is reachable. +func liveValues(f *Func, reachable []bool) []bool { + live := make([]bool, f.NumValues()) + + // After regalloc, consider all values to be live. + // See the comment at the top of regalloc.go and in deadcode for details. + if f.RegAlloc != nil { + for i := range live { + live[i] = true + } + return live + } // Find all live values - live = make([]bool, f.NumValues()) // flag to set for each live value - var q []*Value // stack-like worklist of unscanned values + var q []*Value // stack-like worklist of unscanned values // Starting set: all control values of reachable blocks are live. for _, b := range f.Blocks { @@ -72,7 +79,7 @@ func findlive(f *Func) (reachable []bool, live []bool) { } } - return reachable, live + return live } // deadcode removes dead code from f. @@ -85,27 +92,8 @@ func deadcode(f *Func) { f.Fatalf("deadcode after regalloc") } - reachable, live := findlive(f) - - // Remove dead values from blocks' value list. Return dead - // value ids to the allocator. - for _, b := range f.Blocks { - i := 0 - for _, v := range b.Values { - if live[v.ID] { - b.Values[i] = v - i++ - } else { - f.vid.put(v.ID) - } - } - // aid GC - tail := b.Values[i:] - for j := range tail { - tail[j] = nil - } - b.Values = b.Values[:i] - } + // Find reachable blocks. + reachable := reachableBlocks(f) // Get rid of edges from dead to live code. for _, b := range f.Blocks { @@ -131,6 +119,7 @@ func deadcode(f *Func) { b.Succs[1] = nil b.Succs = b.Succs[:1] b.Kind = BlockPlain + b.Likely = BranchUnknown if reachable[c.ID] { // Note: c must be reachable through some other edge. @@ -138,41 +127,20 @@ func deadcode(f *Func) { } } - // Remove unreachable blocks. Return dead block ids to allocator. - i := 0 - for _, b := range f.Blocks { - if reachable[b.ID] { - f.Blocks[i] = b - i++ - } else { - if len(b.Values) > 0 { - b.Fatalf("live values in unreachable block %v: %v", b, b.Values) - } - b.Preds = nil - b.Succs = nil - b.Control = nil - b.Kind = BlockDead - f.bid.put(b.ID) - } - } - // zero remainder to help GC - tail := f.Blocks[i:] - for j := range tail { - tail[j] = nil - } - f.Blocks = f.Blocks[:i] + // Splice out any copies introduced during dead block removal. + copyelim(f) + + // Find live values. + live := liveValues(f, reachable) // Remove dead & duplicate entries from namedValues map. s := newSparseSet(f.NumValues()) - i = 0 + i := 0 for _, name := range f.Names { j := 0 s.clear() values := f.NamedValues[name] for _, v := range values { - for v.Op == OpCopy { - v = v.Args[0] - } if live[v.ID] && !s.contains(v.ID) { values[j] = v j++ @@ -195,6 +163,50 @@ func deadcode(f *Func) { } f.Names = f.Names[:i] + // Remove dead values from blocks' value list. Return dead + // value ids to the allocator. + for _, b := range f.Blocks { + i := 0 + for _, v := range b.Values { + if live[v.ID] { + b.Values[i] = v + i++ + } else { + f.vid.put(v.ID) + } + } + // aid GC + tail := b.Values[i:] + for j := range tail { + tail[j] = nil + } + b.Values = b.Values[:i] + } + + // Remove unreachable blocks. Return dead block ids to allocator. + i = 0 + for _, b := range f.Blocks { + if reachable[b.ID] { + f.Blocks[i] = b + i++ + } else { + if len(b.Values) > 0 { + b.Fatalf("live values in unreachable block %v: %v", b, b.Values) + } + b.Preds = nil + b.Succs = nil + b.Control = nil + b.Kind = BlockDead + f.bid.put(b.ID) + } + } + // zero remainder to help GC + tail := f.Blocks[i:] + for j := range tail { + tail[j] = nil + } + f.Blocks = f.Blocks[:i] + // TODO: renumber Blocks and Values densely? // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? } diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 0edbfdaa1a..9db3abb9f0 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -130,73 +130,73 @@ // Unsigned shifts need to return 0 if shift amount is >= width of shifted value. // result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff) // Note: for small shifts we generate 32 bits of mask even when we don't need it all. -(Lsh64x64 x y) -> (ANDQ (SHLQ x y) (SBBQcarrymask (CMPQconst [64] y))) -(Lsh64x32 x y) -> (ANDQ (SHLQ x y) (SBBQcarrymask (CMPLconst [64] y))) -(Lsh64x16 x y) -> (ANDQ (SHLQ x y) (SBBQcarrymask (CMPWconst [64] y))) -(Lsh64x8 x y) -> (ANDQ (SHLQ x y) (SBBQcarrymask (CMPBconst [64] y))) - -(Lsh32x64 x y) -> (ANDL (SHLL x y) (SBBLcarrymask (CMPQconst [32] y))) -(Lsh32x32 x y) -> (ANDL (SHLL x y) (SBBLcarrymask (CMPLconst [32] y))) -(Lsh32x16 x y) -> (ANDL (SHLL x y) (SBBLcarrymask (CMPWconst [32] y))) -(Lsh32x8 x y) -> (ANDL (SHLL x y) (SBBLcarrymask (CMPBconst [32] y))) - -(Lsh16x64 x y) -> (ANDW (SHLW x y) (SBBLcarrymask (CMPQconst [16] y))) -(Lsh16x32 x y) -> (ANDW (SHLW x y) (SBBLcarrymask (CMPLconst [16] y))) -(Lsh16x16 x y) -> (ANDW (SHLW x y) (SBBLcarrymask (CMPWconst [16] y))) -(Lsh16x8 x y) -> (ANDW (SHLW x y) (SBBLcarrymask (CMPBconst [16] y))) - -(Lsh8x64 x y) -> (ANDB (SHLB x y) (SBBLcarrymask (CMPQconst [8] y))) -(Lsh8x32 x y) -> (ANDB (SHLB x y) (SBBLcarrymask (CMPLconst [8] y))) -(Lsh8x16 x y) -> (ANDB (SHLB x y) (SBBLcarrymask (CMPWconst [8] y))) -(Lsh8x8 x y) -> (ANDB (SHLB x y) (SBBLcarrymask (CMPBconst [8] y))) +(Lsh64x64 x y) -> (ANDQ (SHLQ x y) (SBBQcarrymask (CMPQconst y [64]))) +(Lsh64x32 x y) -> (ANDQ (SHLQ x y) (SBBQcarrymask (CMPLconst y [64]))) +(Lsh64x16 x y) -> (ANDQ (SHLQ x y) (SBBQcarrymask (CMPWconst y [64]))) +(Lsh64x8 x y) -> (ANDQ (SHLQ x y) (SBBQcarrymask (CMPBconst y [64]))) + +(Lsh32x64 x y) -> (ANDL (SHLL x y) (SBBLcarrymask (CMPQconst y [32]))) +(Lsh32x32 x y) -> (ANDL (SHLL x y) (SBBLcarrymask (CMPLconst y [32]))) +(Lsh32x16 x y) -> (ANDL (SHLL x y) (SBBLcarrymask (CMPWconst y [32]))) +(Lsh32x8 x y) -> (ANDL (SHLL x y) (SBBLcarrymask (CMPBconst y [32]))) + +(Lsh16x64 x y) -> (ANDW (SHLW x y) (SBBLcarrymask (CMPQconst y [16]))) +(Lsh16x32 x y) -> (ANDW (SHLW x y) (SBBLcarrymask (CMPLconst y [16]))) +(Lsh16x16 x y) -> (ANDW (SHLW x y) (SBBLcarrymask (CMPWconst y [16]))) +(Lsh16x8 x y) -> (ANDW (SHLW x y) (SBBLcarrymask (CMPBconst y [16]))) + +(Lsh8x64 x y) -> (ANDB (SHLB x y) (SBBLcarrymask (CMPQconst y [8]))) +(Lsh8x32 x y) -> (ANDB (SHLB x y) (SBBLcarrymask (CMPLconst y [8]))) +(Lsh8x16 x y) -> (ANDB (SHLB x y) (SBBLcarrymask (CMPWconst y [8]))) +(Lsh8x8 x y) -> (ANDB (SHLB x y) (SBBLcarrymask (CMPBconst y [8]))) (Lrot64 x [c]) -> (ROLQconst [c&63] x) (Lrot32 x [c]) -> (ROLLconst [c&31] x) (Lrot16 x [c]) -> (ROLWconst [c&15] x) (Lrot8 x [c]) -> (ROLBconst [c&7] x) -(Rsh64Ux64 x y) -> (ANDQ (SHRQ x y) (SBBQcarrymask (CMPQconst [64] y))) -(Rsh64Ux32 x y) -> (ANDQ (SHRQ x y) (SBBQcarrymask (CMPLconst [64] y))) -(Rsh64Ux16 x y) -> (ANDQ (SHRQ x y) (SBBQcarrymask (CMPWconst [64] y))) -(Rsh64Ux8 x y) -> (ANDQ (SHRQ x y) (SBBQcarrymask (CMPBconst [64] y))) +(Rsh64Ux64 x y) -> (ANDQ (SHRQ x y) (SBBQcarrymask (CMPQconst y [64]))) +(Rsh64Ux32 x y) -> (ANDQ (SHRQ x y) (SBBQcarrymask (CMPLconst y [64]))) +(Rsh64Ux16 x y) -> (ANDQ (SHRQ x y) (SBBQcarrymask (CMPWconst y [64]))) +(Rsh64Ux8 x y) -> (ANDQ (SHRQ x y) (SBBQcarrymask (CMPBconst y [64]))) -(Rsh32Ux64 x y) -> (ANDL (SHRL x y) (SBBLcarrymask (CMPQconst [32] y))) -(Rsh32Ux32 x y) -> (ANDL (SHRL x y) (SBBLcarrymask (CMPLconst [32] y))) -(Rsh32Ux16 x y) -> (ANDL (SHRL x y) (SBBLcarrymask (CMPWconst [32] y))) -(Rsh32Ux8 x y) -> (ANDL (SHRL x y) (SBBLcarrymask (CMPBconst [32] y))) +(Rsh32Ux64 x y) -> (ANDL (SHRL x y) (SBBLcarrymask (CMPQconst y [32]))) +(Rsh32Ux32 x y) -> (ANDL (SHRL x y) (SBBLcarrymask (CMPLconst y [32]))) +(Rsh32Ux16 x y) -> (ANDL (SHRL x y) (SBBLcarrymask (CMPWconst y [32]))) +(Rsh32Ux8 x y) -> (ANDL (SHRL x y) (SBBLcarrymask (CMPBconst y [32]))) -(Rsh16Ux64 x y) -> (ANDW (SHRW x y) (SBBLcarrymask (CMPQconst [16] y))) -(Rsh16Ux32 x y) -> (ANDW (SHRW x y) (SBBLcarrymask (CMPLconst [16] y))) -(Rsh16Ux16 x y) -> (ANDW (SHRW x y) (SBBLcarrymask (CMPWconst [16] y))) -(Rsh16Ux8 x y) -> (ANDW (SHRW x y) (SBBLcarrymask (CMPBconst [16] y))) +(Rsh16Ux64 x y) -> (ANDW (SHRW x y) (SBBLcarrymask (CMPQconst y [16]))) +(Rsh16Ux32 x y) -> (ANDW (SHRW x y) (SBBLcarrymask (CMPLconst y [16]))) +(Rsh16Ux16 x y) -> (ANDW (SHRW x y) (SBBLcarrymask (CMPWconst y [16]))) +(Rsh16Ux8 x y) -> (ANDW (SHRW x y) (SBBLcarrymask (CMPBconst y [16]))) -(Rsh8Ux64 x y) -> (ANDB (SHRB x y) (SBBLcarrymask (CMPQconst [8] y))) -(Rsh8Ux32 x y) -> (ANDB (SHRB x y) (SBBLcarrymask (CMPLconst [8] y))) -(Rsh8Ux16 x y) -> (ANDB (SHRB x y) (SBBLcarrymask (CMPWconst [8] y))) -(Rsh8Ux8 x y) -> (ANDB (SHRB x y) (SBBLcarrymask (CMPBconst [8] y))) +(Rsh8Ux64 x y) -> (ANDB (SHRB x y) (SBBLcarrymask (CMPQconst y [8]))) +(Rsh8Ux32 x y) -> (ANDB (SHRB x y) (SBBLcarrymask (CMPLconst y [8]))) +(Rsh8Ux16 x y) -> (ANDB (SHRB x y) (SBBLcarrymask (CMPWconst y [8]))) +(Rsh8Ux8 x y) -> (ANDB (SHRB x y) (SBBLcarrymask (CMPBconst y [8]))) // Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value. // We implement this by setting the shift value to -1 (all ones) if the shift value is >= width. // Note: for small shift widths we generate 32 bits of mask even when we don't need it all. -(Rsh64x64 x y) -> (SARQ x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst [64] y))))) -(Rsh64x32 x y) -> (SARQ x (ORL y (NOTL (SBBLcarrymask (CMPLconst [64] y))))) -(Rsh64x16 x y) -> (SARQ x (ORW y (NOTL (SBBLcarrymask (CMPWconst [64] y))))) -(Rsh64x8 x y) -> (SARQ x (ORB y (NOTL (SBBLcarrymask (CMPBconst [64] y))))) - -(Rsh32x64 x y) -> (SARL x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst [32] y))))) -(Rsh32x32 x y) -> (SARL x (ORL y (NOTL (SBBLcarrymask (CMPLconst [32] y))))) -(Rsh32x16 x y) -> (SARL x (ORW y (NOTL (SBBLcarrymask (CMPWconst [32] y))))) -(Rsh32x8 x y) -> (SARL x (ORB y (NOTL (SBBLcarrymask (CMPBconst [32] y))))) - -(Rsh16x64 x y) -> (SARW x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst [16] y))))) -(Rsh16x32 x y) -> (SARW x (ORL y (NOTL (SBBLcarrymask (CMPLconst [16] y))))) -(Rsh16x16 x y) -> (SARW x (ORW y (NOTL (SBBLcarrymask (CMPWconst [16] y))))) -(Rsh16x8 x y) -> (SARW x (ORB y (NOTL (SBBLcarrymask (CMPBconst [16] y))))) - -(Rsh8x64 x y) -> (SARB x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst [8] y))))) -(Rsh8x32 x y) -> (SARB x (ORL y (NOTL (SBBLcarrymask (CMPLconst [8] y))))) -(Rsh8x16 x y) -> (SARB x (ORW y (NOTL (SBBLcarrymask (CMPWconst [8] y))))) -(Rsh8x8 x y) -> (SARB x (ORB y (NOTL (SBBLcarrymask (CMPBconst [8] y))))) +(Rsh64x64 x y) -> (SARQ x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst y [64]))))) +(Rsh64x32 x y) -> (SARQ x (ORL y (NOTL (SBBLcarrymask (CMPLconst y [64]))))) +(Rsh64x16 x y) -> (SARQ x (ORW y (NOTL (SBBLcarrymask (CMPWconst y [64]))))) +(Rsh64x8 x y) -> (SARQ x (ORB y (NOTL (SBBLcarrymask (CMPBconst y [64]))))) + +(Rsh32x64 x y) -> (SARL x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst y [32]))))) +(Rsh32x32 x y) -> (SARL x (ORL y (NOTL (SBBLcarrymask (CMPLconst y [32]))))) +(Rsh32x16 x y) -> (SARL x (ORW y (NOTL (SBBLcarrymask (CMPWconst y [32]))))) +(Rsh32x8 x y) -> (SARL x (ORB y (NOTL (SBBLcarrymask (CMPBconst y [32]))))) + +(Rsh16x64 x y) -> (SARW x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst y [16]))))) +(Rsh16x32 x y) -> (SARW x (ORL y (NOTL (SBBLcarrymask (CMPLconst y [16]))))) +(Rsh16x16 x y) -> (SARW x (ORW y (NOTL (SBBLcarrymask (CMPWconst y [16]))))) +(Rsh16x8 x y) -> (SARW x (ORB y (NOTL (SBBLcarrymask (CMPBconst y [16]))))) + +(Rsh8x64 x y) -> (SARB x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst y [8]))))) +(Rsh8x32 x y) -> (SARB x (ORL y (NOTL (SBBLcarrymask (CMPLconst y [8]))))) +(Rsh8x16 x y) -> (SARB x (ORW y (NOTL (SBBLcarrymask (CMPWconst y [8]))))) +(Rsh8x8 x y) -> (SARB x (ORB y (NOTL (SBBLcarrymask (CMPBconst y [8]))))) (Less64 x y) -> (SETL (CMPQ x y)) (Less32 x y) -> (SETL (CMPL x y)) @@ -700,23 +700,168 @@ (EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no) (NE (InvertFlags cmp) yes no) -> (NE cmp yes no) -// get rid of overflow code for constant shifts -(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds64(d, c) -> (MOVQconst [-1]) -(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds64(d, c) -> (MOVQconst [0]) -(SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) && inBounds32(d, c) -> (MOVQconst [-1]) -(SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) && !inBounds32(d, c) -> (MOVQconst [0]) -(SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) && inBounds16(d, c) -> (MOVQconst [-1]) -(SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) && !inBounds16(d, c) -> (MOVQconst [0]) -(SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) && inBounds8(d, c) -> (MOVQconst [-1]) -(SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) && !inBounds8(d, c) -> (MOVQconst [0]) -(SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds64(d, c) -> (MOVLconst [-1]) -(SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds64(d, c) -> (MOVLconst [0]) -(SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) && inBounds32(d, c) -> (MOVLconst [-1]) -(SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) && !inBounds32(d, c) -> (MOVLconst [0]) -(SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) && inBounds16(d, c) -> (MOVLconst [-1]) -(SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) && !inBounds16(d, c) -> (MOVLconst [0]) -(SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) && inBounds8(d, c) -> (MOVLconst [-1]) -(SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) && !inBounds8(d, c) -> (MOVLconst [0]) +// Constant comparisons. +(CMPQconst (MOVQconst [x]) [y]) && x==y -> (FlagEQ) +(CMPQconst (MOVQconst [x]) [y]) && x (FlagLT_ULT) +(CMPQconst (MOVQconst [x]) [y]) && xuint64(y) -> (FlagLT_UGT) +(CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x) (FlagGT_ULT) +(CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT) +(CMPLconst (MOVLconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ) +(CMPLconst (MOVLconst [x]) [y]) && int32(x) (FlagLT_ULT) +(CMPLconst (MOVLconst [x]) [y]) && int32(x)uint32(y) -> (FlagLT_UGT) +(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x) (FlagGT_ULT) +(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT) +(CMPWconst (MOVWconst [x]) [y]) && int16(x)==int16(y) -> (FlagEQ) +(CMPWconst (MOVWconst [x]) [y]) && int16(x) (FlagLT_ULT) +(CMPWconst (MOVWconst [x]) [y]) && int16(x)uint16(y) -> (FlagLT_UGT) +(CMPWconst (MOVWconst [x]) [y]) && int16(x)>int16(y) && uint16(x) (FlagGT_ULT) +(CMPWconst (MOVWconst [x]) [y]) && int16(x)>int16(y) && uint16(x)>uint16(y) -> (FlagGT_UGT) +(CMPBconst (MOVBconst [x]) [y]) && int8(x)==int8(y) -> (FlagEQ) +(CMPBconst (MOVBconst [x]) [y]) && int8(x) (FlagLT_ULT) +(CMPBconst (MOVBconst [x]) [y]) && int8(x)uint8(y) -> (FlagLT_UGT) +(CMPBconst (MOVBconst [x]) [y]) && int8(x)>int8(y) && uint8(x) (FlagGT_ULT) +(CMPBconst (MOVBconst [x]) [y]) && int8(x)>int8(y) && uint8(x)>uint8(y) -> (FlagGT_UGT) + +// Other known comparisons. +(CMPQconst (ANDQconst _ [m]) [n]) && m+1==n && isPowerOfTwo(n) -> (FlagLT_ULT) +(CMPLconst (ANDLconst _ [m]) [n]) && int32(m)+1==int32(n) && isPowerOfTwo(int64(int32(n))) -> (FlagLT_ULT) +(CMPWconst (ANDWconst _ [m]) [n]) && int16(m)+1==int16(n) && isPowerOfTwo(int64(int16(n))) -> (FlagLT_ULT) +(CMPBconst (ANDBconst _ [m]) [n]) && int8(m)+1==int8(n) && isPowerOfTwo(int64(int8(n))) -> (FlagLT_ULT) +// TODO: DIVxU also. + +// Absorb flag constants into SBB ops. +(SBBQcarrymask (FlagEQ)) -> (MOVQconst [0]) +(SBBQcarrymask (FlagLT_ULT)) -> (MOVQconst [-1]) +(SBBQcarrymask (FlagLT_UGT)) -> (MOVQconst [0]) +(SBBQcarrymask (FlagGT_ULT)) -> (MOVQconst [-1]) +(SBBQcarrymask (FlagGT_UGT)) -> (MOVQconst [0]) +(SBBLcarrymask (FlagEQ)) -> (MOVLconst [0]) +(SBBLcarrymask (FlagLT_ULT)) -> (MOVLconst [-1]) +(SBBLcarrymask (FlagLT_UGT)) -> (MOVLconst [0]) +(SBBLcarrymask (FlagGT_ULT)) -> (MOVLconst [-1]) +(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) + +(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) + +(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) + +(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) + +(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) + +(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) + +(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) + +(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) + +(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) + +(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) + +// Absorb flag constants into SETxx ops. +(SETEQ (FlagEQ)) -> (MOVBconst [1]) +(SETEQ (FlagLT_ULT)) -> (MOVBconst [0]) +(SETEQ (FlagLT_UGT)) -> (MOVBconst [0]) +(SETEQ (FlagGT_ULT)) -> (MOVBconst [0]) +(SETEQ (FlagGT_UGT)) -> (MOVBconst [0]) + +(SETNE (FlagEQ)) -> (MOVBconst [0]) +(SETNE (FlagLT_ULT)) -> (MOVBconst [1]) +(SETNE (FlagLT_UGT)) -> (MOVBconst [1]) +(SETNE (FlagGT_ULT)) -> (MOVBconst [1]) +(SETNE (FlagGT_UGT)) -> (MOVBconst [1]) + +(SETL (FlagEQ)) -> (MOVBconst [0]) +(SETL (FlagLT_ULT)) -> (MOVBconst [1]) +(SETL (FlagLT_UGT)) -> (MOVBconst [1]) +(SETL (FlagGT_ULT)) -> (MOVBconst [0]) +(SETL (FlagGT_UGT)) -> (MOVBconst [0]) + +(SETLE (FlagEQ)) -> (MOVBconst [1]) +(SETLE (FlagLT_ULT)) -> (MOVBconst [1]) +(SETLE (FlagLT_UGT)) -> (MOVBconst [1]) +(SETLE (FlagGT_ULT)) -> (MOVBconst [0]) +(SETLE (FlagGT_UGT)) -> (MOVBconst [0]) + +(SETG (FlagEQ)) -> (MOVBconst [0]) +(SETG (FlagLT_ULT)) -> (MOVBconst [0]) +(SETG (FlagLT_UGT)) -> (MOVBconst [0]) +(SETG (FlagGT_ULT)) -> (MOVBconst [1]) +(SETG (FlagGT_UGT)) -> (MOVBconst [1]) + +(SETGE (FlagEQ)) -> (MOVBconst [1]) +(SETGE (FlagLT_ULT)) -> (MOVBconst [0]) +(SETGE (FlagLT_UGT)) -> (MOVBconst [0]) +(SETGE (FlagGT_ULT)) -> (MOVBconst [1]) +(SETGE (FlagGT_UGT)) -> (MOVBconst [1]) + +(SETB (FlagEQ)) -> (MOVBconst [0]) +(SETB (FlagLT_ULT)) -> (MOVBconst [1]) +(SETB (FlagLT_UGT)) -> (MOVBconst [0]) +(SETB (FlagGT_ULT)) -> (MOVBconst [1]) +(SETB (FlagGT_UGT)) -> (MOVBconst [0]) + +(SETBE (FlagEQ)) -> (MOVBconst [1]) +(SETBE (FlagLT_ULT)) -> (MOVBconst [1]) +(SETBE (FlagLT_UGT)) -> (MOVBconst [0]) +(SETBE (FlagGT_ULT)) -> (MOVBconst [1]) +(SETBE (FlagGT_UGT)) -> (MOVBconst [0]) + +(SETA (FlagEQ)) -> (MOVBconst [0]) +(SETA (FlagLT_ULT)) -> (MOVBconst [0]) +(SETA (FlagLT_UGT)) -> (MOVBconst [1]) +(SETA (FlagGT_ULT)) -> (MOVBconst [0]) +(SETA (FlagGT_UGT)) -> (MOVBconst [1]) + +(SETAE (FlagEQ)) -> (MOVBconst [1]) +(SETAE (FlagLT_ULT)) -> (MOVBconst [0]) +(SETAE (FlagLT_UGT)) -> (MOVBconst [1]) +(SETAE (FlagGT_ULT)) -> (MOVBconst [0]) +(SETAE (FlagGT_UGT)) -> (MOVBconst [1]) // Remove redundant *const ops (ADDQconst [0] x) -> x diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 461026bd7b..daee7336b0 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -472,6 +472,19 @@ func init() { // gets correctly ordered with respect to GC safepoints. // arg0=ptr/int arg1=mem, output=int/ptr {name: "MOVQconvert", reg: gp11nf, asm: "MOVQ"}, + + // Constant flag values. For any comparison, there are 5 possible + // outcomes: the three from the signed total order (<,==,>) and the + // three from the unsigned total order. The == cases overlap. + // Note: there's a sixth "unordered" outcome for floating-point + // comparisons, but we don't use such a beast yet. + // These ops are for temporary use by rewrite rules. They + // cannot appear in the generated assembly. + {name: "FlagEQ"}, // equal + {name: "FlagLT_ULT"}, // signed < and unsigned < + {name: "FlagLT_UGT"}, // signed < and unsigned > + {name: "FlagGT_UGT"}, // signed > and unsigned < + {name: "FlagGT_ULT"}, // signed > and unsigned > } var AMD64blocks = []blockData{ diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index bf3c15f78b..1b50eb642b 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -21,7 +21,7 @@ func checkLower(f *Func) { continue // lowered } switch v.Op { - case OpSP, OpSB, OpInitMem, OpArg, OpCopy, OpPhi, OpVarDef, OpVarKill: + case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill: continue // ok not to lower } s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString() diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index bbedf2fb64..2fd7f6b7a4 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -283,6 +283,11 @@ const ( OpAMD64LoweredGetClosurePtr OpAMD64LoweredNilCheck OpAMD64MOVQconvert + OpAMD64FlagEQ + OpAMD64FlagLT_ULT + OpAMD64FlagLT_UGT + OpAMD64FlagGT_UGT + OpAMD64FlagGT_ULT OpAdd8 OpAdd16 @@ -3232,6 +3237,26 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "FlagEQ", + reg: regInfo{}, + }, + { + name: "FlagLT_ULT", + reg: regInfo{}, + }, + { + name: "FlagLT_UGT", + reg: regInfo{}, + }, + { + name: "FlagGT_UGT", + reg: regInfo{}, + }, + { + name: "FlagGT_ULT", + reg: regInfo{}, + }, { name: "Add8", diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 5c2f3db4b2..3d682f0040 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -65,12 +65,20 @@ func rewriteValueAMD64(v *Value, config *Config) bool { return rewriteValueAMD64_OpAnd8(v, config) case OpAMD64CMPB: return rewriteValueAMD64_OpAMD64CMPB(v, config) + case OpAMD64CMPBconst: + return rewriteValueAMD64_OpAMD64CMPBconst(v, config) case OpAMD64CMPL: return rewriteValueAMD64_OpAMD64CMPL(v, config) + case OpAMD64CMPLconst: + return rewriteValueAMD64_OpAMD64CMPLconst(v, config) case OpAMD64CMPQ: return rewriteValueAMD64_OpAMD64CMPQ(v, config) + case OpAMD64CMPQconst: + return rewriteValueAMD64_OpAMD64CMPQconst(v, config) case OpAMD64CMPW: return rewriteValueAMD64_OpAMD64CMPW(v, config) + case OpAMD64CMPWconst: + return rewriteValueAMD64_OpAMD64CMPWconst(v, config) case OpClosureCall: return rewriteValueAMD64_OpClosureCall(v, config) case OpCom16: @@ -2167,6 +2175,137 @@ end25ab646f9eb8749ea58c8fbbb4bf6bcd: ; return false } +func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (CMPBconst (MOVBconst [x]) [y]) + // cond: int8(x)==int8(y) + // result: (FlagEQ) + { + if v.Args[0].Op != OpAMD64MOVBconst { + goto end1be300bd80b7d8cd0fa37e1907c75a77 + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(int8(x) == int8(y)) { + goto end1be300bd80b7d8cd0fa37e1907c75a77 + } + v.Op = OpAMD64FlagEQ + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end1be300bd80b7d8cd0fa37e1907c75a77 +end1be300bd80b7d8cd0fa37e1907c75a77: + ; + // match: (CMPBconst (MOVBconst [x]) [y]) + // cond: int8(x)uint8(y) + // result: (FlagLT_UGT) + { + if v.Args[0].Op != OpAMD64MOVBconst { + goto endbfa2ca974f69ec9ceb8a24ad6db45efb + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(int8(x) < int8(y) && uint8(x) > uint8(y)) { + goto endbfa2ca974f69ec9ceb8a24ad6db45efb + } + v.Op = OpAMD64FlagLT_UGT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto endbfa2ca974f69ec9ceb8a24ad6db45efb +endbfa2ca974f69ec9ceb8a24ad6db45efb: + ; + // match: (CMPBconst (MOVBconst [x]) [y]) + // cond: int8(x)>int8(y) && uint8(x) int8(y) && uint8(x) < uint8(y)) { + goto end68ac2e7dcb3704e235e1c292669320ed + } + v.Op = OpAMD64FlagGT_ULT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end68ac2e7dcb3704e235e1c292669320ed +end68ac2e7dcb3704e235e1c292669320ed: + ; + // match: (CMPBconst (MOVBconst [x]) [y]) + // cond: int8(x)>int8(y) && uint8(x)>uint8(y) + // result: (FlagGT_UGT) + { + if v.Args[0].Op != OpAMD64MOVBconst { + goto endac1c49c82fb6b76dd324042c4588973c + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(int8(x) > int8(y) && uint8(x) > uint8(y)) { + goto endac1c49c82fb6b76dd324042c4588973c + } + v.Op = OpAMD64FlagGT_UGT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto endac1c49c82fb6b76dd324042c4588973c +endac1c49c82fb6b76dd324042c4588973c: + ; + // match: (CMPBconst (ANDBconst _ [m]) [n]) + // cond: int8(m)+1==int8(n) && isPowerOfTwo(int64(int8(n))) + // result: (FlagLT_ULT) + { + if v.Args[0].Op != OpAMD64ANDBconst { + goto end82aa9d89330cb5dc58592048bfc16ebc + } + m := v.Args[0].AuxInt + n := v.AuxInt + if !(int8(m)+1 == int8(n) && isPowerOfTwo(int64(int8(n)))) { + goto end82aa9d89330cb5dc58592048bfc16ebc + } + v.Op = OpAMD64FlagLT_ULT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end82aa9d89330cb5dc58592048bfc16ebc +end82aa9d89330cb5dc58592048bfc16ebc: + ; + return false +} func rewriteValueAMD64_OpAMD64CMPL(v *Value, config *Config) bool { b := v.Block _ = b @@ -2215,6 +2354,137 @@ end7d89230086678ab4ed5cc96a3ae358d6: ; return false } +func rewriteValueAMD64_OpAMD64CMPLconst(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (CMPLconst (MOVLconst [x]) [y]) + // cond: int32(x)==int32(y) + // result: (FlagEQ) + { + if v.Args[0].Op != OpAMD64MOVLconst { + goto end7c53f3fc20f710e60f327bf63b4c8d4e + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(int32(x) == int32(y)) { + goto end7c53f3fc20f710e60f327bf63b4c8d4e + } + v.Op = OpAMD64FlagEQ + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end7c53f3fc20f710e60f327bf63b4c8d4e +end7c53f3fc20f710e60f327bf63b4c8d4e: + ; + // match: (CMPLconst (MOVLconst [x]) [y]) + // cond: int32(x)uint32(y) + // result: (FlagLT_UGT) + { + if v.Args[0].Op != OpAMD64MOVLconst { + goto end66603988bfeb71e410328b40425c3418 + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(int32(x) < int32(y) && uint32(x) > uint32(y)) { + goto end66603988bfeb71e410328b40425c3418 + } + v.Op = OpAMD64FlagLT_UGT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end66603988bfeb71e410328b40425c3418 +end66603988bfeb71e410328b40425c3418: + ; + // match: (CMPLconst (MOVLconst [x]) [y]) + // cond: int32(x)>int32(y) && uint32(x) int32(y) && uint32(x) < uint32(y)) { + goto endb1b0b14302e765637328dade12e1ce87 + } + v.Op = OpAMD64FlagGT_ULT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto endb1b0b14302e765637328dade12e1ce87 +endb1b0b14302e765637328dade12e1ce87: + ; + // match: (CMPLconst (MOVLconst [x]) [y]) + // cond: int32(x)>int32(y) && uint32(x)>uint32(y) + // result: (FlagGT_UGT) + { + if v.Args[0].Op != OpAMD64MOVLconst { + goto endc7b8e86e537d6e106e237023dc2c9a7b + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(int32(x) > int32(y) && uint32(x) > uint32(y)) { + goto endc7b8e86e537d6e106e237023dc2c9a7b + } + v.Op = OpAMD64FlagGT_UGT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto endc7b8e86e537d6e106e237023dc2c9a7b +endc7b8e86e537d6e106e237023dc2c9a7b: + ; + // match: (CMPLconst (ANDLconst _ [m]) [n]) + // cond: int32(m)+1==int32(n) && isPowerOfTwo(int64(int32(n))) + // result: (FlagLT_ULT) + { + if v.Args[0].Op != OpAMD64ANDLconst { + goto endf202b9830a1e45f3888f2598c762c702 + } + m := v.Args[0].AuxInt + n := v.AuxInt + if !(int32(m)+1 == int32(n) && isPowerOfTwo(int64(int32(n)))) { + goto endf202b9830a1e45f3888f2598c762c702 + } + v.Op = OpAMD64FlagLT_ULT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto endf202b9830a1e45f3888f2598c762c702 +endf202b9830a1e45f3888f2598c762c702: + ; + return false +} func rewriteValueAMD64_OpAMD64CMPQ(v *Value, config *Config) bool { b := v.Block _ = b @@ -2269,6 +2539,137 @@ end153e951c4d9890ee40bf6f189ff6280e: ; return false } +func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (CMPQconst (MOVQconst [x]) [y]) + // cond: x==y + // result: (FlagEQ) + { + if v.Args[0].Op != OpAMD64MOVQconst { + goto enda7a434ec055a51246d67ff14b48e455d + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(x == y) { + goto enda7a434ec055a51246d67ff14b48e455d + } + v.Op = OpAMD64FlagEQ + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto enda7a434ec055a51246d67ff14b48e455d +enda7a434ec055a51246d67ff14b48e455d: + ; + // match: (CMPQconst (MOVQconst [x]) [y]) + // cond: xuint64(y) + // result: (FlagLT_UGT) + { + if v.Args[0].Op != OpAMD64MOVQconst { + goto end38a2207ac4547f3f0cfb2bc48748e033 + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(x < y && uint64(x) > uint64(y)) { + goto end38a2207ac4547f3f0cfb2bc48748e033 + } + v.Op = OpAMD64FlagLT_UGT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end38a2207ac4547f3f0cfb2bc48748e033 +end38a2207ac4547f3f0cfb2bc48748e033: + ; + // match: (CMPQconst (MOVQconst [x]) [y]) + // cond: x>y && uint64(x) y && uint64(x) < uint64(y)) { + goto end0adaa13f82a881b97095d7a210b96f3c + } + v.Op = OpAMD64FlagGT_ULT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end0adaa13f82a881b97095d7a210b96f3c +end0adaa13f82a881b97095d7a210b96f3c: + ; + // match: (CMPQconst (MOVQconst [x]) [y]) + // cond: x>y && uint64(x)>uint64(y) + // result: (FlagGT_UGT) + { + if v.Args[0].Op != OpAMD64MOVQconst { + goto end1248b87e4a141c78bc8eff05d3fac70e + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(x > y && uint64(x) > uint64(y)) { + goto end1248b87e4a141c78bc8eff05d3fac70e + } + v.Op = OpAMD64FlagGT_UGT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end1248b87e4a141c78bc8eff05d3fac70e +end1248b87e4a141c78bc8eff05d3fac70e: + ; + // match: (CMPQconst (ANDQconst _ [m]) [n]) + // cond: m+1==n && isPowerOfTwo(n) + // result: (FlagLT_ULT) + { + if v.Args[0].Op != OpAMD64ANDQconst { + goto end934098fb12e383829b654938269abc12 + } + m := v.Args[0].AuxInt + n := v.AuxInt + if !(m+1 == n && isPowerOfTwo(n)) { + goto end934098fb12e383829b654938269abc12 + } + v.Op = OpAMD64FlagLT_ULT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end934098fb12e383829b654938269abc12 +end934098fb12e383829b654938269abc12: + ; + return false +} func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool { b := v.Block _ = b @@ -2317,6 +2718,137 @@ end3c52d0ae6e3d186bf131b41276c21889: ; return false } +func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (CMPWconst (MOVWconst [x]) [y]) + // cond: int16(x)==int16(y) + // result: (FlagEQ) + { + if v.Args[0].Op != OpAMD64MOVWconst { + goto endff7e81d2095a9997513cae77cd245b43 + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(int16(x) == int16(y)) { + goto endff7e81d2095a9997513cae77cd245b43 + } + v.Op = OpAMD64FlagEQ + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto endff7e81d2095a9997513cae77cd245b43 +endff7e81d2095a9997513cae77cd245b43: + ; + // match: (CMPWconst (MOVWconst [x]) [y]) + // cond: int16(x)uint16(y) + // result: (FlagLT_UGT) + { + if v.Args[0].Op != OpAMD64MOVWconst { + goto ended901a2a49e592c431e45ffc17ca213d + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(int16(x) < int16(y) && uint16(x) > uint16(y)) { + goto ended901a2a49e592c431e45ffc17ca213d + } + v.Op = OpAMD64FlagLT_UGT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto ended901a2a49e592c431e45ffc17ca213d +ended901a2a49e592c431e45ffc17ca213d: + ; + // match: (CMPWconst (MOVWconst [x]) [y]) + // cond: int16(x)>int16(y) && uint16(x) int16(y) && uint16(x) < uint16(y)) { + goto end66b1d55596a00cdc04ad83bfdeb6be8b + } + v.Op = OpAMD64FlagGT_ULT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end66b1d55596a00cdc04ad83bfdeb6be8b +end66b1d55596a00cdc04ad83bfdeb6be8b: + ; + // match: (CMPWconst (MOVWconst [x]) [y]) + // cond: int16(x)>int16(y) && uint16(x)>uint16(y) + // result: (FlagGT_UGT) + { + if v.Args[0].Op != OpAMD64MOVWconst { + goto end4493f5af38d242ebb4bc2f64055a0854 + } + x := v.Args[0].AuxInt + y := v.AuxInt + if !(int16(x) > int16(y) && uint16(x) > uint16(y)) { + goto end4493f5af38d242ebb4bc2f64055a0854 + } + v.Op = OpAMD64FlagGT_UGT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto end4493f5af38d242ebb4bc2f64055a0854 +end4493f5af38d242ebb4bc2f64055a0854: + ; + // match: (CMPWconst (ANDWconst _ [m]) [n]) + // cond: int16(m)+1==int16(n) && isPowerOfTwo(int64(int16(n))) + // result: (FlagLT_ULT) + { + if v.Args[0].Op != OpAMD64ANDWconst { + goto endfcea07d93ded49b0e02d5fa0059309a4 + } + m := v.Args[0].AuxInt + n := v.AuxInt + if !(int16(m)+1 == int16(n) && isPowerOfTwo(int64(int16(n)))) { + goto endfcea07d93ded49b0e02d5fa0059309a4 + } + v.Op = OpAMD64FlagLT_ULT + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + return true + } + goto endfcea07d93ded49b0e02d5fa0059309a4 +endfcea07d93ded49b0e02d5fa0059309a4: + ; + return false +} func rewriteValueAMD64_OpClosureCall(v *Value, config *Config) bool { b := v.Block _ = b @@ -4782,7 +5314,7 @@ func rewriteValueAMD64_OpLsh16x16(v *Value, config *Config) bool { _ = b // match: (Lsh16x16 x y) // cond: - // result: (ANDW (SHLW x y) (SBBLcarrymask (CMPWconst [16] y))) + // result: (ANDW (SHLW x y) (SBBLcarrymask (CMPWconst y [16]))) { t := v.Type x := v.Args[0] @@ -4799,15 +5331,15 @@ func rewriteValueAMD64_OpLsh16x16(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v2.AuxInt = 16 v2.AddArg(y) + v2.AuxInt = 16 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end7ffc4f31c526f7fcb2283215b458f589 -end7ffc4f31c526f7fcb2283215b458f589: + goto ende1a6e1781dd669bd74d66fc34c97218f +ende1a6e1781dd669bd74d66fc34c97218f: ; return false } @@ -4816,7 +5348,7 @@ func rewriteValueAMD64_OpLsh16x32(v *Value, config *Config) bool { _ = b // match: (Lsh16x32 x y) // cond: - // result: (ANDW (SHLW x y) (SBBLcarrymask (CMPLconst [16] y))) + // result: (ANDW (SHLW x y) (SBBLcarrymask (CMPLconst y [16]))) { t := v.Type x := v.Args[0] @@ -4833,15 +5365,15 @@ func rewriteValueAMD64_OpLsh16x32(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v2.AuxInt = 16 v2.AddArg(y) + v2.AuxInt = 16 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto enddcc0e751d315967423c99518c0cc065e -enddcc0e751d315967423c99518c0cc065e: + goto end711e661a5b6682f98e7993c2dfa72f45 +end711e661a5b6682f98e7993c2dfa72f45: ; return false } @@ -4850,7 +5382,7 @@ func rewriteValueAMD64_OpLsh16x64(v *Value, config *Config) bool { _ = b // match: (Lsh16x64 x y) // cond: - // result: (ANDW (SHLW x y) (SBBLcarrymask (CMPQconst [16] y))) + // result: (ANDW (SHLW x y) (SBBLcarrymask (CMPQconst y [16]))) { t := v.Type x := v.Args[0] @@ -4867,15 +5399,15 @@ func rewriteValueAMD64_OpLsh16x64(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v2.AuxInt = 16 v2.AddArg(y) + v2.AuxInt = 16 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto endf6368b59d046ca83050cd75fbe8715d2 -endf6368b59d046ca83050cd75fbe8715d2: + goto end4800d2b7d4f0e5acafcdf4e765941570 +end4800d2b7d4f0e5acafcdf4e765941570: ; return false } @@ -4884,7 +5416,7 @@ func rewriteValueAMD64_OpLsh16x8(v *Value, config *Config) bool { _ = b // match: (Lsh16x8 x y) // cond: - // result: (ANDW (SHLW x y) (SBBLcarrymask (CMPBconst [16] y))) + // result: (ANDW (SHLW x y) (SBBLcarrymask (CMPBconst y [16]))) { t := v.Type x := v.Args[0] @@ -4901,15 +5433,15 @@ func rewriteValueAMD64_OpLsh16x8(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v2.AuxInt = 16 v2.AddArg(y) + v2.AuxInt = 16 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end8730d944c8fb358001ba2d165755bdc4 -end8730d944c8fb358001ba2d165755bdc4: + goto endbe15f4a70f6c490f30f12a5db0f24ec4 +endbe15f4a70f6c490f30f12a5db0f24ec4: ; return false } @@ -4918,7 +5450,7 @@ func rewriteValueAMD64_OpLsh32x16(v *Value, config *Config) bool { _ = b // match: (Lsh32x16 x y) // cond: - // result: (ANDL (SHLL x y) (SBBLcarrymask (CMPWconst [32] y))) + // result: (ANDL (SHLL x y) (SBBLcarrymask (CMPWconst y [32]))) { t := v.Type x := v.Args[0] @@ -4935,15 +5467,15 @@ func rewriteValueAMD64_OpLsh32x16(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v2.AuxInt = 32 v2.AddArg(y) + v2.AuxInt = 32 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end5a43b7e9b0780e62f622bac0a68524d2 -end5a43b7e9b0780e62f622bac0a68524d2: + goto end6e9dfb6e850fc86393b2f6b1d509287f +end6e9dfb6e850fc86393b2f6b1d509287f: ; return false } @@ -4952,7 +5484,7 @@ func rewriteValueAMD64_OpLsh32x32(v *Value, config *Config) bool { _ = b // match: (Lsh32x32 x y) // cond: - // result: (ANDL (SHLL x y) (SBBLcarrymask (CMPLconst [32] y))) + // result: (ANDL (SHLL x y) (SBBLcarrymask (CMPLconst y [32]))) { t := v.Type x := v.Args[0] @@ -4969,15 +5501,15 @@ func rewriteValueAMD64_OpLsh32x32(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v2.AuxInt = 32 v2.AddArg(y) + v2.AuxInt = 32 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end9ce0ab6f9095c24ea46ca8fe2d7e5507 -end9ce0ab6f9095c24ea46ca8fe2d7e5507: + goto end9a4d057653a8fdad133aaf4a6b4f2b74 +end9a4d057653a8fdad133aaf4a6b4f2b74: ; return false } @@ -4986,7 +5518,7 @@ func rewriteValueAMD64_OpLsh32x64(v *Value, config *Config) bool { _ = b // match: (Lsh32x64 x y) // cond: - // result: (ANDL (SHLL x y) (SBBLcarrymask (CMPQconst [32] y))) + // result: (ANDL (SHLL x y) (SBBLcarrymask (CMPQconst y [32]))) { t := v.Type x := v.Args[0] @@ -5003,15 +5535,15 @@ func rewriteValueAMD64_OpLsh32x64(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v2.AuxInt = 32 v2.AddArg(y) + v2.AuxInt = 32 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end646b5471b709d5ea6c21f49a2815236f -end646b5471b709d5ea6c21f49a2815236f: + goto endae1486be93eb21ebac539419b5a109cb +endae1486be93eb21ebac539419b5a109cb: ; return false } @@ -5020,7 +5552,7 @@ func rewriteValueAMD64_OpLsh32x8(v *Value, config *Config) bool { _ = b // match: (Lsh32x8 x y) // cond: - // result: (ANDL (SHLL x y) (SBBLcarrymask (CMPBconst [32] y))) + // result: (ANDL (SHLL x y) (SBBLcarrymask (CMPBconst y [32]))) { t := v.Type x := v.Args[0] @@ -5037,15 +5569,15 @@ func rewriteValueAMD64_OpLsh32x8(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v2.AuxInt = 32 v2.AddArg(y) + v2.AuxInt = 32 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end96a677c71370e7c9179125f92cbdfda8 -end96a677c71370e7c9179125f92cbdfda8: + goto endede3d7bbbb6e7ac26b598b75409703f5 +endede3d7bbbb6e7ac26b598b75409703f5: ; return false } @@ -5054,7 +5586,7 @@ func rewriteValueAMD64_OpLsh64x16(v *Value, config *Config) bool { _ = b // match: (Lsh64x16 x y) // cond: - // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPWconst [64] y))) + // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPWconst y [64]))) { t := v.Type x := v.Args[0] @@ -5071,15 +5603,15 @@ func rewriteValueAMD64_OpLsh64x16(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v2.AuxInt = 64 v2.AddArg(y) + v2.AuxInt = 64 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end5f88f241d68d38954222d81559cd7f9f -end5f88f241d68d38954222d81559cd7f9f: + goto end4dc49d47e1079e618e480ee95c20df6d +end4dc49d47e1079e618e480ee95c20df6d: ; return false } @@ -5088,7 +5620,7 @@ func rewriteValueAMD64_OpLsh64x32(v *Value, config *Config) bool { _ = b // match: (Lsh64x32 x y) // cond: - // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPLconst [64] y))) + // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPLconst y [64]))) { t := v.Type x := v.Args[0] @@ -5105,15 +5637,15 @@ func rewriteValueAMD64_OpLsh64x32(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v2.AuxInt = 64 v2.AddArg(y) + v2.AuxInt = 64 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto endae1705f03ed3d6f43cd63b53496a910a -endae1705f03ed3d6f43cd63b53496a910a: + goto end52a5e8c44a38fe265cf0619081d1723b +end52a5e8c44a38fe265cf0619081d1723b: ; return false } @@ -5122,7 +5654,7 @@ func rewriteValueAMD64_OpLsh64x64(v *Value, config *Config) bool { _ = b // match: (Lsh64x64 x y) // cond: - // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPQconst [64] y))) + // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPQconst y [64]))) { t := v.Type x := v.Args[0] @@ -5139,15 +5671,15 @@ func rewriteValueAMD64_OpLsh64x64(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v2.AuxInt = 64 v2.AddArg(y) + v2.AuxInt = 64 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end1f6f5f510c5c68e4ce4a78643e6d85a1 -end1f6f5f510c5c68e4ce4a78643e6d85a1: + goto enda2931f1f1a64c3e0251febeb894666b0 +enda2931f1f1a64c3e0251febeb894666b0: ; return false } @@ -5156,7 +5688,7 @@ func rewriteValueAMD64_OpLsh64x8(v *Value, config *Config) bool { _ = b // match: (Lsh64x8 x y) // cond: - // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPBconst [64] y))) + // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPBconst y [64]))) { t := v.Type x := v.Args[0] @@ -5173,15 +5705,15 @@ func rewriteValueAMD64_OpLsh64x8(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v2.AuxInt = 64 v2.AddArg(y) + v2.AuxInt = 64 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto endd14f5c89e3496b0e425aa1ae366f4b53 -endd14f5c89e3496b0e425aa1ae366f4b53: + goto end8535fcd7c1fc28bbc53844b29ffbdb22 +end8535fcd7c1fc28bbc53844b29ffbdb22: ; return false } @@ -5190,7 +5722,7 @@ func rewriteValueAMD64_OpLsh8x16(v *Value, config *Config) bool { _ = b // match: (Lsh8x16 x y) // cond: - // result: (ANDB (SHLB x y) (SBBLcarrymask (CMPWconst [8] y))) + // result: (ANDB (SHLB x y) (SBBLcarrymask (CMPWconst y [8]))) { t := v.Type x := v.Args[0] @@ -5207,15 +5739,15 @@ func rewriteValueAMD64_OpLsh8x16(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v2.AuxInt = 8 v2.AddArg(y) + v2.AuxInt = 8 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end0926c3d8b9a0776ba5058946f6e1a4b7 -end0926c3d8b9a0776ba5058946f6e1a4b7: + goto endc4b0328ed4d6943ac1af3662b93ad8e2 +endc4b0328ed4d6943ac1af3662b93ad8e2: ; return false } @@ -5224,7 +5756,7 @@ func rewriteValueAMD64_OpLsh8x32(v *Value, config *Config) bool { _ = b // match: (Lsh8x32 x y) // cond: - // result: (ANDB (SHLB x y) (SBBLcarrymask (CMPLconst [8] y))) + // result: (ANDB (SHLB x y) (SBBLcarrymask (CMPLconst y [8]))) { t := v.Type x := v.Args[0] @@ -5241,15 +5773,15 @@ func rewriteValueAMD64_OpLsh8x32(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v2.AuxInt = 8 v2.AddArg(y) + v2.AuxInt = 8 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end5987682d77f197ef0fd95251f413535a -end5987682d77f197ef0fd95251f413535a: + goto end1e6cfcdb7439ccc73f4f59874f3559b2 +end1e6cfcdb7439ccc73f4f59874f3559b2: ; return false } @@ -5258,7 +5790,7 @@ func rewriteValueAMD64_OpLsh8x64(v *Value, config *Config) bool { _ = b // match: (Lsh8x64 x y) // cond: - // result: (ANDB (SHLB x y) (SBBLcarrymask (CMPQconst [8] y))) + // result: (ANDB (SHLB x y) (SBBLcarrymask (CMPQconst y [8]))) { t := v.Type x := v.Args[0] @@ -5275,15 +5807,15 @@ func rewriteValueAMD64_OpLsh8x64(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v2.AuxInt = 8 v2.AddArg(y) + v2.AuxInt = 8 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end9ffe6731d7d6514b8c0482f1645eee18 -end9ffe6731d7d6514b8c0482f1645eee18: + goto endf3ea2e740c7fd7ea2caa24357b0bf798 +endf3ea2e740c7fd7ea2caa24357b0bf798: ; return false } @@ -5292,7 +5824,7 @@ func rewriteValueAMD64_OpLsh8x8(v *Value, config *Config) bool { _ = b // match: (Lsh8x8 x y) // cond: - // result: (ANDB (SHLB x y) (SBBLcarrymask (CMPBconst [8] y))) + // result: (ANDB (SHLB x y) (SBBLcarrymask (CMPBconst y [8]))) { t := v.Type x := v.Args[0] @@ -5309,15 +5841,15 @@ func rewriteValueAMD64_OpLsh8x8(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v2.AuxInt = 8 v2.AddArg(y) + v2.AuxInt = 8 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end2b75242a31c3713ffbfdd8f0288b1c12 -end2b75242a31c3713ffbfdd8f0288b1c12: + goto end5d557e41670b7ac83d122eeb4029363d +end5d557e41670b7ac83d122eeb4029363d: ; return false } @@ -9516,7 +10048,7 @@ func rewriteValueAMD64_OpRsh16Ux16(v *Value, config *Config) bool { _ = b // match: (Rsh16Ux16 x y) // cond: - // result: (ANDW (SHRW x y) (SBBLcarrymask (CMPWconst [16] y))) + // result: (ANDW (SHRW x y) (SBBLcarrymask (CMPWconst y [16]))) { t := v.Type x := v.Args[0] @@ -9533,15 +10065,15 @@ func rewriteValueAMD64_OpRsh16Ux16(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v2.AuxInt = 16 v2.AddArg(y) + v2.AuxInt = 16 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end4d5e000764dcea396f2d86472c2af6eb -end4d5e000764dcea396f2d86472c2af6eb: + goto end291acf0117b46a676e5e1fe524459800 +end291acf0117b46a676e5e1fe524459800: ; return false } @@ -9550,7 +10082,7 @@ func rewriteValueAMD64_OpRsh16Ux32(v *Value, config *Config) bool { _ = b // match: (Rsh16Ux32 x y) // cond: - // result: (ANDW (SHRW x y) (SBBLcarrymask (CMPLconst [16] y))) + // result: (ANDW (SHRW x y) (SBBLcarrymask (CMPLconst y [16]))) { t := v.Type x := v.Args[0] @@ -9567,15 +10099,15 @@ func rewriteValueAMD64_OpRsh16Ux32(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v2.AuxInt = 16 v2.AddArg(y) + v2.AuxInt = 16 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end9ef4fe2ea4565865cd4b3aa9c7596c00 -end9ef4fe2ea4565865cd4b3aa9c7596c00: + goto endea051fe538151b144cd630ce63d35bf7 +endea051fe538151b144cd630ce63d35bf7: ; return false } @@ -9584,7 +10116,7 @@ func rewriteValueAMD64_OpRsh16Ux64(v *Value, config *Config) bool { _ = b // match: (Rsh16Ux64 x y) // cond: - // result: (ANDW (SHRW x y) (SBBLcarrymask (CMPQconst [16] y))) + // result: (ANDW (SHRW x y) (SBBLcarrymask (CMPQconst y [16]))) { t := v.Type x := v.Args[0] @@ -9601,15 +10133,15 @@ func rewriteValueAMD64_OpRsh16Ux64(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v2.AuxInt = 16 v2.AddArg(y) + v2.AuxInt = 16 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end48bc94b9a68aad454eaabc42b2e1d646 -end48bc94b9a68aad454eaabc42b2e1d646: + goto endd1a8f3aa91391fbd13c2dcd03a75283a +endd1a8f3aa91391fbd13c2dcd03a75283a: ; return false } @@ -9618,7 +10150,7 @@ func rewriteValueAMD64_OpRsh16Ux8(v *Value, config *Config) bool { _ = b // match: (Rsh16Ux8 x y) // cond: - // result: (ANDW (SHRW x y) (SBBLcarrymask (CMPBconst [16] y))) + // result: (ANDW (SHRW x y) (SBBLcarrymask (CMPBconst y [16]))) { t := v.Type x := v.Args[0] @@ -9635,15 +10167,15 @@ func rewriteValueAMD64_OpRsh16Ux8(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v2.AuxInt = 16 v2.AddArg(y) + v2.AuxInt = 16 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto ende98f618fa53b1f1d5d3f79781d5cb2cc -ende98f618fa53b1f1d5d3f79781d5cb2cc: + goto end9de32652fceccadca5a6206066bcbb10 +end9de32652fceccadca5a6206066bcbb10: ; return false } @@ -9652,7 +10184,7 @@ func rewriteValueAMD64_OpRsh16x16(v *Value, config *Config) bool { _ = b // match: (Rsh16x16 x y) // cond: - // result: (SARW x (ORW y (NOTL (SBBLcarrymask (CMPWconst [16] y))))) + // result: (SARW x (ORW y (NOTL (SBBLcarrymask (CMPWconst y [16]))))) { t := v.Type x := v.Args[0] @@ -9671,8 +10203,8 @@ func rewriteValueAMD64_OpRsh16x16(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v3.AuxInt = 16 v3.AddArg(y) + v3.AuxInt = 16 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -9680,8 +10212,8 @@ func rewriteValueAMD64_OpRsh16x16(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end1de548dcf8d7c7222c7a739809597526 -end1de548dcf8d7c7222c7a739809597526: + goto end71e3cf43426d4351f7fac15145ca6cd9 +end71e3cf43426d4351f7fac15145ca6cd9: ; return false } @@ -9690,7 +10222,7 @@ func rewriteValueAMD64_OpRsh16x32(v *Value, config *Config) bool { _ = b // match: (Rsh16x32 x y) // cond: - // result: (SARW x (ORL y (NOTL (SBBLcarrymask (CMPLconst [16] y))))) + // result: (SARW x (ORL y (NOTL (SBBLcarrymask (CMPLconst y [16]))))) { t := v.Type x := v.Args[0] @@ -9709,8 +10241,8 @@ func rewriteValueAMD64_OpRsh16x32(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v3.AuxInt = 16 v3.AddArg(y) + v3.AuxInt = 16 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -9718,8 +10250,8 @@ func rewriteValueAMD64_OpRsh16x32(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end74419e1036ea7e0c3a09d05b1eabad22 -end74419e1036ea7e0c3a09d05b1eabad22: + goto endfc3bf56711046c6b29b676b155af7c98 +endfc3bf56711046c6b29b676b155af7c98: ; return false } @@ -9728,7 +10260,7 @@ func rewriteValueAMD64_OpRsh16x64(v *Value, config *Config) bool { _ = b // match: (Rsh16x64 x y) // cond: - // result: (SARW x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst [16] y))))) + // result: (SARW x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst y [16]))))) { t := v.Type x := v.Args[0] @@ -9747,8 +10279,8 @@ func rewriteValueAMD64_OpRsh16x64(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v3.AuxInt = 16 v3.AddArg(y) + v3.AuxInt = 16 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -9756,8 +10288,8 @@ func rewriteValueAMD64_OpRsh16x64(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto ende35d1c2918196fae04fca22e80936bab -ende35d1c2918196fae04fca22e80936bab: + goto endeaf40562fd3394586c63adceca4d9559 +endeaf40562fd3394586c63adceca4d9559: ; return false } @@ -9766,7 +10298,7 @@ func rewriteValueAMD64_OpRsh16x8(v *Value, config *Config) bool { _ = b // match: (Rsh16x8 x y) // cond: - // result: (SARW x (ORB y (NOTL (SBBLcarrymask (CMPBconst [16] y))))) + // result: (SARW x (ORB y (NOTL (SBBLcarrymask (CMPBconst y [16]))))) { t := v.Type x := v.Args[0] @@ -9785,8 +10317,8 @@ func rewriteValueAMD64_OpRsh16x8(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v3.AuxInt = 16 v3.AddArg(y) + v3.AuxInt = 16 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -9794,8 +10326,8 @@ func rewriteValueAMD64_OpRsh16x8(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto endaa6a45afc4c6552c1a90a13160578fba -endaa6a45afc4c6552c1a90a13160578fba: + goto endc6cd0d3ecc71bc1830e01c07f274ff7b +endc6cd0d3ecc71bc1830e01c07f274ff7b: ; return false } @@ -9804,7 +10336,7 @@ func rewriteValueAMD64_OpRsh32Ux16(v *Value, config *Config) bool { _ = b // match: (Rsh32Ux16 x y) // cond: - // result: (ANDL (SHRL x y) (SBBLcarrymask (CMPWconst [32] y))) + // result: (ANDL (SHRL x y) (SBBLcarrymask (CMPWconst y [32]))) { t := v.Type x := v.Args[0] @@ -9821,15 +10353,15 @@ func rewriteValueAMD64_OpRsh32Ux16(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v2.AuxInt = 32 v2.AddArg(y) + v2.AuxInt = 32 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end74495683df77023ed619b4ecee98d94a -end74495683df77023ed619b4ecee98d94a: + goto end74ddc1443f6ffb1fe911f455ff982bfb +end74ddc1443f6ffb1fe911f455ff982bfb: ; return false } @@ -9838,7 +10370,7 @@ func rewriteValueAMD64_OpRsh32Ux32(v *Value, config *Config) bool { _ = b // match: (Rsh32Ux32 x y) // cond: - // result: (ANDL (SHRL x y) (SBBLcarrymask (CMPLconst [32] y))) + // result: (ANDL (SHRL x y) (SBBLcarrymask (CMPLconst y [32]))) { t := v.Type x := v.Args[0] @@ -9855,15 +10387,15 @@ func rewriteValueAMD64_OpRsh32Ux32(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v2.AuxInt = 32 v2.AddArg(y) + v2.AuxInt = 32 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto enda7d6c92ab2d7467102db447d6b431b28 -enda7d6c92ab2d7467102db447d6b431b28: + goto enda93828d8aa54be68080640034f94ed96 +enda93828d8aa54be68080640034f94ed96: ; return false } @@ -9872,7 +10404,7 @@ func rewriteValueAMD64_OpRsh32Ux64(v *Value, config *Config) bool { _ = b // match: (Rsh32Ux64 x y) // cond: - // result: (ANDL (SHRL x y) (SBBLcarrymask (CMPQconst [32] y))) + // result: (ANDL (SHRL x y) (SBBLcarrymask (CMPQconst y [32]))) { t := v.Type x := v.Args[0] @@ -9889,15 +10421,15 @@ func rewriteValueAMD64_OpRsh32Ux64(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v2.AuxInt = 32 v2.AddArg(y) + v2.AuxInt = 32 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end7c0829166a6219a15de2c0aa688a9bb3 -end7c0829166a6219a15de2c0aa688a9bb3: + goto end4f644f3f89ef842f4b0567fc385a58e3 +end4f644f3f89ef842f4b0567fc385a58e3: ; return false } @@ -9906,7 +10438,7 @@ func rewriteValueAMD64_OpRsh32Ux8(v *Value, config *Config) bool { _ = b // match: (Rsh32Ux8 x y) // cond: - // result: (ANDL (SHRL x y) (SBBLcarrymask (CMPBconst [32] y))) + // result: (ANDL (SHRL x y) (SBBLcarrymask (CMPBconst y [32]))) { t := v.Type x := v.Args[0] @@ -9923,15 +10455,15 @@ func rewriteValueAMD64_OpRsh32Ux8(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v2.AuxInt = 32 v2.AddArg(y) + v2.AuxInt = 32 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end221315aa8a09c9d8d2f243bf445446ea -end221315aa8a09c9d8d2f243bf445446ea: + goto end2a8f279bb4900b9bf3846378f36d7994 +end2a8f279bb4900b9bf3846378f36d7994: ; return false } @@ -9940,7 +10472,7 @@ func rewriteValueAMD64_OpRsh32x16(v *Value, config *Config) bool { _ = b // match: (Rsh32x16 x y) // cond: - // result: (SARL x (ORW y (NOTL (SBBLcarrymask (CMPWconst [32] y))))) + // result: (SARL x (ORW y (NOTL (SBBLcarrymask (CMPWconst y [32]))))) { t := v.Type x := v.Args[0] @@ -9959,8 +10491,8 @@ func rewriteValueAMD64_OpRsh32x16(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v3.AuxInt = 32 v3.AddArg(y) + v3.AuxInt = 32 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -9968,8 +10500,8 @@ func rewriteValueAMD64_OpRsh32x16(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end521b60d91648f07fe1be359f1cdbde29 -end521b60d91648f07fe1be359f1cdbde29: + goto end1b3a698a50c89c656aa6f7acd72e3f5e +end1b3a698a50c89c656aa6f7acd72e3f5e: ; return false } @@ -9978,7 +10510,7 @@ func rewriteValueAMD64_OpRsh32x32(v *Value, config *Config) bool { _ = b // match: (Rsh32x32 x y) // cond: - // result: (SARL x (ORL y (NOTL (SBBLcarrymask (CMPLconst [32] y))))) + // result: (SARL x (ORL y (NOTL (SBBLcarrymask (CMPLconst y [32]))))) { t := v.Type x := v.Args[0] @@ -9997,8 +10529,8 @@ func rewriteValueAMD64_OpRsh32x32(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v3.AuxInt = 32 v3.AddArg(y) + v3.AuxInt = 32 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10006,8 +10538,8 @@ func rewriteValueAMD64_OpRsh32x32(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end0fc03188975afbca2139e28c38b7cd17 -end0fc03188975afbca2139e28c38b7cd17: + goto endc6596de1c198fd84c4076aaa3c6486e5 +endc6596de1c198fd84c4076aaa3c6486e5: ; return false } @@ -10016,7 +10548,7 @@ func rewriteValueAMD64_OpRsh32x64(v *Value, config *Config) bool { _ = b // match: (Rsh32x64 x y) // cond: - // result: (SARL x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst [32] y))))) + // result: (SARL x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst y [32]))))) { t := v.Type x := v.Args[0] @@ -10035,8 +10567,8 @@ func rewriteValueAMD64_OpRsh32x64(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v3.AuxInt = 32 v3.AddArg(y) + v3.AuxInt = 32 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10044,8 +10576,8 @@ func rewriteValueAMD64_OpRsh32x64(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto endf36790cc7ba330d448b403a450a7c1d4 -endf36790cc7ba330d448b403a450a7c1d4: + goto enddda2e730607e2d13b18f1006316e0ebb +enddda2e730607e2d13b18f1006316e0ebb: ; return false } @@ -10054,7 +10586,7 @@ func rewriteValueAMD64_OpRsh32x8(v *Value, config *Config) bool { _ = b // match: (Rsh32x8 x y) // cond: - // result: (SARL x (ORB y (NOTL (SBBLcarrymask (CMPBconst [32] y))))) + // result: (SARL x (ORB y (NOTL (SBBLcarrymask (CMPBconst y [32]))))) { t := v.Type x := v.Args[0] @@ -10073,8 +10605,8 @@ func rewriteValueAMD64_OpRsh32x8(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v3.AuxInt = 32 v3.AddArg(y) + v3.AuxInt = 32 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10082,8 +10614,8 @@ func rewriteValueAMD64_OpRsh32x8(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end1242709228488be2f2505ead8eabb871 -end1242709228488be2f2505ead8eabb871: + goto endd9cb28c7e3a43fbd7a877750f34df72a +endd9cb28c7e3a43fbd7a877750f34df72a: ; return false } @@ -10092,7 +10624,7 @@ func rewriteValueAMD64_OpRsh64Ux16(v *Value, config *Config) bool { _ = b // match: (Rsh64Ux16 x y) // cond: - // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPWconst [64] y))) + // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPWconst y [64]))) { t := v.Type x := v.Args[0] @@ -10109,15 +10641,15 @@ func rewriteValueAMD64_OpRsh64Ux16(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v2.AuxInt = 64 v2.AddArg(y) + v2.AuxInt = 64 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end0bc6c36a57ebaf0b90fc418f976fe210 -end0bc6c36a57ebaf0b90fc418f976fe210: + goto end04dfdfa8a2dcffaf7ab1ee93a96b8677 +end04dfdfa8a2dcffaf7ab1ee93a96b8677: ; return false } @@ -10126,7 +10658,7 @@ func rewriteValueAMD64_OpRsh64Ux32(v *Value, config *Config) bool { _ = b // match: (Rsh64Ux32 x y) // cond: - // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPLconst [64] y))) + // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPLconst y [64]))) { t := v.Type x := v.Args[0] @@ -10143,15 +10675,15 @@ func rewriteValueAMD64_OpRsh64Ux32(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v2.AuxInt = 64 v2.AddArg(y) + v2.AuxInt = 64 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto ende3f52062f53bc3b5aa0461a644e38a1b -ende3f52062f53bc3b5aa0461a644e38a1b: + goto end2b2f03d14fb01fd490115a96d893ddb3 +end2b2f03d14fb01fd490115a96d893ddb3: ; return false } @@ -10160,7 +10692,7 @@ func rewriteValueAMD64_OpRsh64Ux64(v *Value, config *Config) bool { _ = b // match: (Rsh64Ux64 x y) // cond: - // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPQconst [64] y))) + // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPQconst y [64]))) { t := v.Type x := v.Args[0] @@ -10177,15 +10709,15 @@ func rewriteValueAMD64_OpRsh64Ux64(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v2.AuxInt = 64 v2.AddArg(y) + v2.AuxInt = 64 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto endaec410d0544f817303c79bad739c50fd -endaec410d0544f817303c79bad739c50fd: + goto endb24ca32f261a5c799d3e5a572f7cdcff +endb24ca32f261a5c799d3e5a572f7cdcff: ; return false } @@ -10194,7 +10726,7 @@ func rewriteValueAMD64_OpRsh64Ux8(v *Value, config *Config) bool { _ = b // match: (Rsh64Ux8 x y) // cond: - // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPBconst [64] y))) + // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPBconst y [64]))) { t := v.Type x := v.Args[0] @@ -10211,15 +10743,15 @@ func rewriteValueAMD64_OpRsh64Ux8(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v2.AuxInt = 64 v2.AddArg(y) + v2.AuxInt = 64 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end0318851ecb02e4ad8a2669034adf7862 -end0318851ecb02e4ad8a2669034adf7862: + goto end05a9a99310c9e282df012d5c48b58475 +end05a9a99310c9e282df012d5c48b58475: ; return false } @@ -10228,7 +10760,7 @@ func rewriteValueAMD64_OpRsh64x16(v *Value, config *Config) bool { _ = b // match: (Rsh64x16 x y) // cond: - // result: (SARQ x (ORW y (NOTL (SBBLcarrymask (CMPWconst [64] y))))) + // result: (SARQ x (ORW y (NOTL (SBBLcarrymask (CMPWconst y [64]))))) { t := v.Type x := v.Args[0] @@ -10247,8 +10779,8 @@ func rewriteValueAMD64_OpRsh64x16(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v3.AuxInt = 64 v3.AddArg(y) + v3.AuxInt = 64 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10256,8 +10788,8 @@ func rewriteValueAMD64_OpRsh64x16(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto endcf8bbca9a7a848fbebaaaa8b699cd086 -endcf8bbca9a7a848fbebaaaa8b699cd086: + goto endb97b88b7c4e431bd64ced5690f0e85c4 +endb97b88b7c4e431bd64ced5690f0e85c4: ; return false } @@ -10266,7 +10798,7 @@ func rewriteValueAMD64_OpRsh64x32(v *Value, config *Config) bool { _ = b // match: (Rsh64x32 x y) // cond: - // result: (SARQ x (ORL y (NOTL (SBBLcarrymask (CMPLconst [64] y))))) + // result: (SARQ x (ORL y (NOTL (SBBLcarrymask (CMPLconst y [64]))))) { t := v.Type x := v.Args[0] @@ -10285,8 +10817,8 @@ func rewriteValueAMD64_OpRsh64x32(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v3.AuxInt = 64 v3.AddArg(y) + v3.AuxInt = 64 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10294,8 +10826,8 @@ func rewriteValueAMD64_OpRsh64x32(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end7604d45b06ee69bf2feddf88b2f33cb6 -end7604d45b06ee69bf2feddf88b2f33cb6: + goto end95f72c0d315e6b1d70015b31a0f5f4ca +end95f72c0d315e6b1d70015b31a0f5f4ca: ; return false } @@ -10304,7 +10836,7 @@ func rewriteValueAMD64_OpRsh64x64(v *Value, config *Config) bool { _ = b // match: (Rsh64x64 x y) // cond: - // result: (SARQ x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst [64] y))))) + // result: (SARQ x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst y [64]))))) { t := v.Type x := v.Args[0] @@ -10323,8 +10855,8 @@ func rewriteValueAMD64_OpRsh64x64(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v3.AuxInt = 64 v3.AddArg(y) + v3.AuxInt = 64 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10332,8 +10864,8 @@ func rewriteValueAMD64_OpRsh64x64(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end12a3b44af604b515ad5530502336486f -end12a3b44af604b515ad5530502336486f: + goto enda8ddfaa8e519c0ed70c344a136ba9126 +enda8ddfaa8e519c0ed70c344a136ba9126: ; return false } @@ -10342,7 +10874,7 @@ func rewriteValueAMD64_OpRsh64x8(v *Value, config *Config) bool { _ = b // match: (Rsh64x8 x y) // cond: - // result: (SARQ x (ORB y (NOTL (SBBLcarrymask (CMPBconst [64] y))))) + // result: (SARQ x (ORB y (NOTL (SBBLcarrymask (CMPBconst y [64]))))) { t := v.Type x := v.Args[0] @@ -10361,8 +10893,8 @@ func rewriteValueAMD64_OpRsh64x8(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v3.AuxInt = 64 v3.AddArg(y) + v3.AuxInt = 64 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10370,8 +10902,8 @@ func rewriteValueAMD64_OpRsh64x8(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end4e2a83809914aad301a2f74d3c38fbbb -end4e2a83809914aad301a2f74d3c38fbbb: + goto end62f4adae0bbd0c4d5d6eb7d5eda6a5e3 +end62f4adae0bbd0c4d5d6eb7d5eda6a5e3: ; return false } @@ -10380,7 +10912,7 @@ func rewriteValueAMD64_OpRsh8Ux16(v *Value, config *Config) bool { _ = b // match: (Rsh8Ux16 x y) // cond: - // result: (ANDB (SHRB x y) (SBBLcarrymask (CMPWconst [8] y))) + // result: (ANDB (SHRB x y) (SBBLcarrymask (CMPWconst y [8]))) { t := v.Type x := v.Args[0] @@ -10397,15 +10929,15 @@ func rewriteValueAMD64_OpRsh8Ux16(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v2.AuxInt = 8 v2.AddArg(y) + v2.AuxInt = 8 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end724175a51b6efac60c6bb9d83d81215a -end724175a51b6efac60c6bb9d83d81215a: + goto endb791c8283bd486da9809520a7262d5ba +endb791c8283bd486da9809520a7262d5ba: ; return false } @@ -10414,7 +10946,7 @@ func rewriteValueAMD64_OpRsh8Ux32(v *Value, config *Config) bool { _ = b // match: (Rsh8Ux32 x y) // cond: - // result: (ANDB (SHRB x y) (SBBLcarrymask (CMPLconst [8] y))) + // result: (ANDB (SHRB x y) (SBBLcarrymask (CMPLconst y [8]))) { t := v.Type x := v.Args[0] @@ -10431,15 +10963,15 @@ func rewriteValueAMD64_OpRsh8Ux32(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v2.AuxInt = 8 v2.AddArg(y) + v2.AuxInt = 8 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end9d973431bed6682c1d557a535cf440ed -end9d973431bed6682c1d557a535cf440ed: + goto end5f360ab34942dc218e8f75624c86bbb2 +end5f360ab34942dc218e8f75624c86bbb2: ; return false } @@ -10448,7 +10980,7 @@ func rewriteValueAMD64_OpRsh8Ux64(v *Value, config *Config) bool { _ = b // match: (Rsh8Ux64 x y) // cond: - // result: (ANDB (SHRB x y) (SBBLcarrymask (CMPQconst [8] y))) + // result: (ANDB (SHRB x y) (SBBLcarrymask (CMPQconst y [8]))) { t := v.Type x := v.Args[0] @@ -10465,15 +10997,15 @@ func rewriteValueAMD64_OpRsh8Ux64(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v2.AuxInt = 8 v2.AddArg(y) + v2.AuxInt = 8 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto end9586937cdeb7946c337d46cd30cb9a11 -end9586937cdeb7946c337d46cd30cb9a11: + goto end7138df590f00234cd21cf02da8ed109e +end7138df590f00234cd21cf02da8ed109e: ; return false } @@ -10482,7 +11014,7 @@ func rewriteValueAMD64_OpRsh8Ux8(v *Value, config *Config) bool { _ = b // match: (Rsh8Ux8 x y) // cond: - // result: (ANDB (SHRB x y) (SBBLcarrymask (CMPBconst [8] y))) + // result: (ANDB (SHRB x y) (SBBLcarrymask (CMPBconst y [8]))) { t := v.Type x := v.Args[0] @@ -10499,15 +11031,15 @@ func rewriteValueAMD64_OpRsh8Ux8(v *Value, config *Config) bool { v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v1.Type = t v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v2.AuxInt = 8 v2.AddArg(y) + v2.AuxInt = 8 v2.Type = TypeFlags v1.AddArg(v2) v.AddArg(v1) return true } - goto endc5a55ef63d86e6b8d4d366a947bf563d -endc5a55ef63d86e6b8d4d366a947bf563d: + goto end3aab873310bf7b2f3f90705fbd082b93 +end3aab873310bf7b2f3f90705fbd082b93: ; return false } @@ -10516,7 +11048,7 @@ func rewriteValueAMD64_OpRsh8x16(v *Value, config *Config) bool { _ = b // match: (Rsh8x16 x y) // cond: - // result: (SARB x (ORW y (NOTL (SBBLcarrymask (CMPWconst [8] y))))) + // result: (SARB x (ORW y (NOTL (SBBLcarrymask (CMPWconst y [8]))))) { t := v.Type x := v.Args[0] @@ -10535,8 +11067,8 @@ func rewriteValueAMD64_OpRsh8x16(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeInvalid) - v3.AuxInt = 8 v3.AddArg(y) + v3.AuxInt = 8 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10544,8 +11076,8 @@ func rewriteValueAMD64_OpRsh8x16(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto endfa967d6583c1bb9644514c2013b919f8 -endfa967d6583c1bb9644514c2013b919f8: + goto ende275bad06ac788b484b038f1bb3afc8d +ende275bad06ac788b484b038f1bb3afc8d: ; return false } @@ -10554,7 +11086,7 @@ func rewriteValueAMD64_OpRsh8x32(v *Value, config *Config) bool { _ = b // match: (Rsh8x32 x y) // cond: - // result: (SARB x (ORL y (NOTL (SBBLcarrymask (CMPLconst [8] y))))) + // result: (SARB x (ORL y (NOTL (SBBLcarrymask (CMPLconst y [8]))))) { t := v.Type x := v.Args[0] @@ -10573,8 +11105,8 @@ func rewriteValueAMD64_OpRsh8x32(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeInvalid) - v3.AuxInt = 8 v3.AddArg(y) + v3.AuxInt = 8 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10582,8 +11114,8 @@ func rewriteValueAMD64_OpRsh8x32(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto ende5a630810624a1bd3677618c2cbc8619 -ende5a630810624a1bd3677618c2cbc8619: + goto end00833cba5173dc390952b6c4644af376 +end00833cba5173dc390952b6c4644af376: ; return false } @@ -10592,7 +11124,7 @@ func rewriteValueAMD64_OpRsh8x64(v *Value, config *Config) bool { _ = b // match: (Rsh8x64 x y) // cond: - // result: (SARB x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst [8] y))))) + // result: (SARB x (ORQ y (NOTQ (SBBQcarrymask (CMPQconst y [8]))))) { t := v.Type x := v.Args[0] @@ -10611,8 +11143,8 @@ func rewriteValueAMD64_OpRsh8x64(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) - v3.AuxInt = 8 v3.AddArg(y) + v3.AuxInt = 8 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10620,8 +11152,8 @@ func rewriteValueAMD64_OpRsh8x64(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end23c55e49d8bc44afc680b2a4eade5af6 -end23c55e49d8bc44afc680b2a4eade5af6: + goto end039cf4d3a939b89164b058d09f532fb5 +end039cf4d3a939b89164b058d09f532fb5: ; return false } @@ -10630,7 +11162,7 @@ func rewriteValueAMD64_OpRsh8x8(v *Value, config *Config) bool { _ = b // match: (Rsh8x8 x y) // cond: - // result: (SARB x (ORB y (NOTL (SBBLcarrymask (CMPBconst [8] y))))) + // result: (SARB x (ORB y (NOTL (SBBLcarrymask (CMPBconst y [8]))))) { t := v.Type x := v.Args[0] @@ -10649,8 +11181,8 @@ func rewriteValueAMD64_OpRsh8x8(v *Value, config *Config) bool { v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, TypeInvalid) v2.Type = y.Type v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeInvalid) - v3.AuxInt = 8 v3.AddArg(y) + v3.AuxInt = 8 v3.Type = TypeFlags v2.AddArg(v3) v1.AddArg(v2) @@ -10658,8 +11190,8 @@ func rewriteValueAMD64_OpRsh8x8(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto enddab0c33c56e2e9434b880e1718621979 -enddab0c33c56e2e9434b880e1718621979: + goto end6453a48c573d0dc7c8b0163a266c6218 +end6453a48c573d0dc7c8b0163a266c6218: ; return false } @@ -10862,45 +11394,12 @@ endca23e80dba22ab574f843c7a4cef24ab: func rewriteValueAMD64_OpAMD64SBBLcarrymask(v *Value, config *Config) bool { b := v.Block _ = b - // match: (SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) - // cond: inBounds64(d, c) - // result: (MOVLconst [-1]) - { - if v.Args[0].Op != OpAMD64CMPQconst { - goto end490c8a7039bab41e90e564fbb8500233 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto end490c8a7039bab41e90e564fbb8500233 - } - d := v.Args[0].Args[0].AuxInt - if !(inBounds64(d, c)) { - goto end490c8a7039bab41e90e564fbb8500233 - } - v.Op = OpAMD64MOVLconst - v.AuxInt = 0 - v.Aux = nil - v.resetArgs() - v.AuxInt = -1 - return true - } - goto end490c8a7039bab41e90e564fbb8500233 -end490c8a7039bab41e90e564fbb8500233: - ; - // match: (SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) - // cond: !inBounds64(d, c) + // match: (SBBLcarrymask (FlagEQ)) + // cond: // result: (MOVLconst [0]) { - if v.Args[0].Op != OpAMD64CMPQconst { - goto end95e703eabe71d831b7a3d2f9fabe7de9 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto end95e703eabe71d831b7a3d2f9fabe7de9 - } - d := v.Args[0].Args[0].AuxInt - if !(!inBounds64(d, c)) { - goto end95e703eabe71d831b7a3d2f9fabe7de9 + if v.Args[0].Op != OpAMD64FlagEQ { + goto end49bb4f49864044e2cd06c9c8e2c05f12 } v.Op = OpAMD64MOVLconst v.AuxInt = 0 @@ -10909,23 +11408,15 @@ end490c8a7039bab41e90e564fbb8500233: v.AuxInt = 0 return true } - goto end95e703eabe71d831b7a3d2f9fabe7de9 -end95e703eabe71d831b7a3d2f9fabe7de9: + goto end49bb4f49864044e2cd06c9c8e2c05f12 +end49bb4f49864044e2cd06c9c8e2c05f12: ; - // match: (SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) - // cond: inBounds32(d, c) + // match: (SBBLcarrymask (FlagLT_ULT)) + // cond: // result: (MOVLconst [-1]) { - if v.Args[0].Op != OpAMD64CMPLconst { - goto end00c0a561340b0172c9a21f63648b86e2 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVLconst { - goto end00c0a561340b0172c9a21f63648b86e2 - } - d := v.Args[0].Args[0].AuxInt - if !(inBounds32(d, c)) { - goto end00c0a561340b0172c9a21f63648b86e2 + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto ende534d42c655e8b95b051e7ec44d4fdf9 } v.Op = OpAMD64MOVLconst v.AuxInt = 0 @@ -10934,23 +11425,15 @@ end95e703eabe71d831b7a3d2f9fabe7de9: v.AuxInt = -1 return true } - goto end00c0a561340b0172c9a21f63648b86e2 -end00c0a561340b0172c9a21f63648b86e2: + goto ende534d42c655e8b95b051e7ec44d4fdf9 +ende534d42c655e8b95b051e7ec44d4fdf9: ; - // match: (SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) - // cond: !inBounds32(d, c) + // match: (SBBLcarrymask (FlagLT_UGT)) + // cond: // result: (MOVLconst [0]) { - if v.Args[0].Op != OpAMD64CMPLconst { - goto enda73c8bf14f7b45dd97c6a006e317b0b8 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVLconst { - goto enda73c8bf14f7b45dd97c6a006e317b0b8 - } - d := v.Args[0].Args[0].AuxInt - if !(!inBounds32(d, c)) { - goto enda73c8bf14f7b45dd97c6a006e317b0b8 + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto end212628069f217f165eaf49dcfd9e8c76 } v.Op = OpAMD64MOVLconst v.AuxInt = 0 @@ -10959,23 +11442,15 @@ end00c0a561340b0172c9a21f63648b86e2: v.AuxInt = 0 return true } - goto enda73c8bf14f7b45dd97c6a006e317b0b8 -enda73c8bf14f7b45dd97c6a006e317b0b8: + goto end212628069f217f165eaf49dcfd9e8c76 +end212628069f217f165eaf49dcfd9e8c76: ; - // match: (SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) - // cond: inBounds16(d, c) + // match: (SBBLcarrymask (FlagGT_ULT)) + // cond: // result: (MOVLconst [-1]) { - if v.Args[0].Op != OpAMD64CMPWconst { - goto endb94dc44cd77f66ed3bf3742874b666fc - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVWconst { - goto endb94dc44cd77f66ed3bf3742874b666fc - } - d := v.Args[0].Args[0].AuxInt - if !(inBounds16(d, c)) { - goto endb94dc44cd77f66ed3bf3742874b666fc + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto end4df0bf7db9772a6011ed89bd3ce95f1d } v.Op = OpAMD64MOVLconst v.AuxInt = 0 @@ -10984,23 +11459,15 @@ enda73c8bf14f7b45dd97c6a006e317b0b8: v.AuxInt = -1 return true } - goto endb94dc44cd77f66ed3bf3742874b666fc -endb94dc44cd77f66ed3bf3742874b666fc: + goto end4df0bf7db9772a6011ed89bd3ce95f1d +end4df0bf7db9772a6011ed89bd3ce95f1d: ; - // match: (SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) - // cond: !inBounds16(d, c) + // match: (SBBLcarrymask (FlagGT_UGT)) + // cond: // result: (MOVLconst [0]) { - if v.Args[0].Op != OpAMD64CMPWconst { - goto end7a02def6194822f7ab937d78088504d2 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVWconst { - goto end7a02def6194822f7ab937d78088504d2 - } - d := v.Args[0].Args[0].AuxInt - if !(!inBounds16(d, c)) { - goto end7a02def6194822f7ab937d78088504d2 + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto end4d9d1509d6d260332f0a345332ce89e2 } v.Op = OpAMD64MOVLconst v.AuxInt = 0 @@ -11009,78 +11476,37 @@ endb94dc44cd77f66ed3bf3742874b666fc: v.AuxInt = 0 return true } - goto end7a02def6194822f7ab937d78088504d2 -end7a02def6194822f7ab937d78088504d2: - ; - // match: (SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) - // cond: inBounds8(d, c) - // result: (MOVLconst [-1]) - { - if v.Args[0].Op != OpAMD64CMPBconst { - goto end79c8e4a20761df731521e6cd956c4245 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVBconst { - goto end79c8e4a20761df731521e6cd956c4245 - } - d := v.Args[0].Args[0].AuxInt - if !(inBounds8(d, c)) { - goto end79c8e4a20761df731521e6cd956c4245 - } - v.Op = OpAMD64MOVLconst - v.AuxInt = 0 - v.Aux = nil - v.resetArgs() - v.AuxInt = -1 - return true - } - goto end79c8e4a20761df731521e6cd956c4245 -end79c8e4a20761df731521e6cd956c4245: + goto end4d9d1509d6d260332f0a345332ce89e2 +end4d9d1509d6d260332f0a345332ce89e2: ; - // match: (SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) - // cond: !inBounds8(d, c) - // result: (MOVLconst [0]) + return false +} +func rewriteValueAMD64_OpAMD64SBBQcarrymask(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (SBBQcarrymask (FlagEQ)) + // cond: + // result: (MOVQconst [0]) { - if v.Args[0].Op != OpAMD64CMPBconst { - goto end95b5b21dd7756ae41575759a1eff2bea + if v.Args[0].Op != OpAMD64FlagEQ { + goto end6b4a6f105b53df8063846a528bab0abb } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVBconst { - goto end95b5b21dd7756ae41575759a1eff2bea - } - d := v.Args[0].Args[0].AuxInt - if !(!inBounds8(d, c)) { - goto end95b5b21dd7756ae41575759a1eff2bea - } - v.Op = OpAMD64MOVLconst + v.Op = OpAMD64MOVQconst v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = 0 return true } - goto end95b5b21dd7756ae41575759a1eff2bea -end95b5b21dd7756ae41575759a1eff2bea: + goto end6b4a6f105b53df8063846a528bab0abb +end6b4a6f105b53df8063846a528bab0abb: ; - return false -} -func rewriteValueAMD64_OpAMD64SBBQcarrymask(v *Value, config *Config) bool { - b := v.Block - _ = b - // match: (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) - // cond: inBounds64(d, c) + // match: (SBBQcarrymask (FlagLT_ULT)) + // cond: // result: (MOVQconst [-1]) { - if v.Args[0].Op != OpAMD64CMPQconst { - goto end0c26df98feb38f149eca12f33c15de1b - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto end0c26df98feb38f149eca12f33c15de1b - } - d := v.Args[0].Args[0].AuxInt - if !(inBounds64(d, c)) { - goto end0c26df98feb38f149eca12f33c15de1b + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto endbfed0a1a93d6d8570f304898550d9558 } v.Op = OpAMD64MOVQconst v.AuxInt = 0 @@ -11089,23 +11515,15 @@ func rewriteValueAMD64_OpAMD64SBBQcarrymask(v *Value, config *Config) bool { v.AuxInt = -1 return true } - goto end0c26df98feb38f149eca12f33c15de1b -end0c26df98feb38f149eca12f33c15de1b: + goto endbfed0a1a93d6d8570f304898550d9558 +endbfed0a1a93d6d8570f304898550d9558: ; - // match: (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) - // cond: !inBounds64(d, c) + // match: (SBBQcarrymask (FlagLT_UGT)) + // cond: // result: (MOVQconst [0]) { - if v.Args[0].Op != OpAMD64CMPQconst { - goto end8965aa1e1153e5ecd123bbb31a618570 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto end8965aa1e1153e5ecd123bbb31a618570 - } - d := v.Args[0].Args[0].AuxInt - if !(!inBounds64(d, c)) { - goto end8965aa1e1153e5ecd123bbb31a618570 + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto end8edf88458891c571a6ea6e52e0267b40 } v.Op = OpAMD64MOVQconst v.AuxInt = 0 @@ -11114,23 +11532,15 @@ end0c26df98feb38f149eca12f33c15de1b: v.AuxInt = 0 return true } - goto end8965aa1e1153e5ecd123bbb31a618570 -end8965aa1e1153e5ecd123bbb31a618570: + goto end8edf88458891c571a6ea6e52e0267b40 +end8edf88458891c571a6ea6e52e0267b40: ; - // match: (SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) - // cond: inBounds32(d, c) + // match: (SBBQcarrymask (FlagGT_ULT)) + // cond: // result: (MOVQconst [-1]) { - if v.Args[0].Op != OpAMD64CMPLconst { - goto end8772ede6098981a61af0f478841d7d54 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVLconst { - goto end8772ede6098981a61af0f478841d7d54 - } - d := v.Args[0].Args[0].AuxInt - if !(inBounds32(d, c)) { - goto end8772ede6098981a61af0f478841d7d54 + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto end4663340439f2fa7a666e81f0ebc68436 } v.Op = OpAMD64MOVQconst v.AuxInt = 0 @@ -11139,23 +11549,15 @@ end8965aa1e1153e5ecd123bbb31a618570: v.AuxInt = -1 return true } - goto end8772ede6098981a61af0f478841d7d54 -end8772ede6098981a61af0f478841d7d54: + goto end4663340439f2fa7a666e81f0ebc68436 +end4663340439f2fa7a666e81f0ebc68436: ; - // match: (SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) - // cond: !inBounds32(d, c) + // match: (SBBQcarrymask (FlagGT_UGT)) + // cond: // result: (MOVQconst [0]) { - if v.Args[0].Op != OpAMD64CMPLconst { - goto end2d535e90075ee777fc616e6b9847a384 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVLconst { - goto end2d535e90075ee777fc616e6b9847a384 - } - d := v.Args[0].Args[0].AuxInt - if !(!inBounds32(d, c)) { - goto end2d535e90075ee777fc616e6b9847a384 + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto end7262400b0380a163bd65b88e0c3db985 } v.Op = OpAMD64MOVQconst v.AuxInt = 0 @@ -11164,131 +11566,116 @@ end8772ede6098981a61af0f478841d7d54: v.AuxInt = 0 return true } - goto end2d535e90075ee777fc616e6b9847a384 -end2d535e90075ee777fc616e6b9847a384: + goto end7262400b0380a163bd65b88e0c3db985 +end7262400b0380a163bd65b88e0c3db985: ; - // match: (SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) - // cond: inBounds16(d, c) - // result: (MOVQconst [-1]) + return false +} +func rewriteValueAMD64_OpAMD64SETA(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (SETA (InvertFlags x)) + // cond: + // result: (SETB x) { - if v.Args[0].Op != OpAMD64CMPWconst { - goto end3103c51e14b4fc894b4170f16f37eebc - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVWconst { - goto end3103c51e14b4fc894b4170f16f37eebc - } - d := v.Args[0].Args[0].AuxInt - if !(inBounds16(d, c)) { - goto end3103c51e14b4fc894b4170f16f37eebc + if v.Args[0].Op != OpAMD64InvertFlags { + goto enda4ac36e94fc279d762b5a6c7c6cc665d } - v.Op = OpAMD64MOVQconst + x := v.Args[0].Args[0] + v.Op = OpAMD64SETB v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AuxInt = -1 + v.AddArg(x) return true } - goto end3103c51e14b4fc894b4170f16f37eebc -end3103c51e14b4fc894b4170f16f37eebc: + goto enda4ac36e94fc279d762b5a6c7c6cc665d +enda4ac36e94fc279d762b5a6c7c6cc665d: ; - // match: (SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) - // cond: !inBounds16(d, c) - // result: (MOVQconst [0]) + // match: (SETA (FlagEQ)) + // cond: + // result: (MOVBconst [0]) { - if v.Args[0].Op != OpAMD64CMPWconst { - goto enddae2191a59cfef5efb04ebab9354745c - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVWconst { - goto enddae2191a59cfef5efb04ebab9354745c + if v.Args[0].Op != OpAMD64FlagEQ { + goto end1521942d06b7f0caba92883aee0bb90e } - d := v.Args[0].Args[0].AuxInt - if !(!inBounds16(d, c)) { - goto enddae2191a59cfef5efb04ebab9354745c - } - v.Op = OpAMD64MOVQconst + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = 0 return true } - goto enddae2191a59cfef5efb04ebab9354745c -enddae2191a59cfef5efb04ebab9354745c: + goto end1521942d06b7f0caba92883aee0bb90e +end1521942d06b7f0caba92883aee0bb90e: ; - // match: (SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) - // cond: inBounds8(d, c) - // result: (MOVQconst [-1]) + // match: (SETA (FlagLT_ULT)) + // cond: + // result: (MOVBconst [0]) { - if v.Args[0].Op != OpAMD64CMPBconst { - goto end72e088325ca005b0251b1ee82da3c5d9 - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVBconst { - goto end72e088325ca005b0251b1ee82da3c5d9 + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto endf79d69b18a140d5c6669216ad65f60f0 } - d := v.Args[0].Args[0].AuxInt - if !(inBounds8(d, c)) { - goto end72e088325ca005b0251b1ee82da3c5d9 - } - v.Op = OpAMD64MOVQconst + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AuxInt = -1 + v.AuxInt = 0 return true } - goto end72e088325ca005b0251b1ee82da3c5d9 -end72e088325ca005b0251b1ee82da3c5d9: + goto endf79d69b18a140d5c6669216ad65f60f0 +endf79d69b18a140d5c6669216ad65f60f0: ; - // match: (SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) - // cond: !inBounds8(d, c) - // result: (MOVQconst [0]) + // match: (SETA (FlagLT_UGT)) + // cond: + // result: (MOVBconst [1]) { - if v.Args[0].Op != OpAMD64CMPBconst { - goto endcb388100f5b933aa94095096d2bb425e - } - c := v.Args[0].AuxInt - if v.Args[0].Args[0].Op != OpAMD64MOVBconst { - goto endcb388100f5b933aa94095096d2bb425e + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto end272c1e5fca714e319fb1c335023826db } - d := v.Args[0].Args[0].AuxInt - if !(!inBounds8(d, c)) { - goto endcb388100f5b933aa94095096d2bb425e + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end272c1e5fca714e319fb1c335023826db +end272c1e5fca714e319fb1c335023826db: + ; + // match: (SETA (FlagGT_ULT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto ende0cf0104de1315266d93ded9a092302c } - v.Op = OpAMD64MOVQconst + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = 0 return true } - goto endcb388100f5b933aa94095096d2bb425e -endcb388100f5b933aa94095096d2bb425e: + goto ende0cf0104de1315266d93ded9a092302c +ende0cf0104de1315266d93ded9a092302c: ; - return false -} -func rewriteValueAMD64_OpAMD64SETA(v *Value, config *Config) bool { - b := v.Block - _ = b - // match: (SETA (InvertFlags x)) + // match: (SETA (FlagGT_UGT)) // cond: - // result: (SETB x) + // result: (MOVBconst [1]) { - if v.Args[0].Op != OpAMD64InvertFlags { - goto enda4ac36e94fc279d762b5a6c7c6cc665d + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto end85507f7549319577f9994826ee379f3b } - x := v.Args[0].Args[0] - v.Op = OpAMD64SETB + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AddArg(x) + v.AuxInt = 1 return true } - goto enda4ac36e94fc279d762b5a6c7c6cc665d -enda4ac36e94fc279d762b5a6c7c6cc665d: + goto end85507f7549319577f9994826ee379f3b +end85507f7549319577f9994826ee379f3b: ; return false } @@ -11313,19 +11700,104 @@ func rewriteValueAMD64_OpAMD64SETAE(v *Value, config *Config) bool { goto end0468f5be6caf682fdea6b91d6648991e end0468f5be6caf682fdea6b91d6648991e: ; - return false -} -func rewriteValueAMD64_OpAMD64SETB(v *Value, config *Config) bool { - b := v.Block - _ = b - // match: (SETB (InvertFlags x)) + // match: (SETAE (FlagEQ)) // cond: - // result: (SETA x) + // result: (MOVBconst [1]) { - if v.Args[0].Op != OpAMD64InvertFlags { - goto endc9eba7aa1e54a228570d2f5cc96f3565 + if v.Args[0].Op != OpAMD64FlagEQ { + goto endc6396df3825db703a99be0e624c6396f } - x := v.Args[0].Args[0] + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto endc6396df3825db703a99be0e624c6396f +endc6396df3825db703a99be0e624c6396f: + ; + // match: (SETAE (FlagLT_ULT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto end2392c77d6746969c65a422c68ad193bc + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end2392c77d6746969c65a422c68ad193bc +end2392c77d6746969c65a422c68ad193bc: + ; + // match: (SETAE (FlagLT_UGT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto end081f3b2b98d3a990739d2a5562d4f254 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end081f3b2b98d3a990739d2a5562d4f254 +end081f3b2b98d3a990739d2a5562d4f254: + ; + // match: (SETAE (FlagGT_ULT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto end47a6cc5efdd00e349c5e23be3624d719 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end47a6cc5efdd00e349c5e23be3624d719 +end47a6cc5efdd00e349c5e23be3624d719: + ; + // match: (SETAE (FlagGT_UGT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto endd47bb51035b00c560b5347b3be19e20e + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto endd47bb51035b00c560b5347b3be19e20e +endd47bb51035b00c560b5347b3be19e20e: + ; + return false +} +func rewriteValueAMD64_OpAMD64SETB(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (SETB (InvertFlags x)) + // cond: + // result: (SETA x) + { + if v.Args[0].Op != OpAMD64InvertFlags { + goto endc9eba7aa1e54a228570d2f5cc96f3565 + } + x := v.Args[0].Args[0] v.Op = OpAMD64SETA v.AuxInt = 0 v.Aux = nil @@ -11333,100 +11805,525 @@ func rewriteValueAMD64_OpAMD64SETB(v *Value, config *Config) bool { v.AddArg(x) return true } - goto endc9eba7aa1e54a228570d2f5cc96f3565 -endc9eba7aa1e54a228570d2f5cc96f3565: + goto endc9eba7aa1e54a228570d2f5cc96f3565 +endc9eba7aa1e54a228570d2f5cc96f3565: + ; + // match: (SETB (FlagEQ)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagEQ { + goto endaf8a2c61689b00c8ad90dd090e634c81 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto endaf8a2c61689b00c8ad90dd090e634c81 +endaf8a2c61689b00c8ad90dd090e634c81: + ; + // match: (SETB (FlagLT_ULT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto endab96387d5f049ab9c87863473a5d6510 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto endab96387d5f049ab9c87863473a5d6510 +endab96387d5f049ab9c87863473a5d6510: + ; + // match: (SETB (FlagLT_UGT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto endbf7af56278add8851974cd1a538b3b7f + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto endbf7af56278add8851974cd1a538b3b7f +endbf7af56278add8851974cd1a538b3b7f: + ; + // match: (SETB (FlagGT_ULT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto end2d07a10db28e5160fccf66ee44c4823e + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end2d07a10db28e5160fccf66ee44c4823e +end2d07a10db28e5160fccf66ee44c4823e: + ; + // match: (SETB (FlagGT_UGT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto end87ec5187683c0ee498c0a2c4de59f4c0 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end87ec5187683c0ee498c0a2c4de59f4c0 +end87ec5187683c0ee498c0a2c4de59f4c0: + ; + return false +} +func rewriteValueAMD64_OpAMD64SETBE(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (SETBE (InvertFlags x)) + // cond: + // result: (SETAE x) + { + if v.Args[0].Op != OpAMD64InvertFlags { + goto end9d9031643469798b14b8cad1f5a7a1ba + } + x := v.Args[0].Args[0] + v.Op = OpAMD64SETAE + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AddArg(x) + return true + } + goto end9d9031643469798b14b8cad1f5a7a1ba +end9d9031643469798b14b8cad1f5a7a1ba: + ; + // match: (SETBE (FlagEQ)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagEQ { + goto ende6a02d3ce0e1584e806c7861de97eb5b + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto ende6a02d3ce0e1584e806c7861de97eb5b +ende6a02d3ce0e1584e806c7861de97eb5b: + ; + // match: (SETBE (FlagLT_ULT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto end7ea0208cd10e6311655d09e8aa354169 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end7ea0208cd10e6311655d09e8aa354169 +end7ea0208cd10e6311655d09e8aa354169: + ; + // match: (SETBE (FlagLT_UGT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto enddbfa0595802c67348d3a3bd22b198231 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto enddbfa0595802c67348d3a3bd22b198231 +enddbfa0595802c67348d3a3bd22b198231: + ; + // match: (SETBE (FlagGT_ULT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto end5b26e1d28d6a517ed004b0f9b80df27b + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end5b26e1d28d6a517ed004b0f9b80df27b +end5b26e1d28d6a517ed004b0f9b80df27b: + ; + // match: (SETBE (FlagGT_UGT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto end679e2e0ccd0dd526ea781fc64102cb88 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end679e2e0ccd0dd526ea781fc64102cb88 +end679e2e0ccd0dd526ea781fc64102cb88: + ; + return false +} +func rewriteValueAMD64_OpAMD64SETEQ(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (SETEQ (InvertFlags x)) + // cond: + // result: (SETEQ x) + { + if v.Args[0].Op != OpAMD64InvertFlags { + goto end5d2039c9368d8c0cfba23b5a85b459e1 + } + x := v.Args[0].Args[0] + v.Op = OpAMD64SETEQ + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AddArg(x) + return true + } + goto end5d2039c9368d8c0cfba23b5a85b459e1 +end5d2039c9368d8c0cfba23b5a85b459e1: + ; + // match: (SETEQ (FlagEQ)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagEQ { + goto end74e09087ca9d4bdf7740f4f052d2b9d3 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end74e09087ca9d4bdf7740f4f052d2b9d3 +end74e09087ca9d4bdf7740f4f052d2b9d3: + ; + // match: (SETEQ (FlagLT_ULT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto ende5d3756d09e616648de68d364b2c308f + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto ende5d3756d09e616648de68d364b2c308f +ende5d3756d09e616648de68d364b2c308f: + ; + // match: (SETEQ (FlagLT_UGT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto end1a86a603a5c6e0f328f63b9279137bcc + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end1a86a603a5c6e0f328f63b9279137bcc +end1a86a603a5c6e0f328f63b9279137bcc: + ; + // match: (SETEQ (FlagGT_ULT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto endbf907332cd6004c73b88f43b5e20275f + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto endbf907332cd6004c73b88f43b5e20275f +endbf907332cd6004c73b88f43b5e20275f: + ; + // match: (SETEQ (FlagGT_UGT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto end707540a9904307c186884f60e425ca62 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end707540a9904307c186884f60e425ca62 +end707540a9904307c186884f60e425ca62: + ; + return false +} +func rewriteValueAMD64_OpAMD64SETG(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (SETG (InvertFlags x)) + // cond: + // result: (SETL x) + { + if v.Args[0].Op != OpAMD64InvertFlags { + goto endf7586738694c9cd0b74ae28bbadb649f + } + x := v.Args[0].Args[0] + v.Op = OpAMD64SETL + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AddArg(x) + return true + } + goto endf7586738694c9cd0b74ae28bbadb649f +endf7586738694c9cd0b74ae28bbadb649f: + ; + // match: (SETG (FlagEQ)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagEQ { + goto endc952db8883f26126822bac29276b0690 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto endc952db8883f26126822bac29276b0690 +endc952db8883f26126822bac29276b0690: + ; + // match: (SETG (FlagLT_ULT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto end3b6d659c9285d30eba022a85c6c6f1c9 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end3b6d659c9285d30eba022a85c6c6f1c9 +end3b6d659c9285d30eba022a85c6c6f1c9: + ; + // match: (SETG (FlagLT_UGT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto end2eabfc908ca06e7d5d217142dd48af33 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end2eabfc908ca06e7d5d217142dd48af33 +end2eabfc908ca06e7d5d217142dd48af33: + ; + // match: (SETG (FlagGT_ULT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto end7c059e63a98776c77bb8e43759d2d864 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end7c059e63a98776c77bb8e43759d2d864 +end7c059e63a98776c77bb8e43759d2d864: + ; + // match: (SETG (FlagGT_UGT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto enddcb3196491c82060bcb90da722ffa8bd + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto enddcb3196491c82060bcb90da722ffa8bd +enddcb3196491c82060bcb90da722ffa8bd: + ; + return false +} +func rewriteValueAMD64_OpAMD64SETGE(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (SETGE (InvertFlags x)) + // cond: + // result: (SETLE x) + { + if v.Args[0].Op != OpAMD64InvertFlags { + goto end82c11eff6f842159f564f2dad3d2eedc + } + x := v.Args[0].Args[0] + v.Op = OpAMD64SETLE + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AddArg(x) + return true + } + goto end82c11eff6f842159f564f2dad3d2eedc +end82c11eff6f842159f564f2dad3d2eedc: ; - return false -} -func rewriteValueAMD64_OpAMD64SETBE(v *Value, config *Config) bool { - b := v.Block - _ = b - // match: (SETBE (InvertFlags x)) + // match: (SETGE (FlagEQ)) // cond: - // result: (SETAE x) + // result: (MOVBconst [1]) { - if v.Args[0].Op != OpAMD64InvertFlags { - goto end9d9031643469798b14b8cad1f5a7a1ba + if v.Args[0].Op != OpAMD64FlagEQ { + goto end1152b03b15fb4ea1822b2cc1c6815887 } - x := v.Args[0].Args[0] - v.Op = OpAMD64SETAE + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AddArg(x) + v.AuxInt = 1 return true } - goto end9d9031643469798b14b8cad1f5a7a1ba -end9d9031643469798b14b8cad1f5a7a1ba: + goto end1152b03b15fb4ea1822b2cc1c6815887 +end1152b03b15fb4ea1822b2cc1c6815887: ; - return false -} -func rewriteValueAMD64_OpAMD64SETEQ(v *Value, config *Config) bool { - b := v.Block - _ = b - // match: (SETEQ (InvertFlags x)) + // match: (SETGE (FlagLT_ULT)) // cond: - // result: (SETEQ x) + // result: (MOVBconst [0]) { - if v.Args[0].Op != OpAMD64InvertFlags { - goto end5d2039c9368d8c0cfba23b5a85b459e1 + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto endd55763184b306cc32397b421df6fc994 } - x := v.Args[0].Args[0] - v.Op = OpAMD64SETEQ + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AddArg(x) + v.AuxInt = 0 return true } - goto end5d2039c9368d8c0cfba23b5a85b459e1 -end5d2039c9368d8c0cfba23b5a85b459e1: + goto endd55763184b306cc32397b421df6fc994 +endd55763184b306cc32397b421df6fc994: ; - return false -} -func rewriteValueAMD64_OpAMD64SETG(v *Value, config *Config) bool { - b := v.Block - _ = b - // match: (SETG (InvertFlags x)) + // match: (SETGE (FlagLT_UGT)) // cond: - // result: (SETL x) + // result: (MOVBconst [0]) { - if v.Args[0].Op != OpAMD64InvertFlags { - goto endf7586738694c9cd0b74ae28bbadb649f + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto end209fbc531c4d6696b0b226c1ac016add } - x := v.Args[0].Args[0] - v.Op = OpAMD64SETL + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AddArg(x) + v.AuxInt = 0 return true } - goto endf7586738694c9cd0b74ae28bbadb649f -endf7586738694c9cd0b74ae28bbadb649f: + goto end209fbc531c4d6696b0b226c1ac016add +end209fbc531c4d6696b0b226c1ac016add: ; - return false -} -func rewriteValueAMD64_OpAMD64SETGE(v *Value, config *Config) bool { - b := v.Block - _ = b - // match: (SETGE (InvertFlags x)) + // match: (SETGE (FlagGT_ULT)) // cond: - // result: (SETLE x) + // result: (MOVBconst [1]) { - if v.Args[0].Op != OpAMD64InvertFlags { - goto end82c11eff6f842159f564f2dad3d2eedc + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto end41600cc6b5af1497fc534af49eaf60a2 } - x := v.Args[0].Args[0] - v.Op = OpAMD64SETLE + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AddArg(x) + v.AuxInt = 1 return true } - goto end82c11eff6f842159f564f2dad3d2eedc -end82c11eff6f842159f564f2dad3d2eedc: + goto end41600cc6b5af1497fc534af49eaf60a2 +end41600cc6b5af1497fc534af49eaf60a2: + ; + // match: (SETGE (FlagGT_UGT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto endaa33fb1204dba90a141a9a945a9643a2 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto endaa33fb1204dba90a141a9a945a9643a2 +endaa33fb1204dba90a141a9a945a9643a2: ; return false } @@ -11450,6 +12347,91 @@ func rewriteValueAMD64_OpAMD64SETL(v *Value, config *Config) bool { } goto ende33160cd86b9d4d3b77e02fb4658d5d3 ende33160cd86b9d4d3b77e02fb4658d5d3: + ; + // match: (SETL (FlagEQ)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagEQ { + goto end52e421ca76fa5dfba6b9bc35b220c0bf + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end52e421ca76fa5dfba6b9bc35b220c0bf +end52e421ca76fa5dfba6b9bc35b220c0bf: + ; + // match: (SETL (FlagLT_ULT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto end4d9781536010887bcf6f6ffd563e6aac + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end4d9781536010887bcf6f6ffd563e6aac +end4d9781536010887bcf6f6ffd563e6aac: + ; + // match: (SETL (FlagLT_UGT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto end9d0dd525ca800cb3ec73e94d60c3cbf1 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end9d0dd525ca800cb3ec73e94d60c3cbf1 +end9d0dd525ca800cb3ec73e94d60c3cbf1: + ; + // match: (SETL (FlagGT_ULT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto end6d77da1539ee0ebebee0e162c55e8f6e + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end6d77da1539ee0ebebee0e162c55e8f6e +end6d77da1539ee0ebebee0e162c55e8f6e: + ; + // match: (SETL (FlagGT_UGT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto end6c129bef0cc197325a338d17720516d1 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end6c129bef0cc197325a338d17720516d1 +end6c129bef0cc197325a338d17720516d1: ; return false } @@ -11473,6 +12455,91 @@ func rewriteValueAMD64_OpAMD64SETLE(v *Value, config *Config) bool { } goto end9307d96753efbeb888d1c98a6aba7a29 end9307d96753efbeb888d1c98a6aba7a29: + ; + // match: (SETLE (FlagEQ)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagEQ { + goto end43f998d2f9524fcdf45bab9fe672aa7c + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end43f998d2f9524fcdf45bab9fe672aa7c +end43f998d2f9524fcdf45bab9fe672aa7c: + ; + // match: (SETLE (FlagLT_ULT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto end80212f1ca6a01bccdf4bbd5aa15d5aab + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end80212f1ca6a01bccdf4bbd5aa15d5aab +end80212f1ca6a01bccdf4bbd5aa15d5aab: + ; + // match: (SETLE (FlagLT_UGT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto endd5ab2a8df7344cd7c8e1092d78bfd871 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto endd5ab2a8df7344cd7c8e1092d78bfd871 +endd5ab2a8df7344cd7c8e1092d78bfd871: + ; + // match: (SETLE (FlagGT_ULT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto enda74997e85c6f82ff1c530e6051d01e21 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto enda74997e85c6f82ff1c530e6051d01e21 +enda74997e85c6f82ff1c530e6051d01e21: + ; + // match: (SETLE (FlagGT_UGT)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto end7694b41632545d10fcc6339063c53f07 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end7694b41632545d10fcc6339063c53f07 +end7694b41632545d10fcc6339063c53f07: ; return false } @@ -11486,16 +12553,101 @@ func rewriteValueAMD64_OpAMD64SETNE(v *Value, config *Config) bool { if v.Args[0].Op != OpAMD64InvertFlags { goto endbc71811b789475308014550f638026eb } - x := v.Args[0].Args[0] - v.Op = OpAMD64SETNE + x := v.Args[0].Args[0] + v.Op = OpAMD64SETNE + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AddArg(x) + return true + } + goto endbc71811b789475308014550f638026eb +endbc71811b789475308014550f638026eb: + ; + // match: (SETNE (FlagEQ)) + // cond: + // result: (MOVBconst [0]) + { + if v.Args[0].Op != OpAMD64FlagEQ { + goto end6b66ea2ed518a926a071fe0d3dce46d8 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 0 + return true + } + goto end6b66ea2ed518a926a071fe0d3dce46d8 +end6b66ea2ed518a926a071fe0d3dce46d8: + ; + // match: (SETNE (FlagLT_ULT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagLT_ULT { + goto ende4d3b99f9dff014be3067a577ba0b016 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto ende4d3b99f9dff014be3067a577ba0b016 +ende4d3b99f9dff014be3067a577ba0b016: + ; + // match: (SETNE (FlagLT_UGT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagLT_UGT { + goto endb98d73ed6e5d3d21c2ea33840ab2a21c + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto endb98d73ed6e5d3d21c2ea33840ab2a21c +endb98d73ed6e5d3d21c2ea33840ab2a21c: + ; + // match: (SETNE (FlagGT_ULT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagGT_ULT { + goto end3bceb5cece8d0112cc8cd53435d64ef4 + } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end3bceb5cece8d0112cc8cd53435d64ef4 +end3bceb5cece8d0112cc8cd53435d64ef4: + ; + // match: (SETNE (FlagGT_UGT)) + // cond: + // result: (MOVBconst [1]) + { + if v.Args[0].Op != OpAMD64FlagGT_UGT { + goto end9249b3ed3e1e582dd5435fb73cbc13ac + } + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AddArg(x) + v.AuxInt = 1 return true } - goto endbc71811b789475308014550f638026eb -endbc71811b789475308014550f638026eb: + goto end9249b3ed3e1e582dd5435fb73cbc13ac +end9249b3ed3e1e582dd5435fb73cbc13ac: ; return false } @@ -13908,6 +15060,105 @@ func rewriteBlockAMD64(b *Block) bool { goto end6b8e9afc73b1c4d528f31a60d2575fae end6b8e9afc73b1c4d528f31a60d2575fae: ; + // match: (EQ (FlagEQ) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto end9ff0ac95bed10cc8e2b88351720bf254 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end9ff0ac95bed10cc8e2b88351720bf254 + end9ff0ac95bed10cc8e2b88351720bf254: + ; + // match: (EQ (FlagLT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto endb087fca771315fb0f3e36b4f3daa1b4f + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto endb087fca771315fb0f3e36b4f3daa1b4f + endb087fca771315fb0f3e36b4f3daa1b4f: + ; + // match: (EQ (FlagLT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto endd1884731c9bd3c1cc1b27617e4573add + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto endd1884731c9bd3c1cc1b27617e4573add + endd1884731c9bd3c1cc1b27617e4573add: + ; + // match: (EQ (FlagGT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto end13acc127fef124a130ad1e79fd6a58c9 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end13acc127fef124a130ad1e79fd6a58c9 + end13acc127fef124a130ad1e79fd6a58c9: + ; + // match: (EQ (FlagGT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto end4bdb3694a7ed9860cc65f54840b11e84 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end4bdb3694a7ed9860cc65f54840b11e84 + end4bdb3694a7ed9860cc65f54840b11e84: + ; case BlockAMD64GE: // match: (GE (InvertFlags cmp) yes no) // cond: @@ -13929,6 +15180,103 @@ func rewriteBlockAMD64(b *Block) bool { goto end0610f000a6988ee8310307ec2ea138f8 end0610f000a6988ee8310307ec2ea138f8: ; + // match: (GE (FlagEQ) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto end24ae40580bbb8675d15f6d1451beeb56 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end24ae40580bbb8675d15f6d1451beeb56 + end24ae40580bbb8675d15f6d1451beeb56: + ; + // match: (GE (FlagLT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto end40cf2bb5d1a99146cc6ce5e9a9dc7eee + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end40cf2bb5d1a99146cc6ce5e9a9dc7eee + end40cf2bb5d1a99146cc6ce5e9a9dc7eee: + ; + // match: (GE (FlagLT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto end2d4809306e6243116f4c1b27c7c9e503 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end2d4809306e6243116f4c1b27c7c9e503 + end2d4809306e6243116f4c1b27c7c9e503: + ; + // match: (GE (FlagGT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto end842c411ddb1c5583e1e986f2826bb3cf + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end842c411ddb1c5583e1e986f2826bb3cf + end842c411ddb1c5583e1e986f2826bb3cf: + ; + // match: (GE (FlagGT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto end7402ddc29ccc96070353e9a04e126444 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end7402ddc29ccc96070353e9a04e126444 + end7402ddc29ccc96070353e9a04e126444: + ; case BlockAMD64GT: // match: (GT (InvertFlags cmp) yes no) // cond: @@ -13950,6 +15298,104 @@ func rewriteBlockAMD64(b *Block) bool { goto endf60c0660b6a8aa9565c97fc87f04eb34 endf60c0660b6a8aa9565c97fc87f04eb34: ; + // match: (GT (FlagEQ) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto end2ba8650a12af813cee310b2a81b9ba1b + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end2ba8650a12af813cee310b2a81b9ba1b + end2ba8650a12af813cee310b2a81b9ba1b: + ; + // match: (GT (FlagLT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto endbe873b5adbcdd272c99e04e063f9b7ce + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto endbe873b5adbcdd272c99e04e063f9b7ce + endbe873b5adbcdd272c99e04e063f9b7ce: + ; + // match: (GT (FlagLT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto ende5dd5906f7fdb5c0e59eeed92a3684d3 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto ende5dd5906f7fdb5c0e59eeed92a3684d3 + ende5dd5906f7fdb5c0e59eeed92a3684d3: + ; + // match: (GT (FlagGT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto end7d92e57429ee02c3707f39d861c94f4c + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end7d92e57429ee02c3707f39d861c94f4c + end7d92e57429ee02c3707f39d861c94f4c: + ; + // match: (GT (FlagGT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto end9d77d9a15c1b0938558a4ce821d50aa1 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end9d77d9a15c1b0938558a4ce821d50aa1 + end9d77d9a15c1b0938558a4ce821d50aa1: + ; case BlockIf: // match: (If (SETL cmp) yes no) // cond: @@ -14273,6 +15719,103 @@ func rewriteBlockAMD64(b *Block) bool { goto end0d49d7d087fe7578e8015cf13dae37e3 end0d49d7d087fe7578e8015cf13dae37e3: ; + // match: (LE (FlagEQ) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto end794469f5273ff9b2867ec900775c72d2 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end794469f5273ff9b2867ec900775c72d2 + end794469f5273ff9b2867ec900775c72d2: + ; + // match: (LE (FlagLT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto end0b9fee7a7eb47fe268039bc0e529d6ac + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end0b9fee7a7eb47fe268039bc0e529d6ac + end0b9fee7a7eb47fe268039bc0e529d6ac: + ; + // match: (LE (FlagLT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto end519d8c93a652b9062fba49942dc7d28d + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end519d8c93a652b9062fba49942dc7d28d + end519d8c93a652b9062fba49942dc7d28d: + ; + // match: (LE (FlagGT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto endbd11ec75f000579a43fd6507282b307d + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto endbd11ec75f000579a43fd6507282b307d + endbd11ec75f000579a43fd6507282b307d: + ; + // match: (LE (FlagGT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto end3828ab56cc3c548c96ac30592e5f865a + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end3828ab56cc3c548c96ac30592e5f865a + end3828ab56cc3c548c96ac30592e5f865a: + ; case BlockAMD64LT: // match: (LT (InvertFlags cmp) yes no) // cond: @@ -14291,8 +15834,106 @@ func rewriteBlockAMD64(b *Block) bool { b.Succs[1] = no return true } - goto end6a408cde0fee0ae7b7da0443c8d902bf - end6a408cde0fee0ae7b7da0443c8d902bf: + goto end6a408cde0fee0ae7b7da0443c8d902bf + end6a408cde0fee0ae7b7da0443c8d902bf: + ; + // match: (LT (FlagEQ) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto enda9dfcd37198ce9684d4bb3a2e54feea9 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto enda9dfcd37198ce9684d4bb3a2e54feea9 + enda9dfcd37198ce9684d4bb3a2e54feea9: + ; + // match: (LT (FlagLT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto ende2b678683d46e68bb0b1503f351917dc + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto ende2b678683d46e68bb0b1503f351917dc + ende2b678683d46e68bb0b1503f351917dc: + ; + // match: (LT (FlagLT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto end24e744700aa56591fbd23e1335d6e293 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end24e744700aa56591fbd23e1335d6e293 + end24e744700aa56591fbd23e1335d6e293: + ; + // match: (LT (FlagGT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto enda178f2150e3da5c17e768a4f81af5f9a + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto enda178f2150e3da5c17e768a4f81af5f9a + enda178f2150e3da5c17e768a4f81af5f9a: + ; + // match: (LT (FlagGT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto end361a42127127ede8ea30e991bb099ebb + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end361a42127127ede8ea30e991bb099ebb + end361a42127127ede8ea30e991bb099ebb: ; case BlockAMD64NE: // match: (NE (TESTB (SETL cmp)) yes no) @@ -14637,6 +16278,102 @@ func rewriteBlockAMD64(b *Block) bool { goto end713001aba794e50b582fbff930e110af end713001aba794e50b582fbff930e110af: ; + // match: (NE (FlagEQ) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto end55cc491bc7fc08ef27cadaa80d197545 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end55cc491bc7fc08ef27cadaa80d197545 + end55cc491bc7fc08ef27cadaa80d197545: + ; + // match: (NE (FlagLT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto end3293c7b37d9fcc6bd5add16c94108a4b + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end3293c7b37d9fcc6bd5add16c94108a4b + end3293c7b37d9fcc6bd5add16c94108a4b: + ; + // match: (NE (FlagLT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto end1a49ef88420e9d7fd745f9675ca01d6e + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end1a49ef88420e9d7fd745f9675ca01d6e + end1a49ef88420e9d7fd745f9675ca01d6e: + ; + // match: (NE (FlagGT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto endbd468825bdf21bca47f8d83d580794ec + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto endbd468825bdf21bca47f8d83d580794ec + endbd468825bdf21bca47f8d83d580794ec: + ; + // match: (NE (FlagGT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto end43cf7171afb4610818c4b63cc14c1f30 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end43cf7171afb4610818c4b63cc14c1f30 + end43cf7171afb4610818c4b63cc14c1f30: + ; case BlockAMD64UGE: // match: (UGE (InvertFlags cmp) yes no) // cond: @@ -14658,6 +16395,103 @@ func rewriteBlockAMD64(b *Block) bool { goto ende3e4ddc183ca1a46598b11c2d0d13966 ende3e4ddc183ca1a46598b11c2d0d13966: ; + // match: (UGE (FlagEQ) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto end13b873811b0cfc7b08501fa2b96cbaa5 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end13b873811b0cfc7b08501fa2b96cbaa5 + end13b873811b0cfc7b08501fa2b96cbaa5: + ; + // match: (UGE (FlagLT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto end399c10dc3dcdb5864558ecbac4566b7d + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end399c10dc3dcdb5864558ecbac4566b7d + end399c10dc3dcdb5864558ecbac4566b7d: + ; + // match: (UGE (FlagLT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto end3013dbd3841b20b5030bafb98ee5e38f + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end3013dbd3841b20b5030bafb98ee5e38f + end3013dbd3841b20b5030bafb98ee5e38f: + ; + // match: (UGE (FlagGT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto end9727eb4bb399457be62dc382bb9a0913 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end9727eb4bb399457be62dc382bb9a0913 + end9727eb4bb399457be62dc382bb9a0913: + ; + // match: (UGE (FlagGT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto ende4099f954bd6511668fda560c56e89b1 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto ende4099f954bd6511668fda560c56e89b1 + ende4099f954bd6511668fda560c56e89b1: + ; case BlockAMD64UGT: // match: (UGT (InvertFlags cmp) yes no) // cond: @@ -14679,6 +16513,104 @@ func rewriteBlockAMD64(b *Block) bool { goto end49818853af2e5251175d06c62768cae7 end49818853af2e5251175d06c62768cae7: ; + // match: (UGT (FlagEQ) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto end97e91c3348cb91e9278902aaa7fb050a + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end97e91c3348cb91e9278902aaa7fb050a + end97e91c3348cb91e9278902aaa7fb050a: + ; + // match: (UGT (FlagLT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto ende2c57da783c6ad18203c9c418ab0de6a + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto ende2c57da783c6ad18203c9c418ab0de6a + ende2c57da783c6ad18203c9c418ab0de6a: + ; + // match: (UGT (FlagLT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto end65100b76cf3975a42b235b0e10fea2b1 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end65100b76cf3975a42b235b0e10fea2b1 + end65100b76cf3975a42b235b0e10fea2b1: + ; + // match: (UGT (FlagGT_ULT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto end5db8fa9a32980847176e980aa1899bb3 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end5db8fa9a32980847176e980aa1899bb3 + end5db8fa9a32980847176e980aa1899bb3: + ; + // match: (UGT (FlagGT_UGT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto end1095a388cf1534294952f4ef4ce3e940 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end1095a388cf1534294952f4ef4ce3e940 + end1095a388cf1534294952f4ef4ce3e940: + ; case BlockAMD64ULE: // match: (ULE (InvertFlags cmp) yes no) // cond: @@ -14700,6 +16632,103 @@ func rewriteBlockAMD64(b *Block) bool { goto endd6698aac0d67261293b558c95ea17b4f endd6698aac0d67261293b558c95ea17b4f: ; + // match: (ULE (FlagEQ) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto end2d801e9ad76753e9ff3e19ee7c9f8a86 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end2d801e9ad76753e9ff3e19ee7c9f8a86 + end2d801e9ad76753e9ff3e19ee7c9f8a86: + ; + // match: (ULE (FlagLT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto end93b751a70b8587ce2c2dc0545a77246c + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end93b751a70b8587ce2c2dc0545a77246c + end93b751a70b8587ce2c2dc0545a77246c: + ; + // match: (ULE (FlagLT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto enda318623645491582b19f9de9b3da20e9 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto enda318623645491582b19f9de9b3da20e9 + enda318623645491582b19f9de9b3da20e9: + ; + // match: (ULE (FlagGT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto end1dfb9e417c0a518e1fa9c92edd57723e + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end1dfb9e417c0a518e1fa9c92edd57723e + end1dfb9e417c0a518e1fa9c92edd57723e: + ; + // match: (ULE (FlagGT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto end7c9881aac5c0b34d8df3572c8f7b50f3 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end7c9881aac5c0b34d8df3572c8f7b50f3 + end7c9881aac5c0b34d8df3572c8f7b50f3: + ; case BlockAMD64ULT: // match: (ULT (InvertFlags cmp) yes no) // cond: @@ -14720,6 +16749,104 @@ func rewriteBlockAMD64(b *Block) bool { } goto end35105dbc9646f02577167e45ae2f2fd2 end35105dbc9646f02577167e45ae2f2fd2: + ; + // match: (ULT (FlagEQ) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagEQ { + goto end4f7ea32f328981623154b68f21c9585f + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end4f7ea32f328981623154b68f21c9585f + end4f7ea32f328981623154b68f21c9585f: + ; + // match: (ULT (FlagLT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagLT_ULT { + goto endf8739cbf4e7cdcb02b891bbfc103654a + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto endf8739cbf4e7cdcb02b891bbfc103654a + endf8739cbf4e7cdcb02b891bbfc103654a: + ; + // match: (ULT (FlagLT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagLT_UGT { + goto enddb12a8de4bdb237aa8a1b6186a0f5f01 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto enddb12a8de4bdb237aa8a1b6186a0f5f01 + enddb12a8de4bdb237aa8a1b6186a0f5f01: + ; + // match: (ULT (FlagGT_ULT) yes no) + // cond: + // result: (First nil yes no) + { + v := b.Control + if v.Op != OpAMD64FlagGT_ULT { + goto end5ceb130f54533e645b6be48ac28dd7a1 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end5ceb130f54533e645b6be48ac28dd7a1 + end5ceb130f54533e645b6be48ac28dd7a1: + ; + // match: (ULT (FlagGT_UGT) yes no) + // cond: + // result: (First nil no yes) + { + v := b.Control + if v.Op != OpAMD64FlagGT_UGT { + goto end17191a994592b633cbf6f935efbeaf72 + } + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockFirst + b.Control = nil + b.Succs[0] = no + b.Succs[1] = yes + b.Likely *= -1 + return true + } + goto end17191a994592b633cbf6f935efbeaf72 + end17191a994592b633cbf6f935efbeaf72: } return false } -- cgit v1.3 From 2f57d0fe024c19b1b7a86084d72e7267863415a6 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 28 Jan 2016 13:46:30 -0800 Subject: [dev.ssa] cmd/compile: preallocate small-numbered values and blocks Speeds up the compiler ~5%. Change-Id: Ia5cf0bcd58701fd14018ec77d01f03d5c7d6385b Reviewed-on: https://go-review.googlesource.com/19060 Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/gc/pgen.go | 1 + src/cmd/compile/internal/gc/ssa.go | 13 +- src/cmd/compile/internal/ssa/check.go | 12 +- src/cmd/compile/internal/ssa/config.go | 26 ++- src/cmd/compile/internal/ssa/deadcode.go | 6 +- src/cmd/compile/internal/ssa/func.go | 269 ++++++++++++++----------------- src/cmd/compile/internal/ssa/id.go | 11 -- src/cmd/compile/internal/ssa/regalloc.go | 4 +- 8 files changed, 167 insertions(+), 175 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index 6e7e10e163..6f5913406e 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -496,6 +496,7 @@ func compile(fn *Node) { if Curfn.Func.Endlineno != 0 { lineno = Curfn.Func.Endlineno } + ssafn.Free() return } Genlist(Curfn.Func.Enter) diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 203de6421c..ae747324be 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -21,6 +21,9 @@ import ( // Smallest possible faulting page at address zero. const minZeroPage = 4096 +var ssaConfig *ssa.Config +var ssaExp ssaExport + func shouldssa(fn *Node) bool { if Thearch.Thestring != "amd64" { return false @@ -119,9 +122,13 @@ func buildssa(fn *Node) *ssa.Func { // TODO(khr): build config just once at the start of the compiler binary - var e ssaExport - e.log = printssa - s.config = ssa.NewConfig(Thearch.Thestring, &e, Ctxt, Debug['N'] == 0) + ssaExp.log = printssa + ssaExp.unimplemented = false + ssaExp.mustImplement = true + if ssaConfig == nil { + ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0) + } + s.config = ssaConfig s.f = s.config.NewFunc() s.f.Name = name s.exitCode = fn.Func.Exit diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index b74371008c..e6f8716d5b 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -219,14 +219,14 @@ func checkFunc(f *Func) { f.Fatalf("control value for %s is missing: %v", b, b.Control) } } - for _, id := range f.bid.free { - if blockMark[id] { - f.Fatalf("used block b%d in free list", id) + for b := f.freeBlocks; b != nil; b = b.Aux.(*Block) { + if blockMark[b.ID] { + f.Fatalf("used block b%d in free list", b.ID) } } - for _, id := range f.vid.free { - if valueMark[id] { - f.Fatalf("used value v%d in free list", id) + for v := f.freeValues; v != nil; v = v.argstorage[0] { + if valueMark[v.ID] { + f.Fatalf("used value v%d in free list", v.ID) } } diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 7325873a15..52e772ce81 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -16,8 +16,13 @@ type Config struct { HTML *HTMLWriter // html writer, for debugging ctxt *obj.Link // Generic arch information optimize bool // Do optimization + curFunc *Func // TODO: more stuff. Compiler flags of interest, ... + + // Storage for low-numbered values and blocks. + values [2000]Value + blocks [200]Block } type TypeSource interface { @@ -100,15 +105,29 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config c.ctxt = ctxt c.optimize = optimize + // Assign IDs to preallocated values/blocks. + for i := range c.values { + c.values[i].ID = ID(i) + } + for i := range c.blocks { + c.blocks[i].ID = ID(i) + } + return c } func (c *Config) Frontend() Frontend { return c.fe } -// NewFunc returns a new, empty function object +// NewFunc returns a new, empty function object. +// Caller must call f.Free() before calling NewFunc again. func (c *Config) NewFunc() *Func { // TODO(khr): should this function take name, type, etc. as arguments? - return &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}} + if c.curFunc != nil { + c.Fatalf(0, "NewFunc called without previous Free") + } + f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}} + c.curFunc = f + return f } func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) } @@ -118,6 +137,3 @@ func (c *Config) Unimplementedf(line int32, msg string, args ...interface{}) { } func (c *Config) Warnl(line int, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) } func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() } - -// TODO(khr): do we really need a separate Config, or can we just -// store all its fields inside a Func? diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 429708213f..faf16a3816 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -164,7 +164,7 @@ func deadcode(f *Func) { f.Names = f.Names[:i] // Remove dead values from blocks' value list. Return dead - // value ids to the allocator. + // values to the allocator. for _, b := range f.Blocks { i := 0 for _, v := range b.Values { @@ -172,7 +172,7 @@ func deadcode(f *Func) { b.Values[i] = v i++ } else { - f.vid.put(v.ID) + f.freeValue(v) } } // aid GC @@ -197,7 +197,7 @@ func deadcode(f *Func) { b.Succs = nil b.Control = nil b.Kind = BlockDead - f.bid.put(b.ID) + f.freeBlock(b) } } // zero remainder to help GC diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 371dae3b17..26e4283a23 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -4,10 +4,7 @@ package ssa -import ( - "math" - "sync" -) +import "math" // A Func represents a Go func declaration (or function literal) and // its body. This package compiles each Func independently. @@ -31,6 +28,9 @@ type Func struct { // Names is a copy of NamedValues.Keys. We keep a separate list // of keys to make iteration order deterministic. Names []LocalSlot + + freeValues *Value // free Values linked by argstorage[0]. All other fields except ID are 0/nil. + freeBlocks *Block // free Blocks linked by Aux.(*Block). All other fields except ID are 0/nil. } // NumBlocks returns an integer larger than the id of any Block in the Func. @@ -43,68 +43,85 @@ func (f *Func) NumValues() int { return f.vid.num() } -const ( - blockSize = 100 -) - -// blockPool provides a contiguous array of Blocks which -// improves the speed of traversing dominator trees. -type blockPool struct { - blocks []Block - mu sync.Mutex +// newValue allocates a new Value with the given fields and places it at the end of b.Values. +func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value { + var v *Value + if f.freeValues != nil { + v = f.freeValues + f.freeValues = v.argstorage[0] + v.argstorage[0] = nil + } else { + ID := f.vid.get() + if int(ID) < len(f.Config.values) { + v = &f.Config.values[ID] + } else { + v = &Value{ID: ID} + } + } + v.Op = op + v.Type = t + v.Block = b + v.Line = line + b.Values = append(b.Values, v) + return v } -func (bp *blockPool) newBlock() *Block { - bp.mu.Lock() - defer bp.mu.Unlock() - - if len(bp.blocks) == 0 { - bp.blocks = make([]Block, blockSize, blockSize) +// freeValue frees a value. It must no longer be referenced. +func (f *Func) freeValue(v *Value) { + if v.Type == nil { + f.Fatalf("trying to free an already freed value") } - - res := &bp.blocks[0] - bp.blocks = bp.blocks[1:] - return res + // Clear everything but ID (which we reuse). + id := v.ID + *v = Value{} + v.ID = id + v.argstorage[0] = f.freeValues + f.freeValues = v } -var bp blockPool - -// NewBlock returns a new block of the given kind and appends it to f.Blocks. +// newBlock allocates a new Block of the given kind and places it at the end of f.Blocks. func (f *Func) NewBlock(kind BlockKind) *Block { - b := bp.newBlock() - b.ID = f.bid.get() + var b *Block + if f.freeBlocks != nil { + b = f.freeBlocks + f.freeBlocks = b.Aux.(*Block) + b.Aux = nil + } else { + ID := f.bid.get() + if int(ID) < len(f.Config.blocks) { + b = &f.Config.blocks[ID] + } else { + b = &Block{ID: ID} + } + } b.Kind = kind b.Func = f f.Blocks = append(f.Blocks, b) return b } +func (f *Func) freeBlock(b *Block) { + // Clear everything but ID (which we reuse). + id := b.ID + *b = Block{} + b.ID = id + b.Aux = f.freeBlocks + f.freeBlocks = b +} + // NewValue0 returns a new value in the block with no arguments and zero aux values. func (b *Block) NewValue0(line int32, op Op, t Type) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = 0 v.Args = v.argstorage[:0] - b.Values = append(b.Values, v) return v } // NewValue returns a new value in the block with no arguments and an auxint value. func (b *Block) NewValue0I(line int32, op Op, t Type, auxint int64) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - AuxInt: auxint, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = auxint v.Args = v.argstorage[:0] - b.Values = append(b.Values, v) return v } @@ -116,158 +133,93 @@ func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value { // to prevent errors like using NewValue1A instead of NewValue1I. b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) } - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - Aux: aux, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = 0 + v.Aux = aux v.Args = v.argstorage[:0] - b.Values = append(b.Values, v) return v } // NewValue returns a new value in the block with no arguments and both an auxint and aux values. func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interface{}) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - AuxInt: auxint, - Aux: aux, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = auxint + v.Aux = aux v.Args = v.argstorage[:0] - b.Values = append(b.Values, v) return v } // NewValue1 returns a new value in the block with one argument and zero aux values. func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = 0 v.Args = v.argstorage[:1] - v.Args[0] = arg - b.Values = append(b.Values, v) + v.argstorage[0] = arg return v } // NewValue1I returns a new value in the block with one argument and an auxint value. func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - AuxInt: auxint, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = auxint v.Args = v.argstorage[:1] - v.Args[0] = arg - b.Values = append(b.Values, v) + v.argstorage[0] = arg return v } // NewValue1A returns a new value in the block with one argument and an aux value. func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Value) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - Aux: aux, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = 0 + v.Aux = aux v.Args = v.argstorage[:1] - v.Args[0] = arg - b.Values = append(b.Values, v) + v.argstorage[0] = arg return v } // NewValue1IA returns a new value in the block with one argument and both an auxint and aux values. func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - AuxInt: auxint, - Aux: aux, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = auxint + v.Aux = aux v.Args = v.argstorage[:1] - v.Args[0] = arg - b.Values = append(b.Values, v) + v.argstorage[0] = arg return v } // NewValue2 returns a new value in the block with two arguments and zero aux values. func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = 0 v.Args = v.argstorage[:2] - v.Args[0] = arg0 - v.Args[1] = arg1 - b.Values = append(b.Values, v) + v.argstorage[0] = arg0 + v.argstorage[1] = arg1 return v } // NewValue2I returns a new value in the block with two arguments and an auxint value. -func (b *Block) NewValue2I(line int32, op Op, t Type, aux int64, arg0, arg1 *Value) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - AuxInt: aux, - Block: b, - Line: line, - } +func (b *Block) NewValue2I(line int32, op Op, t Type, auxint int64, arg0, arg1 *Value) *Value { + v := b.Func.newValue(op, t, b, line) + v.AuxInt = auxint v.Args = v.argstorage[:2] - v.Args[0] = arg0 - v.Args[1] = arg1 - b.Values = append(b.Values, v) + v.argstorage[0] = arg0 + v.argstorage[1] = arg1 return v } // NewValue3 returns a new value in the block with three arguments and zero aux values. func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - Block: b, - Line: line, - } + v := b.Func.newValue(op, t, b, line) + v.AuxInt = 0 v.Args = []*Value{arg0, arg1, arg2} - b.Values = append(b.Values, v) return v } // NewValue3I returns a new value in the block with three arguments and an auxint value. -func (b *Block) NewValue3I(line int32, op Op, t Type, aux int64, arg0, arg1, arg2 *Value) *Value { - v := &Value{ - ID: b.Func.vid.get(), - Op: op, - Type: t, - AuxInt: aux, - Block: b, - Line: line, - } +func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1, arg2 *Value) *Value { + v := b.Func.newValue(op, t, b, line) + v.AuxInt = auxint v.Args = []*Value{arg0, arg1, arg2} - b.Values = append(b.Values, v) return v } @@ -310,3 +262,32 @@ func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry func (f *Func) Unimplementedf(msg string, args ...interface{}) { f.Config.Unimplementedf(f.Entry.Line, msg, args...) } + +func (f *Func) Free() { + // Clear values. + n := f.vid.num() + if n > len(f.Config.values) { + n = len(f.Config.values) + } + for i := 1; i < n; i++ { + f.Config.values[i] = Value{} + f.Config.values[i].ID = ID(i) + } + + // Clear blocks. + n = f.bid.num() + if n > len(f.Config.blocks) { + n = len(f.Config.blocks) + } + for i := 1; i < n; i++ { + f.Config.blocks[i] = Block{} + f.Config.blocks[i].ID = ID(i) + } + + // Unregister from config. + if f.Config.curFunc != f { + f.Fatalf("free of function which isn't the last one allocated") + } + f.Config.curFunc = nil + *f = Func{} // just in case +} diff --git a/src/cmd/compile/internal/ssa/id.go b/src/cmd/compile/internal/ssa/id.go index 3f53e1a434..367e687abf 100644 --- a/src/cmd/compile/internal/ssa/id.go +++ b/src/cmd/compile/internal/ssa/id.go @@ -9,16 +9,10 @@ type ID int32 // idAlloc provides an allocator for unique integers. type idAlloc struct { last ID - free []ID } // get allocates an ID and returns it. func (a *idAlloc) get() ID { - if n := len(a.free); n > 0 { - x := a.free[n-1] - a.free = a.free[:n-1] - return x - } x := a.last x++ if x == 1<<31-1 { @@ -28,11 +22,6 @@ func (a *idAlloc) get() ID { return x } -// put deallocates an ID. -func (a *idAlloc) put(x ID) { - a.free = append(a.free, x) -} - // num returns the maximum ID ever returned + 1. func (a *idAlloc) num() int { return int(a.last + 1) diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 9238999074..2a92624319 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -964,9 +964,7 @@ func (s *regAllocState) regalloc(f *Func) { // Constants, SP, SB, ... continue } - spill.Op = OpInvalid - spill.Type = TypeInvalid - spill.resetArgs() + f.freeValue(spill) } for _, b := range f.Blocks { i := 0 -- cgit v1.3 From 056c09bb88008f683904e88cea582722eeac2f27 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 28 Jan 2016 15:54:45 -0800 Subject: [dev.ssa] cmd/compile: add backing store buffers for block.{Preds,Succs,Values} Speeds up compilation by 6%. Change-Id: Ibaad95710323ddbe13c1b0351843fe43a48d776e Reviewed-on: https://go-review.googlesource.com/19080 Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/ssa/block.go | 5 +++++ src/cmd/compile/internal/ssa/check.go | 2 +- src/cmd/compile/internal/ssa/deadcode.go | 9 +-------- src/cmd/compile/internal/ssa/func.go | 16 +++++++++++----- src/cmd/compile/internal/ssa/fuse.go | 7 ++++++- 5 files changed, 24 insertions(+), 15 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go index 02673f0650..6585528b28 100644 --- a/src/cmd/compile/internal/ssa/block.go +++ b/src/cmd/compile/internal/ssa/block.go @@ -53,6 +53,11 @@ type Block struct { // After flagalloc, records whether flags are live at the end of the block. FlagsLiveAtEnd bool + + // Storage for Succs, Preds, and Values + succstorage [2]*Block + predstorage [4]*Block + valstorage [8]*Value } // kind control successors diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index e6f8716d5b..1c36160f8f 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -219,7 +219,7 @@ func checkFunc(f *Func) { f.Fatalf("control value for %s is missing: %v", b, b.Control) } } - for b := f.freeBlocks; b != nil; b = b.Aux.(*Block) { + for b := f.freeBlocks; b != nil; b = b.succstorage[0] { if blockMark[b.ID] { f.Fatalf("used block b%d in free list", b.ID) } diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index faf16a3816..80e1490014 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -183,7 +183,7 @@ func deadcode(f *Func) { b.Values = b.Values[:i] } - // Remove unreachable blocks. Return dead block ids to allocator. + // Remove unreachable blocks. Return dead blocks to allocator. i = 0 for _, b := range f.Blocks { if reachable[b.ID] { @@ -193,10 +193,6 @@ func deadcode(f *Func) { if len(b.Values) > 0 { b.Fatalf("live values in unreachable block %v: %v", b, b.Values) } - b.Preds = nil - b.Succs = nil - b.Control = nil - b.Kind = BlockDead f.freeBlock(b) } } @@ -206,9 +202,6 @@ func deadcode(f *Func) { tail[j] = nil } f.Blocks = f.Blocks[:i] - - // TODO: renumber Blocks and Values densely? - // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? } // removePred removes the predecessor p from b's predecessor list. diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 26e4283a23..6d20a2797d 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -30,7 +30,7 @@ type Func struct { Names []LocalSlot freeValues *Value // free Values linked by argstorage[0]. All other fields except ID are 0/nil. - freeBlocks *Block // free Blocks linked by Aux.(*Block). All other fields except ID are 0/nil. + freeBlocks *Block // free Blocks linked by succstorage[0]. All other fields except ID are 0/nil. } // NumBlocks returns an integer larger than the id of any Block in the Func. @@ -68,7 +68,7 @@ func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value { // freeValue frees a value. It must no longer be referenced. func (f *Func) freeValue(v *Value) { - if v.Type == nil { + if v.Block == nil { f.Fatalf("trying to free an already freed value") } // Clear everything but ID (which we reuse). @@ -84,8 +84,8 @@ func (f *Func) NewBlock(kind BlockKind) *Block { var b *Block if f.freeBlocks != nil { b = f.freeBlocks - f.freeBlocks = b.Aux.(*Block) - b.Aux = nil + f.freeBlocks = b.succstorage[0] + b.succstorage[0] = nil } else { ID := f.bid.get() if int(ID) < len(f.Config.blocks) { @@ -96,16 +96,22 @@ func (f *Func) NewBlock(kind BlockKind) *Block { } b.Kind = kind b.Func = f + b.Preds = b.predstorage[:0] + b.Succs = b.succstorage[:0] + b.Values = b.valstorage[:0] f.Blocks = append(f.Blocks, b) return b } func (f *Func) freeBlock(b *Block) { + if b.Func == nil { + f.Fatalf("trying to free an already freed block") + } // Clear everything but ID (which we reuse). id := b.ID *b = Block{} b.ID = id - b.Aux = f.freeBlocks + b.succstorage[0] = f.freeBlocks f.freeBlocks = b } diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go index e390fc4998..f191c7f9fd 100644 --- a/src/cmd/compile/internal/ssa/fuse.go +++ b/src/cmd/compile/internal/ssa/fuse.go @@ -22,7 +22,12 @@ func fuse(f *Func) { } // replace b->c edge with preds(b) -> c - c.Preds = b.Preds + c.predstorage[0] = nil + if len(b.Preds) > len(b.predstorage) { + c.Preds = b.Preds + } else { + c.Preds = append(c.predstorage[:0], b.Preds...) + } for _, p := range c.Preds { for i, q := range p.Succs { if q == b { -- cgit v1.3 From f962f33035bccd67c08fa3e0002659d6b9978bbc Mon Sep 17 00:00:00 2001 From: Todd Neal Date: Thu, 28 Jan 2016 22:19:46 -0600 Subject: [dev.ssa] cmd/compile: reuse sparse sets across compiler passes Cache sparse sets in the function so they can be reused by subsequent compiler passes. benchmark old ns/op new ns/op delta BenchmarkDSEPass-8 206945 180022 -13.01% BenchmarkDSEPassBlock-8 5286103 2614054 -50.55% BenchmarkCSEPass-8 1790277 1790655 +0.02% BenchmarkCSEPassBlock-8 18083588 18112771 +0.16% BenchmarkDeadcodePass-8 59837 41375 -30.85% BenchmarkDeadcodePassBlock-8 1651575 511169 -69.05% BenchmarkMultiPass-8 531529 427506 -19.57% BenchmarkMultiPassBlock-8 7033496 4487814 -36.19% benchmark old allocs new allocs delta BenchmarkDSEPass-8 11 4 -63.64% BenchmarkDSEPassBlock-8 599 120 -79.97% BenchmarkCSEPass-8 18 18 +0.00% BenchmarkCSEPassBlock-8 2700 2700 +0.00% BenchmarkDeadcodePass-8 4 3 -25.00% BenchmarkDeadcodePassBlock-8 30 9 -70.00% BenchmarkMultiPass-8 24 20 -16.67% BenchmarkMultiPassBlock-8 1800 1000 -44.44% benchmark old bytes new bytes delta BenchmarkDSEPass-8 221367 142 -99.94% BenchmarkDSEPassBlock-8 3695207 3846 -99.90% BenchmarkCSEPass-8 303328 303328 +0.00% BenchmarkCSEPassBlock-8 5006400 5006400 +0.00% BenchmarkDeadcodePass-8 84232 10506 -87.53% BenchmarkDeadcodePassBlock-8 1274940 163680 -87.16% BenchmarkMultiPass-8 608674 313834 -48.44% BenchmarkMultiPassBlock-8 9906001 5003450 -49.49% Change-Id: Ib1fa58c7f494b374d1a4bb9cffbc2c48377b59d3 Reviewed-on: https://go-review.googlesource.com/19100 Reviewed-by: David Chase Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/deadcode.go | 3 +- src/cmd/compile/internal/ssa/deadstore.go | 9 ++- src/cmd/compile/internal/ssa/func.go | 25 +++++++ src/cmd/compile/internal/ssa/layout.go | 6 +- src/cmd/compile/internal/ssa/passbm_test.go | 101 ++++++++++++++++++++++++++++ src/cmd/compile/internal/ssa/regalloc.go | 3 +- src/cmd/compile/internal/ssa/sparseset.go | 4 ++ src/cmd/compile/internal/ssa/stackalloc.go | 9 ++- 8 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 src/cmd/compile/internal/ssa/passbm_test.go (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 80e1490014..87244a6248 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -134,7 +134,8 @@ func deadcode(f *Func) { live := liveValues(f, reachable) // Remove dead & duplicate entries from namedValues map. - s := newSparseSet(f.NumValues()) + s := f.newSparseSet(f.NumValues()) + defer f.retSparseSet(s) i := 0 for _, name := range f.Names { j := 0 diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go index 89f7504341..bad0e0096f 100644 --- a/src/cmd/compile/internal/ssa/deadstore.go +++ b/src/cmd/compile/internal/ssa/deadstore.go @@ -10,9 +10,12 @@ package ssa // This implementation only works within a basic block. TODO: use something more global. func dse(f *Func) { var stores []*Value - loadUse := newSparseSet(f.NumValues()) - storeUse := newSparseSet(f.NumValues()) - shadowed := newSparseSet(f.NumValues()) + loadUse := f.newSparseSet(f.NumValues()) + defer f.retSparseSet(loadUse) + storeUse := f.newSparseSet(f.NumValues()) + defer f.retSparseSet(storeUse) + shadowed := f.newSparseSet(f.NumValues()) + defer f.retSparseSet(shadowed) for _, b := range f.Blocks { // Find all the stores in this block. Categorize their uses: // loadUse contains stores which are used by a subsequent load. diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index a28484010d..9da390904d 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -31,6 +31,8 @@ type Func struct { freeValues *Value // free Values linked by argstorage[0]. All other fields except ID are 0/nil. freeBlocks *Block // free Blocks linked by succstorage[0]. All other fields except ID are 0/nil. + + scrSparse []*sparseSet // sparse sets to be re-used. } // NumBlocks returns an integer larger than the id of any Block in the Func. @@ -43,6 +45,29 @@ func (f *Func) NumValues() int { return f.vid.num() } +// newSparseSet returns a sparse set that can store at least up to n integers. +func (f *Func) newSparseSet(n int) *sparseSet { + for i, scr := range f.scrSparse { + if scr != nil && scr.cap() >= n { + f.scrSparse[i] = nil + scr.clear() + return scr + } + } + return newSparseSet(n) +} + +// retSparseSet returns a sparse set to the function's cache to be reused by f.newSparseSet. +func (f *Func) retSparseSet(ss *sparseSet) { + for i, scr := range f.scrSparse { + if scr == nil { + f.scrSparse[i] = ss + return + } + } + f.scrSparse = append(f.scrSparse, ss) +} + // newValue allocates a new Value with the given fields and places it at the end of b.Values. func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value { var v *Value diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go index 7e865f948e..8dd4b65979 100644 --- a/src/cmd/compile/internal/ssa/layout.go +++ b/src/cmd/compile/internal/ssa/layout.go @@ -12,8 +12,10 @@ func layout(f *Func) { scheduled := make([]bool, f.NumBlocks()) idToBlock := make([]*Block, f.NumBlocks()) indegree := make([]int, f.NumBlocks()) - posdegree := newSparseSet(f.NumBlocks()) // blocks with positive remaining degree - zerodegree := newSparseSet(f.NumBlocks()) // blocks with zero remaining degree + posdegree := f.newSparseSet(f.NumBlocks()) // blocks with positive remaining degree + defer f.retSparseSet(posdegree) + zerodegree := f.newSparseSet(f.NumBlocks()) // blocks with zero remaining degree + defer f.retSparseSet(zerodegree) // Initialize indegree of each block for _, b := range f.Blocks { diff --git a/src/cmd/compile/internal/ssa/passbm_test.go b/src/cmd/compile/internal/ssa/passbm_test.go new file mode 100644 index 0000000000..9b11ff1256 --- /dev/null +++ b/src/cmd/compile/internal/ssa/passbm_test.go @@ -0,0 +1,101 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package ssa + +import ( + "fmt" + "testing" +) + +const ( + blockCount = 1000 + passCount = 15000 +) + +type passFunc func(*Func) + +func BenchmarkDSEPass(b *testing.B) { benchFnPass(b, dse, blockCount, genFunction) } +func BenchmarkDSEPassBlock(b *testing.B) { benchFnBlock(b, dse, genFunction) } +func BenchmarkCSEPass(b *testing.B) { benchFnPass(b, cse, blockCount, genFunction) } +func BenchmarkCSEPassBlock(b *testing.B) { benchFnBlock(b, cse, genFunction) } +func BenchmarkDeadcodePass(b *testing.B) { benchFnPass(b, deadcode, blockCount, genFunction) } +func BenchmarkDeadcodePassBlock(b *testing.B) { benchFnBlock(b, deadcode, genFunction) } + +func multi(f *Func) { + cse(f) + dse(f) + deadcode(f) +} +func BenchmarkMultiPass(b *testing.B) { benchFnPass(b, multi, blockCount, genFunction) } +func BenchmarkMultiPassBlock(b *testing.B) { benchFnBlock(b, multi, genFunction) } + +// benchFnPass runs passFunc b.N times across a single function. +func benchFnPass(b *testing.B, fn passFunc, size int, bg blockGen) { + b.ReportAllocs() + c := NewConfig("amd64", DummyFrontend{b}, nil, true) + fun := Fun(c, "entry", bg(size)...) + + CheckFunc(fun.f) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fn(fun.f) + b.StopTimer() + CheckFunc(fun.f) + b.StartTimer() + } +} + +// benchFnPass runs passFunc across a function with b.N blocks. +func benchFnBlock(b *testing.B, fn passFunc, bg blockGen) { + b.ReportAllocs() + c := NewConfig("amd64", DummyFrontend{b}, nil, true) + fun := Fun(c, "entry", bg(b.N)...) + + CheckFunc(fun.f) + b.ResetTimer() + for i := 0; i < passCount; i++ { + fn(fun.f) + } + b.StopTimer() +} + +func genFunction(size int) []bloc { + var blocs []bloc + elemType := &TypeImpl{Size_: 8, Name: "testtype"} + ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing + + valn := func(s string, m, n int) string { return fmt.Sprintf("%s%d-%d", s, m, n) } + blocs = append(blocs, + Bloc("entry", + Valu(valn("store", 0, 4), OpArg, TypeMem, 0, ".mem"), + Valu("sb", OpSB, TypeInvalid, 0, nil), + Goto(blockn(1)), + ), + ) + for i := 1; i < size+1; i++ { + blocs = append(blocs, Bloc(blockn(i), + Valu(valn("v", i, 0), OpConstBool, TypeBool, 1, nil), + Valu(valn("addr", i, 1), OpAddr, ptrType, 0, nil, "sb"), + Valu(valn("addr", i, 2), OpAddr, ptrType, 0, nil, "sb"), + Valu(valn("addr", i, 3), OpAddr, ptrType, 0, nil, "sb"), + Valu(valn("zero", i, 1), OpZero, TypeMem, 8, nil, valn("addr", i, 3), + valn("store", i-1, 4)), + Valu(valn("store", i, 1), OpStore, TypeMem, 0, nil, valn("addr", i, 1), + valn("v", i, 0), valn("zero", i, 1)), + Valu(valn("store", i, 2), OpStore, TypeMem, 0, nil, valn("addr", i, 2), + valn("v", i, 0), valn("store", i, 1)), + Valu(valn("store", i, 3), OpStore, TypeMem, 0, nil, valn("addr", i, 1), + valn("v", i, 0), valn("store", i, 2)), + Valu(valn("store", i, 4), OpStore, TypeMem, 0, nil, valn("addr", i, 3), + valn("v", i, 0), valn("store", i, 3)), + Goto(blockn(i+1)))) + } + + blocs = append(blocs, + Bloc(blockn(size+1), Goto("exit")), + Bloc("exit", Exit("store0-4")), + ) + + return blocs +} diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 61f694355e..2d88850999 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -559,7 +559,8 @@ func (s *regAllocState) compatRegs(t Type) regMask { } func (s *regAllocState) regalloc(f *Func) { - liveSet := newSparseSet(f.NumValues()) + liveSet := f.newSparseSet(f.NumValues()) + defer f.retSparseSet(liveSet) var oldSched []*Value var phis []*Value var phiRegs []register diff --git a/src/cmd/compile/internal/ssa/sparseset.go b/src/cmd/compile/internal/ssa/sparseset.go index b79aee8497..66bebf139e 100644 --- a/src/cmd/compile/internal/ssa/sparseset.go +++ b/src/cmd/compile/internal/ssa/sparseset.go @@ -18,6 +18,10 @@ func newSparseSet(n int) *sparseSet { return &sparseSet{nil, make([]int, n)} } +func (s *sparseSet) cap() int { + return len(s.sparse) +} + func (s *sparseSet) size() int { return len(s.dense) } diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 797a6b05e6..0e6cae0924 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -182,8 +182,10 @@ func (s *stackAllocState) stackalloc() { func (s *stackAllocState) computeLive(spillLive [][]ID) { s.live = make([][]ID, s.f.NumBlocks()) var phis []*Value - live := newSparseSet(s.f.NumValues()) - t := newSparseSet(s.f.NumValues()) + live := s.f.newSparseSet(s.f.NumValues()) + defer s.f.retSparseSet(live) + t := s.f.newSparseSet(s.f.NumValues()) + defer s.f.retSparseSet(t) // Instead of iterating over f.Blocks, iterate over their postordering. // Liveness information flows backward, so starting at the end @@ -271,7 +273,8 @@ func (f *Func) setHome(v *Value, loc Location) { func (s *stackAllocState) buildInterferenceGraph() { f := s.f s.interfere = make([][]ID, f.NumValues()) - live := newSparseSet(f.NumValues()) + live := f.newSparseSet(f.NumValues()) + defer f.retSparseSet(live) for _, b := range f.Blocks { // Propagate liveness backwards to the start of the block. // Two values interfere if one is defined while the other is live. -- cgit v1.3 From 40f2b57e0b007aaabe2b6ec5650223d047cd1452 Mon Sep 17 00:00:00 2001 From: Alexandru Moșoi Date: Mon, 22 Feb 2016 17:14:53 +0100 Subject: [dev.ssa] cmd/compile/internal/ssa: eliminate phis during deadcode removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While investigating the differences between 19710 (remove tautological controls) and 12960 (bounds and nil propagation) I observed that part of the wins of 19710 come from missed opportunities for deadcode elimination due to phis. See for example runtime.stackcacherelease. 19710 happens much later than 12960 and has more chances to eliminate bounds. Size of pkg/tool/linux_amd64/* excluding compile: -this -12960 95882248 +this -12960 95880120 -this +12960 95581512 +this +12960 95555224 This change saves about 25k. Change-Id: Id2f4e55fc92b71595842ce493c3ed527d424fe0e Reviewed-on: https://go-review.googlesource.com/19728 Reviewed-by: David Chase Run-TryBot: Alexandru Moșoi TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/ssa/deadcode.go | 66 ++++++++++++++++---------------- src/cmd/compile/internal/ssa/phielim.go | 6 ++- 2 files changed, 37 insertions(+), 35 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode.go') diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 87244a6248..a33de438e2 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -234,39 +234,37 @@ func (b *Block) removePred(p *Block) { v.Args[i] = v.Args[n] v.Args[n] = nil // aid GC v.Args = v.Args[:n] - if n == 1 { - v.Op = OpCopy - // Note: this is trickier than it looks. Replacing - // a Phi with a Copy can in general cause problems because - // Phi and Copy don't have exactly the same semantics. - // Phi arguments always come from a predecessor block, - // whereas copies don't. This matters in loops like: - // 1: x = (Phi y) - // y = (Add x 1) - // goto 1 - // If we replace Phi->Copy, we get - // 1: x = (Copy y) - // y = (Add x 1) - // goto 1 - // (Phi y) refers to the *previous* value of y, whereas - // (Copy y) refers to the *current* value of y. - // The modified code has a cycle and the scheduler - // will barf on it. - // - // Fortunately, this situation can only happen for dead - // code loops. We know the code we're working with is - // not dead, so we're ok. - // Proof: If we have a potential bad cycle, we have a - // situation like this: - // x = (Phi z) - // y = (op1 x ...) - // z = (op2 y ...) - // Where opX are not Phi ops. But such a situation - // implies a cycle in the dominator graph. In the - // example, x.Block dominates y.Block, y.Block dominates - // z.Block, and z.Block dominates x.Block (treating - // "dominates" as reflexive). Cycles in the dominator - // graph can only happen in an unreachable cycle. - } + phielimValue(v) + // Note: this is trickier than it looks. Replacing + // a Phi with a Copy can in general cause problems because + // Phi and Copy don't have exactly the same semantics. + // Phi arguments always come from a predecessor block, + // whereas copies don't. This matters in loops like: + // 1: x = (Phi y) + // y = (Add x 1) + // goto 1 + // If we replace Phi->Copy, we get + // 1: x = (Copy y) + // y = (Add x 1) + // goto 1 + // (Phi y) refers to the *previous* value of y, whereas + // (Copy y) refers to the *current* value of y. + // The modified code has a cycle and the scheduler + // will barf on it. + // + // Fortunately, this situation can only happen for dead + // code loops. We know the code we're working with is + // not dead, so we're ok. + // Proof: If we have a potential bad cycle, we have a + // situation like this: + // x = (Phi z) + // y = (op1 x ...) + // z = (op2 y ...) + // Where opX are not Phi ops. But such a situation + // implies a cycle in the dominator graph. In the + // example, x.Block dominates y.Block, y.Block dominates + // z.Block, and z.Block dominates x.Block (treating + // "dominates" as reflexive). Cycles in the dominator + // graph can only happen in an unreachable cycle. } } diff --git a/src/cmd/compile/internal/ssa/phielim.go b/src/cmd/compile/internal/ssa/phielim.go index 20ce592030..d69449ee21 100644 --- a/src/cmd/compile/internal/ssa/phielim.go +++ b/src/cmd/compile/internal/ssa/phielim.go @@ -40,7 +40,11 @@ func phielimValue(v *Value) bool { // are not v itself, then the phi must remain. // Otherwise, we can replace it with a copy. var w *Value - for _, x := range v.Args { + for i, x := range v.Args { + if b := v.Block.Preds[i]; b.Kind == BlockFirst && b.Succs[1] == v.Block { + // This branch is never taken so we can just eliminate it. + continue + } if x == v { continue } -- cgit v1.3