diff options
author | Cherry Zhang <cherryyz@google.com> | 2020-04-02 14:00:59 -0400 |
---|---|---|
committer | Cherry Zhang <cherryyz@google.com> | 2020-04-02 14:06:19 -0400 |
commit | 6b6eb230417765f6fe67661fe2f142ee1543b4f7 (patch) | |
tree | 13a2b1bd16263ba2f90c7405efa9eea5e592fbf5 | |
parent | d92a5a80b5c06b5d9915c5f888ab5cac6a94b11e (diff) | |
parent | aa4d92b8aab63c847ab077417b809694a2a6ea81 (diff) | |
download | go-6b6eb230417765f6fe67661fe2f142ee1543b4f7.tar.gz go-6b6eb230417765f6fe67661fe2f142ee1543b4f7.zip |
[dev.link] all: merge branch 'master' into dev.link
The only conflict is a modify-deletion conflict in
cmd/link/internal/ld/link.go, where the old error reporter is
deleted in the new linker. Ported to
cmd/link/internal/ld/errors.go.
Change-Id: I5c78f398ea95bc1d7e6579c84dd8252c9f2196b7
113 files changed, 5195 insertions, 6748 deletions
diff --git a/doc/contribute.html b/doc/contribute.html index 551d510288..5fefac6bba 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -552,9 +552,7 @@ $ ./all.bash </pre> <p> -(To build under Windows use <code>all.bat</code>; this also requires -setting the environment variable <code>GOROOT_BOOTSTRAP</code> to the -directory holding the Go tree for the bootstrap compiler.) +(To build under Windows use <code>all.bat</code>) </p> <p> @@ -1008,7 +1006,7 @@ followed by <code>run.bash</code>. <li> In this section, we'll call the directory into which you cloned the Go repository <code>$GODIR</code>. -The <code>go</code> tool built by <code>$GODIR/make.bash</code> will be installed +The <code>go</code> tool built by <code>$GODIR/src/make.bash</code> will be installed in <code>$GODIR/bin/go</code> and you can invoke it to test your code. For instance, if you diff --git a/doc/go1.15.html b/doc/go1.15.html index aa951eefad..c59fc4f151 100644 --- a/doc/go1.15.html +++ b/doc/go1.15.html @@ -43,6 +43,18 @@ TODO <h3 id="go-command">Go command</h3> +<p><!-- golang.org/issue/37367 --> + The <code>GOPROXY</code> environment variable now supports skipping proxies + that return errors. Proxy URLs may now be separated with either commas + (<code>,</code>) or pipe characters (<code>|</code>). If a proxy URL is + followed by a comma, the <code>go</code> command will only try the next proxy + in the list after a 404 or 410 HTTP response. If a proxy URL is followed by a + pipe character, the <code>go</code> command will try the next proxy in the + list after any error. Note that the default value of <code>GOPROXY</code> + remains <code>https://proxy.golang.org,direct</code>, which does not fall + back to <code>direct</code> in case of errors. +</p> + <p> TODO </p> diff --git a/doc/install-source.html b/doc/install-source.html index 17b1c9cbb7..3d42a10ad6 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -106,23 +106,17 @@ Go does not support CentOS 6 on these systems. </div> -<h2 id="go14">Install Go compiler binaries</h2> +<h2 id="go14">Install Go compiler binaries for bootstrap</h2> <p> The Go toolchain is written in Go. To build it, you need a Go compiler installed. -The scripts that do the initial build of the tools look for an existing Go tool -chain in <code>$GOROOT_BOOTSTRAP</code>. -If unset, the default value of <code>GOROOT_BOOTSTRAP</code> -is <code>$HOME/go1.4</code>. -</p> - -<p> -There are many options for the bootstrap toolchain. -After obtaining one, set <code>GOROOT_BOOTSTRAP</code> to the -directory containing the unpacked tree. -For example, <code>$GOROOT_BOOTSTRAP/bin/go</code> should be -the <code>go</code> command binary for the bootstrap toolchain. -</p> +The scripts that do the initial build of the tools look for a "go" command +in <code>$PATH</code>, so as long as you have Go installed in your +system and configured in your <code>$PATH</code>, you are ready to build Go +from source. +Or if you prefer you can set <code>$GOROOT_BOOTSTRAP</code> to the +root of a Go installation to use to build the new Go toolchain; +<code>$GOROOT_BOOTSTRAP/bin/go</code> should be the go command to use.</p> <h3 id="bootstrapFromBinaryRelease">Bootstrap toolchain from binary release</h3> diff --git a/doc/install.html b/doc/install.html index 40faadb2fa..706d66c007 100644 --- a/doc/install.html +++ b/doc/install.html @@ -17,7 +17,7 @@ <p> <a href="/dl/" target="_blank">Official binary distributions</a> are available for the FreeBSD (release 10-STABLE and above), -Linux, macOS (10.10 and above), and Windows operating systems and +Linux, macOS (10.11 and above), and Windows operating systems and the 32-bit (<code>386</code>) and 64-bit (<code>amd64</code>) x86 processor architectures. </p> @@ -49,7 +49,7 @@ If your OS or architecture is not on the list, you may be able to <tr><td colspan="3"><hr></td></tr> <tr><td>FreeBSD 10.3 or later</td> <td>amd64, 386</td> <td>Debian GNU/kFreeBSD not supported</td></tr> <tr valign='top'><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm, arm64,<br>s390x, ppc64le</td> <td>CentOS/RHEL 5.x not supported.<br>Install from source for other libc.</td></tr> -<tr><td>macOS 10.10 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup> for <code>cgo</code> support</td></tr> +<tr><td>macOS 10.11 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup> for <code>cgo</code> support</td></tr> <tr valign='top'><td>Windows 7, Server 2008R2 or later</td> <td>amd64, 386</td> <td>use MinGW (<code>386</code>) or MinGW-W64 (<code>amd64</code>) gcc<sup>†</sup>.<br>No need for cygwin or msys.</td></tr> </table> diff --git a/misc/cgo/testgodefs/testdata/issue37479.go b/misc/cgo/testgodefs/testdata/issue37479.go new file mode 100644 index 0000000000..a210eb5bc5 --- /dev/null +++ b/misc/cgo/testgodefs/testdata/issue37479.go @@ -0,0 +1,33 @@ +// Copyright 2020 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. +// +// +build ignore + +package main + +/* +typedef struct A A; + +typedef struct { + struct A *next; + struct A **prev; +} N; + +struct A +{ + N n; +}; + +typedef struct B +{ + A* a; +} B; +*/ +import "C" + +type N C.N + +type A C.A + +type B C.B diff --git a/misc/cgo/testgodefs/testdata/issue37621.go b/misc/cgo/testgodefs/testdata/issue37621.go new file mode 100644 index 0000000000..d5ace3f6d6 --- /dev/null +++ b/misc/cgo/testgodefs/testdata/issue37621.go @@ -0,0 +1,23 @@ +// Copyright 2020 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. +// +// +build ignore + +package main + +/* +struct tt { + long long a; + long long b; +}; + +struct s { + struct tt ts[3]; +}; +*/ +import "C" + +type TT C.struct_tt + +type S C.struct_s diff --git a/misc/cgo/testgodefs/testdata/main.go b/misc/cgo/testgodefs/testdata/main.go index 1ce0fd0d1e..ef45b95e65 100644 --- a/misc/cgo/testgodefs/testdata/main.go +++ b/misc/cgo/testgodefs/testdata/main.go @@ -11,5 +11,13 @@ var v2 = v1.L // Test that P, Q, and R all point to byte. var v3 = Issue8478{P: (*byte)(nil), Q: (**byte)(nil), R: (***byte)(nil)} +// Test that N, A and B are fully defined +var v4 = N{} +var v5 = A{} +var v6 = B{} + +// Test that S is fully defined +var v7 = S{} + func main() { } diff --git a/misc/cgo/testgodefs/testgodefs_test.go b/misc/cgo/testgodefs/testgodefs_test.go index c02c3ff0ac..438d23d65c 100644 --- a/misc/cgo/testgodefs/testgodefs_test.go +++ b/misc/cgo/testgodefs/testgodefs_test.go @@ -21,6 +21,8 @@ var filePrefixes = []string{ "anonunion", "issue8478", "fieldtypedef", + "issue37479", + "issue37621", } func TestGoDefs(t *testing.T) { diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go index d9ba6670e8..2e5d0ff991 100644 --- a/src/cmd/asm/internal/arch/arch.go +++ b/src/cmd/asm/internal/arch/arch.go @@ -88,7 +88,8 @@ func jumpX86(word string) bool { func jumpRISCV(word string) bool { switch word { - case "BEQ", "BNE", "BLT", "BGE", "BLTU", "BGEU", "CALL", "JAL", "JALR", "JMP": + case "BEQ", "BEQZ", "BGE", "BGEU", "BGEZ", "BGT", "BGTU", "BGTZ", "BLE", "BLEU", "BLEZ", + "BLT", "BLTU", "BLTZ", "BNE", "BNEZ", "CALL", "JAL", "JALR", "JMP": return true } return false diff --git a/src/cmd/asm/internal/asm/testdata/riscvenc.s b/src/cmd/asm/internal/asm/testdata/riscvenc.s index 74bc43d727..8d301f2dd5 100644 --- a/src/cmd/asm/internal/asm/testdata/riscvenc.s +++ b/src/cmd/asm/internal/asm/testdata/riscvenc.s @@ -330,6 +330,19 @@ start: CALL asmtest(SB) // 970f0000 JMP asmtest(SB) // 970f0000 + // Branch pseudo-instructions + BEQZ X5, start // BEQZ X5, 2 // e38a02c2 + BGEZ X5, start // BGEZ X5, 2 // e3d802c2 + BGT X5, X6, start // BGT X5, X6, 2 // e3c662c2 + BGTU X5, X6, start // BGTU X5, X6, 2 // e3e462c2 + BGTZ X5, start // BGTZ X5, 2 // e34250c2 + BLE X5, X6, start // BLE X5, X6, 2 // e3d062c2 + BLEU X5, X6, start // BLEU X5, X6, 2 // e3fe62c0 + BLEZ X5, start // BLEZ X5, 2 // e35c50c0 + BLTZ X5, start // BLTZ X5, 2 // e3ca02c0 + BNEZ X5, start // BNEZ X5, 2 // e39802c0 + + // Set pseudo-instructions SEQZ X15, X15 // 93b71700 SNEZ X15, X15 // b337f000 diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index fcab494ea0..c4128e9502 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -2243,7 +2243,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ // Translate to zero-length array instead. count = 0 } - sub := c.loadType(dt.Type, pos, key) + sub := c.Type(dt.Type, pos) t.Align = sub.Align t.Go = &ast.ArrayType{ Len: c.intExpr(count), @@ -2388,7 +2388,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ c.ptrs[key] = append(c.ptrs[key], t) case *dwarf.QualType: - t1 := c.loadType(dt.Type, pos, key) + t1 := c.Type(dt.Type, pos) t.Size = t1.Size t.Align = t1.Align t.Go = t1.Go @@ -2472,7 +2472,13 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ } name := c.Ident("_Ctype_" + dt.Name) goIdent[name.Name] = name - sub := c.loadType(dt.Type, pos, key) + akey := "" + if c.anonymousStructTypedef(dt) { + // only load type recursively for typedefs of anonymous + // structs, see issues 37479 and 37621. + akey = key + } + sub := c.loadType(dt.Type, pos, akey) if c.badPointerTypedef(dt) { // Treat this typedef as a uintptr. s := *sub @@ -2993,6 +2999,13 @@ func fieldPrefix(fld []*ast.Field) string { return prefix } +// anonymousStructTypedef reports whether dt is a C typedef for an anonymous +// struct. +func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool { + st, ok := dt.Type.(*dwarf.StructType) + return ok && st.StructName == "" +} + // badPointerTypedef reports whether t is a C typedef that should not be considered a pointer in Go. // A typedef is bad if C code sometimes stores non-pointers in this type. // TODO: Currently our best solution is to find these manually and list them as diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index b6c1039d9e..210ac13092 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -681,6 +681,19 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { gc.AddAux2(&p.From, v, sc.Off()) p.To.Type = obj.TYPE_CONST p.To.Offset = sc.Val() + case ssa.OpAMD64CMPQloadidx8, ssa.OpAMD64CMPQloadidx1, ssa.OpAMD64CMPLloadidx4, ssa.OpAMD64CMPLloadidx1, ssa.OpAMD64CMPWloadidx2, ssa.OpAMD64CMPWloadidx1, ssa.OpAMD64CMPBloadidx1: + p := s.Prog(v.Op.Asm()) + memIdx(&p.From, v) + gc.AddAux(&p.From, v) + p.To.Type = obj.TYPE_REG + p.To.Reg = v.Args[2].Reg() + case ssa.OpAMD64CMPQconstloadidx8, ssa.OpAMD64CMPQconstloadidx1, ssa.OpAMD64CMPLconstloadidx4, ssa.OpAMD64CMPLconstloadidx1, ssa.OpAMD64CMPWconstloadidx2, ssa.OpAMD64CMPWconstloadidx1, ssa.OpAMD64CMPBconstloadidx1: + sc := v.AuxValAndOff() + p := s.Prog(v.Op.Asm()) + memIdx(&p.From, v) + gc.AddAux2(&p.From, v, sc.Off()) + p.To.Type = obj.TYPE_CONST + p.To.Offset = sc.Val() case ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst: x := v.Reg() @@ -947,7 +960,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { p := s.Prog(obj.ACALL) p.To.Type = obj.TYPE_MEM p.To.Name = obj.NAME_EXTERN - p.To.Sym = v.Aux.(*obj.LSym) + // arg0 is in DI. Set sym to match where regalloc put arg1. + p.To.Sym = gc.GCWriteBarrierReg[v.Args[1].Reg()] case ssa.OpAMD64LoweredPanicBoundsA, ssa.OpAMD64LoweredPanicBoundsB, ssa.OpAMD64LoweredPanicBoundsC: p := s.Prog(obj.ACALL) diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index b6b47440ce..deefed7f19 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -13,6 +13,7 @@ var runtimeDecls = [...]struct { {"panicdivide", funcTag, 5}, {"panicshift", funcTag, 5}, {"panicmakeslicelen", funcTag, 5}, + {"panicmakeslicecap", funcTag, 5}, {"throwinit", funcTag, 5}, {"panicwrap", funcTag, 5}, {"gopanic", funcTag, 7}, diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index afeae3e794..9bcb3688b4 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -18,6 +18,7 @@ func newobject(typ *byte) *any func panicdivide() func panicshift() func panicmakeslicelen() +func panicmakeslicecap() func throwinit() func panicwrap() diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 85c857c214..d2a1b21cbd 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -334,3 +334,6 @@ var ( WasmTruncU, SigPanic *obj.LSym ) + +// GCWriteBarrierReg maps from registers to gcWriteBarrier implementation LSyms. +var GCWriteBarrierReg map[int16]*obj.LSym diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 68acf876f8..b9460ed6d6 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -575,6 +575,12 @@ func inlnode(n *Node, maxCost int32) *Node { // so escape analysis can avoid more heapmoves. case OCLOSURE: return n + case OCALLMETH: + // Prevent inlining some reflect.Value methods when using checkptr, + // even when package reflect was compiled without it (#35073). + if s := n.Left.Sym; Debug_checkptr != 0 && s.Pkg.Path == "reflect" && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") { + return n + } } lno := setlineno(n) diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index b7dc511fd3..00587aa3bf 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -16,6 +16,7 @@ import ( "cmd/compile/internal/ssa" "cmd/compile/internal/types" "cmd/internal/obj" + "cmd/internal/obj/x86" "cmd/internal/objabi" "cmd/internal/src" "cmd/internal/sys" @@ -104,6 +105,20 @@ func initssaconfig() { writeBarrier = sysvar("writeBarrier") // struct { bool; ... } zerobaseSym = sysvar("zerobase") + // asm funcs with special ABI + if thearch.LinkArch.Name == "amd64" { + GCWriteBarrierReg = map[int16]*obj.LSym{ + x86.REG_AX: sysvar("gcWriteBarrier"), + x86.REG_CX: sysvar("gcWriteBarrierCX"), + x86.REG_DX: sysvar("gcWriteBarrierDX"), + x86.REG_BX: sysvar("gcWriteBarrierBX"), + x86.REG_BP: sysvar("gcWriteBarrierBP"), + x86.REG_SI: sysvar("gcWriteBarrierSI"), + x86.REG_R8: sysvar("gcWriteBarrierR8"), + x86.REG_R9: sysvar("gcWriteBarrierR9"), + } + } + if thearch.LinkArch.Family == sys.Wasm { BoundsCheckFunc[ssa.BoundsIndex] = sysvar("goPanicIndex") BoundsCheckFunc[ssa.BoundsIndexU] = sysvar("goPanicIndexU") diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 0a2a11663e..7c1ab89b78 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -542,7 +542,7 @@ func methtype(t *types.Type) *types.Type { // Is type src assignment compatible to type dst? // If so, return op code to use in conversion. // If not, return OXXX. -func assignop(src *types.Type, dst *types.Type, why *string) Op { +func assignop(src, dst *types.Type, why *string) Op { if why != nil { *why = "" } @@ -665,7 +665,8 @@ func assignop(src *types.Type, dst *types.Type, why *string) Op { // Can we convert a value of type src to a value of type dst? // If so, return op code to use in conversion (maybe OCONVNOP). // If not, return OXXX. -func convertop(src *types.Type, dst *types.Type, why *string) Op { +// srcConstant indicates whether the value of type src is a constant. +func convertop(srcConstant bool, src, dst *types.Type, why *string) Op { if why != nil { *why = "" } @@ -741,6 +742,13 @@ func convertop(src *types.Type, dst *types.Type, why *string) Op { return OCONV } + // Special case for constant conversions: any numeric + // conversion is potentially okay. We'll validate further + // within evconst. See #38117. + if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) { + return OCONV + } + // 6. src is an integer or has type []byte or []rune // and dst is a string type. if src.IsInteger() && dst.IsString() { diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 2ca7f2dbe4..6e04908b46 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -1634,7 +1634,7 @@ func typecheck1(n *Node, top int) (res *Node) { return n } var why string - n.Op = convertop(t, n.Type, &why) + n.Op = convertop(n.Left.Op == OLITERAL, t, n.Type, &why) if n.Op == 0 { if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() { yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why) diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 289a75b59c..14d088c7fd 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -354,14 +354,13 @@ func isSmallMakeSlice(n *Node) bool { if n.Op != OMAKESLICE { return false } - l := n.Left r := n.Right if r == nil { - r = l + r = n.Left } t := n.Type - return smallintconst(l) && smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < maxImplicitStackVarSize/t.Elem().Width) + return smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < maxImplicitStackVarSize/t.Elem().Width) } // walk the whole tree of the body of an @@ -1338,6 +1337,20 @@ opswitch: if i < 0 { Fatalf("walkexpr: invalid index %v", r) } + + // cap is constrained to [0,2^31), so it's safe to do: + // + // if uint64(len) > cap { + // if len < 0 { panicmakeslicelen() } + // panicmakeslicecap() + // } + nif := nod(OIF, nod(OGT, conv(l, types.Types[TUINT64]), nodintconst(i)), nil) + niflen := nod(OIF, nod(OLT, l, nodintconst(0)), nil) + niflen.Nbody.Set1(mkcall("panicmakeslicelen", nil, init)) + nif.Nbody.Append(niflen, mkcall("panicmakeslicecap", nil, init)) + nif = typecheck(nif, ctxStmt) + init.Append(nif) + t = types.NewArray(t.Elem(), i) // [r]T var_ := temp(t) a := nod(OAS, var_, nil) // zero temp diff --git a/src/cmd/compile/internal/ssa/addressingmodes.go b/src/cmd/compile/internal/ssa/addressingmodes.go index 8874b56a9b..f06f82420d 100644 --- a/src/cmd/compile/internal/ssa/addressingmodes.go +++ b/src/cmd/compile/internal/ssa/addressingmodes.go @@ -11,8 +11,8 @@ func addressingModes(f *Func) { default: // Most architectures can't do this. return - case "amd64": - // TODO: 386, s390x? + case "amd64", "386": + // TODO: s390x? } var tmp []*Value @@ -21,7 +21,17 @@ func addressingModes(f *Func) { if !combineFirst[v.Op] { continue } - p := v.Args[0] + // All matched operations have the pointer in arg[0]. + // All results have the pointer in arg[0] and the index in arg[1]. + // *Except* for operations which update a register, + // which are marked with resultInArg0. Those have + // the pointer in arg[1], and the corresponding result op + // has the pointer in arg[1] and the index in arg[2]. + ptrIndex := 0 + if opcodeTable[v.Op].resultInArg0 { + ptrIndex = 1 + } + p := v.Args[ptrIndex] c, ok := combine[[2]Op{v.Op, p.Op}] if !ok { continue @@ -71,10 +81,11 @@ func addressingModes(f *Func) { f.Fatalf("unknown aux combining for %s and %s\n", v.Op, p.Op) } // Combine the operations. - tmp = append(tmp[:0], v.Args[1:]...) + tmp = append(tmp[:0], v.Args[:ptrIndex]...) + tmp = append(tmp, p.Args...) + tmp = append(tmp, v.Args[ptrIndex+1:]...) v.resetArgs() v.Op = c - v.AddArgs(p.Args...) v.AddArgs(tmp...) } } @@ -97,6 +108,7 @@ func init() { // x.Args[0].Args + x.Args[1:] // Additionally, the Aux/AuxInt from x.Args[0] is merged into x. var combine = map[[2]Op]Op{ + // amd64 [2]Op{OpAMD64MOVBload, OpAMD64ADDQ}: OpAMD64MOVBloadidx1, [2]Op{OpAMD64MOVWload, OpAMD64ADDQ}: OpAMD64MOVWloadidx1, [2]Op{OpAMD64MOVLload, OpAMD64ADDQ}: OpAMD64MOVLloadidx1, @@ -150,5 +162,90 @@ var combine = map[[2]Op]Op{ [2]Op{OpAMD64MOVQstoreconst, OpAMD64LEAQ1}: OpAMD64MOVQstoreconstidx1, [2]Op{OpAMD64MOVQstoreconst, OpAMD64LEAQ8}: OpAMD64MOVQstoreconstidx8, - // TODO: 386 + [2]Op{OpAMD64CMPBload, OpAMD64ADDQ}: OpAMD64CMPBloadidx1, + [2]Op{OpAMD64CMPWload, OpAMD64ADDQ}: OpAMD64CMPWloadidx1, + [2]Op{OpAMD64CMPLload, OpAMD64ADDQ}: OpAMD64CMPLloadidx1, + [2]Op{OpAMD64CMPQload, OpAMD64ADDQ}: OpAMD64CMPQloadidx1, + + [2]Op{OpAMD64CMPBload, OpAMD64LEAQ1}: OpAMD64CMPBloadidx1, + [2]Op{OpAMD64CMPWload, OpAMD64LEAQ1}: OpAMD64CMPWloadidx1, + [2]Op{OpAMD64CMPWload, OpAMD64LEAQ2}: OpAMD64CMPWloadidx2, + [2]Op{OpAMD64CMPLload, OpAMD64LEAQ1}: OpAMD64CMPLloadidx1, + [2]Op{OpAMD64CMPLload, OpAMD64LEAQ4}: OpAMD64CMPLloadidx4, + [2]Op{OpAMD64CMPQload, OpAMD64LEAQ1}: OpAMD64CMPQloadidx1, + [2]Op{OpAMD64CMPQload, OpAMD64LEAQ8}: OpAMD64CMPQloadidx8, + + [2]Op{OpAMD64CMPBconstload, OpAMD64ADDQ}: OpAMD64CMPBconstloadidx1, + [2]Op{OpAMD64CMPWconstload, OpAMD64ADDQ}: OpAMD64CMPWconstloadidx1, + [2]Op{OpAMD64CMPLconstload, OpAMD64ADDQ}: OpAMD64CMPLconstloadidx1, + [2]Op{OpAMD64CMPQconstload, OpAMD64ADDQ}: OpAMD64CMPQconstloadidx1, + + [2]Op{OpAMD64CMPBconstload, OpAMD64LEAQ1}: OpAMD64CMPBconstloadidx1, + [2]Op{OpAMD64CMPWconstload, OpAMD64LEAQ1}: OpAMD64CMPWconstloadidx1, + [2]Op{OpAMD64CMPWconstload, OpAMD64LEAQ2}: OpAMD64CMPWconstloadidx2, + [2]Op{OpAMD64CMPLconstload, OpAMD64LEAQ1}: OpAMD64CMPLconstloadidx1, + [2]Op{OpAMD64CMPLconstload, OpAMD64LEAQ4}: OpAMD64CMPLconstloadidx4, + [2]Op{OpAMD64CMPQconstload, OpAMD64LEAQ1}: OpAMD64CMPQconstloadidx1, + [2]Op{OpAMD64CMPQconstload, OpAMD64LEAQ8}: OpAMD64CMPQconstloadidx8, + + // 386 + [2]Op{Op386MOVBload, Op386ADDL}: Op386MOVBloadidx1, + [2]Op{Op386MOVWload, Op386ADDL}: Op386MOVWloadidx1, + [2]Op{Op386MOVLload, Op386ADDL}: Op386MOVLloadidx1, + [2]Op{Op386MOVSSload, Op386ADDL}: Op386MOVSSloadidx1, + [2]Op{Op386MOVSDload, Op386ADDL}: Op386MOVSDloadidx1, + + [2]Op{Op386MOVBstore, Op386ADDL}: Op386MOVBstoreidx1, + [2]Op{Op386MOVWstore, Op386ADDL}: Op386MOVWstoreidx1, + [2]Op{Op386MOVLstore, Op386ADDL}: Op386MOVLstoreidx1, + [2]Op{Op386MOVSSstore, Op386ADDL}: Op386MOVSSstoreidx1, + [2]Op{Op386MOVSDstore, Op386ADDL}: Op386MOVSDstoreidx1, + + [2]Op{Op386MOVBstoreconst, Op386ADDL}: Op386MOVBstoreconstidx1, + [2]Op{Op386MOVWstoreconst, Op386ADDL}: Op386MOVWstoreconstidx1, + [2]Op{Op386MOVLstoreconst, Op386ADDL}: Op386MOVLstoreconstidx1, + + [2]Op{Op386MOVBload, Op386LEAL1}: Op386MOVBloadidx1, + [2]Op{Op386MOVWload, Op386LEAL1}: Op386MOVWloadidx1, + [2]Op{Op386MOVWload, Op386LEAL2}: Op386MOVWloadidx2, + [2]Op{Op386MOVLload, Op386LEAL1}: Op386MOVLloadidx1, + [2]Op{Op386MOVLload, Op386LEAL4}: Op386MOVLloadidx4, + [2]Op{Op386MOVSSload, Op386LEAL1}: Op386MOVSSloadidx1, + [2]Op{Op386MOVSSload, Op386LEAL4}: Op386MOVSSloadidx4, + [2]Op{Op386MOVSDload, Op386LEAL1}: Op386MOVSDloadidx1, + [2]Op{Op386MOVSDload, Op386LEAL8}: Op386MOVSDloadidx8, + + [2]Op{Op386MOVBstore, Op386LEAL1}: Op386MOVBstoreidx1, + [2]Op{Op386MOVWstore, Op386LEAL1}: Op386MOVWstoreidx1, + [2]Op{Op386MOVWstore, Op386LEAL2}: Op386MOVWstoreidx2, + [2]Op{Op386MOVLstore, Op386LEAL1}: Op386MOVLstoreidx1, + [2]Op{Op386MOVLstore, Op386LEAL4}: Op386MOVLstoreidx4, + [2]Op{Op386MOVSSstore, Op386LEAL1}: Op386MOVSSstoreidx1, + [2]Op{Op386MOVSSstore, Op386LEAL4}: Op386MOVSSstoreidx4, + [2]Op{Op386MOVSDstore, Op386LEAL1}: Op386MOVSDstoreidx1, + [2]Op{Op386MOVSDstore, Op386LEAL8}: Op386MOVSDstoreidx8, + + [2]Op{Op386MOVBstoreconst, Op386LEAL1}: Op386MOVBstoreconstidx1, + [2]Op{Op386MOVWstoreconst, Op386LEAL1}: Op386MOVWstoreconstidx1, + [2]Op{Op386MOVWstoreconst, Op386LEAL2}: Op386MOVWstoreconstidx2, + [2]Op{Op386MOVLstoreconst, Op386LEAL1}: Op386MOVLstoreconstidx1, + [2]Op{Op386MOVLstoreconst, Op386LEAL4}: Op386MOVLstoreconstidx4, + + [2]Op{Op386ADDLload, Op386LEAL4}: Op386ADDLloadidx4, + [2]Op{Op386SUBLload, Op386LEAL4}: Op386SUBLloadidx4, + [2]Op{Op386MULLload, Op386LEAL4}: Op386MULLloadidx4, + [2]Op{Op386ANDLload, Op386LEAL4}: Op386ANDLloadidx4, + [2]Op{Op386ORLload, Op386LEAL4}: Op386ORLloadidx4, + [2]Op{Op386XORLload, Op386LEAL4}: Op386XORLloadidx4, + + [2]Op{Op386ADDLmodify, Op386LEAL4}: Op386ADDLmodifyidx4, + [2]Op{Op386SUBLmodify, Op386LEAL4}: Op386SUBLmodifyidx4, + [2]Op{Op386ANDLmodify, Op386LEAL4}: Op386ANDLmodifyidx4, + [2]Op{Op386ORLmodify, Op386LEAL4}: Op386ORLmodifyidx4, + [2]Op{Op386XORLmodify, Op386LEAL4}: Op386XORLmodifyidx4, + + [2]Op{Op386ADDLconstmodify, Op386LEAL4}: Op386ADDLconstmodifyidx4, + [2]Op{Op386ANDLconstmodify, Op386LEAL4}: Op386ANDLconstmodifyidx4, + [2]Op{Op386ORLconstmodify, Op386LEAL4}: Op386ORLconstmodifyidx4, + [2]Op{Op386XORLconstmodify, Op386LEAL4}: Op386XORLconstmodifyidx4, } diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules index 64a6cbaf84..2c48994a5f 100644 --- a/src/cmd/compile/internal/ssa/gen/386.rules +++ b/src/cmd/compile/internal/ssa/gen/386.rules @@ -588,10 +588,6 @@ (MOVWLSX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWLSXload <v.Type> [off] {sym} ptr mem) (MOVWLZX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem) -(MOVBLZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem) -(MOVWLZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem) -(MOVWLZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem) - // replace load from same location as preceding store with zero/sign extension (or copy in case of full width) (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLZX x) (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLZX x) @@ -611,34 +607,22 @@ // fold constants into memory operations // Note that this is not always a good idea because if not all the uses of -// the ADDQconst get eliminated, we still have to compute the ADDQconst and we now -// have potentially two live values (ptr and (ADDQconst [off] ptr)) instead of one. +// the ADDLconst get eliminated, we still have to compute the ADDLconst and we now +// have potentially two live values (ptr and (ADDLconst [off] ptr)) instead of one. // Nevertheless, let's do it! (MOV(L|W|B|SS|SD)load [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOV(L|W|B|SS|SD)load [off1+off2] {sym} ptr mem) (MOV(L|W|B|SS|SD)store [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOV(L|W|B|SS|SD)store [off1+off2] {sym} ptr val mem) ((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) -> ((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {sym} val base mem) -((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) && is32Bit(off1+off2) -> - ((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {sym} val base idx mem) -((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) && is32Bit(off1+off2*4) -> - ((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2*4] {sym} val base idx mem) ((ADD|SUB|MUL|DIV)SSload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) -> ((ADD|SUB|MUL|DIV)SSload [off1+off2] {sym} val base mem) ((ADD|SUB|MUL|DIV)SDload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) -> ((ADD|SUB|MUL|DIV)SDload [off1+off2] {sym} val base mem) ((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym} (ADDLconst [off2] base) val mem) && is32Bit(off1+off2) -> ((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {sym} base val mem) -((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem) && is32Bit(off1+off2) -> - ((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2] {sym} base idx val mem) -((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem) && is32Bit(off1+off2*4) -> - ((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2*4] {sym} base idx val mem) ((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) && ValAndOff(valoff1).canAdd(off2) -> ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) -((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem) && ValAndOff(valoff1).canAdd(off2) -> - ((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem) -((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem) && ValAndOff(valoff1).canAdd(off2*4) -> - ((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem) // Fold constants into stores. (MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) -> @@ -652,7 +636,7 @@ (MOV(L|W|B)storeconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) -> (MOV(L|W|B)storeconst [ValAndOff(sc).add(off)] {s} ptr mem) -// We need to fold LEAQ into the MOVx ops so that the live variable analysis knows +// We need to fold LEAL into the MOVx ops so that the live variable analysis knows // what variables are being read/written by the ops. // Note: we turn off this merging for operations on globals when building // position-independent code (when Flag_shared is set). @@ -672,31 +656,9 @@ && (ptr.Op != OpSB || !config.ctxt.Flag_shared) -> (MOV(L|W|B)storeconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem) -// generating indexed loads and stores -(MOV(B|W|L|SS|SD)load [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - (MOV(B|W|L|SS|SD)loadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) -(MOVWload [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - (MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) -(MOV(L|SS)load [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - (MOV(L|SS)loadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) -(MOVSDload [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - -(MOV(B|W|L|SS|SD)store [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - (MOV(B|W|L|SS|SD)storeidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) -(MOVWstore [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - (MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) -(MOV(L|SS)store [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - (MOV(L|SS)storeidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) -(MOVSDstore [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - ((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> ((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem) -((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem) - && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> - ((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem) ((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> ((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem) @@ -706,97 +668,20 @@ ((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> ((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) -((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem) - && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> - ((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem) ((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem) && ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) -((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem) - && ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> - ((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem) - -(MOV(B|W|L|SS|SD)load [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)loadidx1 [off] {sym} ptr idx mem) -(MOV(B|W|L|SS|SD)store [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)storeidx1 [off] {sym} ptr idx val mem) - -(MOV(B|W|L)storeconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) -> - (MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem) -(MOVWstoreconst [x] {sym1} (LEAL2 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) -> - (MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem) -(MOVLstoreconst [x] {sym1} (LEAL4 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) -> - (MOVLstoreconstidx4 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem) - -(MOV(B|W|L)storeconst [x] {sym} (ADDL ptr idx) mem) -> (MOV(B|W|L)storeconstidx1 [x] {sym} ptr idx mem) - -// combine SHLL into indexed loads and stores -(MOVWloadidx1 [c] {sym} ptr (SHLLconst [1] idx) mem) -> (MOVWloadidx2 [c] {sym} ptr idx mem) -(MOVLloadidx1 [c] {sym} ptr (SHLLconst [2] idx) mem) -> (MOVLloadidx4 [c] {sym} ptr idx mem) -(MOVWstoreidx1 [c] {sym} ptr (SHLLconst [1] idx) val mem) -> (MOVWstoreidx2 [c] {sym} ptr idx val mem) -(MOVLstoreidx1 [c] {sym} ptr (SHLLconst [2] idx) val mem) -> (MOVLstoreidx4 [c] {sym} ptr idx val mem) -(MOVWstoreconstidx1 [c] {sym} ptr (SHLLconst [1] idx) mem) -> (MOVWstoreconstidx2 [c] {sym} ptr idx mem) -(MOVLstoreconstidx1 [c] {sym} ptr (SHLLconst [2] idx) mem) -> (MOVLstoreconstidx4 [c] {sym} ptr idx mem) - -// combine ADDL into indexed loads and stores -(MOV(B|W|L|SS|SD)loadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOV(B|W|L|SS|SD)loadidx1 [int64(int32(c+d))] {sym} ptr idx mem) -(MOVWloadidx2 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVWloadidx2 [int64(int32(c+d))] {sym} ptr idx mem) -(MOV(L|SS)loadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOV(L|SS)loadidx4 [int64(int32(c+d))] {sym} ptr idx mem) -(MOVSDloadidx8 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSDloadidx8 [int64(int32(c+d))] {sym} ptr idx mem) - -(MOV(B|W|L|SS|SD)storeidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOV(B|W|L|SS|SD)storeidx1 [int64(int32(c+d))] {sym} ptr idx val mem) -(MOVWstoreidx2 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVWstoreidx2 [int64(int32(c+d))] {sym} ptr idx val mem) -(MOV(L|SS)storeidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOV(L|SS)storeidx4 [int64(int32(c+d))] {sym} ptr idx val mem) -(MOVSDstoreidx8 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSDstoreidx8 [int64(int32(c+d))] {sym} ptr idx val mem) - -(MOV(B|W|L|SS|SD)loadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOV(B|W|L|SS|SD)loadidx1 [int64(int32(c+d))] {sym} ptr idx mem) -(MOVWloadidx2 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVWloadidx2 [int64(int32(c+2*d))] {sym} ptr idx mem) -(MOV(L|SS)loadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOV(L|SS)loadidx4 [int64(int32(c+4*d))] {sym} ptr idx mem) -(MOVSDloadidx8 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSDloadidx8 [int64(int32(c+8*d))] {sym} ptr idx mem) - -(MOV(B|W|L|SS|SD)storeidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOV(B|W|L|SS|SD)storeidx1 [int64(int32(c+d))] {sym} ptr idx val mem) -(MOVWstoreidx2 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVWstoreidx2 [int64(int32(c+2*d))] {sym} ptr idx val mem) -(MOV(L|SS)storeidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOV(L|SS)storeidx4 [int64(int32(c+4*d))] {sym} ptr idx val mem) -(MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSDstoreidx8 [int64(int32(c+8*d))] {sym} ptr idx val mem) // Merge load/store to op ((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) -> ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem) -((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) && canMergeLoadClobber(v, l, x) && clobber(l) -> - ((ADD|AND|OR|XOR|SUB|MUL)Lloadidx4 x [off] {sym} ptr idx mem) -((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem) - && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - ((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem) ((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem) ((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem) (MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem) (MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) -> ((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem) -(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|AND|OR|XOR)Lloadidx4 x [off] {sym} ptr idx mem) mem) && y.Uses==1 && clobber(y) -> - ((ADD|AND|OR|XOR)Lmodifyidx4 [off] {sym} ptr idx x mem) -(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|SUB|AND|OR|XOR)L l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) -> - ((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off] {sym} ptr idx x mem) (MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(c,off) -> ((ADD|AND|OR|XOR)Lconstmodify [makeValAndOff(c,off)] {sym} ptr mem) -(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem) - && y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(c,off) -> - ((ADD|AND|OR|XOR)Lconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) -((ADD|AND|OR|XOR)Lmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) && validValAndOff(c,off) -> - ((ADD|AND|OR|XOR)Lconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) -(SUBLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) && validValAndOff(-c,off) -> - (ADDLconstmodifyidx4 [makeValAndOff(-c,off)] {sym} ptr idx mem) - -(MOV(B|W|L)storeconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) -> - (MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem) -(MOVWstoreconstidx2 [x] {sym} (ADDLconst [c] ptr) idx mem) -> - (MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem) -(MOVLstoreconstidx4 [x] {sym} (ADDLconst [c] ptr) idx mem) -> - (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem) - -(MOV(B|W|L)storeconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) -> - (MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem) -(MOVWstoreconstidx2 [x] {sym} ptr (ADDLconst [c] idx) mem) -> - (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem) -(MOVLstoreconstidx4 [x] {sym} ptr (ADDLconst [c] idx) mem) -> - (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem) // fold LEALs together (LEAL [off1] {sym1} (LEAL [off2] {sym2} x)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> @@ -826,6 +711,16 @@ (LEAL [off1] {sym1} (LEAL8 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> (LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y) +// LEAL[1248] into LEAL[1248]. Only some such merges are possible. +(LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} y y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> + (LEAL2 [off1+off2] {mergeSym(sym1, sym2)} x y) +(LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> + (LEAL2 [off1+off2] {mergeSym(sym1, sym2)} y x) +(LEAL2 [off1] {sym} x (LEAL1 [off2] {nil} y y)) && is32Bit(off1+2*off2) -> + (LEAL4 [off1+2*off2] {sym} x y) +(LEAL4 [off1] {sym} x (LEAL1 [off2] {nil} y y)) && is32Bit(off1+4*off2) -> + (LEAL8 [off1+4*off2] {sym} x y) + // Absorb InvertFlags into branches. (LT (InvertFlags cmp) yes no) -> (GT cmp yes no) (GT (InvertFlags cmp) yes no) -> (LT cmp yes no) @@ -1039,6 +934,9 @@ // TEST %reg,%reg is shorter than CMP (CMP(L|W|B)const x [0]) -> (TEST(L|W|B) x x) +// Convert LEAL1 back to ADDL if we can +(LEAL1 [0] {nil} x y) -> (ADDL x y) + // Combining byte loads into larger (unaligned) loads. // There are many ways these combinations could occur. This is // designed to match the way encoding/binary.LittleEndian does it. @@ -1052,6 +950,16 @@ && clobber(x0, x1, s0) -> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem) +(ORL x0:(MOVBload [i] {s} p0 mem) + s0:(SHLLconst [8] x1:(MOVBload [i] {s} p1 mem))) + && x0.Uses == 1 + && x1.Uses == 1 + && s0.Uses == 1 + && sequentialAddresses(p0, p1, 1) + && mergePoint(b,x0,x1) != nil + && clobber(x0, x1, s0) + -> @mergePoint(b,x0,x1) (MOVWload [i] {s} p0 mem) + (ORL o0:(ORL x0:(MOVWload [i0] {s} p mem) s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p mem))) @@ -1068,31 +976,21 @@ && clobber(x0, x1, x2, s0, s1, o0) -> @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p mem) -(ORL x0:(MOVBloadidx1 [i0] {s} p idx mem) - s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem))) - && i1==i0+1 - && x0.Uses == 1 - && x1.Uses == 1 - && s0.Uses == 1 - && mergePoint(b,x0,x1) != nil - && clobber(x0, x1, s0) - -> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem) - (ORL o0:(ORL - x0:(MOVWloadidx1 [i0] {s} p idx mem) - s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))) - s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem))) - && i2 == i0+2 - && i3 == i0+3 + x0:(MOVWload [i] {s} p0 mem) + s0:(SHLLconst [16] x1:(MOVBload [i] {s} p1 mem))) + s1:(SHLLconst [24] x2:(MOVBload [i] {s} p2 mem))) && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 + && sequentialAddresses(p0, p1, 2) + && sequentialAddresses(p1, p2, 1) && mergePoint(b,x0,x1,x2) != nil && clobber(x0, x1, x2, s0, s1, o0) - -> @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem) + -> @mergePoint(b,x0,x1,x2) (MOVLload [i] {s} p0 mem) // Combine constant stores into larger (unaligned) stores. (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem)) @@ -1105,6 +1003,20 @@ && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x) -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem) + +(MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem)) + && x.Uses == 1 + && ValAndOff(a).Off() == ValAndOff(c).Off() + && sequentialAddresses(p0, p1, 1) + && clobber(x) + -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem) +(MOVBstoreconst [a] {s} p0 x:(MOVBstoreconst [c] {s} p1 mem)) + && x.Uses == 1 + && ValAndOff(a).Off() == ValAndOff(c).Off() + && sequentialAddresses(p0, p1, 1) + && clobber(x) + -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem) + (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) && x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() @@ -1116,22 +1028,18 @@ && clobber(x) -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem) -(MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem)) - && x.Uses == 1 - && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() - && clobber(x) - -> (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem) -(MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem)) +(MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem)) && x.Uses == 1 - && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() + && ValAndOff(a).Off() == ValAndOff(c).Off() + && sequentialAddresses(p0, p1, 2) && clobber(x) - -> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem) - -(MOVWstoreconstidx2 [c] {s} p i x:(MOVWstoreconstidx2 [a] {s} p i mem)) + -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem) +(MOVWstoreconst [a] {s} p0 x:(MOVWstoreconst [c] {s} p1 mem)) && x.Uses == 1 - && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() + && ValAndOff(a).Off() == ValAndOff(c).Off() + && sequentialAddresses(p0, p1, 2) && clobber(x) - -> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLLconst <i.Type> [1] i) mem) + -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem) // Combine stores into larger (unaligned) stores. (MOVBstore [i] {s} p (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p w mem)) @@ -1146,44 +1054,42 @@ && x.Uses == 1 && clobber(x) -> (MOVWstore [i-1] {s} p w0 mem) -(MOVWstore [i] {s} p (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p w mem)) - && x.Uses == 1 - && clobber(x) - -> (MOVLstore [i-2] {s} p w mem) -(MOVWstore [i] {s} p (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRLconst [j-16] w) mem)) - && x.Uses == 1 - && clobber(x) - -> (MOVLstore [i-2] {s} p w0 mem) -(MOVBstoreidx1 [i] {s} p idx (SHR(L|W)const [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem)) +(MOVBstore [i] {s} p1 (SHR(W|L)const [8] w) x:(MOVBstore [i] {s} p0 w mem)) && x.Uses == 1 + && sequentialAddresses(p0, p1, 1) && clobber(x) - -> (MOVWstoreidx1 [i-1] {s} p idx w mem) -(MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} p idx (SHR(L|W)const [8] w) mem)) + -> (MOVWstore [i] {s} p0 w mem) +(MOVBstore [i] {s} p0 w x:(MOVBstore {s} [i] p1 (SHR(W|L)const [8] w) mem)) && x.Uses == 1 + && sequentialAddresses(p0, p1, 1) && clobber(x) - -> (MOVWstoreidx1 [i] {s} p idx w mem) -(MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem)) + -> (MOVWstore [i] {s} p0 w mem) +(MOVBstore [i] {s} p1 (SHRLconst [j] w) x:(MOVBstore [i] {s} p0 w0:(SHRLconst [j-8] w) mem)) && x.Uses == 1 + && sequentialAddresses(p0, p1, 1) && clobber(x) - -> (MOVWstoreidx1 [i-1] {s} p idx w0 mem) -(MOVWstoreidx1 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem)) + -> (MOVWstore [i] {s} p0 w0 mem) + +(MOVWstore [i] {s} p (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p w mem)) && x.Uses == 1 && clobber(x) - -> (MOVLstoreidx1 [i-2] {s} p idx w mem) -(MOVWstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem)) + -> (MOVLstore [i-2] {s} p w mem) +(MOVWstore [i] {s} p (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRLconst [j-16] w) mem)) && x.Uses == 1 && clobber(x) - -> (MOVLstoreidx1 [i-2] {s} p idx w0 mem) + -> (MOVLstore [i-2] {s} p w0 mem) -(MOVWstoreidx2 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem)) +(MOVWstore [i] {s} p1 (SHRLconst [16] w) x:(MOVWstore [i] {s} p0 w mem)) && x.Uses == 1 + && sequentialAddresses(p0, p1, 2) && clobber(x) - -> (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w mem) -(MOVWstoreidx2 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem)) + -> (MOVLstore [i] {s} p0 w mem) +(MOVWstore [i] {s} p1 (SHRLconst [j] w) x:(MOVWstore [i] {s} p0 w0:(SHRLconst [j-16] w) mem)) && x.Uses == 1 + && sequentialAddresses(p0, p1, 2) && clobber(x) - -> (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w0 mem) + -> (MOVLstore [i] {s} p0 w0 mem) // For PIC, break floating-point constant loading into two instructions so we have // a register to use for holding the address of the constant pool entry. diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 306847d28c..b5133d6c14 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -1491,65 +1491,70 @@ // Little-endian loads -(ORL x0:(MOVBload [i0] {s} p0 mem) - sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p1 mem))) +(OR(L|Q) x0:(MOVBload [i0] {s} p mem) + sh:(SHL(L|Q)const [8] x1:(MOVBload [i1] {s} p mem))) && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - -> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p0 mem) + -> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem) -(ORQ x0:(MOVBload [i0] {s} p0 mem) - sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p1 mem))) - && i1 == i0+1 +(OR(L|Q) x0:(MOVBload [i] {s} p0 mem) + sh:(SHL(L|Q)const [8] x1:(MOVBload [i] {s} p1 mem))) && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - -> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p0 mem) + -> @mergePoint(b,x0,x1) (MOVWload [i] {s} p0 mem) -(ORL x0:(MOVWload [i0] {s} p0 mem) - sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p1 mem))) +(OR(L|Q) x0:(MOVWload [i0] {s} p mem) + sh:(SHL(L|Q)const [16] x1:(MOVWload [i1] {s} p mem))) && i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - -> @mergePoint(b,x0,x1) (MOVLload [i0] {s} p0 mem) + -> @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem) -(ORQ x0:(MOVWload [i0] {s} p0 mem) - sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p1 mem))) - && i1 == i0+2 +(OR(L|Q) x0:(MOVWload [i] {s} p0 mem) + sh:(SHL(L|Q)const [16] x1:(MOVWload [i] {s} p1 mem))) && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 2) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - -> @mergePoint(b,x0,x1) (MOVLload [i0] {s} p0 mem) + -> @mergePoint(b,x0,x1) (MOVLload [i] {s} p0 mem) -(ORQ x0:(MOVLload [i0] {s} p0 mem) - sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p1 mem))) +(ORQ x0:(MOVLload [i0] {s} p mem) + sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p mem))) && i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - -> @mergePoint(b,x0,x1) (MOVQload [i0] {s} p0 mem) + -> @mergePoint(b,x0,x1) (MOVQload [i0] {s} p mem) -(ORL - s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p0 mem)) - or:(ORL - s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p1 mem)) +(ORQ x0:(MOVLload [i] {s} p0 mem) + sh:(SHLQconst [32] x1:(MOVLload [i] {s} p1 mem))) + && x0.Uses == 1 + && x1.Uses == 1 + && sh.Uses == 1 + && sequentialAddresses(p0, p1, 4) + && mergePoint(b,x0,x1) != nil + && clobber(x0, x1, sh) + -> @mergePoint(b,x0,x1) (MOVQload [i] {s} p0 mem) + +(OR(L|Q) + s1:(SHL(L|Q)const [j1] x1:(MOVBload [i1] {s} p mem)) + or:(OR(L|Q) + s0:(SHL(L|Q)const [j0] x0:(MOVBload [i0] {s} p mem)) y)) && i1 == i0+1 && j1 == j0+8 @@ -1559,17 +1564,15 @@ && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - -> @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p0 mem)) y) + -> @mergePoint(b,x0,x1,y) (OR(L|Q) <v.Type> (SHL(L|Q)const <v.Type> [j0] (MOVWload [i0] {s} p mem)) y) -(ORQ - s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p0 mem)) - or:(ORQ - s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p1 mem)) +(OR(L|Q) + s1:(SHL(L|Q)const [j1] x1:(MOVBload [i] {s} p1 mem)) + or:(OR(L|Q) + s0:(SHL(L|Q)const [j0] x0:(MOVBload [i] {s} p0 mem)) y)) - && i1 == i0+1 && j1 == j0+8 && j0 % 16 == 0 && x0.Uses == 1 @@ -1577,15 +1580,15 @@ && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - -> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p0 mem)) y) + -> @mergePoint(b,x0,x1,y) (OR(L|Q) <v.Type> (SHL(L|Q)const <v.Type> [j0] (MOVWload [i] {s} p0 mem)) y) (ORQ - s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p0 mem)) + s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p mem)) or:(ORQ - s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p1 mem)) + s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p mem)) y)) && i1 == i0+2 && j1 == j0+16 @@ -1595,105 +1598,107 @@ && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - -> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p0 mem)) y) - -// Little-endian indexed loads - -// Move constants offsets from LEAQx up into load. This lets the above combining -// rules discover indexed load-combining instances. -(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ1 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1) --> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) mem) -(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ2 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1) --> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) mem) -(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ4 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1) --> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) mem) -(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ8 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1) --> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) mem) - -(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ1 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1) --> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) val mem) -(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ2 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1) --> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) val mem) -(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ4 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1) --> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) val mem) -(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ8 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1) --> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) val mem) + -> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p mem)) y) + +(ORQ + s1:(SHLQconst [j1] x1:(MOVWload [i] {s} p1 mem)) + or:(ORQ + s0:(SHLQconst [j0] x0:(MOVWload [i] {s} p0 mem)) + y)) + && j1 == j0+16 + && j0 % 32 == 0 + && x0.Uses == 1 + && x1.Uses == 1 + && s0.Uses == 1 + && s1.Uses == 1 + && or.Uses == 1 + && sequentialAddresses(p0, p1, 2) + && mergePoint(b,x0,x1,y) != nil + && clobber(x0, x1, s0, s1, or) + -> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i] {s} p0 mem)) y) // Big-endian loads -(ORL - x1:(MOVBload [i1] {s} p0 mem) - sh:(SHLLconst [8] x0:(MOVBload [i0] {s} p1 mem))) +(OR(L|Q) + x1:(MOVBload [i1] {s} p mem) + sh:(SHL(L|Q)const [8] x0:(MOVBload [i0] {s} p mem))) && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - -> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p0 mem)) + -> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem)) -(ORQ - x1:(MOVBload [i1] {s} p0 mem) - sh:(SHLQconst [8] x0:(MOVBload [i0] {s} p1 mem))) - && i1 == i0+1 +(OR(L|Q) + x1:(MOVBload [i] {s} p1 mem) + sh:(SHL(L|Q)const [8] x0:(MOVBload [i] {s} p0 mem))) && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - -> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p0 mem)) + -> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i] {s} p0 mem)) -(ORL - r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p0 mem)) - sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p1 mem)))) +(OR(L|Q) + r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)) + sh:(SHL(L|Q)const [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem)))) && i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) - -> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p0 mem)) + -> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem)) -(ORQ - r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p0 mem)) - sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p1 mem)))) - && i1 == i0+2 +(OR(L|Q) + r1:(ROLWconst [8] x1:(MOVWload [i] {s} p1 mem)) + sh:(SHL(L|Q)const [16] r0:(ROLWconst [8] x0:(MOVWload [i] {s} p0 mem)))) && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 2) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) - -> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p0 mem)) + -> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i] {s} p0 mem)) (ORQ - r1:(BSWAPL x1:(MOVLload [i1] {s} p0 mem)) - sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p1 mem)))) + r1:(BSWAPL x1:(MOVLload [i1] {s} p mem)) + sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p mem)))) && i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) - -> @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i0] {s} p0 mem)) + -> @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i0] {s} p mem)) + +(ORQ + r1:(BSWAPL x1:(MOVLload [i] {s} p1 mem)) + sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i] {s} p0 mem)))) + && x0.Uses == 1 + && x1.Uses == 1 + && r0.Uses == 1 + && r1.Uses == 1 + && sh.Uses == 1 + && sequentialAddresses(p0, p1, 4) + && mergePoint(b,x0,x1) != nil + && clobber(x0, x1, r0, r1, sh) + -> @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i] {s} p0 mem)) -(ORL - s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p0 mem)) - or:(ORL - s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p1 mem)) +(OR(L|Q) + s0:(SHL(L|Q)const [j0] x0:(MOVBload [i0] {s} p mem)) + or:(OR(L|Q) + s1:(SHL(L|Q)const [j1] x1:(MOVBload [i1] {s} p mem)) y)) && i1 == i0+1 && j1 == j0-8 @@ -1703,17 +1708,15 @@ && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - -> @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p0 mem))) y) + -> @mergePoint(b,x0,x1,y) (OR(L|Q) <v.Type> (SHL(L|Q)const <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y) -(ORQ - s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p0 mem)) - or:(ORQ - s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p1 mem)) +(OR(L|Q) + s0:(SHL(L|Q)const [j0] x0:(MOVBload [i] {s} p0 mem)) + or:(OR(L|Q) + s1:(SHL(L|Q)const [j1] x1:(MOVBload [i] {s} p1 mem)) y)) - && i1 == i0+1 && j1 == j0-8 && j1 % 16 == 0 && x0.Uses == 1 @@ -1721,15 +1724,15 @@ && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - -> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p0 mem))) y) + -> @mergePoint(b,x0,x1,y) (OR(L|Q) <v.Type> (SHL(L|Q)const <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i] {s} p0 mem))) y) (ORQ - s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p0 mem))) + s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))) or:(ORQ - s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p1 mem))) + s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))) y)) && i1 == i0+2 && j1 == j0-16 @@ -1741,41 +1744,90 @@ && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 - && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, r0, r1, s0, s1, or) - -> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p0 mem))) y) + -> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p mem))) y) + +(ORQ + s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i] {s} p0 mem))) + or:(ORQ + s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i] {s} p1 mem))) + y)) + && j1 == j0-16 + && j1 % 32 == 0 + && x0.Uses == 1 + && x1.Uses == 1 + && r0.Uses == 1 + && r1.Uses == 1 + && s0.Uses == 1 + && s1.Uses == 1 + && or.Uses == 1 + && sequentialAddresses(p0, p1, 2) + && mergePoint(b,x0,x1,y) != nil + && clobber(x0, x1, r0, r1, s0, s1, or) + -> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i] {s} p0 mem))) y) // Combine 2 byte stores + shift into rolw 8 + word store +(MOVBstore [i] {s} p w + x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem)) + && x0.Uses == 1 + && clobber(x0) + -> (MOVWstore [i-1] {s} p (ROLWconst <w.Type> [8] w) mem) (MOVBstore [i] {s} p1 w - x0:(MOVBstore [i-1] {s} p0 (SHRWconst [8] w) mem)) + x0:(MOVBstore [i] {s} p0 (SHRWconst [8] w) mem)) && x0.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 1) && clobber(x0) - -> (MOVWstore [i-1] {s} p0 (ROLWconst <w.Type> [8] w) mem) + -> (MOVWstore [i] {s} p0 (ROLWconst <w.Type> [8] w) mem) // Combine stores + shifts into bswap and larger (unaligned) stores +(MOVBstore [i] {s} p w + x2:(MOVBstore [i-1] {s} p (SHRLconst [8] w) + x1:(MOVBstore [i-2] {s} p (SHRLconst [16] w) + x0:(MOVBstore [i-3] {s} p (SHRLconst [24] w) mem)))) + && x0.Uses == 1 + && x1.Uses == 1 + && x2.Uses == 1 + && clobber(x0, x1, x2) + -> (MOVLstore [i-3] {s} p (BSWAPL <w.Type> w) mem) (MOVBstore [i] {s} p3 w - x2:(MOVBstore [i-1] {s} p2 (SHRLconst [8] w) - x1:(MOVBstore [i-2] {s} p1 (SHRLconst [16] w) - x0:(MOVBstore [i-3] {s} p0 (SHRLconst [24] w) mem)))) + x2:(MOVBstore [i] {s} p2 (SHRLconst [8] w) + x1:(MOVBstore [i] {s} p1 (SHRLconst [16] w) + x0:(MOVBstore [i] {s} p0 (SHRLconst [24] w) mem)))) && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 - && same(p0, p1, 1) - && same(p1, p2, 1) - && same(p2, p3, 1) + && sequentialAddresses(p0, p1, 1) + && sequentialAddresses(p1, p2, 1) + && sequentialAddresses(p2, p3, 1) && clobber(x0, x1, x2) - -> (MOVLstore [i-3] {s} p0 (BSWAPL <w.Type> w) mem) - + -> (MOVLstore [i] {s} p0 (BSWAPL <w.Type> w) mem) + +(MOVBstore [i] {s} p w + x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w) + x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w) + x4:(MOVBstore [i-3] {s} p (SHRQconst [24] w) + x3:(MOVBstore [i-4] {s} p (SHRQconst [32] w) + x2:(MOVBstore [i-5] {s} p (SHRQconst [40] w) + x1:(MOVBstore [i-6] {s} p (SHRQconst [48] w) + x0:(MOVBstore [i-7] {s} p (SHRQconst [56] w) mem)))))))) + && x0.Uses == 1 + && x1.Uses == 1 + && x2.Uses == 1 + && x3.Uses == 1 + && x4.Uses == 1 + && x5.Uses == 1 + && x6.Uses == 1 + && clobber(x0, x1, x2, x3, x4, x5, x6) + -> (MOVQstore [i-7] {s} p (BSWAPQ <w.Type> w) mem) (MOVBstore [i] {s} p7 w - x6:(MOVBstore [i-1] {s} p6 (SHRQconst [8] w) - x5:(MOVBstore [i-2] {s} p5 (SHRQconst [16] w) - x4:(MOVBstore [i-3] {s} p4 (SHRQconst [24] w) - x3:(MOVBstore [i-4] {s} p3 (SHRQconst [32] w) - x2:(MOVBstore [i-5] {s} p2 (SHRQconst [40] w) - x1:(MOVBstore [i-6] {s} p1 (SHRQconst [48] w) - x0:(MOVBstore [i-7] {s} p0 (SHRQconst [56] w) mem)))))))) + x6:(MOVBstore [i] {s} p6 (SHRQconst [8] w) + x5:(MOVBstore [i] {s} p5 (SHRQconst [16] w) + x4:(MOVBstore [i] {s} p4 (SHRQconst [24] w) + x3:(MOVBstore [i] {s} p3 (SHRQconst [32] w) + x2:(MOVBstore [i] {s} p2 (SHRQconst [40] w) + x1:(MOVBstore [i] {s} p1 (SHRQconst [48] w) + x0:(MOVBstore [i] {s} p0 (SHRQconst [56] w) mem)))))))) && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 @@ -1783,99 +1835,122 @@ && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 - && same(p0, p1, 1) - && same(p1, p2, 1) - && same(p2, p3, 1) - && same(p3, p4, 1) - && same(p4, p5, 1) - && same(p5, p6, 1) - && same(p6, p7, 1) + && sequentialAddresses(p0, p1, 1) + && sequentialAddresses(p1, p2, 1) + && sequentialAddresses(p2, p3, 1) + && sequentialAddresses(p3, p4, 1) + && sequentialAddresses(p4, p5, 1) + && sequentialAddresses(p5, p6, 1) + && sequentialAddresses(p6, p7, 1) && clobber(x0, x1, x2, x3, x4, x5, x6) - -> (MOVQstore [i-7] {s} p0 (BSWAPQ <w.Type> w) mem) + -> (MOVQstore [i] {s} p0 (BSWAPQ <w.Type> w) mem) // Combine constant stores into larger (unaligned) stores. -(MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem)) +(MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem)) && x.Uses == 1 - && same(p0, p1, 1) && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x) - -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem) -(MOVBstoreconst [a] {s} p1 x:(MOVBstoreconst [c] {s} p0 mem)) + -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem) +(MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem)) && x.Uses == 1 - && same(p0, p1, 1) && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x) - -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem) -(MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem)) + -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem) +(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) && x.Uses == 1 - && same(p0, p1, 1) && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) - -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem) -(MOVWstoreconst [a] {s} p1 x:(MOVWstoreconst [c] {s} p0 mem)) + -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem) +(MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem)) && x.Uses == 1 - && same(p0, p1, 1) && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) - -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem) -(MOVLstoreconst [c] {s} p1 x:(MOVLstoreconst [a] {s} p0 mem)) + -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem) +(MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem)) && x.Uses == 1 - && same(p0, p1, 1) && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x) - -> (MOVQstore [ValAndOff(a).Off()] {s} p0 (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem) -(MOVLstoreconst [a] {s} p1 x:(MOVLstoreconst [c] {s} p0 mem)) + -> (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem) +(MOVLstoreconst [a] {s} p x:(MOVLstoreconst [c] {s} p mem)) && x.Uses == 1 - && same(p0, p1, 1) && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x) - -> (MOVQstore [ValAndOff(a).Off()] {s} p0 (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem) -(MOVQstoreconst [c] {s} p1 x:(MOVQstoreconst [c2] {s} p0 mem)) + -> (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem) +(MOVQstoreconst [c] {s} p x:(MOVQstoreconst [c2] {s} p mem)) && config.useSSE && x.Uses == 1 - && same(p0, p1, 1) && ValAndOff(c2).Off() + 8 == ValAndOff(c).Off() && ValAndOff(c).Val() == 0 && ValAndOff(c2).Val() == 0 && clobber(x) - -> (MOVOstore [ValAndOff(c2).Off()] {s} p0 (MOVOconst [0]) mem) + -> (MOVOstore [ValAndOff(c2).Off()] {s} p (MOVOconst [0]) mem) -// Combine stores into larger (unaligned) stores. -(MOVBstore [i] {s} p1 (SHR(W|L|Q)const [8] w) x:(MOVBstore [i-1] {s} p0 w mem)) +// Combine stores into larger (unaligned) stores. Little endian. +(MOVBstore [i] {s} p (SHR(W|L|Q)const [8] w) x:(MOVBstore [i-1] {s} p w mem)) + && x.Uses == 1 + && clobber(x) + -> (MOVWstore [i-1] {s} p w mem) +(MOVBstore [i] {s} p w x:(MOVBstore [i+1] {s} p (SHR(W|L|Q)const [8] w) mem)) && x.Uses == 1 - && same(p0, p1, 1) && clobber(x) - -> (MOVWstore [i-1] {s} p0 w mem) -(MOVBstore [i] {s} p1 w x:(MOVBstore [i+1] {s} p0 (SHR(W|L|Q)const [8] w) mem)) + -> (MOVWstore [i] {s} p w mem) +(MOVBstore [i] {s} p (SHR(L|Q)const [j] w) x:(MOVBstore [i-1] {s} p w0:(SHR(L|Q)const [j-8] w) mem)) + && x.Uses == 1 + && clobber(x) + -> (MOVWstore [i-1] {s} p w0 mem) +(MOVBstore [i] {s} p1 (SHR(W|L|Q)const [8] w) x:(MOVBstore [i] {s} p0 w mem)) + && x.Uses == 1 + && sequentialAddresses(p0, p1, 1) + && clobber(x) + -> (MOVWstore [i] {s} p0 w mem) +(MOVBstore [i] {s} p0 w x:(MOVBstore [i] {s} p1 (SHR(W|L|Q)const [8] w) mem)) && x.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 1) && clobber(x) -> (MOVWstore [i] {s} p0 w mem) -(MOVBstore [i] {s} p1 (SHR(L|Q)const [j] w) x:(MOVBstore [i-1] {s} p0 w0:(SHR(L|Q)const [j-8] w) mem)) +(MOVBstore [i] {s} p1 (SHR(L|Q)const [j] w) x:(MOVBstore [i] {s} p0 w0:(SHR(L|Q)const [j-8] w) mem)) && x.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 1) && clobber(x) - -> (MOVWstore [i-1] {s} p0 w0 mem) -(MOVWstore [i] {s} p1 (SHR(L|Q)const [16] w) x:(MOVWstore [i-2] {s} p0 w mem)) + -> (MOVWstore [i] {s} p0 w0 mem) + +(MOVWstore [i] {s} p (SHR(L|Q)const [16] w) x:(MOVWstore [i-2] {s} p w mem)) + && x.Uses == 1 + && clobber(x) + -> (MOVLstore [i-2] {s} p w mem) +(MOVWstore [i] {s} p (SHR(L|Q)const [j] w) x:(MOVWstore [i-2] {s} p w0:(SHR(L|Q)const [j-16] w) mem)) + && x.Uses == 1 + && clobber(x) + -> (MOVLstore [i-2] {s} p w0 mem) +(MOVWstore [i] {s} p1 (SHR(L|Q)const [16] w) x:(MOVWstore [i] {s} p0 w mem)) + && x.Uses == 1 + && sequentialAddresses(p0, p1, 2) + && clobber(x) + -> (MOVLstore [i] {s} p0 w mem) +(MOVWstore [i] {s} p1 (SHR(L|Q)const [j] w) x:(MOVWstore [i] {s} p0 w0:(SHR(L|Q)const [j-16] w) mem)) + && x.Uses == 1 + && sequentialAddresses(p0, p1, 2) + && clobber(x) + -> (MOVLstore [i] {s} p0 w0 mem) + +(MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem)) && x.Uses == 1 - && same(p0, p1, 1) && clobber(x) - -> (MOVLstore [i-2] {s} p0 w mem) -(MOVWstore [i] {s} p1 (SHR(L|Q)const [j] w) x:(MOVWstore [i-2] {s} p0 w0:(SHR(L|Q)const [j-16] w) mem)) + -> (MOVQstore [i-4] {s} p w mem) +(MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem)) && x.Uses == 1 - && same(p0, p1, 1) && clobber(x) - -> (MOVLstore [i-2] {s} p0 w0 mem) -(MOVLstore [i] {s} p1 (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p0 w mem)) + -> (MOVQstore [i-4] {s} p w0 mem) +(MOVLstore [i] {s} p1 (SHRQconst [32] w) x:(MOVLstore [i] {s} p0 w mem)) && x.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 4) && clobber(x) - -> (MOVQstore [i-4] {s} p0 w mem) -(MOVLstore [i] {s} p1 (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p0 w0:(SHRQconst [j-32] w) mem)) + -> (MOVQstore [i] {s} p0 w mem) +(MOVLstore [i] {s} p1 (SHRQconst [j] w) x:(MOVLstore [i] {s} p0 w0:(SHRQconst [j-32] w) mem)) && x.Uses == 1 - && same(p0, p1, 1) + && sequentialAddresses(p0, p1, 4) && clobber(x) - -> (MOVQstore [i-4] {s} p0 w0 mem) + -> (MOVQstore [i] {s} p0 w0 mem) (MOVBstore [i] {s} p x1:(MOVBload [j] {s2} p2 mem) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 08aa65b0a8..bf949abc20 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -127,6 +127,7 @@ func init() { gp1flags = regInfo{inputs: []regMask{gpsp}} gp0flagsLoad = regInfo{inputs: []regMask{gpspsb, 0}} gp1flagsLoad = regInfo{inputs: []regMask{gpspsb, gpsp, 0}} + gp2flagsLoad = regInfo{inputs: []regMask{gpspsb, gpsp, gpsp, 0}} flagsgp = regInfo{inputs: nil, outputs: gponly} gp11flags = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, 0}} @@ -299,6 +300,24 @@ func init() { {name: "CMPWconstload", argLength: 2, reg: gp0flagsLoad, asm: "CMPW", aux: "SymValAndOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, {name: "CMPBconstload", argLength: 2, reg: gp0flagsLoad, asm: "CMPB", aux: "SymValAndOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, + // compare *(arg0+N*arg1+auxint+aux) to arg2 (in that order). arg3=mem. + {name: "CMPQloadidx8", argLength: 4, reg: gp2flagsLoad, asm: "CMPQ", scale: 8, aux: "SymOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPQloadidx1", argLength: 4, reg: gp2flagsLoad, asm: "CMPQ", scale: 1, commutative: true, aux: "SymOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPLloadidx4", argLength: 4, reg: gp2flagsLoad, asm: "CMPL", scale: 4, aux: "SymOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPLloadidx1", argLength: 4, reg: gp2flagsLoad, asm: "CMPL", scale: 1, commutative: true, aux: "SymOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPWloadidx2", argLength: 4, reg: gp2flagsLoad, asm: "CMPW", scale: 2, aux: "SymOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPWloadidx1", argLength: 4, reg: gp2flagsLoad, asm: "CMPW", scale: 1, commutative: true, aux: "SymOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPBloadidx1", argLength: 4, reg: gp2flagsLoad, asm: "CMPB", scale: 1, commutative: true, aux: "SymOff", typ: "Flags", symEffect: "Read"}, + + // compare *(arg0+N*arg1+ValAndOff(AuxInt).Off()+aux) to ValAndOff(AuxInt).Val() (in that order). arg2=mem. + {name: "CMPQconstloadidx8", argLength: 3, reg: gp1flagsLoad, asm: "CMPQ", scale: 8, aux: "SymValAndOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPQconstloadidx1", argLength: 3, reg: gp1flagsLoad, asm: "CMPQ", scale: 1, commutative: true, aux: "SymValAndOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPLconstloadidx4", argLength: 3, reg: gp1flagsLoad, asm: "CMPL", scale: 4, aux: "SymValAndOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPLconstloadidx1", argLength: 3, reg: gp1flagsLoad, asm: "CMPL", scale: 1, commutative: true, aux: "SymValAndOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPWconstloadidx2", argLength: 3, reg: gp1flagsLoad, asm: "CMPW", scale: 2, aux: "SymValAndOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPWconstloadidx1", argLength: 3, reg: gp1flagsLoad, asm: "CMPW", scale: 1, commutative: true, aux: "SymValAndOff", typ: "Flags", symEffect: "Read"}, + {name: "CMPBconstloadidx1", argLength: 3, reg: gp1flagsLoad, asm: "CMPB", scale: 1, commutative: true, aux: "SymValAndOff", typ: "Flags", symEffect: "Read"}, + {name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32 {name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64 @@ -717,7 +736,7 @@ func init() { {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpsp}}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true}, // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier // It saves all GP registers if necessary, but may clobber others. - {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("DI"), ax}, clobbers: callerSave &^ gp}, clobberFlags: true, aux: "Sym", symEffect: "None"}, + {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("DI"), buildReg("AX CX DX BX BP SI R8 R9")}, clobbers: callerSave &^ gp}, clobberFlags: true, aux: "Sym", symEffect: "None"}, // There are three of these functions so that they can have three different register inputs. // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the diff --git a/src/cmd/compile/internal/ssa/gen/AMD64splitload.rules b/src/cmd/compile/internal/ssa/gen/AMD64splitload.rules index e8e1b4d258..5fd4429a1b 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64splitload.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64splitload.rules @@ -14,3 +14,13 @@ (CMP(Q|L|W|B)load {sym} [off] ptr x mem) -> (CMP(Q|L|W|B) (MOV(Q|L|W|B)load {sym} [off] ptr mem) x) (CMP(Q|L|W|B)constload {sym} [vo] ptr mem) -> (CMP(Q|L|W|B)const (MOV(Q|L|W|B)load {sym} [offOnly(vo)] ptr mem) [valOnly(vo)]) + +(CMP(Q|L|W|B)loadidx1 {sym} [off] ptr idx x mem) -> (CMP(Q|L|W|B) (MOV(Q|L|W|B)loadidx1 {sym} [off] ptr idx mem) x) +(CMPQloadidx8 {sym} [off] ptr idx x mem) -> (CMPQ (MOVQloadidx8 {sym} [off] ptr idx mem) x) +(CMPLloadidx4 {sym} [off] ptr idx x mem) -> (CMPL (MOVLloadidx4 {sym} [off] ptr idx mem) x) +(CMPWloadidx2 {sym} [off] ptr idx x mem) -> (CMPW (MOVWloadidx2 {sym} [off] ptr idx mem) x) + +(CMP(Q|L|W|B)constloadidx1 {sym} [vo] ptr idx mem) -> (CMP(Q|L|W|B)const (MOV(Q|L|W|B)loadidx1 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) +(CMPQconstloadidx8 {sym} [vo] ptr idx mem) -> (CMPQconst (MOVQloadidx8 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) +(CMPLconstloadidx4 {sym} [vo] ptr idx mem) -> (CMPLconst (MOVLloadidx4 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) +(CMPWconstloadidx2 {sym} [vo] ptr idx mem) -> (CMPWconst (MOVWloadidx2 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go index 283a0fa6b5..65460bf6f7 100644 --- a/src/cmd/compile/internal/ssa/gen/S390XOps.go +++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go @@ -630,6 +630,7 @@ func init() { asm: "STMG", faultOnNilArg0: true, symEffect: "Write", + clobberFlags: true, // TODO(mundaym): currently uses AGFI to handle large offsets }, { name: "STMG3", @@ -640,6 +641,7 @@ func init() { asm: "STMG", faultOnNilArg0: true, symEffect: "Write", + clobberFlags: true, // TODO(mundaym): currently uses AGFI to handle large offsets }, { name: "STMG4", @@ -657,6 +659,7 @@ func init() { asm: "STMG", faultOnNilArg0: true, symEffect: "Write", + clobberFlags: true, // TODO(mundaym): currently uses AGFI to handle large offsets }, { name: "STM2", @@ -667,6 +670,7 @@ func init() { asm: "STMY", faultOnNilArg0: true, symEffect: "Write", + clobberFlags: true, // TODO(mundaym): currently uses AGFI to handle large offsets }, { name: "STM3", @@ -677,6 +681,7 @@ func init() { asm: "STMY", faultOnNilArg0: true, symEffect: "Write", + clobberFlags: true, // TODO(mundaym): currently uses AGFI to handle large offsets }, { name: "STM4", @@ -694,6 +699,7 @@ func init() { asm: "STMY", faultOnNilArg0: true, symEffect: "Write", + clobberFlags: true, // TODO(mundaym): currently uses AGFI to handle large offsets }, // large move diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 8ec22d86e7..c7f6a232c6 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -137,6 +137,16 @@ (Xor32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c^d))]) (Xor64 (Const64 [c]) (Const64 [d])) -> (Const64 [c^d]) +(Ctz64 (Const64 [c])) && config.PtrSize == 4 -> (Const32 [ntz(c)]) +(Ctz32 (Const32 [c])) && config.PtrSize == 4 -> (Const32 [ntz32(c)]) +(Ctz16 (Const16 [c])) && config.PtrSize == 4 -> (Const32 [ntz16(c)]) +(Ctz8 (Const8 [c])) && config.PtrSize == 4 -> (Const32 [ntz8(c)]) + +(Ctz64 (Const64 [c])) && config.PtrSize == 8 -> (Const64 [ntz(c)]) +(Ctz32 (Const32 [c])) && config.PtrSize == 8 -> (Const64 [ntz32(c)]) +(Ctz16 (Const16 [c])) && config.PtrSize == 8 -> (Const64 [ntz16(c)]) +(Ctz8 (Const8 [c])) && config.PtrSize == 8 -> (Const64 [ntz8(c)]) + (Div8 (Const8 [c]) (Const8 [d])) && d != 0 -> (Const8 [int64(int8(c)/int8(d))]) (Div16 (Const16 [c]) (Const16 [d])) && d != 0 -> (Const16 [int64(int16(c)/int16(d))]) (Div32 (Const32 [c]) (Const32 [d])) && d != 0 -> (Const32 [int64(int32(c)/int32(d))]) @@ -917,7 +927,7 @@ (If (ConstBool [c]) yes no) && c == 0 -> (First no yes) // Get rid of Convert ops for pointer arithmetic on unsafe.Pointer. -(Convert (Add(64|32) (Convert ptr mem) off) mem) -> (Add(64|32) ptr off) +(Convert (Add(64|32) (Convert ptr mem) off) mem) -> (AddPtr ptr off) (Convert (Convert ptr mem) mem) -> ptr // strength reduction of divide by a constant. @@ -1780,6 +1790,10 @@ // is constant, which pushes constants to the outside // of the expression. At that point, any constant-folding // opportunities should be obvious. +// Note: don't include AddPtr here! In order to maintain the +// invariant that pointers must stay within the pointed-to object, +// we can't pull part of a pointer computation above the AddPtr. +// See issue 37881. // x + (C + z) -> C + (x + z) (Add64 (Add64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Add64 i (Add64 <t> z x)) diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go index 8e88d0b6a3..3caa06038a 100644 --- a/src/cmd/compile/internal/ssa/gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/gen/rulegen.go @@ -715,6 +715,11 @@ func (w *bodyBase) add(node Statement) { // declared reports if the body contains a Declare with the given name. func (w *bodyBase) declared(name string) bool { + if name == "nil" { + // Treat "nil" as having already been declared. + // This lets us use nil to match an aux field. + return true + } for _, s := range w.list { if decl, ok := s.(*Declare); ok && decl.name == name { return true diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index 54fa54a477..66fff88d7c 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -19,9 +19,12 @@ import ( type HTMLWriter struct { Logger - w io.WriteCloser - path string - dot *dotWriter + w io.WriteCloser + path string + dot *dotWriter + prevHash []byte + pendingPhases []string + pendingTitles []string } func NewHTMLWriter(path string, logger Logger, funcname, cfgMask string) *HTMLWriter { @@ -88,27 +91,22 @@ th, td { td > h2 { cursor: pointer; font-size: 120%; + margin: 5px 0px 5px 0px; } td.collapsed { font-size: 12px; width: 12px; border: 1px solid white; - padding: 0; + padding: 2px; cursor: pointer; background: #fafafa; } -td.collapsed div { - -moz-transform: rotate(-90.0deg); /* FF3.5+ */ - -o-transform: rotate(-90.0deg); /* Opera 10.5 */ - -webkit-transform: rotate(-90.0deg); /* Saf3.1+, Chrome */ - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083); /* IE6,IE7 */ - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)"; /* IE8 */ - margin-top: 10.3em; - margin-left: -10em; - margin-right: -10em; - text-align: right; +td.collapsed div { + /* TODO: Flip the direction of the phase's title 90 degrees on a collapsed column. */ + writing-mode: vertical-lr; + white-space: pre; } code, pre, .lines, .ast { @@ -263,6 +261,14 @@ body.darkmode table, th { border: 1px solid gray; } +body.darkmode text { + fill: white; +} + +body.darkmode svg polygon:first-child { + fill: rgb(21, 21, 21); +} + .highlight-aquamarine { background-color: aquamarine; color: black; } .highlight-coral { background-color: coral; color: black; } .highlight-lightpink { background-color: lightpink; color: black; } @@ -304,7 +310,7 @@ body.darkmode table, th { color: gray; } -.outline-blue { outline: blue solid 2px; } +.outline-blue { outline: #2893ff solid 2px; } .outline-red { outline: red solid 2px; } .outline-blueviolet { outline: blueviolet solid 2px; } .outline-darkolivegreen { outline: darkolivegreen solid 2px; } @@ -316,7 +322,7 @@ body.darkmode table, th { .outline-maroon { outline: maroon solid 2px; } .outline-black { outline: black solid 2px; } -ellipse.outline-blue { stroke-width: 2px; stroke: blue; } +ellipse.outline-blue { stroke-width: 2px; stroke: #2893ff; } ellipse.outline-red { stroke-width: 2px; stroke: red; } ellipse.outline-blueviolet { stroke-width: 2px; stroke: blueviolet; } ellipse.outline-darkolivegreen { stroke-width: 2px; stroke: darkolivegreen; } @@ -473,7 +479,7 @@ window.onload = function() { "deadcode", "opt", "lower", - "late deadcode", + "late-deadcode", "regalloc", "genssa", ]; @@ -495,15 +501,34 @@ window.onload = function() { } // Go through all columns and collapse needed phases. - var td = document.getElementsByTagName("td"); - for (var i = 0; i < td.length; i++) { - var id = td[i].id; - var phase = id.substr(0, id.length-4); - var show = expandedDefault.indexOf(phase) !== -1 + const td = document.getElementsByTagName("td"); + for (let i = 0; i < td.length; i++) { + const id = td[i].id; + const phase = id.substr(0, id.length-4); + let show = expandedDefault.indexOf(phase) !== -1 + + // If show == false, check to see if this is a combined column (multiple phases). + // If combined, check each of the phases to see if they are in our expandedDefaults. + // If any are found, that entire combined column gets shown. + if (!show) { + const combined = phase.split('--+--'); + const len = combined.length; + if (len > 1) { + for (let i = 0; i < len; i++) { + if (expandedDefault.indexOf(combined[i]) !== -1) { + show = true; + break; + } + } + } + } if (id.endsWith("-exp")) { - var h2 = td[i].getElementsByTagName("h2"); - if (h2 && h2[0]) { - h2[0].addEventListener('click', toggler(phase)); + const h2Els = td[i].getElementsByTagName("h2"); + const len = h2Els.length; + if (len > 0) { + for (let i = 0; i < len; i++) { + h2Els[i].addEventListener('click', toggler(phase)); + } } } else { td[i].addEventListener('click', toggler(phase)); @@ -642,12 +667,35 @@ function makeDraggable(event) { function toggleDarkMode() { document.body.classList.toggle('darkmode'); + // Collect all of the "collapsed" elements and apply dark mode on each collapsed column const collapsedEls = document.getElementsByClassName('collapsed'); const len = collapsedEls.length; for (let i = 0; i < len; i++) { collapsedEls[i].classList.toggle('darkmode'); } + + // Collect and spread the appropriate elements from all of the svgs on the page into one array + const svgParts = [ + ...document.querySelectorAll('path'), + ...document.querySelectorAll('ellipse'), + ...document.querySelectorAll('polygon'), + ]; + + // Iterate over the svgParts specifically looking for white and black fill/stroke to be toggled. + // The verbose conditional is intentional here so that we do not mutate any svg path, ellipse, or polygon that is of any color other than white or black. + svgParts.forEach(el => { + if (el.attributes.stroke.value === 'white') { + el.attributes.stroke.value = 'black'; + } else if (el.attributes.stroke.value === 'black') { + el.attributes.stroke.value = 'white'; + } + if (el.attributes.fill.value === 'white') { + el.attributes.fill.value = 'black'; + } else if (el.attributes.fill.value === 'black') { + el.attributes.fill.value = 'white'; + } + }); } </script> @@ -707,8 +755,16 @@ func (w *HTMLWriter) WriteFunc(phase, title string, f *Func) { if w == nil { return // avoid generating HTML just to discard it } - //w.WriteColumn(phase, title, "", f.HTML()) - w.WriteColumn(phase, title, "", f.HTML(phase, w.dot)) + hash := hashFunc(f) + w.pendingPhases = append(w.pendingPhases, phase) + w.pendingTitles = append(w.pendingTitles, title) + if !bytes.Equal(hash, w.prevHash) { + phases := strings.Join(w.pendingPhases, " + ") + w.WriteMultiTitleColumn(phases, w.pendingTitles, fmt.Sprintf("hash-%x", hash), f.HTML(phase, w.dot)) + w.pendingPhases = w.pendingPhases[:0] + w.pendingTitles = w.pendingTitles[:0] + } + w.prevHash = hash } // FuncLines contains source code for a function to be displayed @@ -822,6 +878,10 @@ func (w *HTMLWriter) WriteAST(phase string, buf *bytes.Buffer) { // WriteColumn writes raw HTML in a column headed by title. // It is intended for pre- and post-compilation log output. func (w *HTMLWriter) WriteColumn(phase, title, class, html string) { + w.WriteMultiTitleColumn(phase, []string{title}, class, html) +} + +func (w *HTMLWriter) WriteMultiTitleColumn(phase string, titles []string, class, html string) { if w == nil { return } @@ -834,9 +894,11 @@ func (w *HTMLWriter) WriteColumn(phase, title, class, html string) { } else { w.Printf("<td id=\"%v-exp\" class=\"%v\">", id, class) } - w.WriteString("<h2>" + title + "</h2>") + for _, title := range titles { + w.WriteString("<h2>" + title + "</h2>") + } w.WriteString(html) - w.WriteString("</td>") + w.WriteString("</td>\n") } func (w *HTMLWriter) Printf(msg string, v ...interface{}) { @@ -1016,7 +1078,7 @@ func (d *dotWriter) writeFuncSVG(w io.Writer, phase string, f *Func) { arrow = "dotvee" layoutDrawn[s.b.ID] = true } else if isBackEdge(b.ID, s.b.ID) { - color = "blue" + color = "#2893ff" } fmt.Fprintf(pipe, `%v -> %v [label=" %d ",style="%s",color="%s",arrowhead="%s"];`, b, s.b, i, style, color, arrow) } diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index e2b83e20b3..bf48bff8f1 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -602,6 +602,20 @@ const ( OpAMD64CMPLconstload OpAMD64CMPWconstload OpAMD64CMPBconstload + OpAMD64CMPQloadidx8 + OpAMD64CMPQloadidx1 + OpAMD64CMPLloadidx4 + OpAMD64CMPLloadidx1 + OpAMD64CMPWloadidx2 + OpAMD64CMPWloadidx1 + OpAMD64CMPBloadidx1 + OpAMD64CMPQconstloadidx8 + OpAMD64CMPQconstloadidx1 + OpAMD64CMPLconstloadidx4 + OpAMD64CMPLconstloadidx1 + OpAMD64CMPWconstloadidx2 + OpAMD64CMPWconstloadidx1 + OpAMD64CMPBconstloadidx1 OpAMD64UCOMISS OpAMD64UCOMISD OpAMD64BTL @@ -7535,6 +7549,217 @@ var opcodeTable = [...]opInfo{ }, }, { + name: "CMPQloadidx8", + auxType: auxSymOff, + argLen: 4, + symEffect: SymRead, + asm: x86.ACMPQ, + scale: 8, + reg: regInfo{ + 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: "CMPQloadidx1", + auxType: auxSymOff, + argLen: 4, + commutative: true, + symEffect: SymRead, + asm: x86.ACMPQ, + scale: 1, + reg: regInfo{ + 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: "CMPLloadidx4", + auxType: auxSymOff, + argLen: 4, + symEffect: SymRead, + asm: x86.ACMPL, + scale: 4, + reg: regInfo{ + 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: "CMPLloadidx1", + auxType: auxSymOff, + argLen: 4, + commutative: true, + symEffect: SymRead, + asm: x86.ACMPL, + scale: 1, + reg: regInfo{ + 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: "CMPWloadidx2", + auxType: auxSymOff, + argLen: 4, + symEffect: SymRead, + asm: x86.ACMPW, + scale: 2, + reg: regInfo{ + 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: "CMPWloadidx1", + auxType: auxSymOff, + argLen: 4, + commutative: true, + symEffect: SymRead, + asm: x86.ACMPW, + scale: 1, + reg: regInfo{ + 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: "CMPBloadidx1", + auxType: auxSymOff, + argLen: 4, + commutative: true, + symEffect: SymRead, + asm: x86.ACMPB, + scale: 1, + reg: regInfo{ + 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: "CMPQconstloadidx8", + auxType: auxSymValAndOff, + argLen: 3, + symEffect: SymRead, + asm: x86.ACMPQ, + scale: 8, + reg: regInfo{ + 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 + }, + }, + }, + { + name: "CMPQconstloadidx1", + auxType: auxSymValAndOff, + argLen: 3, + commutative: true, + symEffect: SymRead, + asm: x86.ACMPQ, + scale: 1, + reg: regInfo{ + 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 + }, + }, + }, + { + name: "CMPLconstloadidx4", + auxType: auxSymValAndOff, + argLen: 3, + symEffect: SymRead, + asm: x86.ACMPL, + scale: 4, + reg: regInfo{ + 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 + }, + }, + }, + { + name: "CMPLconstloadidx1", + auxType: auxSymValAndOff, + argLen: 3, + commutative: true, + symEffect: SymRead, + asm: x86.ACMPL, + scale: 1, + reg: regInfo{ + 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 + }, + }, + }, + { + name: "CMPWconstloadidx2", + auxType: auxSymValAndOff, + argLen: 3, + symEffect: SymRead, + asm: x86.ACMPW, + scale: 2, + reg: regInfo{ + 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 + }, + }, + }, + { + name: "CMPWconstloadidx1", + auxType: auxSymValAndOff, + argLen: 3, + commutative: true, + symEffect: SymRead, + asm: x86.ACMPW, + scale: 1, + reg: regInfo{ + 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 + }, + }, + }, + { + name: "CMPBconstloadidx1", + auxType: auxSymValAndOff, + argLen: 3, + commutative: true, + symEffect: SymRead, + asm: x86.ACMPB, + scale: 1, + reg: regInfo{ + 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 + }, + }, + }, + { name: "UCOMISS", argLen: 2, asm: x86.AUCOMISS, @@ -11420,7 +11645,7 @@ var opcodeTable = [...]opInfo{ reg: regInfo{ inputs: []inputInfo{ {0, 128}, // DI - {1, 1}, // AX + {1, 879}, // AX CX DX BX BP SI R8 R9 }, clobbers: 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 }, @@ -29885,6 +30110,7 @@ var opcodeTable = [...]opInfo{ name: "STMG2", auxType: auxSymOff, argLen: 4, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymWrite, asm: s390x.ASTMG, @@ -29900,6 +30126,7 @@ var opcodeTable = [...]opInfo{ name: "STMG3", auxType: auxSymOff, argLen: 5, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymWrite, asm: s390x.ASTMG, @@ -29916,6 +30143,7 @@ var opcodeTable = [...]opInfo{ name: "STMG4", auxType: auxSymOff, argLen: 6, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymWrite, asm: s390x.ASTMG, @@ -29933,6 +30161,7 @@ var opcodeTable = [...]opInfo{ name: "STM2", auxType: auxSymOff, argLen: 4, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymWrite, asm: s390x.ASTMY, @@ -29948,6 +30177,7 @@ var opcodeTable = [...]opInfo{ name: "STM3", auxType: auxSymOff, argLen: 5, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymWrite, asm: s390x.ASTMY, @@ -29964,6 +30194,7 @@ var opcodeTable = [...]opInfo{ name: "STM4", auxType: auxSymOff, argLen: 6, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymWrite, asm: s390x.ASTMY, diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go index 58e4c3bbbe..36f09c3ad9 100644 --- a/src/cmd/compile/internal/ssa/print.go +++ b/src/cmd/compile/internal/ssa/print.go @@ -6,6 +6,7 @@ package ssa import ( "bytes" + "crypto/sha256" "fmt" "io" ) @@ -14,6 +15,13 @@ func printFunc(f *Func) { f.Logf("%s", f) } +func hashFunc(f *Func) []byte { + h := sha256.New() + p := stringFuncPrinter{w: h} + fprintFunc(p, f) + return h.Sum(nil) +} + func (f *Func) String() string { var buf bytes.Buffer p := stringFuncPrinter{w: &buf} diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index b3e7d34779..727fd2402d 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -347,9 +347,10 @@ func nlz(x int64) int64 { } // ntz returns the number of trailing zeros. -func ntz(x int64) int64 { - return int64(bits.TrailingZeros64(uint64(x))) -} +func ntz(x int64) int64 { return int64(bits.TrailingZeros64(uint64(x))) } +func ntz32(x int64) int64 { return int64(bits.TrailingZeros32(uint32(x))) } +func ntz16(x int64) int64 { return int64(bits.TrailingZeros16(uint16(x))) } +func ntz8(x int64) int64 { return int64(bits.TrailingZeros8(uint8(x))) } func oneBit(x int64) bool { return bits.OnesCount64(uint64(x)) == 1 @@ -990,7 +991,9 @@ func zeroUpper32Bits(x *Value, depth int) bool { OpAMD64ORLload, OpAMD64XORLload, OpAMD64CVTTSD2SL, OpAMD64ADDL, OpAMD64ADDLconst, OpAMD64SUBL, OpAMD64SUBLconst, OpAMD64ANDL, OpAMD64ANDLconst, OpAMD64ORL, OpAMD64ORLconst, - OpAMD64XORL, OpAMD64XORLconst, OpAMD64NEGL, OpAMD64NOTL: + OpAMD64XORL, OpAMD64XORLconst, OpAMD64NEGL, OpAMD64NOTL, + OpAMD64SHRL, OpAMD64SHRLconst, OpAMD64SARL, OpAMD64SARLconst, + OpAMD64SHLL, OpAMD64SHLLconst: return true case OpArg: return x.Type.Width == 4 @@ -1248,42 +1251,27 @@ func read64(sym interface{}, off int64, byteorder binary.ByteOrder) uint64 { return byteorder.Uint64(buf) } -// same reports whether x and y are the same value. -// It checks to a maximum depth of d, so it may report -// a false negative. -func same(x, y *Value, depth int) bool { - if x == y { +// sequentialAddresses reports true if it can prove that x + n == y +func sequentialAddresses(x, y *Value, n int64) bool { + if x.Op == Op386ADDL && y.Op == Op386LEAL1 && y.AuxInt == n && y.Aux == nil && + (x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] || + x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) { return true } - if depth <= 0 { - return false - } - if x.Op != y.Op || x.Aux != y.Aux || x.AuxInt != y.AuxInt { - return false - } - if len(x.Args) != len(y.Args) { - return false + if x.Op == Op386LEAL1 && y.Op == Op386LEAL1 && y.AuxInt == x.AuxInt+n && x.Aux == y.Aux && + (x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] || + x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) { + return true } - if opcodeTable[x.Op].commutative { - // Check exchanged ordering first. - for i, a := range x.Args { - j := i - if j < 2 { - j ^= 1 - } - b := y.Args[j] - if !same(a, b, depth-1) { - goto checkNormalOrder - } - } + if x.Op == OpAMD64ADDQ && y.Op == OpAMD64LEAQ1 && y.AuxInt == n && y.Aux == nil && + (x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] || + x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) { return true - checkNormalOrder: } - for i, a := range x.Args { - b := y.Args[i] - if !same(a, b, depth-1) { - return false - } + if x.Op == OpAMD64LEAQ1 && y.Op == OpAMD64LEAQ1 && y.AuxInt == x.AuxInt+n && x.Aux == y.Aux && + (x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] || + x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) { + return true } - return true + return false } diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go index 8b2da94c13..2a0a92bb83 100644 --- a/src/cmd/compile/internal/ssa/rewrite386.go +++ b/src/cmd/compile/internal/ssa/rewrite386.go @@ -18,16 +18,10 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386ADDLconst(v) case Op386ADDLconstmodify: return rewriteValue386_Op386ADDLconstmodify(v) - case Op386ADDLconstmodifyidx4: - return rewriteValue386_Op386ADDLconstmodifyidx4(v) case Op386ADDLload: return rewriteValue386_Op386ADDLload(v) - case Op386ADDLloadidx4: - return rewriteValue386_Op386ADDLloadidx4(v) case Op386ADDLmodify: return rewriteValue386_Op386ADDLmodify(v) - case Op386ADDLmodifyidx4: - return rewriteValue386_Op386ADDLmodifyidx4(v) case Op386ADDSD: return rewriteValue386_Op386ADDSD(v) case Op386ADDSDload: @@ -42,16 +36,10 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386ANDLconst(v) case Op386ANDLconstmodify: return rewriteValue386_Op386ANDLconstmodify(v) - case Op386ANDLconstmodifyidx4: - return rewriteValue386_Op386ANDLconstmodifyidx4(v) case Op386ANDLload: return rewriteValue386_Op386ANDLload(v) - case Op386ANDLloadidx4: - return rewriteValue386_Op386ANDLloadidx4(v) case Op386ANDLmodify: return rewriteValue386_Op386ANDLmodify(v) - case Op386ANDLmodifyidx4: - return rewriteValue386_Op386ANDLmodifyidx4(v) case Op386CMPB: return rewriteValue386_Op386CMPB(v) case Op386CMPBconst: @@ -96,62 +84,28 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386MOVBLZX(v) case Op386MOVBload: return rewriteValue386_Op386MOVBload(v) - case Op386MOVBloadidx1: - return rewriteValue386_Op386MOVBloadidx1(v) case Op386MOVBstore: return rewriteValue386_Op386MOVBstore(v) case Op386MOVBstoreconst: return rewriteValue386_Op386MOVBstoreconst(v) - case Op386MOVBstoreconstidx1: - return rewriteValue386_Op386MOVBstoreconstidx1(v) - case Op386MOVBstoreidx1: - return rewriteValue386_Op386MOVBstoreidx1(v) case Op386MOVLload: return rewriteValue386_Op386MOVLload(v) - case Op386MOVLloadidx1: - return rewriteValue386_Op386MOVLloadidx1(v) - case Op386MOVLloadidx4: - return rewriteValue386_Op386MOVLloadidx4(v) case Op386MOVLstore: return rewriteValue386_Op386MOVLstore(v) case Op386MOVLstoreconst: return rewriteValue386_Op386MOVLstoreconst(v) - case Op386MOVLstoreconstidx1: - return rewriteValue386_Op386MOVLstoreconstidx1(v) - case Op386MOVLstoreconstidx4: - return rewriteValue386_Op386MOVLstoreconstidx4(v) - case Op386MOVLstoreidx1: - return rewriteValue386_Op386MOVLstoreidx1(v) - case Op386MOVLstoreidx4: - return rewriteValue386_Op386MOVLstoreidx4(v) case Op386MOVSDconst: return rewriteValue386_Op386MOVSDconst(v) case Op386MOVSDload: return rewriteValue386_Op386MOVSDload(v) - case Op386MOVSDloadidx1: - return rewriteValue386_Op386MOVSDloadidx1(v) - case Op386MOVSDloadidx8: - return rewriteValue386_Op386MOVSDloadidx8(v) case Op386MOVSDstore: return rewriteValue386_Op386MOVSDstore(v) - case Op386MOVSDstoreidx1: - return rewriteValue386_Op386MOVSDstoreidx1(v) - case Op386MOVSDstoreidx8: - return rewriteValue386_Op386MOVSDstoreidx8(v) case Op386MOVSSconst: return rewriteValue386_Op386MOVSSconst(v) case Op386MOVSSload: return rewriteValue386_Op386MOVSSload(v) - case Op386MOVSSloadidx1: - return rewriteValue386_Op386MOVSSloadidx1(v) - case Op386MOVSSloadidx4: - return rewriteValue386_Op386MOVSSloadidx4(v) case Op386MOVSSstore: return rewriteValue386_Op386MOVSSstore(v) - case Op386MOVSSstoreidx1: - return rewriteValue386_Op386MOVSSstoreidx1(v) - case Op386MOVSSstoreidx4: - return rewriteValue386_Op386MOVSSstoreidx4(v) case Op386MOVWLSX: return rewriteValue386_Op386MOVWLSX(v) case Op386MOVWLSXload: @@ -160,30 +114,16 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386MOVWLZX(v) case Op386MOVWload: return rewriteValue386_Op386MOVWload(v) - case Op386MOVWloadidx1: - return rewriteValue386_Op386MOVWloadidx1(v) - case Op386MOVWloadidx2: - return rewriteValue386_Op386MOVWloadidx2(v) case Op386MOVWstore: return rewriteValue386_Op386MOVWstore(v) case Op386MOVWstoreconst: return rewriteValue386_Op386MOVWstoreconst(v) - case Op386MOVWstoreconstidx1: - return rewriteValue386_Op386MOVWstoreconstidx1(v) - case Op386MOVWstoreconstidx2: - return rewriteValue386_Op386MOVWstoreconstidx2(v) - case Op386MOVWstoreidx1: - return rewriteValue386_Op386MOVWstoreidx1(v) - case Op386MOVWstoreidx2: - return rewriteValue386_Op386MOVWstoreidx2(v) case Op386MULL: return rewriteValue386_Op386MULL(v) case Op386MULLconst: return rewriteValue386_Op386MULLconst(v) case Op386MULLload: return rewriteValue386_Op386MULLload(v) - case Op386MULLloadidx4: - return rewriteValue386_Op386MULLloadidx4(v) case Op386MULSD: return rewriteValue386_Op386MULSD(v) case Op386MULSDload: @@ -202,16 +142,10 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386ORLconst(v) case Op386ORLconstmodify: return rewriteValue386_Op386ORLconstmodify(v) - case Op386ORLconstmodifyidx4: - return rewriteValue386_Op386ORLconstmodifyidx4(v) case Op386ORLload: return rewriteValue386_Op386ORLload(v) - case Op386ORLloadidx4: - return rewriteValue386_Op386ORLloadidx4(v) case Op386ORLmodify: return rewriteValue386_Op386ORLmodify(v) - case Op386ORLmodifyidx4: - return rewriteValue386_Op386ORLmodifyidx4(v) case Op386ROLBconst: return rewriteValue386_Op386ROLBconst(v) case Op386ROLLconst: @@ -278,12 +212,8 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386SUBLconst(v) case Op386SUBLload: return rewriteValue386_Op386SUBLload(v) - case Op386SUBLloadidx4: - return rewriteValue386_Op386SUBLloadidx4(v) case Op386SUBLmodify: return rewriteValue386_Op386SUBLmodify(v) - case Op386SUBLmodifyidx4: - return rewriteValue386_Op386SUBLmodifyidx4(v) case Op386SUBSD: return rewriteValue386_Op386SUBSD(v) case Op386SUBSDload: @@ -298,16 +228,10 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386XORLconst(v) case Op386XORLconstmodify: return rewriteValue386_Op386XORLconstmodify(v) - case Op386XORLconstmodifyidx4: - return rewriteValue386_Op386XORLconstmodifyidx4(v) case Op386XORLload: return rewriteValue386_Op386XORLload(v) - case Op386XORLloadidx4: - return rewriteValue386_Op386XORLloadidx4(v) case Op386XORLmodify: return rewriteValue386_Op386XORLmodify(v) - case Op386XORLmodifyidx4: - return rewriteValue386_Op386XORLmodifyidx4(v) case OpAdd16: v.Op = Op386ADDL return true @@ -1042,32 +966,6 @@ func rewriteValue386_Op386ADDL(v *Value) bool { } break } - // match: (ADDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) - // cond: canMergeLoadClobber(v, l, x) && clobber(l) - // result: (ADDLloadidx4 x [off] {sym} ptr idx mem) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - l := v_1 - if l.Op != Op386MOVLloadidx4 { - continue - } - off := l.AuxInt - sym := l.Aux - mem := l.Args[2] - ptr := l.Args[0] - idx := l.Args[1] - if !(canMergeLoadClobber(v, l, x) && clobber(l)) { - continue - } - v.reset(Op386ADDLloadidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(x, ptr, idx, mem) - return true - } - break - } // match: (ADDL x (NEGL y)) // result: (SUBL x y) for { @@ -1316,81 +1214,6 @@ func rewriteValue386_Op386ADDLconstmodify(v *Value) bool { } return false } -func rewriteValue386_Op386ADDLconstmodifyidx4(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (ADDLconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem) - // cond: ValAndOff(valoff1).canAdd(off2) - // result: (ADDLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem) - for { - valoff1 := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - off2 := v_0.AuxInt - base := v_0.Args[0] - idx := v_1 - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2)) { - break - } - v.reset(Op386ADDLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2) - v.Aux = sym - v.AddArg3(base, idx, mem) - return true - } - // match: (ADDLconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem) - // cond: ValAndOff(valoff1).canAdd(off2*4) - // result: (ADDLconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem) - for { - valoff1 := v.AuxInt - sym := v.Aux - base := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2 * 4)) { - break - } - v.reset(Op386ADDLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2 * 4) - v.Aux = sym - v.AddArg3(base, idx, mem) - return true - } - // match: (ADDLconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem) - // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (ADDLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem) - for { - valoff1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - base := v_0.Args[0] - idx := v_1 - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386ADDLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2) - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(base, idx, mem) - return true - } - return false -} func rewriteValue386_Op386ADDLload(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -1442,109 +1265,6 @@ func rewriteValue386_Op386ADDLload(v *Value) bool { v.AddArg3(val, base, mem) return true } - // match: (ADDLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (ADDLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL4 { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - idx := v_1.Args[1] - ptr := v_1.Args[0] - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386ADDLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386ADDLloadidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (ADDLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) - // cond: is32Bit(off1+off2) - // result: (ADDLloadidx4 [off1+off2] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386ADDLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (ADDLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) - // cond: is32Bit(off1+off2*4) - // result: (ADDLloadidx4 [off1+off2*4] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - base := v_1 - if v_2.Op != Op386ADDLconst { - break - } - off2 := v_2.AuxInt - idx := v_2.Args[0] - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386ADDLloadidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (ADDLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (ADDLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386ADDLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, base, idx, mem) - return true - } return false } func rewriteValue386_Op386ADDLmodify(v *Value) bool { @@ -1600,107 +1320,6 @@ func rewriteValue386_Op386ADDLmodify(v *Value) bool { } return false } -func rewriteValue386_Op386ADDLmodifyidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (ADDLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem) - // cond: is32Bit(off1+off2) - // result: (ADDLmodifyidx4 [off1+off2] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - off2 := v_0.AuxInt - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386ADDLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (ADDLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem) - // cond: is32Bit(off1+off2*4) - // result: (ADDLmodifyidx4 [off1+off2*4] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - base := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386ADDLmodifyidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (ADDLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (ADDLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386ADDLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(base, idx, val, mem) - return true - } - // match: (ADDLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) - // cond: validValAndOff(c,off) - // result: (ADDLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - if v_2.Op != Op386MOVLconst { - break - } - c := v_2.AuxInt - mem := v_3 - if !(validValAndOff(c, off)) { - break - } - v.reset(Op386ADDLconstmodifyidx4) - v.AuxInt = makeValAndOff(c, off) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} func rewriteValue386_Op386ADDSD(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -1915,32 +1534,6 @@ func rewriteValue386_Op386ANDL(v *Value) bool { } break } - // match: (ANDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) - // cond: canMergeLoadClobber(v, l, x) && clobber(l) - // result: (ANDLloadidx4 x [off] {sym} ptr idx mem) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - l := v_1 - if l.Op != Op386MOVLloadidx4 { - continue - } - off := l.AuxInt - sym := l.Aux - mem := l.Args[2] - ptr := l.Args[0] - idx := l.Args[1] - if !(canMergeLoadClobber(v, l, x) && clobber(l)) { - continue - } - v.reset(Op386ANDLloadidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(x, ptr, idx, mem) - return true - } - break - } // match: (ANDL x x) // result: x for { @@ -2057,81 +1650,6 @@ func rewriteValue386_Op386ANDLconstmodify(v *Value) bool { } return false } -func rewriteValue386_Op386ANDLconstmodifyidx4(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (ANDLconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem) - // cond: ValAndOff(valoff1).canAdd(off2) - // result: (ANDLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem) - for { - valoff1 := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - off2 := v_0.AuxInt - base := v_0.Args[0] - idx := v_1 - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2)) { - break - } - v.reset(Op386ANDLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2) - v.Aux = sym - v.AddArg3(base, idx, mem) - return true - } - // match: (ANDLconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem) - // cond: ValAndOff(valoff1).canAdd(off2*4) - // result: (ANDLconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem) - for { - valoff1 := v.AuxInt - sym := v.Aux - base := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2 * 4)) { - break - } - v.reset(Op386ANDLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2 * 4) - v.Aux = sym - v.AddArg3(base, idx, mem) - return true - } - // match: (ANDLconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem) - // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (ANDLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem) - for { - valoff1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - base := v_0.Args[0] - idx := v_1 - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386ANDLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2) - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(base, idx, mem) - return true - } - return false -} func rewriteValue386_Op386ANDLload(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -2183,109 +1701,6 @@ func rewriteValue386_Op386ANDLload(v *Value) bool { v.AddArg3(val, base, mem) return true } - // match: (ANDLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (ANDLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL4 { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - idx := v_1.Args[1] - ptr := v_1.Args[0] - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386ANDLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386ANDLloadidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (ANDLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) - // cond: is32Bit(off1+off2) - // result: (ANDLloadidx4 [off1+off2] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386ANDLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (ANDLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) - // cond: is32Bit(off1+off2*4) - // result: (ANDLloadidx4 [off1+off2*4] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - base := v_1 - if v_2.Op != Op386ADDLconst { - break - } - off2 := v_2.AuxInt - idx := v_2.Args[0] - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386ANDLloadidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (ANDLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (ANDLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386ANDLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, base, idx, mem) - return true - } return false } func rewriteValue386_Op386ANDLmodify(v *Value) bool { @@ -2341,107 +1756,6 @@ func rewriteValue386_Op386ANDLmodify(v *Value) bool { } return false } -func rewriteValue386_Op386ANDLmodifyidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (ANDLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem) - // cond: is32Bit(off1+off2) - // result: (ANDLmodifyidx4 [off1+off2] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - off2 := v_0.AuxInt - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386ANDLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (ANDLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem) - // cond: is32Bit(off1+off2*4) - // result: (ANDLmodifyidx4 [off1+off2*4] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - base := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386ANDLmodifyidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (ANDLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (ANDLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386ANDLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(base, idx, val, mem) - return true - } - // match: (ANDLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) - // cond: validValAndOff(c,off) - // result: (ANDLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - if v_2.Op != Op386MOVLconst { - break - } - c := v_2.AuxInt - mem := v_3 - if !(validValAndOff(c, off)) { - break - } - v.reset(Op386ANDLconstmodifyidx4) - v.AuxInt = makeValAndOff(c, off) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} func rewriteValue386_Op386CMPB(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -3768,6 +3082,76 @@ func rewriteValue386_Op386LEAL1(v *Value) bool { } break } + // match: (LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} y y)) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (LEAL2 [off1+off2] {mergeSym(sym1, sym2)} x y) + for { + off1 := v.AuxInt + sym1 := v.Aux + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x := v_0 + if v_1.Op != Op386LEAL1 { + continue + } + off2 := v_1.AuxInt + sym2 := v_1.Aux + y := v_1.Args[1] + if y != v_1.Args[0] || !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + continue + } + v.reset(Op386LEAL2) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg2(x, y) + return true + } + break + } + // match: (LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} x y)) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (LEAL2 [off1+off2] {mergeSym(sym1, sym2)} y x) + for { + off1 := v.AuxInt + sym1 := v.Aux + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x := v_0 + if v_1.Op != Op386LEAL1 { + continue + } + off2 := v_1.AuxInt + sym2 := v_1.Aux + _ = v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 { + if x != v_1_0 { + continue + } + y := v_1_1 + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + continue + } + v.reset(Op386LEAL2) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg2(y, x) + return true + } + } + break + } + // match: (LEAL1 [0] {nil} x y) + // result: (ADDL x y) + for { + if v.AuxInt != 0 || v.Aux != nil { + break + } + x := v_0 + y := v_1 + v.reset(Op386ADDL) + v.AddArg2(x, y) + return true + } return false } func rewriteValue386_Op386LEAL2(v *Value) bool { @@ -3869,6 +3253,30 @@ func rewriteValue386_Op386LEAL2(v *Value) bool { v.AddArg2(x, y) return true } + // match: (LEAL2 [off1] {sym} x (LEAL1 [off2] {nil} y y)) + // cond: is32Bit(off1+2*off2) + // result: (LEAL4 [off1+2*off2] {sym} x y) + for { + off1 := v.AuxInt + sym := v.Aux + x := v_0 + if v_1.Op != Op386LEAL1 { + break + } + off2 := v_1.AuxInt + if v_1.Aux != nil { + break + } + y := v_1.Args[1] + if y != v_1.Args[0] || !(is32Bit(off1 + 2*off2)) { + break + } + v.reset(Op386LEAL4) + v.AuxInt = off1 + 2*off2 + v.Aux = sym + v.AddArg2(x, y) + return true + } return false } func rewriteValue386_Op386LEAL4(v *Value) bool { @@ -3954,6 +3362,30 @@ func rewriteValue386_Op386LEAL4(v *Value) bool { v.AddArg2(x, y) return true } + // match: (LEAL4 [off1] {sym} x (LEAL1 [off2] {nil} y y)) + // cond: is32Bit(off1+4*off2) + // result: (LEAL8 [off1+4*off2] {sym} x y) + for { + off1 := v.AuxInt + sym := v.Aux + x := v_0 + if v_1.Op != Op386LEAL1 { + break + } + off2 := v_1.AuxInt + if v_1.Aux != nil { + break + } + y := v_1.Args[1] + if y != v_1.Args[0] || !(is32Bit(off1 + 4*off2)) { + break + } + v.reset(Op386LEAL8) + v.AuxInt = off1 + 4*off2 + v.Aux = sym + v.AddArg2(x, y) + return true + } return false } func rewriteValue386_Op386LEAL8(v *Value) bool { @@ -4146,30 +3578,6 @@ func rewriteValue386_Op386MOVBLZX(v *Value) bool { v0.AddArg2(ptr, mem) return true } - // match: (MOVBLZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) - // cond: x.Uses == 1 && clobber(x) - // result: @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem) - for { - x := v_0 - if x.Op != Op386MOVBloadidx1 { - break - } - off := x.AuxInt - sym := x.Aux - mem := x.Args[2] - ptr := x.Args[0] - idx := x.Args[1] - if !(x.Uses == 1 && clobber(x)) { - break - } - b = x.Block - v0 := b.NewValue0(v.Pos, Op386MOVBloadidx1, v.Type) - v.copyOf(v0) - v0.AuxInt = off - v0.Aux = sym - v0.AddArg3(ptr, idx, mem) - return true - } // match: (MOVBLZX (ANDLconst [c] x)) // result: (ANDLconst [c & 0xff] x) for { @@ -4254,56 +3662,6 @@ func rewriteValue386_Op386MOVBload(v *Value) bool { v.AddArg2(base, mem) return true } - // match: (MOVBload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVBloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVBloadidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVBload [off] {sym} (ADDL ptr idx) mem) - // cond: ptr.Op != OpSB - // result: (MOVBloadidx1 [off] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - mem := v_1 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVBloadidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } // match: (MOVBload [off] {sym} (SB) _) // cond: symIsRO(sym) // result: (MOVLconst [int64(read8(sym, off))]) @@ -4319,54 +3677,6 @@ func rewriteValue386_Op386MOVBload(v *Value) bool { } return false } -func rewriteValue386_Op386MOVBloadidx1(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVBloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) - // result: (MOVBloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != Op386ADDLconst { - continue - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVBloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - // match: (MOVBloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) - // result: (MOVBloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386ADDLconst { - continue - } - d := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVBloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - return false -} func rewriteValue386_Op386MOVBstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -4473,58 +3783,6 @@ func rewriteValue386_Op386MOVBstore(v *Value) bool { v.AddArg3(base, val, mem) return true } - // match: (MOVBstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVBstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - val := v_1 - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVBstoreidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVBstore [off] {sym} (ADDL ptr idx) val mem) - // cond: ptr.Op != OpSB - // result: (MOVBstoreidx1 [off] {sym} ptr idx val mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - val := v_1 - mem := v_2 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVBstoreidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } // match: (MOVBstore [i] {s} p (SHRWconst [8] w) x:(MOVBstore [i-1] {s} p w mem)) // cond: x.Uses == 1 && clobber(x) // result: (MOVWstore [i-1] {s} p w mem) @@ -4657,6 +3915,134 @@ func rewriteValue386_Op386MOVBstore(v *Value) bool { v.AddArg3(p, w0, mem) return true } + // match: (MOVBstore [i] {s} p1 (SHRWconst [8] w) x:(MOVBstore [i] {s} p0 w mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w mem) + for { + i := v.AuxInt + s := v.Aux + p1 := v_0 + if v_1.Op != Op386SHRWconst || v_1.AuxInt != 8 { + break + } + w := v_1.Args[0] + x := v_2 + if x.Op != Op386MOVBstore || x.AuxInt != i || x.Aux != s { + break + } + mem := x.Args[2] + p0 := x.Args[0] + if w != x.Args[1] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { + break + } + v.reset(Op386MOVWstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p0, w, mem) + return true + } + // match: (MOVBstore [i] {s} p1 (SHRLconst [8] w) x:(MOVBstore [i] {s} p0 w mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w mem) + for { + i := v.AuxInt + s := v.Aux + p1 := v_0 + if v_1.Op != Op386SHRLconst || v_1.AuxInt != 8 { + break + } + w := v_1.Args[0] + x := v_2 + if x.Op != Op386MOVBstore || x.AuxInt != i || x.Aux != s { + break + } + mem := x.Args[2] + p0 := x.Args[0] + if w != x.Args[1] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { + break + } + v.reset(Op386MOVWstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p0, w, mem) + return true + } + // match: (MOVBstore [i] {s} p0 w x:(MOVBstore {s} [i] p1 (SHRWconst [8] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w mem) + for { + i := v.AuxInt + s := v.Aux + p0 := v_0 + w := v_1 + x := v_2 + if x.Op != Op386MOVBstore || x.AuxInt != i || x.Aux != s { + break + } + mem := x.Args[2] + p1 := x.Args[0] + x_1 := x.Args[1] + if x_1.Op != Op386SHRWconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { + break + } + v.reset(Op386MOVWstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p0, w, mem) + return true + } + // match: (MOVBstore [i] {s} p0 w x:(MOVBstore {s} [i] p1 (SHRLconst [8] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w mem) + for { + i := v.AuxInt + s := v.Aux + p0 := v_0 + w := v_1 + x := v_2 + if x.Op != Op386MOVBstore || x.AuxInt != i || x.Aux != s { + break + } + mem := x.Args[2] + p1 := x.Args[0] + x_1 := x.Args[1] + if x_1.Op != Op386SHRLconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { + break + } + v.reset(Op386MOVWstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p0, w, mem) + return true + } + // match: (MOVBstore [i] {s} p1 (SHRLconst [j] w) x:(MOVBstore [i] {s} p0 w0:(SHRLconst [j-8] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w0 mem) + for { + i := v.AuxInt + s := v.Aux + p1 := v_0 + if v_1.Op != Op386SHRLconst { + break + } + j := v_1.AuxInt + w := v_1.Args[0] + x := v_2 + if x.Op != Op386MOVBstore || x.AuxInt != i || x.Aux != s { + break + } + mem := x.Args[2] + p0 := x.Args[0] + w0 := x.Args[1] + if w0.Op != Op386SHRLconst || w0.AuxInt != j-8 || w != w0.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { + break + } + v.reset(Op386MOVWstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p0, w0, mem) + return true + } return false } func rewriteValue386_Op386MOVBstoreconst(v *Value) bool { @@ -4707,46 +4093,6 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value) bool { v.AddArg2(ptr, mem) return true } - // match: (MOVBstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) - // cond: canMergeSym(sym1, sym2) - // result: (MOVBstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem) - for { - x := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVBstoreconstidx1) - v.AuxInt = ValAndOff(x).add(off) - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVBstoreconst [x] {sym} (ADDL ptr idx) mem) - // result: (MOVBstoreconstidx1 [x] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - v.reset(Op386MOVBstoreconstidx1) - v.AuxInt = x - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem)) // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x) // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem) @@ -4797,296 +4143,57 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value) bool { v.AddArg2(p, mem) return true } - return false -} -func rewriteValue386_Op386MOVBstoreconstidx1(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVBstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) - // result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - c := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVBstoreconstidx1) - v.AuxInt = ValAndOff(x).add(c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVBstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) - // result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - c := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVBstoreconstidx1) - v.AuxInt = ValAndOff(x).add(c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem)) - // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x) - // result: (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem) + // match: (MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() == ValAndOff(c).Off() && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem) for { c := v.AuxInt s := v.Aux - p := v_0 - i := v_1 - x := v_2 - if x.Op != Op386MOVBstoreconstidx1 { + p1 := v_0 + x := v_1 + if x.Op != Op386MOVBstoreconst { break } a := x.AuxInt if x.Aux != s { break } - mem := x.Args[2] - if p != x.Args[0] || i != x.Args[1] || !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) { + mem := x.Args[1] + p0 := x.Args[0] + if !(x.Uses == 1 && ValAndOff(a).Off() == ValAndOff(c).Off() && sequentialAddresses(p0, p1, 1) && clobber(x)) { break } - v.reset(Op386MOVWstoreconstidx1) + v.reset(Op386MOVWstoreconst) v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off()) v.Aux = s - v.AddArg3(p, i, mem) + v.AddArg2(p0, mem) return true } - return false -} -func rewriteValue386_Op386MOVBstoreidx1(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVBstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) - // result: (MOVBstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != Op386ADDLconst { - continue - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - v.reset(Op386MOVBstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - // match: (MOVBstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) - // result: (MOVBstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386ADDLconst { - continue - } - d := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVBstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - // match: (MOVBstoreidx1 [i] {s} p idx (SHRLconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem)) - // cond: x.Uses == 1 && clobber(x) - // result: (MOVWstoreidx1 [i-1] {s} p idx w mem) - for { - i := v.AuxInt - s := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - p := v_0 - idx := v_1 - if v_2.Op != Op386SHRLconst || v_2.AuxInt != 8 { - continue - } - w := v_2.Args[0] - x := v_3 - if x.Op != Op386MOVBstoreidx1 || x.AuxInt != i-1 || x.Aux != s { - continue - } - mem := x.Args[3] - x_0 := x.Args[0] - x_1 := x.Args[1] - for _i1 := 0; _i1 <= 1; _i1, x_0, x_1 = _i1+1, x_1, x_0 { - if p != x_0 || idx != x_1 || w != x.Args[2] || !(x.Uses == 1 && clobber(x)) { - continue - } - v.reset(Op386MOVWstoreidx1) - v.AuxInt = i - 1 - v.Aux = s - v.AddArg4(p, idx, w, mem) - return true - } - } - break - } - // match: (MOVBstoreidx1 [i] {s} p idx (SHRWconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem)) - // cond: x.Uses == 1 && clobber(x) - // result: (MOVWstoreidx1 [i-1] {s} p idx w mem) - for { - i := v.AuxInt - s := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - p := v_0 - idx := v_1 - if v_2.Op != Op386SHRWconst || v_2.AuxInt != 8 { - continue - } - w := v_2.Args[0] - x := v_3 - if x.Op != Op386MOVBstoreidx1 || x.AuxInt != i-1 || x.Aux != s { - continue - } - mem := x.Args[3] - x_0 := x.Args[0] - x_1 := x.Args[1] - for _i1 := 0; _i1 <= 1; _i1, x_0, x_1 = _i1+1, x_1, x_0 { - if p != x_0 || idx != x_1 || w != x.Args[2] || !(x.Uses == 1 && clobber(x)) { - continue - } - v.reset(Op386MOVWstoreidx1) - v.AuxInt = i - 1 - v.Aux = s - v.AddArg4(p, idx, w, mem) - return true - } - } - break - } - // match: (MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} p idx (SHRLconst [8] w) mem)) - // cond: x.Uses == 1 && clobber(x) - // result: (MOVWstoreidx1 [i] {s} p idx w mem) + // match: (MOVBstoreconst [a] {s} p0 x:(MOVBstoreconst [c] {s} p1 mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() == ValAndOff(c).Off() && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem) for { - i := v.AuxInt + a := v.AuxInt s := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - p := v_0 - idx := v_1 - w := v_2 - x := v_3 - if x.Op != Op386MOVBstoreidx1 || x.AuxInt != i+1 || x.Aux != s { - continue - } - mem := x.Args[3] - x_0 := x.Args[0] - x_1 := x.Args[1] - for _i1 := 0; _i1 <= 1; _i1, x_0, x_1 = _i1+1, x_1, x_0 { - if p != x_0 || idx != x_1 { - continue - } - x_2 := x.Args[2] - if x_2.Op != Op386SHRLconst || x_2.AuxInt != 8 || w != x_2.Args[0] || !(x.Uses == 1 && clobber(x)) { - continue - } - v.reset(Op386MOVWstoreidx1) - v.AuxInt = i - v.Aux = s - v.AddArg4(p, idx, w, mem) - return true - } + p0 := v_0 + x := v_1 + if x.Op != Op386MOVBstoreconst { + break } - break - } - // match: (MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} p idx (SHRWconst [8] w) mem)) - // cond: x.Uses == 1 && clobber(x) - // result: (MOVWstoreidx1 [i] {s} p idx w mem) - for { - i := v.AuxInt - s := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - p := v_0 - idx := v_1 - w := v_2 - x := v_3 - if x.Op != Op386MOVBstoreidx1 || x.AuxInt != i+1 || x.Aux != s { - continue - } - mem := x.Args[3] - x_0 := x.Args[0] - x_1 := x.Args[1] - for _i1 := 0; _i1 <= 1; _i1, x_0, x_1 = _i1+1, x_1, x_0 { - if p != x_0 || idx != x_1 { - continue - } - x_2 := x.Args[2] - if x_2.Op != Op386SHRWconst || x_2.AuxInt != 8 || w != x_2.Args[0] || !(x.Uses == 1 && clobber(x)) { - continue - } - v.reset(Op386MOVWstoreidx1) - v.AuxInt = i - v.Aux = s - v.AddArg4(p, idx, w, mem) - return true - } + c := x.AuxInt + if x.Aux != s { + break } - break - } - // match: (MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem)) - // cond: x.Uses == 1 && clobber(x) - // result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem) - for { - i := v.AuxInt - s := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - p := v_0 - idx := v_1 - if v_2.Op != Op386SHRLconst { - continue - } - j := v_2.AuxInt - w := v_2.Args[0] - x := v_3 - if x.Op != Op386MOVBstoreidx1 || x.AuxInt != i-1 || x.Aux != s { - continue - } - mem := x.Args[3] - x_0 := x.Args[0] - x_1 := x.Args[1] - for _i1 := 0; _i1 <= 1; _i1, x_0, x_1 = _i1+1, x_1, x_0 { - if p != x_0 || idx != x_1 { - continue - } - w0 := x.Args[2] - if w0.Op != Op386SHRLconst || w0.AuxInt != j-8 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { - continue - } - v.reset(Op386MOVWstoreidx1) - v.AuxInt = i - 1 - v.Aux = s - v.AddArg4(p, idx, w0, mem) - return true - } + mem := x.Args[1] + p1 := x.Args[0] + if !(x.Uses == 1 && ValAndOff(a).Off() == ValAndOff(c).Off() && sequentialAddresses(p0, p1, 1) && clobber(x)) { + break } - break + v.reset(Op386MOVWstoreconst) + v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off()) + v.Aux = s + v.AddArg2(p0, mem) + return true } return false } @@ -5158,79 +4265,6 @@ func rewriteValue386_Op386MOVLload(v *Value) bool { v.AddArg2(base, mem) return true } - // match: (MOVLload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVLloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVLloadidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLload [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL4 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLload [off] {sym} (ADDL ptr idx) mem) - // cond: ptr.Op != OpSB - // result: (MOVLloadidx1 [off] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - mem := v_1 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVLloadidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } // match: (MOVLload [off] {sym} (SB) _) // cond: symIsRO(sym) // result: (MOVLconst [int64(int32(read32(sym, off, config.ctxt.Arch.ByteOrder)))]) @@ -5246,116 +4280,6 @@ func rewriteValue386_Op386MOVLload(v *Value) bool { } return false } -func rewriteValue386_Op386MOVLloadidx1(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVLloadidx1 [c] {sym} ptr (SHLLconst [2] idx) mem) - // result: (MOVLloadidx4 [c] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386SHLLconst || v_1.AuxInt != 2 { - continue - } - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVLloadidx4) - v.AuxInt = c - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - // match: (MOVLloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) - // result: (MOVLloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != Op386ADDLconst { - continue - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVLloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - // match: (MOVLloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) - // result: (MOVLloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386ADDLconst { - continue - } - d := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVLloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - return false -} -func rewriteValue386_Op386MOVLloadidx4(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVLloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem) - // result: (MOVLloadidx4 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVLloadidx4) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem) - // result: (MOVLloadidx4 [int64(int32(c+4*d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVLloadidx4) - v.AuxInt = int64(int32(c + 4*d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} func rewriteValue386_Op386MOVLstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -5428,82 +4352,6 @@ func rewriteValue386_Op386MOVLstore(v *Value) bool { v.AddArg3(base, val, mem) return true } - // match: (MOVLstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVLstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - val := v_1 - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVLstoreidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVLstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVLstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL4 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - val := v_1 - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVLstoreidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVLstore [off] {sym} (ADDL ptr idx) val mem) - // cond: ptr.Op != OpSB - // result: (MOVLstoreidx1 [off] {sym} ptr idx val mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - val := v_1 - mem := v_2 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVLstoreidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } // match: (MOVLstore {sym} [off] ptr y:(ADDLload x [off] {sym} ptr mem) mem) // cond: y.Uses==1 && clobber(y) // result: (ADDLmodify [off] {sym} ptr x mem) @@ -5912,658 +4760,6 @@ func rewriteValue386_Op386MOVLstoreconst(v *Value) bool { v.AddArg2(ptr, mem) return true } - // match: (MOVLstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) - // cond: canMergeSym(sym1, sym2) - // result: (MOVLstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem) - for { - x := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVLstoreconstidx1) - v.AuxInt = ValAndOff(x).add(off) - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLstoreconst [x] {sym1} (LEAL4 [off] {sym2} ptr idx) mem) - // cond: canMergeSym(sym1, sym2) - // result: (MOVLstoreconstidx4 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem) - for { - x := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL4 { - break - } - off := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVLstoreconstidx4) - v.AuxInt = ValAndOff(x).add(off) - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLstoreconst [x] {sym} (ADDL ptr idx) mem) - // result: (MOVLstoreconstidx1 [x] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - v.reset(Op386MOVLstoreconstidx1) - v.AuxInt = x - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386MOVLstoreconstidx1(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVLstoreconstidx1 [c] {sym} ptr (SHLLconst [2] idx) mem) - // result: (MOVLstoreconstidx4 [c] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386SHLLconst || v_1.AuxInt != 2 { - break - } - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVLstoreconstidx4) - v.AuxInt = c - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) - // result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - c := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVLstoreconstidx1) - v.AuxInt = ValAndOff(x).add(c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) - // result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - c := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVLstoreconstidx1) - v.AuxInt = ValAndOff(x).add(c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386MOVLstoreconstidx4(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVLstoreconstidx4 [x] {sym} (ADDLconst [c] ptr) idx mem) - // result: (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - c := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVLstoreconstidx4) - v.AuxInt = ValAndOff(x).add(c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLstoreconstidx4 [x] {sym} ptr (ADDLconst [c] idx) mem) - // result: (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - c := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVLstoreconstidx4) - v.AuxInt = ValAndOff(x).add(4 * c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386MOVLstoreidx1(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVLstoreidx1 [c] {sym} ptr (SHLLconst [2] idx) val mem) - // result: (MOVLstoreidx4 [c] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386SHLLconst || v_1.AuxInt != 2 { - continue - } - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVLstoreidx4) - v.AuxInt = c - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - // match: (MOVLstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) - // result: (MOVLstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != Op386ADDLconst { - continue - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - v.reset(Op386MOVLstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - // match: (MOVLstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) - // result: (MOVLstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386ADDLconst { - continue - } - d := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVLstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - return false -} -func rewriteValue386_Op386MOVLstoreidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVLstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem) - // result: (MOVLstoreidx4 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - v.reset(Op386MOVLstoreidx4) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVLstoreidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem) - // result: (MOVLstoreidx4 [int64(int32(c+4*d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVLstoreidx4) - v.AuxInt = int64(int32(c + 4*d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ADDLloadidx4 x [off] {sym} ptr idx mem) mem) - // cond: y.Uses==1 && clobber(y) - // result: (ADDLmodifyidx4 [off] {sym} ptr idx x mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386ADDLloadidx4 || y.AuxInt != off || y.Aux != sym { - break - } - mem := y.Args[3] - x := y.Args[0] - if ptr != y.Args[1] || idx != y.Args[2] || mem != v_3 || !(y.Uses == 1 && clobber(y)) { - break - } - v.reset(Op386ADDLmodifyidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, x, mem) - return true - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ANDLloadidx4 x [off] {sym} ptr idx mem) mem) - // cond: y.Uses==1 && clobber(y) - // result: (ANDLmodifyidx4 [off] {sym} ptr idx x mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386ANDLloadidx4 || y.AuxInt != off || y.Aux != sym { - break - } - mem := y.Args[3] - x := y.Args[0] - if ptr != y.Args[1] || idx != y.Args[2] || mem != v_3 || !(y.Uses == 1 && clobber(y)) { - break - } - v.reset(Op386ANDLmodifyidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, x, mem) - return true - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ORLloadidx4 x [off] {sym} ptr idx mem) mem) - // cond: y.Uses==1 && clobber(y) - // result: (ORLmodifyidx4 [off] {sym} ptr idx x mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386ORLloadidx4 || y.AuxInt != off || y.Aux != sym { - break - } - mem := y.Args[3] - x := y.Args[0] - if ptr != y.Args[1] || idx != y.Args[2] || mem != v_3 || !(y.Uses == 1 && clobber(y)) { - break - } - v.reset(Op386ORLmodifyidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, x, mem) - return true - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(XORLloadidx4 x [off] {sym} ptr idx mem) mem) - // cond: y.Uses==1 && clobber(y) - // result: (XORLmodifyidx4 [off] {sym} ptr idx x mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386XORLloadidx4 || y.AuxInt != off || y.Aux != sym { - break - } - mem := y.Args[3] - x := y.Args[0] - if ptr != y.Args[1] || idx != y.Args[2] || mem != v_3 || !(y.Uses == 1 && clobber(y)) { - break - } - v.reset(Op386XORLmodifyidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, x, mem) - return true - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ADDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) - // result: (ADDLmodifyidx4 [off] {sym} ptr idx x mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386ADDL { - break - } - _ = y.Args[1] - y_0 := y.Args[0] - y_1 := y.Args[1] - for _i0 := 0; _i0 <= 1; _i0, y_0, y_1 = _i0+1, y_1, y_0 { - l := y_0 - if l.Op != Op386MOVLloadidx4 || l.AuxInt != off || l.Aux != sym { - continue - } - mem := l.Args[2] - if ptr != l.Args[0] || idx != l.Args[1] { - continue - } - x := y_1 - if mem != v_3 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l)) { - continue - } - v.reset(Op386ADDLmodifyidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, x, mem) - return true - } - break - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(SUBL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) - // result: (SUBLmodifyidx4 [off] {sym} ptr idx x mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386SUBL { - break - } - x := y.Args[1] - l := y.Args[0] - if l.Op != Op386MOVLloadidx4 || l.AuxInt != off || l.Aux != sym { - break - } - mem := l.Args[2] - if ptr != l.Args[0] || idx != l.Args[1] || mem != v_3 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l)) { - break - } - v.reset(Op386SUBLmodifyidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, x, mem) - return true - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ANDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) - // result: (ANDLmodifyidx4 [off] {sym} ptr idx x mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386ANDL { - break - } - _ = y.Args[1] - y_0 := y.Args[0] - y_1 := y.Args[1] - for _i0 := 0; _i0 <= 1; _i0, y_0, y_1 = _i0+1, y_1, y_0 { - l := y_0 - if l.Op != Op386MOVLloadidx4 || l.AuxInt != off || l.Aux != sym { - continue - } - mem := l.Args[2] - if ptr != l.Args[0] || idx != l.Args[1] { - continue - } - x := y_1 - if mem != v_3 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l)) { - continue - } - v.reset(Op386ANDLmodifyidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, x, mem) - return true - } - break - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) - // result: (ORLmodifyidx4 [off] {sym} ptr idx x mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386ORL { - break - } - _ = y.Args[1] - y_0 := y.Args[0] - y_1 := y.Args[1] - for _i0 := 0; _i0 <= 1; _i0, y_0, y_1 = _i0+1, y_1, y_0 { - l := y_0 - if l.Op != Op386MOVLloadidx4 || l.AuxInt != off || l.Aux != sym { - continue - } - mem := l.Args[2] - if ptr != l.Args[0] || idx != l.Args[1] { - continue - } - x := y_1 - if mem != v_3 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l)) { - continue - } - v.reset(Op386ORLmodifyidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, x, mem) - return true - } - break - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(XORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) - // result: (XORLmodifyidx4 [off] {sym} ptr idx x mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386XORL { - break - } - _ = y.Args[1] - y_0 := y.Args[0] - y_1 := y.Args[1] - for _i0 := 0; _i0 <= 1; _i0, y_0, y_1 = _i0+1, y_1, y_0 { - l := y_0 - if l.Op != Op386MOVLloadidx4 || l.AuxInt != off || l.Aux != sym { - continue - } - mem := l.Args[2] - if ptr != l.Args[0] || idx != l.Args[1] { - continue - } - x := y_1 - if mem != v_3 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l)) { - continue - } - v.reset(Op386XORLmodifyidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, x, mem) - return true - } - break - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ADDLconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(c,off) - // result: (ADDLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386ADDLconst { - break - } - c := y.AuxInt - l := y.Args[0] - if l.Op != Op386MOVLloadidx4 || l.AuxInt != off || l.Aux != sym { - break - } - mem := l.Args[2] - if ptr != l.Args[0] || idx != l.Args[1] || mem != v_3 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l) && validValAndOff(c, off)) { - break - } - v.reset(Op386ADDLconstmodifyidx4) - v.AuxInt = makeValAndOff(c, off) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ANDLconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(c,off) - // result: (ANDLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386ANDLconst { - break - } - c := y.AuxInt - l := y.Args[0] - if l.Op != Op386MOVLloadidx4 || l.AuxInt != off || l.Aux != sym { - break - } - mem := l.Args[2] - if ptr != l.Args[0] || idx != l.Args[1] || mem != v_3 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l) && validValAndOff(c, off)) { - break - } - v.reset(Op386ANDLconstmodifyidx4) - v.AuxInt = makeValAndOff(c, off) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ORLconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(c,off) - // result: (ORLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386ORLconst { - break - } - c := y.AuxInt - l := y.Args[0] - if l.Op != Op386MOVLloadidx4 || l.AuxInt != off || l.Aux != sym { - break - } - mem := l.Args[2] - if ptr != l.Args[0] || idx != l.Args[1] || mem != v_3 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l) && validValAndOff(c, off)) { - break - } - v.reset(Op386ORLconstmodifyidx4) - v.AuxInt = makeValAndOff(c, off) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(XORLconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(c,off) - // result: (XORLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - y := v_2 - if y.Op != Op386XORLconst { - break - } - c := y.AuxInt - l := y.Args[0] - if l.Op != Op386MOVLloadidx4 || l.AuxInt != off || l.Aux != sym { - break - } - mem := l.Args[2] - if ptr != l.Args[0] || idx != l.Args[1] || mem != v_3 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l) && validValAndOff(c, off)) { - break - } - v.reset(Op386XORLconstmodifyidx4) - v.AuxInt = makeValAndOff(c, off) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } return false } func rewriteValue386_Op386MOVSDconst(v *Value) bool { @@ -6634,163 +4830,6 @@ func rewriteValue386_Op386MOVSDload(v *Value) bool { v.AddArg2(base, mem) return true } - // match: (MOVSDload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVSDloadidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVSDload [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL8 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVSDloadidx8) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVSDload [off] {sym} (ADDL ptr idx) mem) - // cond: ptr.Op != OpSB - // result: (MOVSDloadidx1 [off] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - mem := v_1 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVSDloadidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - return false -} -func rewriteValue386_Op386MOVSDloadidx1(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVSDloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) - // result: (MOVSDloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVSDloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVSDloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) - // result: (MOVSDloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVSDloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386MOVSDloadidx8(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVSDloadidx8 [c] {sym} (ADDLconst [d] ptr) idx mem) - // result: (MOVSDloadidx8 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVSDloadidx8) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVSDloadidx8 [c] {sym} ptr (ADDLconst [d] idx) mem) - // result: (MOVSDloadidx8 [int64(int32(c+8*d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVSDloadidx8) - v.AuxInt = int64(int32(c + 8*d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } return false } func rewriteValue386_Op386MOVSDstore(v *Value) bool { @@ -6844,172 +4883,6 @@ func rewriteValue386_Op386MOVSDstore(v *Value) bool { v.AddArg3(base, val, mem) return true } - // match: (MOVSDstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - val := v_1 - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVSDstoreidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVSDstore [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL8 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - val := v_1 - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVSDstoreidx8) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVSDstore [off] {sym} (ADDL ptr idx) val mem) - // cond: ptr.Op != OpSB - // result: (MOVSDstoreidx1 [off] {sym} ptr idx val mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - val := v_1 - mem := v_2 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVSDstoreidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - return false -} -func rewriteValue386_Op386MOVSDstoreidx1(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVSDstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) - // result: (MOVSDstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - v.reset(Op386MOVSDstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVSDstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) - // result: (MOVSDstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVSDstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - return false -} -func rewriteValue386_Op386MOVSDstoreidx8(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVSDstoreidx8 [c] {sym} (ADDLconst [d] ptr) idx val mem) - // result: (MOVSDstoreidx8 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - v.reset(Op386MOVSDstoreidx8) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem) - // result: (MOVSDstoreidx8 [int64(int32(c+8*d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVSDstoreidx8) - v.AuxInt = int64(int32(c + 8*d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } return false } func rewriteValue386_Op386MOVSSconst(v *Value) bool { @@ -7080,163 +4953,6 @@ func rewriteValue386_Op386MOVSSload(v *Value) bool { v.AddArg2(base, mem) return true } - // match: (MOVSSload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVSSloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVSSloadidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVSSload [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVSSloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL4 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVSSloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVSSload [off] {sym} (ADDL ptr idx) mem) - // cond: ptr.Op != OpSB - // result: (MOVSSloadidx1 [off] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - mem := v_1 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVSSloadidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - return false -} -func rewriteValue386_Op386MOVSSloadidx1(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVSSloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) - // result: (MOVSSloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVSSloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVSSloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) - // result: (MOVSSloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVSSloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386MOVSSloadidx4(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVSSloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem) - // result: (MOVSSloadidx4 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVSSloadidx4) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVSSloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem) - // result: (MOVSSloadidx4 [int64(int32(c+4*d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVSSloadidx4) - v.AuxInt = int64(int32(c + 4*d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } return false } func rewriteValue386_Op386MOVSSstore(v *Value) bool { @@ -7290,172 +5006,6 @@ func rewriteValue386_Op386MOVSSstore(v *Value) bool { v.AddArg3(base, val, mem) return true } - // match: (MOVSSstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVSSstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - val := v_1 - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVSSstoreidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVSSstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL4 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - val := v_1 - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVSSstoreidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVSSstore [off] {sym} (ADDL ptr idx) val mem) - // cond: ptr.Op != OpSB - // result: (MOVSSstoreidx1 [off] {sym} ptr idx val mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - val := v_1 - mem := v_2 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVSSstoreidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - return false -} -func rewriteValue386_Op386MOVSSstoreidx1(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVSSstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) - // result: (MOVSSstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - v.reset(Op386MOVSSstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVSSstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) - // result: (MOVSSstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVSSstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - return false -} -func rewriteValue386_Op386MOVSSstoreidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVSSstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem) - // result: (MOVSSstoreidx4 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - v.reset(Op386MOVSSstoreidx4) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVSSstoreidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem) - // result: (MOVSSstoreidx4 [int64(int32(c+4*d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVSSstoreidx4) - v.AuxInt = int64(int32(c + 4*d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } return false } func rewriteValue386_Op386MOVWLSX(v *Value) bool { @@ -7579,54 +5129,6 @@ func rewriteValue386_Op386MOVWLZX(v *Value) bool { v0.AddArg2(ptr, mem) return true } - // match: (MOVWLZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) - // cond: x.Uses == 1 && clobber(x) - // result: @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem) - for { - x := v_0 - if x.Op != Op386MOVWloadidx1 { - break - } - off := x.AuxInt - sym := x.Aux - mem := x.Args[2] - ptr := x.Args[0] - idx := x.Args[1] - if !(x.Uses == 1 && clobber(x)) { - break - } - b = x.Block - v0 := b.NewValue0(v.Pos, Op386MOVWloadidx1, v.Type) - v.copyOf(v0) - v0.AuxInt = off - v0.Aux = sym - v0.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWLZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) - // cond: x.Uses == 1 && clobber(x) - // result: @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem) - for { - x := v_0 - if x.Op != Op386MOVWloadidx2 { - break - } - off := x.AuxInt - sym := x.Aux - mem := x.Args[2] - ptr := x.Args[0] - idx := x.Args[1] - if !(x.Uses == 1 && clobber(x)) { - break - } - b = x.Block - v0 := b.NewValue0(v.Pos, Op386MOVWloadidx2, v.Type) - v.copyOf(v0) - v0.AuxInt = off - v0.Aux = sym - v0.AddArg3(ptr, idx, mem) - return true - } // match: (MOVWLZX (ANDLconst [c] x)) // result: (ANDLconst [c & 0xffff] x) for { @@ -7711,79 +5213,6 @@ func rewriteValue386_Op386MOVWload(v *Value) bool { v.AddArg2(base, mem) return true } - // match: (MOVWload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVWloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVWloadidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWload [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL2 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVWloadidx2) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWload [off] {sym} (ADDL ptr idx) mem) - // cond: ptr.Op != OpSB - // result: (MOVWloadidx1 [off] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - mem := v_1 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVWloadidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } // match: (MOVWload [off] {sym} (SB) _) // cond: symIsRO(sym) // result: (MOVLconst [int64(read16(sym, off, config.ctxt.Arch.ByteOrder))]) @@ -7799,116 +5228,6 @@ func rewriteValue386_Op386MOVWload(v *Value) bool { } return false } -func rewriteValue386_Op386MOVWloadidx1(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVWloadidx1 [c] {sym} ptr (SHLLconst [1] idx) mem) - // result: (MOVWloadidx2 [c] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386SHLLconst || v_1.AuxInt != 1 { - continue - } - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVWloadidx2) - v.AuxInt = c - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - // match: (MOVWloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) - // result: (MOVWloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != Op386ADDLconst { - continue - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVWloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - // match: (MOVWloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) - // result: (MOVWloadidx1 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386ADDLconst { - continue - } - d := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVWloadidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - break - } - return false -} -func rewriteValue386_Op386MOVWloadidx2(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVWloadidx2 [c] {sym} (ADDLconst [d] ptr) idx mem) - // result: (MOVWloadidx2 [int64(int32(c+d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVWloadidx2) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWloadidx2 [c] {sym} ptr (ADDLconst [d] idx) mem) - // result: (MOVWloadidx2 [int64(int32(c+2*d))] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVWloadidx2) - v.AuxInt = int64(int32(c + 2*d)) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} func rewriteValue386_Op386MOVWstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -8015,82 +5334,6 @@ func rewriteValue386_Op386MOVWstore(v *Value) bool { v.AddArg3(base, val, mem) return true } - // match: (MOVWstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVWstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - val := v_1 - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVWstoreidx1) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVWstore [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL2 { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - val := v_1 - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVWstoreidx2) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVWstore [off] {sym} (ADDL ptr idx) val mem) - // cond: ptr.Op != OpSB - // result: (MOVWstoreidx1 [off] {sym} ptr idx val mem) - for { - off := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - v_0_1 := v_0.Args[1] - for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { - ptr := v_0_0 - idx := v_0_1 - val := v_1 - mem := v_2 - if !(ptr.Op != OpSB) { - continue - } - v.reset(Op386MOVWstoreidx1) - v.AuxInt = off - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } // match: (MOVWstore [i] {s} p (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p w mem)) // cond: x.Uses == 1 && clobber(x) // result: (MOVLstore [i-2] {s} p w mem) @@ -8146,6 +5389,60 @@ func rewriteValue386_Op386MOVWstore(v *Value) bool { v.AddArg3(p, w0, mem) return true } + // match: (MOVWstore [i] {s} p1 (SHRLconst [16] w) x:(MOVWstore [i] {s} p0 w mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x) + // result: (MOVLstore [i] {s} p0 w mem) + for { + i := v.AuxInt + s := v.Aux + p1 := v_0 + if v_1.Op != Op386SHRLconst || v_1.AuxInt != 16 { + break + } + w := v_1.Args[0] + x := v_2 + if x.Op != Op386MOVWstore || x.AuxInt != i || x.Aux != s { + break + } + mem := x.Args[2] + p0 := x.Args[0] + if w != x.Args[1] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x)) { + break + } + v.reset(Op386MOVLstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p0, w, mem) + return true + } + // match: (MOVWstore [i] {s} p1 (SHRLconst [j] w) x:(MOVWstore [i] {s} p0 w0:(SHRLconst [j-16] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x) + // result: (MOVLstore [i] {s} p0 w0 mem) + for { + i := v.AuxInt + s := v.Aux + p1 := v_0 + if v_1.Op != Op386SHRLconst { + break + } + j := v_1.AuxInt + w := v_1.Args[0] + x := v_2 + if x.Op != Op386MOVWstore || x.AuxInt != i || x.Aux != s { + break + } + mem := x.Args[2] + p0 := x.Args[0] + w0 := x.Args[1] + if w0.Op != Op386SHRLconst || w0.AuxInt != j-16 || w != w0.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x)) { + break + } + v.reset(Op386MOVLstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p0, w0, mem) + return true + } return false } func rewriteValue386_Op386MOVWstoreconst(v *Value) bool { @@ -8196,69 +5493,6 @@ func rewriteValue386_Op386MOVWstoreconst(v *Value) bool { v.AddArg2(ptr, mem) return true } - // match: (MOVWstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) - // cond: canMergeSym(sym1, sym2) - // result: (MOVWstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem) - for { - x := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL1 { - break - } - off := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVWstoreconstidx1) - v.AuxInt = ValAndOff(x).add(off) - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWstoreconst [x] {sym1} (LEAL2 [off] {sym2} ptr idx) mem) - // cond: canMergeSym(sym1, sym2) - // result: (MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem) - for { - x := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL2 { - break - } - off := v_0.AuxInt - sym2 := v_0.Aux - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - if !(canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MOVWstoreconstidx2) - v.AuxInt = ValAndOff(x).add(off) - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWstoreconst [x] {sym} (ADDL ptr idx) mem) - // result: (MOVWstoreconstidx1 [x] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDL { - break - } - idx := v_0.Args[1] - ptr := v_0.Args[0] - mem := v_1 - v.reset(Op386MOVWstoreconstidx1) - v.AuxInt = x - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } // match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) // result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem) @@ -8309,413 +5543,56 @@ func rewriteValue386_Op386MOVWstoreconst(v *Value) bool { v.AddArg2(p, mem) return true } - return false -} -func rewriteValue386_Op386MOVWstoreconstidx1(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVWstoreconstidx1 [c] {sym} ptr (SHLLconst [1] idx) mem) - // result: (MOVWstoreconstidx2 [c] {sym} ptr idx mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386SHLLconst || v_1.AuxInt != 1 { - break - } - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVWstoreconstidx2) - v.AuxInt = c - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) - // result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - c := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVWstoreconstidx1) - v.AuxInt = ValAndOff(x).add(c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) - // result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - c := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVWstoreconstidx1) - v.AuxInt = ValAndOff(x).add(c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem)) - // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) - // result: (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem) + // match: (MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() == ValAndOff(c).Off() && sequentialAddresses(p0, p1, 2) && clobber(x) + // result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem) for { c := v.AuxInt s := v.Aux - p := v_0 - i := v_1 - x := v_2 - if x.Op != Op386MOVWstoreconstidx1 { + p1 := v_0 + x := v_1 + if x.Op != Op386MOVWstoreconst { break } a := x.AuxInt if x.Aux != s { break } - mem := x.Args[2] - if p != x.Args[0] || i != x.Args[1] || !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) { + mem := x.Args[1] + p0 := x.Args[0] + if !(x.Uses == 1 && ValAndOff(a).Off() == ValAndOff(c).Off() && sequentialAddresses(p0, p1, 2) && clobber(x)) { break } - v.reset(Op386MOVLstoreconstidx1) + v.reset(Op386MOVLstoreconst) v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off()) v.Aux = s - v.AddArg3(p, i, mem) + v.AddArg2(p0, mem) return true } - return false -} -func rewriteValue386_Op386MOVWstoreconstidx2(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (MOVWstoreconstidx2 [x] {sym} (ADDLconst [c] ptr) idx mem) - // result: (MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem) + // match: (MOVWstoreconst [a] {s} p0 x:(MOVWstoreconst [c] {s} p1 mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() == ValAndOff(c).Off() && sequentialAddresses(p0, p1, 2) && clobber(x) + // result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem) for { - x := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - c := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - mem := v_2 - v.reset(Op386MOVWstoreconstidx2) - v.AuxInt = ValAndOff(x).add(c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWstoreconstidx2 [x] {sym} ptr (ADDLconst [c] idx) mem) - // result: (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem) - for { - x := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - c := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - v.reset(Op386MOVWstoreconstidx2) - v.AuxInt = ValAndOff(x).add(2 * c) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - // match: (MOVWstoreconstidx2 [c] {s} p i x:(MOVWstoreconstidx2 [a] {s} p i mem)) - // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) - // result: (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLLconst <i.Type> [1] i) mem) - for { - c := v.AuxInt + a := v.AuxInt s := v.Aux - p := v_0 - i := v_1 - x := v_2 - if x.Op != Op386MOVWstoreconstidx2 { + p0 := v_0 + x := v_1 + if x.Op != Op386MOVWstoreconst { break } - a := x.AuxInt + c := x.AuxInt if x.Aux != s { break } - mem := x.Args[2] - if p != x.Args[0] || i != x.Args[1] || !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) { + mem := x.Args[1] + p1 := x.Args[0] + if !(x.Uses == 1 && ValAndOff(a).Off() == ValAndOff(c).Off() && sequentialAddresses(p0, p1, 2) && clobber(x)) { break } - v.reset(Op386MOVLstoreconstidx1) + v.reset(Op386MOVLstoreconst) v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off()) v.Aux = s - v0 := b.NewValue0(v.Pos, Op386SHLLconst, i.Type) - v0.AuxInt = 1 - v0.AddArg(i) - v.AddArg3(p, v0, mem) - return true - } - return false -} -func rewriteValue386_Op386MOVWstoreidx1(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (MOVWstoreidx1 [c] {sym} ptr (SHLLconst [1] idx) val mem) - // result: (MOVWstoreidx2 [c] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386SHLLconst || v_1.AuxInt != 1 { - continue - } - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVWstoreidx2) - v.AuxInt = c - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - // match: (MOVWstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) - // result: (MOVWstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != Op386ADDLconst { - continue - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - v.reset(Op386MOVWstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - // match: (MOVWstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) - // result: (MOVWstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - ptr := v_0 - if v_1.Op != Op386ADDLconst { - continue - } - d := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVWstoreidx1) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - break - } - // match: (MOVWstoreidx1 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem)) - // cond: x.Uses == 1 && clobber(x) - // result: (MOVLstoreidx1 [i-2] {s} p idx w mem) - for { - i := v.AuxInt - s := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - p := v_0 - idx := v_1 - if v_2.Op != Op386SHRLconst || v_2.AuxInt != 16 { - continue - } - w := v_2.Args[0] - x := v_3 - if x.Op != Op386MOVWstoreidx1 || x.AuxInt != i-2 || x.Aux != s { - continue - } - mem := x.Args[3] - x_0 := x.Args[0] - x_1 := x.Args[1] - for _i1 := 0; _i1 <= 1; _i1, x_0, x_1 = _i1+1, x_1, x_0 { - if p != x_0 || idx != x_1 || w != x.Args[2] || !(x.Uses == 1 && clobber(x)) { - continue - } - v.reset(Op386MOVLstoreidx1) - v.AuxInt = i - 2 - v.Aux = s - v.AddArg4(p, idx, w, mem) - return true - } - } - break - } - // match: (MOVWstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem)) - // cond: x.Uses == 1 && clobber(x) - // result: (MOVLstoreidx1 [i-2] {s} p idx w0 mem) - for { - i := v.AuxInt - s := v.Aux - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - p := v_0 - idx := v_1 - if v_2.Op != Op386SHRLconst { - continue - } - j := v_2.AuxInt - w := v_2.Args[0] - x := v_3 - if x.Op != Op386MOVWstoreidx1 || x.AuxInt != i-2 || x.Aux != s { - continue - } - mem := x.Args[3] - x_0 := x.Args[0] - x_1 := x.Args[1] - for _i1 := 0; _i1 <= 1; _i1, x_0, x_1 = _i1+1, x_1, x_0 { - if p != x_0 || idx != x_1 { - continue - } - w0 := x.Args[2] - if w0.Op != Op386SHRLconst || w0.AuxInt != j-16 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { - continue - } - v.reset(Op386MOVLstoreidx1) - v.AuxInt = i - 2 - v.Aux = s - v.AddArg4(p, idx, w0, mem) - return true - } - } - break - } - return false -} -func rewriteValue386_Op386MOVWstoreidx2(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (MOVWstoreidx2 [c] {sym} (ADDLconst [d] ptr) idx val mem) - // result: (MOVWstoreidx2 [int64(int32(c+d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - d := v_0.AuxInt - ptr := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - v.reset(Op386MOVWstoreidx2) - v.AuxInt = int64(int32(c + d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVWstoreidx2 [c] {sym} ptr (ADDLconst [d] idx) val mem) - // result: (MOVWstoreidx2 [int64(int32(c+2*d))] {sym} ptr idx val mem) - for { - c := v.AuxInt - sym := v.Aux - ptr := v_0 - if v_1.Op != Op386ADDLconst { - break - } - d := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - v.reset(Op386MOVWstoreidx2) - v.AuxInt = int64(int32(c + 2*d)) - v.Aux = sym - v.AddArg4(ptr, idx, val, mem) - return true - } - // match: (MOVWstoreidx2 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem)) - // cond: x.Uses == 1 && clobber(x) - // result: (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w mem) - for { - i := v.AuxInt - s := v.Aux - p := v_0 - idx := v_1 - if v_2.Op != Op386SHRLconst || v_2.AuxInt != 16 { - break - } - w := v_2.Args[0] - x := v_3 - if x.Op != Op386MOVWstoreidx2 || x.AuxInt != i-2 || x.Aux != s { - break - } - mem := x.Args[3] - if p != x.Args[0] || idx != x.Args[1] || w != x.Args[2] || !(x.Uses == 1 && clobber(x)) { - break - } - v.reset(Op386MOVLstoreidx1) - v.AuxInt = i - 2 - v.Aux = s - v0 := b.NewValue0(v.Pos, Op386SHLLconst, idx.Type) - v0.AuxInt = 1 - v0.AddArg(idx) - v.AddArg4(p, v0, w, mem) - return true - } - // match: (MOVWstoreidx2 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem)) - // cond: x.Uses == 1 && clobber(x) - // result: (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w0 mem) - for { - i := v.AuxInt - s := v.Aux - p := v_0 - idx := v_1 - if v_2.Op != Op386SHRLconst { - break - } - j := v_2.AuxInt - w := v_2.Args[0] - x := v_3 - if x.Op != Op386MOVWstoreidx2 || x.AuxInt != i-2 || x.Aux != s { - break - } - mem := x.Args[3] - if p != x.Args[0] || idx != x.Args[1] { - break - } - w0 := x.Args[2] - if w0.Op != Op386SHRLconst || w0.AuxInt != j-16 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { - break - } - v.reset(Op386MOVLstoreidx1) - v.AuxInt = i - 2 - v.Aux = s - v0 := b.NewValue0(v.Pos, Op386SHLLconst, idx.Type) - v0.AuxInt = 1 - v0.AddArg(idx) - v.AddArg4(p, v0, w0, mem) + v.AddArg2(p0, mem) return true } return false @@ -8764,32 +5641,6 @@ func rewriteValue386_Op386MULL(v *Value) bool { } break } - // match: (MULL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) - // cond: canMergeLoadClobber(v, l, x) && clobber(l) - // result: (MULLloadidx4 x [off] {sym} ptr idx mem) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - l := v_1 - if l.Op != Op386MOVLloadidx4 { - continue - } - off := l.AuxInt - sym := l.Aux - mem := l.Args[2] - ptr := l.Args[0] - idx := l.Args[1] - if !(canMergeLoadClobber(v, l, x) && clobber(l)) { - continue - } - v.reset(Op386MULLloadidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(x, ptr, idx, mem) - return true - } - break - } return false } func rewriteValue386_Op386MULLconst(v *Value) bool { @@ -9267,109 +6118,6 @@ func rewriteValue386_Op386MULLload(v *Value) bool { v.AddArg3(val, base, mem) return true } - // match: (MULLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (MULLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL4 { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - idx := v_1.Args[1] - ptr := v_1.Args[0] - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386MULLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386MULLloadidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (MULLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) - // cond: is32Bit(off1+off2) - // result: (MULLloadidx4 [off1+off2] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386MULLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (MULLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) - // cond: is32Bit(off1+off2*4) - // result: (MULLloadidx4 [off1+off2*4] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - base := v_1 - if v_2.Op != Op386ADDLconst { - break - } - off2 := v_2.AuxInt - idx := v_2.Args[0] - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386MULLloadidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (MULLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (MULLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386MULLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, base, idx, mem) - return true - } return false } func rewriteValue386_Op386MULSD(v *Value) bool { @@ -9692,32 +6440,6 @@ func rewriteValue386_Op386ORL(v *Value) bool { } break } - // match: (ORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) - // cond: canMergeLoadClobber(v, l, x) && clobber(l) - // result: (ORLloadidx4 x [off] {sym} ptr idx mem) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - l := v_1 - if l.Op != Op386MOVLloadidx4 { - continue - } - off := l.AuxInt - sym := l.Aux - mem := l.Args[2] - ptr := l.Args[0] - idx := l.Args[1] - if !(canMergeLoadClobber(v, l, x) && clobber(l)) { - continue - } - v.reset(Op386ORLloadidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(x, ptr, idx, mem) - return true - } - break - } // match: (ORL x x) // result: x for { @@ -9767,6 +6489,42 @@ func rewriteValue386_Op386ORL(v *Value) bool { } break } + // match: (ORL x0:(MOVBload [i] {s} p0 mem) s0:(SHLLconst [8] x1:(MOVBload [i] {s} p1 mem))) + // cond: x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, s0) + // result: @mergePoint(b,x0,x1) (MOVWload [i] {s} p0 mem) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x0 := v_0 + if x0.Op != Op386MOVBload { + continue + } + i := x0.AuxInt + s := x0.Aux + mem := x0.Args[1] + p0 := x0.Args[0] + s0 := v_1 + if s0.Op != Op386SHLLconst || s0.AuxInt != 8 { + continue + } + x1 := s0.Args[0] + if x1.Op != Op386MOVBload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] + p1 := x1.Args[0] + if mem != x1.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, s0)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x1.Pos, Op386MOVWload, typ.UInt16) + v.copyOf(v0) + v0.AuxInt = i + v0.Aux = s + v0.AddArg2(p0, mem) + return true + } + break + } // match: (ORL o0:(ORL x0:(MOVWload [i0] {s} p mem) s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p mem))) s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p mem))) // cond: i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b,x0,x1,x2) != nil && clobber(x0, x1, x2, s0, s1, o0) // result: @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p mem) @@ -9831,57 +6589,9 @@ func rewriteValue386_Op386ORL(v *Value) bool { } break } - // match: (ORL x0:(MOVBloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem))) - // cond: i1==i0+1 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, s0) - // result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x0 := v_0 - if x0.Op != Op386MOVBloadidx1 { - continue - } - i0 := x0.AuxInt - s := x0.Aux - mem := x0.Args[2] - x0_0 := x0.Args[0] - x0_1 := x0.Args[1] - for _i1 := 0; _i1 <= 1; _i1, x0_0, x0_1 = _i1+1, x0_1, x0_0 { - p := x0_0 - idx := x0_1 - s0 := v_1 - if s0.Op != Op386SHLLconst || s0.AuxInt != 8 { - continue - } - x1 := s0.Args[0] - if x1.Op != Op386MOVBloadidx1 { - continue - } - i1 := x1.AuxInt - if x1.Aux != s { - continue - } - _ = x1.Args[2] - x1_0 := x1.Args[0] - x1_1 := x1.Args[1] - for _i2 := 0; _i2 <= 1; _i2, x1_0, x1_1 = _i2+1, x1_1, x1_0 { - if p != x1_0 || idx != x1_1 || mem != x1.Args[2] || !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, s0)) { - continue - } - b = mergePoint(b, x0, x1) - v0 := b.NewValue0(v.Pos, Op386MOVWloadidx1, v.Type) - v.copyOf(v0) - v0.AuxInt = i0 - v0.Aux = s - v0.AddArg3(p, idx, mem) - return true - } - } - } - break - } - // match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem))) - // cond: i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b,x0,x1,x2) != nil && clobber(x0, x1, x2, s0, s1, o0) - // result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem) + // match: (ORL o0:(ORL x0:(MOVWload [i] {s} p0 mem) s0:(SHLLconst [16] x1:(MOVBload [i] {s} p1 mem))) s1:(SHLLconst [24] x2:(MOVBload [i] {s} p2 mem))) + // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && sequentialAddresses(p0, p1, 2) && sequentialAddresses(p1, p2, 1) && mergePoint(b,x0,x1,x2) != nil && clobber(x0, x1, x2, s0, s1, o0) + // result: @mergePoint(b,x0,x1,x2) (MOVLload [i] {s} p0 mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { o0 := v_0 @@ -9893,65 +6603,46 @@ func rewriteValue386_Op386ORL(v *Value) bool { o0_1 := o0.Args[1] for _i1 := 0; _i1 <= 1; _i1, o0_0, o0_1 = _i1+1, o0_1, o0_0 { x0 := o0_0 - if x0.Op != Op386MOVWloadidx1 { + if x0.Op != Op386MOVWload { continue } - i0 := x0.AuxInt + i := x0.AuxInt s := x0.Aux - mem := x0.Args[2] - x0_0 := x0.Args[0] - x0_1 := x0.Args[1] - for _i2 := 0; _i2 <= 1; _i2, x0_0, x0_1 = _i2+1, x0_1, x0_0 { - p := x0_0 - idx := x0_1 - s0 := o0_1 - if s0.Op != Op386SHLLconst || s0.AuxInt != 16 { - continue - } - x1 := s0.Args[0] - if x1.Op != Op386MOVBloadidx1 { - continue - } - i2 := x1.AuxInt - if x1.Aux != s { - continue - } - _ = x1.Args[2] - x1_0 := x1.Args[0] - x1_1 := x1.Args[1] - for _i3 := 0; _i3 <= 1; _i3, x1_0, x1_1 = _i3+1, x1_1, x1_0 { - if p != x1_0 || idx != x1_1 || mem != x1.Args[2] { - continue - } - s1 := v_1 - if s1.Op != Op386SHLLconst || s1.AuxInt != 24 { - continue - } - x2 := s1.Args[0] - if x2.Op != Op386MOVBloadidx1 { - continue - } - i3 := x2.AuxInt - if x2.Aux != s { - continue - } - _ = x2.Args[2] - x2_0 := x2.Args[0] - x2_1 := x2.Args[1] - for _i4 := 0; _i4 <= 1; _i4, x2_0, x2_1 = _i4+1, x2_1, x2_0 { - if p != x2_0 || idx != x2_1 || mem != x2.Args[2] || !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0, x1, x2, s0, s1, o0)) { - continue - } - b = mergePoint(b, x0, x1, x2) - v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type) - v.copyOf(v0) - v0.AuxInt = i0 - v0.Aux = s - v0.AddArg3(p, idx, mem) - return true - } - } + mem := x0.Args[1] + p0 := x0.Args[0] + s0 := o0_1 + if s0.Op != Op386SHLLconst || s0.AuxInt != 16 { + continue + } + x1 := s0.Args[0] + if x1.Op != Op386MOVBload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] + p1 := x1.Args[0] + if mem != x1.Args[1] { + continue + } + s1 := v_1 + if s1.Op != Op386SHLLconst || s1.AuxInt != 24 { + continue } + x2 := s1.Args[0] + if x2.Op != Op386MOVBload || x2.AuxInt != i || x2.Aux != s { + continue + } + _ = x2.Args[1] + p2 := x2.Args[0] + if mem != x2.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && sequentialAddresses(p0, p1, 2) && sequentialAddresses(p1, p2, 1) && mergePoint(b, x0, x1, x2) != nil && clobber(x0, x1, x2, s0, s1, o0)) { + continue + } + b = mergePoint(b, x0, x1, x2) + v0 := b.NewValue0(x2.Pos, Op386MOVLload, typ.UInt32) + v.copyOf(v0) + v0.AuxInt = i + v0.Aux = s + v0.AddArg2(p0, mem) + return true } } break @@ -10048,81 +6739,6 @@ func rewriteValue386_Op386ORLconstmodify(v *Value) bool { } return false } -func rewriteValue386_Op386ORLconstmodifyidx4(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (ORLconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem) - // cond: ValAndOff(valoff1).canAdd(off2) - // result: (ORLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem) - for { - valoff1 := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - off2 := v_0.AuxInt - base := v_0.Args[0] - idx := v_1 - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2)) { - break - } - v.reset(Op386ORLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2) - v.Aux = sym - v.AddArg3(base, idx, mem) - return true - } - // match: (ORLconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem) - // cond: ValAndOff(valoff1).canAdd(off2*4) - // result: (ORLconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem) - for { - valoff1 := v.AuxInt - sym := v.Aux - base := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2 * 4)) { - break - } - v.reset(Op386ORLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2 * 4) - v.Aux = sym - v.AddArg3(base, idx, mem) - return true - } - // match: (ORLconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem) - // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (ORLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem) - for { - valoff1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - base := v_0.Args[0] - idx := v_1 - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386ORLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2) - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(base, idx, mem) - return true - } - return false -} func rewriteValue386_Op386ORLload(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -10174,109 +6790,6 @@ func rewriteValue386_Op386ORLload(v *Value) bool { v.AddArg3(val, base, mem) return true } - // match: (ORLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (ORLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL4 { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - idx := v_1.Args[1] - ptr := v_1.Args[0] - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386ORLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386ORLloadidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (ORLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) - // cond: is32Bit(off1+off2) - // result: (ORLloadidx4 [off1+off2] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386ORLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (ORLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) - // cond: is32Bit(off1+off2*4) - // result: (ORLloadidx4 [off1+off2*4] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - base := v_1 - if v_2.Op != Op386ADDLconst { - break - } - off2 := v_2.AuxInt - idx := v_2.Args[0] - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386ORLloadidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (ORLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (ORLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386ORLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, base, idx, mem) - return true - } return false } func rewriteValue386_Op386ORLmodify(v *Value) bool { @@ -10332,107 +6845,6 @@ func rewriteValue386_Op386ORLmodify(v *Value) bool { } return false } -func rewriteValue386_Op386ORLmodifyidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (ORLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem) - // cond: is32Bit(off1+off2) - // result: (ORLmodifyidx4 [off1+off2] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - off2 := v_0.AuxInt - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386ORLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (ORLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem) - // cond: is32Bit(off1+off2*4) - // result: (ORLmodifyidx4 [off1+off2*4] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - base := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386ORLmodifyidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (ORLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (ORLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386ORLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(base, idx, val, mem) - return true - } - // match: (ORLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) - // cond: validValAndOff(c,off) - // result: (ORLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - if v_2.Op != Op386MOVLconst { - break - } - c := v_2.AuxInt - mem := v_3 - if !(validValAndOff(c, off)) { - break - } - v.reset(Op386ORLconstmodifyidx4) - v.AuxInt = makeValAndOff(c, off) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} func rewriteValue386_Op386ROLBconst(v *Value) bool { v_0 := v.Args[0] // match: (ROLBconst [c] (ROLBconst [d] x)) @@ -11629,29 +8041,6 @@ func rewriteValue386_Op386SUBL(v *Value) bool { v.AddArg3(x, ptr, mem) return true } - // match: (SUBL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) - // cond: canMergeLoadClobber(v, l, x) && clobber(l) - // result: (SUBLloadidx4 x [off] {sym} ptr idx mem) - for { - x := v_0 - l := v_1 - if l.Op != Op386MOVLloadidx4 { - break - } - off := l.AuxInt - sym := l.Aux - mem := l.Args[2] - ptr := l.Args[0] - idx := l.Args[1] - if !(canMergeLoadClobber(v, l, x) && clobber(l)) { - break - } - v.reset(Op386SUBLloadidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(x, ptr, idx, mem) - return true - } // match: (SUBL x x) // result: (MOVLconst [0]) for { @@ -11759,109 +8148,6 @@ func rewriteValue386_Op386SUBLload(v *Value) bool { v.AddArg3(val, base, mem) return true } - // match: (SUBLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (SUBLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL4 { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - idx := v_1.Args[1] - ptr := v_1.Args[0] - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386SUBLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386SUBLloadidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (SUBLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) - // cond: is32Bit(off1+off2) - // result: (SUBLloadidx4 [off1+off2] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386SUBLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (SUBLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) - // cond: is32Bit(off1+off2*4) - // result: (SUBLloadidx4 [off1+off2*4] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - base := v_1 - if v_2.Op != Op386ADDLconst { - break - } - off2 := v_2.AuxInt - idx := v_2.Args[0] - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386SUBLloadidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (SUBLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (SUBLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386SUBLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, base, idx, mem) - return true - } return false } func rewriteValue386_Op386SUBLmodify(v *Value) bool { @@ -11917,107 +8203,6 @@ func rewriteValue386_Op386SUBLmodify(v *Value) bool { } return false } -func rewriteValue386_Op386SUBLmodifyidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (SUBLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem) - // cond: is32Bit(off1+off2) - // result: (SUBLmodifyidx4 [off1+off2] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - off2 := v_0.AuxInt - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386SUBLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (SUBLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem) - // cond: is32Bit(off1+off2*4) - // result: (SUBLmodifyidx4 [off1+off2*4] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - base := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386SUBLmodifyidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (SUBLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (SUBLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386SUBLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(base, idx, val, mem) - return true - } - // match: (SUBLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) - // cond: validValAndOff(-c,off) - // result: (ADDLconstmodifyidx4 [makeValAndOff(-c,off)] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - if v_2.Op != Op386MOVLconst { - break - } - c := v_2.AuxInt - mem := v_3 - if !(validValAndOff(-c, off)) { - break - } - v.reset(Op386ADDLconstmodifyidx4) - v.AuxInt = makeValAndOff(-c, off) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} func rewriteValue386_Op386SUBSD(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -12300,32 +8485,6 @@ func rewriteValue386_Op386XORL(v *Value) bool { } break } - // match: (XORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) - // cond: canMergeLoadClobber(v, l, x) && clobber(l) - // result: (XORLloadidx4 x [off] {sym} ptr idx mem) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - l := v_1 - if l.Op != Op386MOVLloadidx4 { - continue - } - off := l.AuxInt - sym := l.Aux - mem := l.Args[2] - ptr := l.Args[0] - idx := l.Args[1] - if !(canMergeLoadClobber(v, l, x) && clobber(l)) { - continue - } - v.reset(Op386XORLloadidx4) - v.AuxInt = off - v.Aux = sym - v.AddArg4(x, ptr, idx, mem) - return true - } - break - } // match: (XORL x x) // result: (MOVLconst [0]) for { @@ -12431,81 +8590,6 @@ func rewriteValue386_Op386XORLconstmodify(v *Value) bool { } return false } -func rewriteValue386_Op386XORLconstmodifyidx4(v *Value) bool { - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (XORLconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem) - // cond: ValAndOff(valoff1).canAdd(off2) - // result: (XORLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem) - for { - valoff1 := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - off2 := v_0.AuxInt - base := v_0.Args[0] - idx := v_1 - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2)) { - break - } - v.reset(Op386XORLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2) - v.Aux = sym - v.AddArg3(base, idx, mem) - return true - } - // match: (XORLconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem) - // cond: ValAndOff(valoff1).canAdd(off2*4) - // result: (XORLconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem) - for { - valoff1 := v.AuxInt - sym := v.Aux - base := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - idx := v_1.Args[0] - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2 * 4)) { - break - } - v.reset(Op386XORLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2 * 4) - v.Aux = sym - v.AddArg3(base, idx, mem) - return true - } - // match: (XORLconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem) - // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (XORLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem) - for { - valoff1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - base := v_0.Args[0] - idx := v_1 - mem := v_2 - if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386XORLconstmodifyidx4) - v.AuxInt = ValAndOff(valoff1).add(off2) - v.Aux = mergeSym(sym1, sym2) - v.AddArg3(base, idx, mem) - return true - } - return false -} func rewriteValue386_Op386XORLload(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -12557,109 +8641,6 @@ func rewriteValue386_Op386XORLload(v *Value) bool { v.AddArg3(val, base, mem) return true } - // match: (XORLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) - // result: (XORLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL4 { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - idx := v_1.Args[1] - ptr := v_1.Args[0] - mem := v_2 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { - break - } - v.reset(Op386XORLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, ptr, idx, mem) - return true - } - return false -} -func rewriteValue386_Op386XORLloadidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (XORLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) - // cond: is32Bit(off1+off2) - // result: (XORLloadidx4 [off1+off2] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386XORLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (XORLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) - // cond: is32Bit(off1+off2*4) - // result: (XORLloadidx4 [off1+off2*4] {sym} val base idx mem) - for { - off1 := v.AuxInt - sym := v.Aux - val := v_0 - base := v_1 - if v_2.Op != Op386ADDLconst { - break - } - off2 := v_2.AuxInt - idx := v_2.Args[0] - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386XORLloadidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(val, base, idx, mem) - return true - } - // match: (XORLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (XORLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - val := v_0 - if v_1.Op != Op386LEAL { - break - } - off2 := v_1.AuxInt - sym2 := v_1.Aux - base := v_1.Args[0] - idx := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386XORLloadidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(val, base, idx, mem) - return true - } return false } func rewriteValue386_Op386XORLmodify(v *Value) bool { @@ -12715,107 +8696,6 @@ func rewriteValue386_Op386XORLmodify(v *Value) bool { } return false } -func rewriteValue386_Op386XORLmodifyidx4(v *Value) bool { - v_3 := v.Args[3] - v_2 := v.Args[2] - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (XORLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem) - // cond: is32Bit(off1+off2) - // result: (XORLmodifyidx4 [off1+off2] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - if v_0.Op != Op386ADDLconst { - break - } - off2 := v_0.AuxInt - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2)) { - break - } - v.reset(Op386XORLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (XORLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem) - // cond: is32Bit(off1+off2*4) - // result: (XORLmodifyidx4 [off1+off2*4] {sym} base idx val mem) - for { - off1 := v.AuxInt - sym := v.Aux - base := v_0 - if v_1.Op != Op386ADDLconst { - break - } - off2 := v_1.AuxInt - idx := v_1.Args[0] - val := v_2 - mem := v_3 - if !(is32Bit(off1 + off2*4)) { - break - } - v.reset(Op386XORLmodifyidx4) - v.AuxInt = off1 + off2*4 - v.Aux = sym - v.AddArg4(base, idx, val, mem) - return true - } - // match: (XORLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem) - // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) - // result: (XORLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem) - for { - off1 := v.AuxInt - sym1 := v.Aux - if v_0.Op != Op386LEAL { - break - } - off2 := v_0.AuxInt - sym2 := v_0.Aux - base := v_0.Args[0] - idx := v_1 - val := v_2 - mem := v_3 - if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { - break - } - v.reset(Op386XORLmodifyidx4) - v.AuxInt = off1 + off2 - v.Aux = mergeSym(sym1, sym2) - v.AddArg4(base, idx, val, mem) - return true - } - // match: (XORLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) - // cond: validValAndOff(c,off) - // result: (XORLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem) - for { - off := v.AuxInt - sym := v.Aux - ptr := v_0 - idx := v_1 - if v_2.Op != Op386MOVLconst { - break - } - c := v_2.AuxInt - mem := v_3 - if !(validValAndOff(c, off)) { - break - } - v.reset(Op386XORLconstmodifyidx4) - v.AuxInt = makeValAndOff(c, off) - v.Aux = sym - v.AddArg3(ptr, idx, mem) - return true - } - return false -} func rewriteValue386_OpConstNil(v *Value) bool { // match: (ConstNil) // result: (MOVLconst [0]) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index b9a401cca9..e4d86485d4 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -10140,7 +10140,6 @@ func rewriteValueAMD64_OpAMD64MOVBatomicload(v *Value) bool { func rewriteValueAMD64_OpAMD64MOVBload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] - b := v.Block // match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) // result: (MOVBQZX x) @@ -10205,118 +10204,6 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value) bool { v.AddArg2(base, mem) return true } - // match: (MOVBload [i0] {s0} l:(LEAQ1 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVBload [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ1 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVBload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ1, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVBload [i0] {s0} l:(LEAQ2 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVBload [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ2 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVBload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVBload [i0] {s0} l:(LEAQ4 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVBload [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ4 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVBload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVBload [i0] {s0} l:(LEAQ8 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVBload [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ8 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVBload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } // match: (MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem) // cond: canMergeSym(sym1, sym2) && is32Bit(off1+off2) // result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem) @@ -10722,159 +10609,124 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.AddArg3(base, val, mem) return true } - // match: (MOVBstore [i0] {s0} l:(LEAQ1 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVBstore [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) val mem) + // match: (MOVBstore [i] {s} p w x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem)) + // cond: x0.Uses == 1 && clobber(x0) + // result: (MOVWstore [i-1] {s} p (ROLWconst <w.Type> [8] w) mem) for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ1 { + i := v.AuxInt + s := v.Aux + p := v_0 + w := v_1 + x0 := v_2 + if x0.Op != OpAMD64MOVBstore || x0.AuxInt != i-1 || x0.Aux != s { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + mem := x0.Args[2] + if p != x0.Args[0] { break } - v.reset(OpAMD64MOVBstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ1, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) + x0_1 := x0.Args[1] + if x0_1.Op != OpAMD64SHRWconst || x0_1.AuxInt != 8 || w != x0_1.Args[0] || !(x0.Uses == 1 && clobber(x0)) { + break + } + v.reset(OpAMD64MOVWstore) + v.AuxInt = i - 1 + v.Aux = s + v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, w.Type) + v0.AuxInt = 8 + v0.AddArg(w) + v.AddArg3(p, v0, mem) return true } - // match: (MOVBstore [i0] {s0} l:(LEAQ2 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVBstore [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) val mem) + // match: (MOVBstore [i] {s} p1 w x0:(MOVBstore [i] {s} p0 (SHRWconst [8] w) mem)) + // cond: x0.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x0) + // result: (MOVWstore [i] {s} p0 (ROLWconst <w.Type> [8] w) mem) for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ2 { + i := v.AuxInt + s := v.Aux + p1 := v_0 + w := v_1 + x0 := v_2 + if x0.Op != OpAMD64MOVBstore || x0.AuxInt != i || x0.Aux != s { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + mem := x0.Args[2] + p0 := x0.Args[0] + x0_1 := x0.Args[1] + if x0_1.Op != OpAMD64SHRWconst || x0_1.AuxInt != 8 || w != x0_1.Args[0] || !(x0.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x0)) { break } - v.reset(OpAMD64MOVBstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) + v.reset(OpAMD64MOVWstore) + v.AuxInt = i + v.Aux = s + v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, w.Type) + v0.AuxInt = 8 + v0.AddArg(w) + v.AddArg3(p0, v0, mem) return true } - // match: (MOVBstore [i0] {s0} l:(LEAQ4 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVBstore [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) val mem) + // match: (MOVBstore [i] {s} p w x2:(MOVBstore [i-1] {s} p (SHRLconst [8] w) x1:(MOVBstore [i-2] {s} p (SHRLconst [16] w) x0:(MOVBstore [i-3] {s} p (SHRLconst [24] w) mem)))) + // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) + // result: (MOVLstore [i-3] {s} p (BSWAPL <w.Type> w) mem) for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ4 { + i := v.AuxInt + s := v.Aux + p := v_0 + w := v_1 + x2 := v_2 + if x2.Op != OpAMD64MOVBstore || x2.AuxInt != i-1 || x2.Aux != s { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + _ = x2.Args[2] + if p != x2.Args[0] { break } - v.reset(OpAMD64MOVBstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) - return true - } - // match: (MOVBstore [i0] {s0} l:(LEAQ8 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVBstore [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) val mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ8 { + x2_1 := x2.Args[1] + if x2_1.Op != OpAMD64SHRLconst || x2_1.AuxInt != 8 || w != x2_1.Args[0] { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + x1 := x2.Args[2] + if x1.Op != OpAMD64MOVBstore || x1.AuxInt != i-2 || x1.Aux != s { break } - v.reset(OpAMD64MOVBstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) - return true - } - // match: (MOVBstore [i] {s} p1 w x0:(MOVBstore [i-1] {s} p0 (SHRWconst [8] w) mem)) - // cond: x0.Uses == 1 && same(p0, p1, 1) && clobber(x0) - // result: (MOVWstore [i-1] {s} p0 (ROLWconst <w.Type> [8] w) mem) - for { - i := v.AuxInt - s := v.Aux - p1 := v_0 - w := v_1 - x0 := v_2 - if x0.Op != OpAMD64MOVBstore || x0.AuxInt != i-1 || x0.Aux != s { + _ = x1.Args[2] + if p != x1.Args[0] { + break + } + x1_1 := x1.Args[1] + if x1_1.Op != OpAMD64SHRLconst || x1_1.AuxInt != 16 || w != x1_1.Args[0] { + break + } + x0 := x1.Args[2] + if x0.Op != OpAMD64MOVBstore || x0.AuxInt != i-3 || x0.Aux != s { break } mem := x0.Args[2] - p0 := x0.Args[0] + if p != x0.Args[0] { + break + } x0_1 := x0.Args[1] - if x0_1.Op != OpAMD64SHRWconst || x0_1.AuxInt != 8 || w != x0_1.Args[0] || !(x0.Uses == 1 && same(p0, p1, 1) && clobber(x0)) { + if x0_1.Op != OpAMD64SHRLconst || x0_1.AuxInt != 24 || w != x0_1.Args[0] || !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2)) { break } - v.reset(OpAMD64MOVWstore) - v.AuxInt = i - 1 + v.reset(OpAMD64MOVLstore) + v.AuxInt = i - 3 v.Aux = s - v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, w.Type) - v0.AuxInt = 8 + v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, w.Type) v0.AddArg(w) - v.AddArg3(p0, v0, mem) + v.AddArg3(p, v0, mem) return true } - // match: (MOVBstore [i] {s} p3 w x2:(MOVBstore [i-1] {s} p2 (SHRLconst [8] w) x1:(MOVBstore [i-2] {s} p1 (SHRLconst [16] w) x0:(MOVBstore [i-3] {s} p0 (SHRLconst [24] w) mem)))) - // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && same(p0, p1, 1) && same(p1, p2, 1) && same(p2, p3, 1) && clobber(x0, x1, x2) - // result: (MOVLstore [i-3] {s} p0 (BSWAPL <w.Type> w) mem) + // match: (MOVBstore [i] {s} p3 w x2:(MOVBstore [i] {s} p2 (SHRLconst [8] w) x1:(MOVBstore [i] {s} p1 (SHRLconst [16] w) x0:(MOVBstore [i] {s} p0 (SHRLconst [24] w) mem)))) + // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && clobber(x0, x1, x2) + // result: (MOVLstore [i] {s} p0 (BSWAPL <w.Type> w) mem) for { i := v.AuxInt s := v.Aux p3 := v_0 w := v_1 x2 := v_2 - if x2.Op != OpAMD64MOVBstore || x2.AuxInt != i-1 || x2.Aux != s { + if x2.Op != OpAMD64MOVBstore || x2.AuxInt != i || x2.Aux != s { break } _ = x2.Args[2] @@ -10884,7 +10736,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } x1 := x2.Args[2] - if x1.Op != OpAMD64MOVBstore || x1.AuxInt != i-2 || x1.Aux != s { + if x1.Op != OpAMD64MOVBstore || x1.AuxInt != i || x1.Aux != s { break } _ = x1.Args[2] @@ -10894,37 +10746,39 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } x0 := x1.Args[2] - if x0.Op != OpAMD64MOVBstore || x0.AuxInt != i-3 || x0.Aux != s { + if x0.Op != OpAMD64MOVBstore || x0.AuxInt != i || x0.Aux != s { break } mem := x0.Args[2] p0 := x0.Args[0] x0_1 := x0.Args[1] - if x0_1.Op != OpAMD64SHRLconst || x0_1.AuxInt != 24 || w != x0_1.Args[0] || !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && same(p0, p1, 1) && same(p1, p2, 1) && same(p2, p3, 1) && clobber(x0, x1, x2)) { + if x0_1.Op != OpAMD64SHRLconst || x0_1.AuxInt != 24 || w != x0_1.Args[0] || !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && clobber(x0, x1, x2)) { break } v.reset(OpAMD64MOVLstore) - v.AuxInt = i - 3 + v.AuxInt = i v.Aux = s v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, w.Type) v0.AddArg(w) v.AddArg3(p0, v0, mem) return true } - // match: (MOVBstore [i] {s} p7 w x6:(MOVBstore [i-1] {s} p6 (SHRQconst [8] w) x5:(MOVBstore [i-2] {s} p5 (SHRQconst [16] w) x4:(MOVBstore [i-3] {s} p4 (SHRQconst [24] w) x3:(MOVBstore [i-4] {s} p3 (SHRQconst [32] w) x2:(MOVBstore [i-5] {s} p2 (SHRQconst [40] w) x1:(MOVBstore [i-6] {s} p1 (SHRQconst [48] w) x0:(MOVBstore [i-7] {s} p0 (SHRQconst [56] w) mem)))))))) - // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && same(p0, p1, 1) && same(p1, p2, 1) && same(p2, p3, 1) && same(p3, p4, 1) && same(p4, p5, 1) && same(p5, p6, 1) && same(p6, p7, 1) && clobber(x0, x1, x2, x3, x4, x5, x6) - // result: (MOVQstore [i-7] {s} p0 (BSWAPQ <w.Type> w) mem) + // match: (MOVBstore [i] {s} p w x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w) x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w) x4:(MOVBstore [i-3] {s} p (SHRQconst [24] w) x3:(MOVBstore [i-4] {s} p (SHRQconst [32] w) x2:(MOVBstore [i-5] {s} p (SHRQconst [40] w) x1:(MOVBstore [i-6] {s} p (SHRQconst [48] w) x0:(MOVBstore [i-7] {s} p (SHRQconst [56] w) mem)))))))) + // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && clobber(x0, x1, x2, x3, x4, x5, x6) + // result: (MOVQstore [i-7] {s} p (BSWAPQ <w.Type> w) mem) for { i := v.AuxInt s := v.Aux - p7 := v_0 + p := v_0 w := v_1 x6 := v_2 if x6.Op != OpAMD64MOVBstore || x6.AuxInt != i-1 || x6.Aux != s { break } _ = x6.Args[2] - p6 := x6.Args[0] + if p != x6.Args[0] { + break + } x6_1 := x6.Args[1] if x6_1.Op != OpAMD64SHRQconst || x6_1.AuxInt != 8 || w != x6_1.Args[0] { break @@ -10934,7 +10788,9 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } _ = x5.Args[2] - p5 := x5.Args[0] + if p != x5.Args[0] { + break + } x5_1 := x5.Args[1] if x5_1.Op != OpAMD64SHRQconst || x5_1.AuxInt != 16 || w != x5_1.Args[0] { break @@ -10944,7 +10800,9 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } _ = x4.Args[2] - p4 := x4.Args[0] + if p != x4.Args[0] { + break + } x4_1 := x4.Args[1] if x4_1.Op != OpAMD64SHRQconst || x4_1.AuxInt != 24 || w != x4_1.Args[0] { break @@ -10954,7 +10812,9 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } _ = x3.Args[2] - p3 := x3.Args[0] + if p != x3.Args[0] { + break + } x3_1 := x3.Args[1] if x3_1.Op != OpAMD64SHRQconst || x3_1.AuxInt != 32 || w != x3_1.Args[0] { break @@ -10964,7 +10824,9 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } _ = x2.Args[2] - p2 := x2.Args[0] + if p != x2.Args[0] { + break + } x2_1 := x2.Args[1] if x2_1.Op != OpAMD64SHRQconst || x2_1.AuxInt != 40 || w != x2_1.Args[0] { break @@ -10974,7 +10836,9 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } _ = x1.Args[2] - p1 := x1.Args[0] + if p != x1.Args[0] { + break + } x1_1 := x1.Args[1] if x1_1.Op != OpAMD64SHRQconst || x1_1.AuxInt != 48 || w != x1_1.Args[0] { break @@ -10984,9 +10848,11 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } mem := x0.Args[2] - p0 := x0.Args[0] + if p != x0.Args[0] { + break + } x0_1 := x0.Args[1] - if x0_1.Op != OpAMD64SHRQconst || x0_1.AuxInt != 56 || w != x0_1.Args[0] || !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && same(p0, p1, 1) && same(p1, p2, 1) && same(p2, p3, 1) && same(p3, p4, 1) && same(p4, p5, 1) && same(p5, p6, 1) && same(p6, p7, 1) && clobber(x0, x1, x2, x3, x4, x5, x6)) { + if x0_1.Op != OpAMD64SHRQconst || x0_1.AuxInt != 56 || w != x0_1.Args[0] || !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && clobber(x0, x1, x2, x3, x4, x5, x6)) { break } v.reset(OpAMD64MOVQstore) @@ -10994,16 +10860,102 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.Aux = s v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, w.Type) v0.AddArg(w) + v.AddArg3(p, v0, mem) + return true + } + // match: (MOVBstore [i] {s} p7 w x6:(MOVBstore [i] {s} p6 (SHRQconst [8] w) x5:(MOVBstore [i] {s} p5 (SHRQconst [16] w) x4:(MOVBstore [i] {s} p4 (SHRQconst [24] w) x3:(MOVBstore [i] {s} p3 (SHRQconst [32] w) x2:(MOVBstore [i] {s} p2 (SHRQconst [40] w) x1:(MOVBstore [i] {s} p1 (SHRQconst [48] w) x0:(MOVBstore [i] {s} p0 (SHRQconst [56] w) mem)))))))) + // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && sequentialAddresses(p3, p4, 1) && sequentialAddresses(p4, p5, 1) && sequentialAddresses(p5, p6, 1) && sequentialAddresses(p6, p7, 1) && clobber(x0, x1, x2, x3, x4, x5, x6) + // result: (MOVQstore [i] {s} p0 (BSWAPQ <w.Type> w) mem) + for { + i := v.AuxInt + s := v.Aux + p7 := v_0 + w := v_1 + x6 := v_2 + if x6.Op != OpAMD64MOVBstore || x6.AuxInt != i || x6.Aux != s { + break + } + _ = x6.Args[2] + p6 := x6.Args[0] + x6_1 := x6.Args[1] + if x6_1.Op != OpAMD64SHRQconst || x6_1.AuxInt != 8 || w != x6_1.Args[0] { + break + } + x5 := x6.Args[2] + if x5.Op != OpAMD64MOVBstore || x5.AuxInt != i || x5.Aux != s { + break + } + _ = x5.Args[2] + p5 := x5.Args[0] + x5_1 := x5.Args[1] + if x5_1.Op != OpAMD64SHRQconst || x5_1.AuxInt != 16 || w != x5_1.Args[0] { + break + } + x4 := x5.Args[2] + if x4.Op != OpAMD64MOVBstore || x4.AuxInt != i || x4.Aux != s { + break + } + _ = x4.Args[2] + p4 := x4.Args[0] + x4_1 := x4.Args[1] + if x4_1.Op != OpAMD64SHRQconst || x4_1.AuxInt != 24 || w != x4_1.Args[0] { + break + } + x3 := x4.Args[2] + if x3.Op != OpAMD64MOVBstore || x3.AuxInt != i || x3.Aux != s { + break + } + _ = x3.Args[2] + p3 := x3.Args[0] + x3_1 := x3.Args[1] + if x3_1.Op != OpAMD64SHRQconst || x3_1.AuxInt != 32 || w != x3_1.Args[0] { + break + } + x2 := x3.Args[2] + if x2.Op != OpAMD64MOVBstore || x2.AuxInt != i || x2.Aux != s { + break + } + _ = x2.Args[2] + p2 := x2.Args[0] + x2_1 := x2.Args[1] + if x2_1.Op != OpAMD64SHRQconst || x2_1.AuxInt != 40 || w != x2_1.Args[0] { + break + } + x1 := x2.Args[2] + if x1.Op != OpAMD64MOVBstore || x1.AuxInt != i || x1.Aux != s { + break + } + _ = x1.Args[2] + p1 := x1.Args[0] + x1_1 := x1.Args[1] + if x1_1.Op != OpAMD64SHRQconst || x1_1.AuxInt != 48 || w != x1_1.Args[0] { + break + } + x0 := x1.Args[2] + if x0.Op != OpAMD64MOVBstore || x0.AuxInt != i || x0.Aux != s { + break + } + mem := x0.Args[2] + p0 := x0.Args[0] + x0_1 := x0.Args[1] + if x0_1.Op != OpAMD64SHRQconst || x0_1.AuxInt != 56 || w != x0_1.Args[0] || !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && sequentialAddresses(p3, p4, 1) && sequentialAddresses(p4, p5, 1) && sequentialAddresses(p5, p6, 1) && sequentialAddresses(p6, p7, 1) && clobber(x0, x1, x2, x3, x4, x5, x6)) { + break + } + v.reset(OpAMD64MOVQstore) + v.AuxInt = i + v.Aux = s + v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, w.Type) + v0.AddArg(w) v.AddArg3(p0, v0, mem) return true } - // match: (MOVBstore [i] {s} p1 (SHRWconst [8] w) x:(MOVBstore [i-1] {s} p0 w mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVWstore [i-1] {s} p0 w mem) + // match: (MOVBstore [i] {s} p (SHRWconst [8] w) x:(MOVBstore [i-1] {s} p w mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVWstore [i-1] {s} p w mem) for { i := v.AuxInt s := v.Aux - p1 := v_0 + p := v_0 if v_1.Op != OpAMD64SHRWconst || v_1.AuxInt != 8 { break } @@ -11013,19 +10965,232 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } mem := x.Args[2] - p0 := x.Args[0] - if w != x.Args[1] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if p != x.Args[0] || w != x.Args[1] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVWstore) + v.AuxInt = i - 1 + v.Aux = s + v.AddArg3(p, w, mem) + return true + } + // match: (MOVBstore [i] {s} p (SHRLconst [8] w) x:(MOVBstore [i-1] {s} p w mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVWstore [i-1] {s} p w mem) + for { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRLconst || v_1.AuxInt != 8 { + break + } + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVBstore || x.AuxInt != i-1 || x.Aux != s { + break + } + mem := x.Args[2] + if p != x.Args[0] || w != x.Args[1] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVWstore) + v.AuxInt = i - 1 + v.Aux = s + v.AddArg3(p, w, mem) + return true + } + // match: (MOVBstore [i] {s} p (SHRQconst [8] w) x:(MOVBstore [i-1] {s} p w mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVWstore [i-1] {s} p w mem) + for { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRQconst || v_1.AuxInt != 8 { + break + } + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVBstore || x.AuxInt != i-1 || x.Aux != s { + break + } + mem := x.Args[2] + if p != x.Args[0] || w != x.Args[1] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVWstore) + v.AuxInt = i - 1 + v.Aux = s + v.AddArg3(p, w, mem) + return true + } + // match: (MOVBstore [i] {s} p w x:(MOVBstore [i+1] {s} p (SHRWconst [8] w) mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVWstore [i] {s} p w mem) + for { + i := v.AuxInt + s := v.Aux + p := v_0 + w := v_1 + x := v_2 + if x.Op != OpAMD64MOVBstore || x.AuxInt != i+1 || x.Aux != s { + break + } + mem := x.Args[2] + if p != x.Args[0] { + break + } + x_1 := x.Args[1] + if x_1.Op != OpAMD64SHRWconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVWstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p, w, mem) + return true + } + // match: (MOVBstore [i] {s} p w x:(MOVBstore [i+1] {s} p (SHRLconst [8] w) mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVWstore [i] {s} p w mem) + for { + i := v.AuxInt + s := v.Aux + p := v_0 + w := v_1 + x := v_2 + if x.Op != OpAMD64MOVBstore || x.AuxInt != i+1 || x.Aux != s { + break + } + mem := x.Args[2] + if p != x.Args[0] { + break + } + x_1 := x.Args[1] + if x_1.Op != OpAMD64SHRLconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVWstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p, w, mem) + return true + } + // match: (MOVBstore [i] {s} p w x:(MOVBstore [i+1] {s} p (SHRQconst [8] w) mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVWstore [i] {s} p w mem) + for { + i := v.AuxInt + s := v.Aux + p := v_0 + w := v_1 + x := v_2 + if x.Op != OpAMD64MOVBstore || x.AuxInt != i+1 || x.Aux != s { + break + } + mem := x.Args[2] + if p != x.Args[0] { + break + } + x_1 := x.Args[1] + if x_1.Op != OpAMD64SHRQconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVWstore) + v.AuxInt = i + v.Aux = s + v.AddArg3(p, w, mem) + return true + } + // match: (MOVBstore [i] {s} p (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRLconst [j-8] w) mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVWstore [i-1] {s} p w0 mem) + for { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRLconst { + break + } + j := v_1.AuxInt + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVBstore || x.AuxInt != i-1 || x.Aux != s { + break + } + mem := x.Args[2] + if p != x.Args[0] { + break + } + w0 := x.Args[1] + if w0.Op != OpAMD64SHRLconst || w0.AuxInt != j-8 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { break } v.reset(OpAMD64MOVWstore) v.AuxInt = i - 1 v.Aux = s + v.AddArg3(p, w0, mem) + return true + } + // match: (MOVBstore [i] {s} p (SHRQconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRQconst [j-8] w) mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVWstore [i-1] {s} p w0 mem) + for { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRQconst { + break + } + j := v_1.AuxInt + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVBstore || x.AuxInt != i-1 || x.Aux != s { + break + } + mem := x.Args[2] + if p != x.Args[0] { + break + } + w0 := x.Args[1] + if w0.Op != OpAMD64SHRQconst || w0.AuxInt != j-8 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVWstore) + v.AuxInt = i - 1 + v.Aux = s + v.AddArg3(p, w0, mem) + return true + } + // match: (MOVBstore [i] {s} p1 (SHRWconst [8] w) x:(MOVBstore [i] {s} p0 w mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w mem) + for { + i := v.AuxInt + s := v.Aux + p1 := v_0 + if v_1.Op != OpAMD64SHRWconst || v_1.AuxInt != 8 { + break + } + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVBstore || x.AuxInt != i || x.Aux != s { + break + } + mem := x.Args[2] + p0 := x.Args[0] + if w != x.Args[1] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { + break + } + v.reset(OpAMD64MOVWstore) + v.AuxInt = i + v.Aux = s v.AddArg3(p0, w, mem) return true } - // match: (MOVBstore [i] {s} p1 (SHRLconst [8] w) x:(MOVBstore [i-1] {s} p0 w mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVWstore [i-1] {s} p0 w mem) + // match: (MOVBstore [i] {s} p1 (SHRLconst [8] w) x:(MOVBstore [i] {s} p0 w mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w mem) for { i := v.AuxInt s := v.Aux @@ -11035,23 +11200,23 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { } w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVBstore || x.AuxInt != i-1 || x.Aux != s { + if x.Op != OpAMD64MOVBstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] - if w != x.Args[1] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w != x.Args[1] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { break } v.reset(OpAMD64MOVWstore) - v.AuxInt = i - 1 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w, mem) return true } - // match: (MOVBstore [i] {s} p1 (SHRQconst [8] w) x:(MOVBstore [i-1] {s} p0 w mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVWstore [i-1] {s} p0 w mem) + // match: (MOVBstore [i] {s} p1 (SHRQconst [8] w) x:(MOVBstore [i] {s} p0 w mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w mem) for { i := v.AuxInt s := v.Aux @@ -11061,36 +11226,36 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { } w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVBstore || x.AuxInt != i-1 || x.Aux != s { + if x.Op != OpAMD64MOVBstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] - if w != x.Args[1] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w != x.Args[1] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { break } v.reset(OpAMD64MOVWstore) - v.AuxInt = i - 1 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w, mem) return true } - // match: (MOVBstore [i] {s} p1 w x:(MOVBstore [i+1] {s} p0 (SHRWconst [8] w) mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) + // match: (MOVBstore [i] {s} p0 w x:(MOVBstore [i] {s} p1 (SHRWconst [8] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) // result: (MOVWstore [i] {s} p0 w mem) for { i := v.AuxInt s := v.Aux - p1 := v_0 + p0 := v_0 w := v_1 x := v_2 - if x.Op != OpAMD64MOVBstore || x.AuxInt != i+1 || x.Aux != s { + if x.Op != OpAMD64MOVBstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] - p0 := x.Args[0] + p1 := x.Args[0] x_1 := x.Args[1] - if x_1.Op != OpAMD64SHRWconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if x_1.Op != OpAMD64SHRWconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { break } v.reset(OpAMD64MOVWstore) @@ -11099,22 +11264,22 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.AddArg3(p0, w, mem) return true } - // match: (MOVBstore [i] {s} p1 w x:(MOVBstore [i+1] {s} p0 (SHRLconst [8] w) mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) + // match: (MOVBstore [i] {s} p0 w x:(MOVBstore [i] {s} p1 (SHRLconst [8] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) // result: (MOVWstore [i] {s} p0 w mem) for { i := v.AuxInt s := v.Aux - p1 := v_0 + p0 := v_0 w := v_1 x := v_2 - if x.Op != OpAMD64MOVBstore || x.AuxInt != i+1 || x.Aux != s { + if x.Op != OpAMD64MOVBstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] - p0 := x.Args[0] + p1 := x.Args[0] x_1 := x.Args[1] - if x_1.Op != OpAMD64SHRLconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if x_1.Op != OpAMD64SHRLconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { break } v.reset(OpAMD64MOVWstore) @@ -11123,22 +11288,22 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.AddArg3(p0, w, mem) return true } - // match: (MOVBstore [i] {s} p1 w x:(MOVBstore [i+1] {s} p0 (SHRQconst [8] w) mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) + // match: (MOVBstore [i] {s} p0 w x:(MOVBstore [i] {s} p1 (SHRQconst [8] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) // result: (MOVWstore [i] {s} p0 w mem) for { i := v.AuxInt s := v.Aux - p1 := v_0 + p0 := v_0 w := v_1 x := v_2 - if x.Op != OpAMD64MOVBstore || x.AuxInt != i+1 || x.Aux != s { + if x.Op != OpAMD64MOVBstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] - p0 := x.Args[0] + p1 := x.Args[0] x_1 := x.Args[1] - if x_1.Op != OpAMD64SHRQconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if x_1.Op != OpAMD64SHRQconst || x_1.AuxInt != 8 || w != x_1.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { break } v.reset(OpAMD64MOVWstore) @@ -11147,9 +11312,9 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.AddArg3(p0, w, mem) return true } - // match: (MOVBstore [i] {s} p1 (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p0 w0:(SHRLconst [j-8] w) mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVWstore [i-1] {s} p0 w0 mem) + // match: (MOVBstore [i] {s} p1 (SHRLconst [j] w) x:(MOVBstore [i] {s} p0 w0:(SHRLconst [j-8] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w0 mem) for { i := v.AuxInt s := v.Aux @@ -11160,24 +11325,24 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { j := v_1.AuxInt w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVBstore || x.AuxInt != i-1 || x.Aux != s { + if x.Op != OpAMD64MOVBstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] w0 := x.Args[1] - if w0.Op != OpAMD64SHRLconst || w0.AuxInt != j-8 || w != w0.Args[0] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w0.Op != OpAMD64SHRLconst || w0.AuxInt != j-8 || w != w0.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { break } v.reset(OpAMD64MOVWstore) - v.AuxInt = i - 1 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w0, mem) return true } - // match: (MOVBstore [i] {s} p1 (SHRQconst [j] w) x:(MOVBstore [i-1] {s} p0 w0:(SHRQconst [j-8] w) mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVWstore [i-1] {s} p0 w0 mem) + // match: (MOVBstore [i] {s} p1 (SHRQconst [j] w) x:(MOVBstore [i] {s} p0 w0:(SHRQconst [j-8] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x) + // result: (MOVWstore [i] {s} p0 w0 mem) for { i := v.AuxInt s := v.Aux @@ -11188,17 +11353,17 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { j := v_1.AuxInt w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVBstore || x.AuxInt != i-1 || x.Aux != s { + if x.Op != OpAMD64MOVBstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] w0 := x.Args[1] - if w0.Op != OpAMD64SHRQconst || w0.AuxInt != j-8 || w != w0.Args[0] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w0.Op != OpAMD64SHRQconst || w0.AuxInt != j-8 || w != w0.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x)) { break } v.reset(OpAMD64MOVWstore) - v.AuxInt = i - 1 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w0, mem) return true @@ -11337,13 +11502,13 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value) bool { v.AddArg2(ptr, mem) return true } - // match: (MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x) - // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem) + // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x) + // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem) for { c := v.AuxInt s := v.Aux - p1 := v_0 + p := v_0 x := v_1 if x.Op != OpAMD64MOVBstoreconst { break @@ -11353,23 +11518,22 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value) bool { break } mem := x.Args[1] - p0 := x.Args[0] - if !(x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) { + if p != x.Args[0] || !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) { break } v.reset(OpAMD64MOVWstoreconst) v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off()) v.Aux = s - v.AddArg2(p0, mem) + v.AddArg2(p, mem) return true } - // match: (MOVBstoreconst [a] {s} p1 x:(MOVBstoreconst [c] {s} p0 mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x) - // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem) + // match: (MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x) + // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem) for { a := v.AuxInt s := v.Aux - p1 := v_0 + p := v_0 x := v_1 if x.Op != OpAMD64MOVBstoreconst { break @@ -11379,14 +11543,13 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value) bool { break } mem := x.Args[1] - p0 := x.Args[0] - if !(x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) { + if p != x.Args[0] || !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) { break } v.reset(OpAMD64MOVWstoreconst) v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off()) v.Aux = s - v.AddArg2(p0, mem) + v.AddArg2(p, mem) return true } // match: (MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) @@ -11860,118 +12023,6 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value) bool { v.AddArg2(base, mem) return true } - // match: (MOVLload [i0] {s0} l:(LEAQ1 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVLload [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ1 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVLload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ1, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVLload [i0] {s0} l:(LEAQ2 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVLload [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ2 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVLload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVLload [i0] {s0} l:(LEAQ4 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVLload [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ4 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVLload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVLload [i0] {s0} l:(LEAQ8 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVLload [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ8 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVLload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } // match: (MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem) // cond: canMergeSym(sym1, sym2) && is32Bit(off1+off2) // result: (MOVLload [off1+off2] {mergeSym(sym1,sym2)} base mem) @@ -12174,125 +12225,64 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { v.AddArg3(base, val, mem) return true } - // match: (MOVLstore [i0] {s0} l:(LEAQ1 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVLstore [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) val mem) + // match: (MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVQstore [i-4] {s} p w mem) for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ1 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRQconst || v_1.AuxInt != 32 { break } - v.reset(OpAMD64MOVLstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ1, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) - return true - } - // match: (MOVLstore [i0] {s0} l:(LEAQ2 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVLstore [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) val mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ2 { + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVLstore || x.AuxInt != i-4 || x.Aux != s { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + mem := x.Args[2] + if p != x.Args[0] || w != x.Args[1] || !(x.Uses == 1 && clobber(x)) { break } - v.reset(OpAMD64MOVLstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) + v.reset(OpAMD64MOVQstore) + v.AuxInt = i - 4 + v.Aux = s + v.AddArg3(p, w, mem) return true } - // match: (MOVLstore [i0] {s0} l:(LEAQ4 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVLstore [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) val mem) + // match: (MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVQstore [i-4] {s} p w0 mem) for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ4 { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRQconst { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + j := v_1.AuxInt + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVLstore || x.AuxInt != i-4 || x.Aux != s { break } - v.reset(OpAMD64MOVLstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) - return true - } - // match: (MOVLstore [i0] {s0} l:(LEAQ8 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVLstore [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) val mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ8 { + mem := x.Args[2] + if p != x.Args[0] { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + w0 := x.Args[1] + if w0.Op != OpAMD64SHRQconst || w0.AuxInt != j-32 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { break } - v.reset(OpAMD64MOVLstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) + v.reset(OpAMD64MOVQstore) + v.AuxInt = i - 4 + v.Aux = s + v.AddArg3(p, w0, mem) return true } - // match: (MOVLstore [i] {s} p1 (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p0 w mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVQstore [i-4] {s} p0 w mem) + // match: (MOVLstore [i] {s} p1 (SHRQconst [32] w) x:(MOVLstore [i] {s} p0 w mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 4) && clobber(x) + // result: (MOVQstore [i] {s} p0 w mem) for { i := v.AuxInt s := v.Aux @@ -12302,23 +12292,23 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { } w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVLstore || x.AuxInt != i-4 || x.Aux != s { + if x.Op != OpAMD64MOVLstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] - if w != x.Args[1] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w != x.Args[1] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 4) && clobber(x)) { break } v.reset(OpAMD64MOVQstore) - v.AuxInt = i - 4 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w, mem) return true } - // match: (MOVLstore [i] {s} p1 (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p0 w0:(SHRQconst [j-32] w) mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVQstore [i-4] {s} p0 w0 mem) + // match: (MOVLstore [i] {s} p1 (SHRQconst [j] w) x:(MOVLstore [i] {s} p0 w0:(SHRQconst [j-32] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 4) && clobber(x) + // result: (MOVQstore [i] {s} p0 w0 mem) for { i := v.AuxInt s := v.Aux @@ -12329,17 +12319,17 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { j := v_1.AuxInt w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVLstore || x.AuxInt != i-4 || x.Aux != s { + if x.Op != OpAMD64MOVLstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] w0 := x.Args[1] - if w0.Op != OpAMD64SHRQconst || w0.AuxInt != j-32 || w != w0.Args[0] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w0.Op != OpAMD64SHRQconst || w0.AuxInt != j-32 || w != w0.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 4) && clobber(x)) { break } v.reset(OpAMD64MOVQstore) - v.AuxInt = i - 4 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w0, mem) return true @@ -13018,13 +13008,13 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool { v.AddArg2(ptr, mem) return true } - // match: (MOVLstoreconst [c] {s} p1 x:(MOVLstoreconst [a] {s} p0 mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x) - // result: (MOVQstore [ValAndOff(a).Off()] {s} p0 (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem) + // match: (MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x) + // result: (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem) for { c := v.AuxInt s := v.Aux - p1 := v_0 + p := v_0 x := v_1 if x.Op != OpAMD64MOVLstoreconst { break @@ -13034,8 +13024,7 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool { break } mem := x.Args[1] - p0 := x.Args[0] - if !(x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) { + if p != x.Args[0] || !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) { break } v.reset(OpAMD64MOVQstore) @@ -13043,16 +13032,16 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool { v.Aux = s v0 := b.NewValue0(x.Pos, OpAMD64MOVQconst, typ.UInt64) v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32 - v.AddArg3(p0, v0, mem) + v.AddArg3(p, v0, mem) return true } - // match: (MOVLstoreconst [a] {s} p1 x:(MOVLstoreconst [c] {s} p0 mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x) - // result: (MOVQstore [ValAndOff(a).Off()] {s} p0 (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem) + // match: (MOVLstoreconst [a] {s} p x:(MOVLstoreconst [c] {s} p mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x) + // result: (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem) for { a := v.AuxInt s := v.Aux - p1 := v_0 + p := v_0 x := v_1 if x.Op != OpAMD64MOVLstoreconst { break @@ -13062,8 +13051,7 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool { break } mem := x.Args[1] - p0 := x.Args[0] - if !(x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) { + if p != x.Args[0] || !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) { break } v.reset(OpAMD64MOVQstore) @@ -13071,7 +13059,7 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool { v.Aux = s v0 := b.NewValue0(x.Pos, OpAMD64MOVQconst, typ.UInt64) v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32 - v.AddArg3(p0, v0, mem) + v.AddArg3(p, v0, mem) return true } // match: (MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) @@ -13423,118 +13411,6 @@ func rewriteValueAMD64_OpAMD64MOVQload(v *Value) bool { v.AddArg2(base, mem) return true } - // match: (MOVQload [i0] {s0} l:(LEAQ1 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVQload [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ1 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVQload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ1, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVQload [i0] {s0} l:(LEAQ2 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVQload [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ2 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVQload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVQload [i0] {s0} l:(LEAQ4 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVQload [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ4 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVQload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVQload [i0] {s0} l:(LEAQ8 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVQload [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ8 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVQload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } // match: (MOVQload [off1] {sym1} (LEAL [off2] {sym2} base) mem) // cond: canMergeSym(sym1, sym2) && is32Bit(off1+off2) // result: (MOVQload [off1+off2] {mergeSym(sym1,sym2)} base mem) @@ -13614,7 +13490,6 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] v_0 := v.Args[0] - b := v.Block // match: (MOVQstore [off1] {sym} (ADDQconst [off2] ptr) val mem) // cond: is32Bit(off1+off2) // result: (MOVQstore [off1+off2] {sym} ptr val mem) @@ -13681,122 +13556,6 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { v.AddArg3(base, val, mem) return true } - // match: (MOVQstore [i0] {s0} l:(LEAQ1 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVQstore [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) val mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ1 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVQstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ1, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) - return true - } - // match: (MOVQstore [i0] {s0} l:(LEAQ2 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVQstore [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) val mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ2 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVQstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) - return true - } - // match: (MOVQstore [i0] {s0} l:(LEAQ4 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVQstore [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) val mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ4 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVQstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) - return true - } - // match: (MOVQstore [i0] {s0} l:(LEAQ8 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVQstore [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) val mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ8 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVQstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) - return true - } // match: (MOVQstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) // cond: canMergeSym(sym1, sym2) && is32Bit(off1+off2) // result: (MOVQstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) @@ -14430,13 +14189,13 @@ func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value) bool { v.AddArg2(ptr, mem) return true } - // match: (MOVQstoreconst [c] {s} p1 x:(MOVQstoreconst [c2] {s} p0 mem)) - // cond: config.useSSE && x.Uses == 1 && same(p0, p1, 1) && ValAndOff(c2).Off() + 8 == ValAndOff(c).Off() && ValAndOff(c).Val() == 0 && ValAndOff(c2).Val() == 0 && clobber(x) - // result: (MOVOstore [ValAndOff(c2).Off()] {s} p0 (MOVOconst [0]) mem) + // match: (MOVQstoreconst [c] {s} p x:(MOVQstoreconst [c2] {s} p mem)) + // cond: config.useSSE && x.Uses == 1 && ValAndOff(c2).Off() + 8 == ValAndOff(c).Off() && ValAndOff(c).Val() == 0 && ValAndOff(c2).Val() == 0 && clobber(x) + // result: (MOVOstore [ValAndOff(c2).Off()] {s} p (MOVOconst [0]) mem) for { c := v.AuxInt s := v.Aux - p1 := v_0 + p := v_0 x := v_1 if x.Op != OpAMD64MOVQstoreconst { break @@ -14446,8 +14205,7 @@ func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value) bool { break } mem := x.Args[1] - p0 := x.Args[0] - if !(config.useSSE && x.Uses == 1 && same(p0, p1, 1) && ValAndOff(c2).Off()+8 == ValAndOff(c).Off() && ValAndOff(c).Val() == 0 && ValAndOff(c2).Val() == 0 && clobber(x)) { + if p != x.Args[0] || !(config.useSSE && x.Uses == 1 && ValAndOff(c2).Off()+8 == ValAndOff(c).Off() && ValAndOff(c).Val() == 0 && ValAndOff(c2).Val() == 0 && clobber(x)) { break } v.reset(OpAMD64MOVOstore) @@ -14455,7 +14213,7 @@ func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value) bool { v.Aux = s v0 := b.NewValue0(x.Pos, OpAMD64MOVOconst, types.TypeInt128) v0.AuxInt = 0 - v.AddArg3(p0, v0, mem) + v.AddArg3(p, v0, mem) return true } // match: (MOVQstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) @@ -15119,118 +14877,6 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value) bool { v.AddArg2(base, mem) return true } - // match: (MOVWload [i0] {s0} l:(LEAQ1 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVWload [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ1 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVWload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ1, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVWload [i0] {s0} l:(LEAQ2 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVWload [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ2 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVWload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVWload [i0] {s0} l:(LEAQ4 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVWload [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ4 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVWload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } - // match: (MOVWload [i0] {s0} l:(LEAQ8 [i1] {s1} x y) mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVWload [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) mem) - for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ8 { - break - } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - mem := v_1 - if !(i1 != 0 && is32Bit(i0+i1)) { - break - } - v.reset(OpAMD64MOVWload) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg2(v0, mem) - return true - } // match: (MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem) // cond: canMergeSym(sym1, sym2) && is32Bit(off1+off2) // result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem) @@ -15416,125 +15062,119 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { v.AddArg3(base, val, mem) return true } - // match: (MOVWstore [i0] {s0} l:(LEAQ1 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVWstore [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) val mem) + // match: (MOVWstore [i] {s} p (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p w mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVLstore [i-2] {s} p w mem) for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ1 { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRLconst || v_1.AuxInt != 16 { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVWstore || x.AuxInt != i-2 || x.Aux != s { break } - v.reset(OpAMD64MOVWstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ1, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) + mem := x.Args[2] + if p != x.Args[0] || w != x.Args[1] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVLstore) + v.AuxInt = i - 2 + v.Aux = s + v.AddArg3(p, w, mem) return true } - // match: (MOVWstore [i0] {s0} l:(LEAQ2 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVWstore [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) val mem) + // match: (MOVWstore [i] {s} p (SHRQconst [16] w) x:(MOVWstore [i-2] {s} p w mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVLstore [i-2] {s} p w mem) for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ2 { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRQconst || v_1.AuxInt != 16 { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVWstore || x.AuxInt != i-2 || x.Aux != s { break } - v.reset(OpAMD64MOVWstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) + mem := x.Args[2] + if p != x.Args[0] || w != x.Args[1] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVLstore) + v.AuxInt = i - 2 + v.Aux = s + v.AddArg3(p, w, mem) return true } - // match: (MOVWstore [i0] {s0} l:(LEAQ4 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVWstore [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) val mem) + // match: (MOVWstore [i] {s} p (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRLconst [j-16] w) mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVLstore [i-2] {s} p w0 mem) for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ4 { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRLconst { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + j := v_1.AuxInt + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVWstore || x.AuxInt != i-2 || x.Aux != s { break } - v.reset(OpAMD64MOVWstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) + mem := x.Args[2] + if p != x.Args[0] { + break + } + w0 := x.Args[1] + if w0.Op != OpAMD64SHRLconst || w0.AuxInt != j-16 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVLstore) + v.AuxInt = i - 2 + v.Aux = s + v.AddArg3(p, w0, mem) return true } - // match: (MOVWstore [i0] {s0} l:(LEAQ8 [i1] {s1} x y) val mem) - // cond: i1 != 0 && is32Bit(i0+i1) - // result: (MOVWstore [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) val mem) + // match: (MOVWstore [i] {s} p (SHRQconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRQconst [j-16] w) mem)) + // cond: x.Uses == 1 && clobber(x) + // result: (MOVLstore [i-2] {s} p w0 mem) for { - i0 := v.AuxInt - s0 := v.Aux - l := v_0 - if l.Op != OpAMD64LEAQ8 { + i := v.AuxInt + s := v.Aux + p := v_0 + if v_1.Op != OpAMD64SHRQconst { break } - i1 := l.AuxInt - s1 := l.Aux - y := l.Args[1] - x := l.Args[0] - val := v_1 - mem := v_2 - if !(i1 != 0 && is32Bit(i0+i1)) { + j := v_1.AuxInt + w := v_1.Args[0] + x := v_2 + if x.Op != OpAMD64MOVWstore || x.AuxInt != i-2 || x.Aux != s { break } - v.reset(OpAMD64MOVWstore) - v.AuxInt = i0 + i1 - v.Aux = s0 - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, l.Type) - v0.AuxInt = 0 - v0.Aux = s1 - v0.AddArg2(x, y) - v.AddArg3(v0, val, mem) + mem := x.Args[2] + if p != x.Args[0] { + break + } + w0 := x.Args[1] + if w0.Op != OpAMD64SHRQconst || w0.AuxInt != j-16 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { + break + } + v.reset(OpAMD64MOVLstore) + v.AuxInt = i - 2 + v.Aux = s + v.AddArg3(p, w0, mem) return true } - // match: (MOVWstore [i] {s} p1 (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p0 w mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVLstore [i-2] {s} p0 w mem) + // match: (MOVWstore [i] {s} p1 (SHRLconst [16] w) x:(MOVWstore [i] {s} p0 w mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x) + // result: (MOVLstore [i] {s} p0 w mem) for { i := v.AuxInt s := v.Aux @@ -15544,23 +15184,23 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { } w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVWstore || x.AuxInt != i-2 || x.Aux != s { + if x.Op != OpAMD64MOVWstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] - if w != x.Args[1] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w != x.Args[1] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x)) { break } v.reset(OpAMD64MOVLstore) - v.AuxInt = i - 2 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w, mem) return true } - // match: (MOVWstore [i] {s} p1 (SHRQconst [16] w) x:(MOVWstore [i-2] {s} p0 w mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVLstore [i-2] {s} p0 w mem) + // match: (MOVWstore [i] {s} p1 (SHRQconst [16] w) x:(MOVWstore [i] {s} p0 w mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x) + // result: (MOVLstore [i] {s} p0 w mem) for { i := v.AuxInt s := v.Aux @@ -15570,23 +15210,23 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { } w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVWstore || x.AuxInt != i-2 || x.Aux != s { + if x.Op != OpAMD64MOVWstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] - if w != x.Args[1] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w != x.Args[1] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x)) { break } v.reset(OpAMD64MOVLstore) - v.AuxInt = i - 2 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w, mem) return true } - // match: (MOVWstore [i] {s} p1 (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p0 w0:(SHRLconst [j-16] w) mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVLstore [i-2] {s} p0 w0 mem) + // match: (MOVWstore [i] {s} p1 (SHRLconst [j] w) x:(MOVWstore [i] {s} p0 w0:(SHRLconst [j-16] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x) + // result: (MOVLstore [i] {s} p0 w0 mem) for { i := v.AuxInt s := v.Aux @@ -15597,24 +15237,24 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { j := v_1.AuxInt w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVWstore || x.AuxInt != i-2 || x.Aux != s { + if x.Op != OpAMD64MOVWstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] w0 := x.Args[1] - if w0.Op != OpAMD64SHRLconst || w0.AuxInt != j-16 || w != w0.Args[0] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w0.Op != OpAMD64SHRLconst || w0.AuxInt != j-16 || w != w0.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x)) { break } v.reset(OpAMD64MOVLstore) - v.AuxInt = i - 2 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w0, mem) return true } - // match: (MOVWstore [i] {s} p1 (SHRQconst [j] w) x:(MOVWstore [i-2] {s} p0 w0:(SHRQconst [j-16] w) mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && clobber(x) - // result: (MOVLstore [i-2] {s} p0 w0 mem) + // match: (MOVWstore [i] {s} p1 (SHRQconst [j] w) x:(MOVWstore [i] {s} p0 w0:(SHRQconst [j-16] w) mem)) + // cond: x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x) + // result: (MOVLstore [i] {s} p0 w0 mem) for { i := v.AuxInt s := v.Aux @@ -15625,17 +15265,17 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { j := v_1.AuxInt w := v_1.Args[0] x := v_2 - if x.Op != OpAMD64MOVWstore || x.AuxInt != i-2 || x.Aux != s { + if x.Op != OpAMD64MOVWstore || x.AuxInt != i || x.Aux != s { break } mem := x.Args[2] p0 := x.Args[0] w0 := x.Args[1] - if w0.Op != OpAMD64SHRQconst || w0.AuxInt != j-16 || w != w0.Args[0] || !(x.Uses == 1 && same(p0, p1, 1) && clobber(x)) { + if w0.Op != OpAMD64SHRQconst || w0.AuxInt != j-16 || w != w0.Args[0] || !(x.Uses == 1 && sequentialAddresses(p0, p1, 2) && clobber(x)) { break } v.reset(OpAMD64MOVLstore) - v.AuxInt = i - 2 + v.AuxInt = i v.Aux = s v.AddArg3(p0, w0, mem) return true @@ -15774,13 +15414,13 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value) bool { v.AddArg2(ptr, mem) return true } - // match: (MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) - // result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem) + // match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) + // result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem) for { c := v.AuxInt s := v.Aux - p1 := v_0 + p := v_0 x := v_1 if x.Op != OpAMD64MOVWstoreconst { break @@ -15790,23 +15430,22 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value) bool { break } mem := x.Args[1] - p0 := x.Args[0] - if !(x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) { + if p != x.Args[0] || !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) { break } v.reset(OpAMD64MOVLstoreconst) v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off()) v.Aux = s - v.AddArg2(p0, mem) + v.AddArg2(p, mem) return true } - // match: (MOVWstoreconst [a] {s} p1 x:(MOVWstoreconst [c] {s} p0 mem)) - // cond: x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) - // result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem) + // match: (MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem)) + // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) + // result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem) for { a := v.AuxInt s := v.Aux - p1 := v_0 + p := v_0 x := v_1 if x.Op != OpAMD64MOVWstoreconst { break @@ -15816,14 +15455,13 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value) bool { break } mem := x.Args[1] - p0 := x.Args[0] - if !(x.Uses == 1 && same(p0, p1, 1) && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) { + if p != x.Args[0] || !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) { break } v.reset(OpAMD64MOVLstoreconst) v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off()) v.Aux = s - v.AddArg2(p0, mem) + v.AddArg2(p, mem) return true } // match: (MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) @@ -17887,9 +17525,9 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { v.copyOf(x) return true } - // match: (ORL x0:(MOVBload [i0] {s} p0 mem) sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p1 mem))) - // cond: i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - // result: @mergePoint(b,x0,x1) (MOVWload [i0] {s} p0 mem) + // match: (ORL x0:(MOVBload [i0] {s} p mem) sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem))) + // cond: i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { x0 := v_0 @@ -17899,7 +17537,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { i0 := x0.AuxInt s := x0.Aux mem := x0.Args[1] - p0 := x0.Args[0] + p := x0.Args[0] sh := v_1 if sh.Op != OpAMD64SHLLconst || sh.AuxInt != 8 { continue @@ -17913,8 +17551,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { continue } _ = x1.Args[1] - p1 := x1.Args[0] - if mem != x1.Args[1] || !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + if p != x1.Args[0] || mem != x1.Args[1] || !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -17922,14 +17559,50 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { v.copyOf(v0) v0.AuxInt = i0 v0.Aux = s + v0.AddArg2(p, mem) + return true + } + break + } + // match: (ORL x0:(MOVBload [i] {s} p0 mem) sh:(SHLLconst [8] x1:(MOVBload [i] {s} p1 mem))) + // cond: x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVWload [i] {s} p0 mem) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x0 := v_0 + if x0.Op != OpAMD64MOVBload { + continue + } + i := x0.AuxInt + s := x0.Aux + mem := x0.Args[1] + p0 := x0.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLLconst || sh.AuxInt != 8 { + continue + } + x1 := sh.Args[0] + if x1.Op != OpAMD64MOVBload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] + p1 := x1.Args[0] + if mem != x1.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x1.Pos, OpAMD64MOVWload, typ.UInt16) + v.copyOf(v0) + v0.AuxInt = i + v0.Aux = s v0.AddArg2(p0, mem) return true } break } - // match: (ORL x0:(MOVWload [i0] {s} p0 mem) sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p1 mem))) - // cond: i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - // result: @mergePoint(b,x0,x1) (MOVLload [i0] {s} p0 mem) + // match: (ORL x0:(MOVWload [i0] {s} p mem) sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p mem))) + // cond: i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { x0 := v_0 @@ -17939,7 +17612,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { i0 := x0.AuxInt s := x0.Aux mem := x0.Args[1] - p0 := x0.Args[0] + p := x0.Args[0] sh := v_1 if sh.Op != OpAMD64SHLLconst || sh.AuxInt != 16 { continue @@ -17953,8 +17626,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { continue } _ = x1.Args[1] - p1 := x1.Args[0] - if mem != x1.Args[1] || !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + if p != x1.Args[0] || mem != x1.Args[1] || !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -17962,14 +17634,50 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { v.copyOf(v0) v0.AuxInt = i0 v0.Aux = s + v0.AddArg2(p, mem) + return true + } + break + } + // match: (ORL x0:(MOVWload [i] {s} p0 mem) sh:(SHLLconst [16] x1:(MOVWload [i] {s} p1 mem))) + // cond: x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVLload [i] {s} p0 mem) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x0 := v_0 + if x0.Op != OpAMD64MOVWload { + continue + } + i := x0.AuxInt + s := x0.Aux + mem := x0.Args[1] + p0 := x0.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLLconst || sh.AuxInt != 16 { + continue + } + x1 := sh.Args[0] + if x1.Op != OpAMD64MOVWload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] + p1 := x1.Args[0] + if mem != x1.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x1.Pos, OpAMD64MOVLload, typ.UInt32) + v.copyOf(v0) + v0.AuxInt = i + v0.Aux = s v0.AddArg2(p0, mem) return true } break } - // match: (ORL s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p0 mem)) or:(ORL s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p1 mem)) y)) - // cond: i1 == i0+1 && j1 == j0+8 && j0 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - // result: @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p0 mem)) y) + // match: (ORL s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem)) or:(ORL s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem)) y)) + // cond: i1 == i0+1 && j1 == j0+8 && j0 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { s1 := v_0 @@ -17984,7 +17692,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { i1 := x1.AuxInt s := x1.Aux mem := x1.Args[1] - p0 := x1.Args[0] + p := x1.Args[0] or := v_1 if or.Op != OpAMD64ORL { continue @@ -18007,12 +17715,11 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { continue } _ = x0.Args[1] - p1 := x0.Args[0] - if mem != x0.Args[1] { + if p != x0.Args[0] || mem != x0.Args[1] { continue } y := or_1 - if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { continue } b = mergePoint(b, x0, x1, y) @@ -18023,6 +17730,66 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { v2 := b.NewValue0(x0.Pos, OpAMD64MOVWload, typ.UInt16) v2.AuxInt = i0 v2.Aux = s + v2.AddArg2(p, mem) + v1.AddArg(v2) + v0.AddArg2(v1, y) + return true + } + } + break + } + // match: (ORL s1:(SHLLconst [j1] x1:(MOVBload [i] {s} p1 mem)) or:(ORL s0:(SHLLconst [j0] x0:(MOVBload [i] {s} p0 mem)) y)) + // cond: j1 == j0+8 && j0 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i] {s} p0 mem)) y) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + s1 := v_0 + if s1.Op != OpAMD64SHLLconst { + continue + } + j1 := s1.AuxInt + x1 := s1.Args[0] + if x1.Op != OpAMD64MOVBload { + continue + } + i := x1.AuxInt + s := x1.Aux + mem := x1.Args[1] + p1 := x1.Args[0] + or := v_1 + if or.Op != OpAMD64ORL { + continue + } + _ = or.Args[1] + or_0 := or.Args[0] + or_1 := or.Args[1] + for _i1 := 0; _i1 <= 1; _i1, or_0, or_1 = _i1+1, or_1, or_0 { + s0 := or_0 + if s0.Op != OpAMD64SHLLconst { + continue + } + j0 := s0.AuxInt + x0 := s0.Args[0] + if x0.Op != OpAMD64MOVBload || x0.AuxInt != i || x0.Aux != s { + continue + } + _ = x0.Args[1] + p0 := x0.Args[0] + if mem != x0.Args[1] { + continue + } + y := or_1 + if !(j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + continue + } + b = mergePoint(b, x0, x1, y) + v0 := b.NewValue0(x0.Pos, OpAMD64ORL, v.Type) + v.copyOf(v0) + v1 := b.NewValue0(x0.Pos, OpAMD64SHLLconst, v.Type) + v1.AuxInt = j0 + v2 := b.NewValue0(x0.Pos, OpAMD64MOVWload, typ.UInt16) + v2.AuxInt = i + v2.Aux = s v2.AddArg2(p0, mem) v1.AddArg(v2) v0.AddArg2(v1, y) @@ -18031,9 +17798,9 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { } break } - // match: (ORL x1:(MOVBload [i1] {s} p0 mem) sh:(SHLLconst [8] x0:(MOVBload [i0] {s} p1 mem))) - // cond: i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - // result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p0 mem)) + // match: (ORL x1:(MOVBload [i1] {s} p mem) sh:(SHLLconst [8] x0:(MOVBload [i0] {s} p mem))) + // cond: i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem)) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { x1 := v_0 @@ -18043,7 +17810,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { i1 := x1.AuxInt s := x1.Aux mem := x1.Args[1] - p0 := x1.Args[0] + p := x1.Args[0] sh := v_1 if sh.Op != OpAMD64SHLLconst || sh.AuxInt != 8 { continue @@ -18057,8 +17824,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { continue } _ = x0.Args[1] - p1 := x0.Args[0] - if mem != x0.Args[1] || !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + if p != x0.Args[0] || mem != x0.Args[1] || !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -18068,15 +17834,54 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { v1 := b.NewValue0(x0.Pos, OpAMD64MOVWload, typ.UInt16) v1.AuxInt = i0 v1.Aux = s + v1.AddArg2(p, mem) + v0.AddArg(v1) + return true + } + break + } + // match: (ORL x1:(MOVBload [i] {s} p1 mem) sh:(SHLLconst [8] x0:(MOVBload [i] {s} p0 mem))) + // cond: x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i] {s} p0 mem)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x1 := v_0 + if x1.Op != OpAMD64MOVBload { + continue + } + i := x1.AuxInt + s := x1.Aux + mem := x1.Args[1] + p1 := x1.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLLconst || sh.AuxInt != 8 { + continue + } + x0 := sh.Args[0] + if x0.Op != OpAMD64MOVBload || x0.AuxInt != i || x0.Aux != s { + continue + } + _ = x0.Args[1] + p0 := x0.Args[0] + if mem != x0.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, v.Type) + v.copyOf(v0) + v0.AuxInt = 8 + v1 := b.NewValue0(x0.Pos, OpAMD64MOVWload, typ.UInt16) + v1.AuxInt = i + v1.Aux = s v1.AddArg2(p0, mem) v0.AddArg(v1) return true } break } - // match: (ORL r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p0 mem)) sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p1 mem)))) - // cond: i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) - // result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p0 mem)) + // match: (ORL r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)) sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem)))) + // cond: i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) + // result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem)) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { r1 := v_0 @@ -18090,7 +17895,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { i1 := x1.AuxInt s := x1.Aux mem := x1.Args[1] - p0 := x1.Args[0] + p := x1.Args[0] sh := v_1 if sh.Op != OpAMD64SHLLconst || sh.AuxInt != 16 { continue @@ -18108,8 +17913,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { continue } _ = x0.Args[1] - p1 := x0.Args[0] - if mem != x0.Args[1] || !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, r0, r1, sh)) { + if p != x0.Args[0] || mem != x0.Args[1] || !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, r0, r1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -18118,15 +17922,61 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { v1 := b.NewValue0(x0.Pos, OpAMD64MOVLload, typ.UInt32) v1.AuxInt = i0 v1.Aux = s + v1.AddArg2(p, mem) + v0.AddArg(v1) + return true + } + break + } + // match: (ORL r1:(ROLWconst [8] x1:(MOVWload [i] {s} p1 mem)) sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i] {s} p0 mem)))) + // cond: x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) + // result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i] {s} p0 mem)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + r1 := v_0 + if r1.Op != OpAMD64ROLWconst || r1.AuxInt != 8 { + continue + } + x1 := r1.Args[0] + if x1.Op != OpAMD64MOVWload { + continue + } + i := x1.AuxInt + s := x1.Aux + mem := x1.Args[1] + p1 := x1.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLLconst || sh.AuxInt != 16 { + continue + } + r0 := sh.Args[0] + if r0.Op != OpAMD64ROLWconst || r0.AuxInt != 8 { + continue + } + x0 := r0.Args[0] + if x0.Op != OpAMD64MOVWload || x0.AuxInt != i || x0.Aux != s { + continue + } + _ = x0.Args[1] + p0 := x0.Args[0] + if mem != x0.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, r0, r1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, v.Type) + v.copyOf(v0) + v1 := b.NewValue0(x0.Pos, OpAMD64MOVLload, typ.UInt32) + v1.AuxInt = i + v1.Aux = s v1.AddArg2(p0, mem) v0.AddArg(v1) return true } break } - // match: (ORL s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p0 mem)) or:(ORL s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p1 mem)) y)) - // cond: i1 == i0+1 && j1 == j0-8 && j1 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - // result: @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p0 mem))) y) + // match: (ORL s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem)) or:(ORL s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem)) y)) + // cond: i1 == i0+1 && j1 == j0-8 && j1 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { s0 := v_0 @@ -18141,7 +17991,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { i0 := x0.AuxInt s := x0.Aux mem := x0.Args[1] - p0 := x0.Args[0] + p := x0.Args[0] or := v_1 if or.Op != OpAMD64ORL { continue @@ -18164,12 +18014,74 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { continue } _ = x1.Args[1] + if p != x1.Args[0] || mem != x1.Args[1] { + continue + } + y := or_1 + if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + continue + } + b = mergePoint(b, x0, x1, y) + v0 := b.NewValue0(x1.Pos, OpAMD64ORL, v.Type) + v.copyOf(v0) + v1 := b.NewValue0(x1.Pos, OpAMD64SHLLconst, v.Type) + v1.AuxInt = j1 + v2 := b.NewValue0(x1.Pos, OpAMD64ROLWconst, typ.UInt16) + v2.AuxInt = 8 + v3 := b.NewValue0(x1.Pos, OpAMD64MOVWload, typ.UInt16) + v3.AuxInt = i0 + v3.Aux = s + v3.AddArg2(p, mem) + v2.AddArg(v3) + v1.AddArg(v2) + v0.AddArg2(v1, y) + return true + } + } + break + } + // match: (ORL s0:(SHLLconst [j0] x0:(MOVBload [i] {s} p0 mem)) or:(ORL s1:(SHLLconst [j1] x1:(MOVBload [i] {s} p1 mem)) y)) + // cond: j1 == j0-8 && j1 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i] {s} p0 mem))) y) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + s0 := v_0 + if s0.Op != OpAMD64SHLLconst { + continue + } + j0 := s0.AuxInt + x0 := s0.Args[0] + if x0.Op != OpAMD64MOVBload { + continue + } + i := x0.AuxInt + s := x0.Aux + mem := x0.Args[1] + p0 := x0.Args[0] + or := v_1 + if or.Op != OpAMD64ORL { + continue + } + _ = or.Args[1] + or_0 := or.Args[0] + or_1 := or.Args[1] + for _i1 := 0; _i1 <= 1; _i1, or_0, or_1 = _i1+1, or_1, or_0 { + s1 := or_0 + if s1.Op != OpAMD64SHLLconst { + continue + } + j1 := s1.AuxInt + x1 := s1.Args[0] + if x1.Op != OpAMD64MOVBload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] p1 := x1.Args[0] if mem != x1.Args[1] { continue } y := or_1 - if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + if !(j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { continue } b = mergePoint(b, x0, x1, y) @@ -18180,7 +18092,7 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { v2 := b.NewValue0(x1.Pos, OpAMD64ROLWconst, typ.UInt16) v2.AuxInt = 8 v3 := b.NewValue0(x1.Pos, OpAMD64MOVWload, typ.UInt16) - v3.AuxInt = i0 + v3.AuxInt = i v3.Aux = s v3.AddArg2(p0, mem) v2.AddArg(v3) @@ -18804,9 +18716,9 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v.copyOf(x) return true } - // match: (ORQ x0:(MOVBload [i0] {s} p0 mem) sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p1 mem))) - // cond: i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - // result: @mergePoint(b,x0,x1) (MOVWload [i0] {s} p0 mem) + // match: (ORQ x0:(MOVBload [i0] {s} p mem) sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p mem))) + // cond: i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { x0 := v_0 @@ -18816,7 +18728,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i0 := x0.AuxInt s := x0.Aux mem := x0.Args[1] - p0 := x0.Args[0] + p := x0.Args[0] sh := v_1 if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 8 { continue @@ -18830,8 +18742,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x1.Args[1] - p1 := x1.Args[0] - if mem != x1.Args[1] || !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + if p != x1.Args[0] || mem != x1.Args[1] || !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -18839,14 +18750,50 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v.copyOf(v0) v0.AuxInt = i0 v0.Aux = s + v0.AddArg2(p, mem) + return true + } + break + } + // match: (ORQ x0:(MOVBload [i] {s} p0 mem) sh:(SHLQconst [8] x1:(MOVBload [i] {s} p1 mem))) + // cond: x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVWload [i] {s} p0 mem) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x0 := v_0 + if x0.Op != OpAMD64MOVBload { + continue + } + i := x0.AuxInt + s := x0.Aux + mem := x0.Args[1] + p0 := x0.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 8 { + continue + } + x1 := sh.Args[0] + if x1.Op != OpAMD64MOVBload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] + p1 := x1.Args[0] + if mem != x1.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x1.Pos, OpAMD64MOVWload, typ.UInt16) + v.copyOf(v0) + v0.AuxInt = i + v0.Aux = s v0.AddArg2(p0, mem) return true } break } - // match: (ORQ x0:(MOVWload [i0] {s} p0 mem) sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p1 mem))) - // cond: i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - // result: @mergePoint(b,x0,x1) (MOVLload [i0] {s} p0 mem) + // match: (ORQ x0:(MOVWload [i0] {s} p mem) sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p mem))) + // cond: i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { x0 := v_0 @@ -18856,7 +18803,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i0 := x0.AuxInt s := x0.Aux mem := x0.Args[1] - p0 := x0.Args[0] + p := x0.Args[0] sh := v_1 if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 16 { continue @@ -18870,8 +18817,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x1.Args[1] - p1 := x1.Args[0] - if mem != x1.Args[1] || !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + if p != x1.Args[0] || mem != x1.Args[1] || !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -18879,14 +18825,50 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v.copyOf(v0) v0.AuxInt = i0 v0.Aux = s + v0.AddArg2(p, mem) + return true + } + break + } + // match: (ORQ x0:(MOVWload [i] {s} p0 mem) sh:(SHLQconst [16] x1:(MOVWload [i] {s} p1 mem))) + // cond: x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVLload [i] {s} p0 mem) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x0 := v_0 + if x0.Op != OpAMD64MOVWload { + continue + } + i := x0.AuxInt + s := x0.Aux + mem := x0.Args[1] + p0 := x0.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 16 { + continue + } + x1 := sh.Args[0] + if x1.Op != OpAMD64MOVWload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] + p1 := x1.Args[0] + if mem != x1.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x1.Pos, OpAMD64MOVLload, typ.UInt32) + v.copyOf(v0) + v0.AuxInt = i + v0.Aux = s v0.AddArg2(p0, mem) return true } break } - // match: (ORQ x0:(MOVLload [i0] {s} p0 mem) sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p1 mem))) - // cond: i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - // result: @mergePoint(b,x0,x1) (MOVQload [i0] {s} p0 mem) + // match: (ORQ x0:(MOVLload [i0] {s} p mem) sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p mem))) + // cond: i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVQload [i0] {s} p mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { x0 := v_0 @@ -18896,7 +18878,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i0 := x0.AuxInt s := x0.Aux mem := x0.Args[1] - p0 := x0.Args[0] + p := x0.Args[0] sh := v_1 if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 32 { continue @@ -18910,8 +18892,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x1.Args[1] - p1 := x1.Args[0] - if mem != x1.Args[1] || !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + if p != x1.Args[0] || mem != x1.Args[1] || !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -18919,14 +18900,50 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v.copyOf(v0) v0.AuxInt = i0 v0.Aux = s + v0.AddArg2(p, mem) + return true + } + break + } + // match: (ORQ x0:(MOVLload [i] {s} p0 mem) sh:(SHLQconst [32] x1:(MOVLload [i] {s} p1 mem))) + // cond: x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 4) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (MOVQload [i] {s} p0 mem) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x0 := v_0 + if x0.Op != OpAMD64MOVLload { + continue + } + i := x0.AuxInt + s := x0.Aux + mem := x0.Args[1] + p0 := x0.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 32 { + continue + } + x1 := sh.Args[0] + if x1.Op != OpAMD64MOVLload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] + p1 := x1.Args[0] + if mem != x1.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 4) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x1.Pos, OpAMD64MOVQload, typ.UInt64) + v.copyOf(v0) + v0.AuxInt = i + v0.Aux = s v0.AddArg2(p0, mem) return true } break } - // match: (ORQ s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p0 mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p1 mem)) y)) - // cond: i1 == i0+1 && j1 == j0+8 && j0 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p0 mem)) y) + // match: (ORQ s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem)) y)) + // cond: i1 == i0+1 && j1 == j0+8 && j0 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { s1 := v_0 @@ -18941,7 +18958,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i1 := x1.AuxInt s := x1.Aux mem := x1.Args[1] - p0 := x1.Args[0] + p := x1.Args[0] or := v_1 if or.Op != OpAMD64ORQ { continue @@ -18964,12 +18981,11 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x0.Args[1] - p1 := x0.Args[0] - if mem != x0.Args[1] { + if p != x0.Args[0] || mem != x0.Args[1] { continue } y := or_1 - if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { continue } b = mergePoint(b, x0, x1, y) @@ -18980,6 +18996,66 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v2 := b.NewValue0(x0.Pos, OpAMD64MOVWload, typ.UInt16) v2.AuxInt = i0 v2.Aux = s + v2.AddArg2(p, mem) + v1.AddArg(v2) + v0.AddArg2(v1, y) + return true + } + } + break + } + // match: (ORQ s1:(SHLQconst [j1] x1:(MOVBload [i] {s} p1 mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVBload [i] {s} p0 mem)) y)) + // cond: j1 == j0+8 && j0 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i] {s} p0 mem)) y) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + s1 := v_0 + if s1.Op != OpAMD64SHLQconst { + continue + } + j1 := s1.AuxInt + x1 := s1.Args[0] + if x1.Op != OpAMD64MOVBload { + continue + } + i := x1.AuxInt + s := x1.Aux + mem := x1.Args[1] + p1 := x1.Args[0] + or := v_1 + if or.Op != OpAMD64ORQ { + continue + } + _ = or.Args[1] + or_0 := or.Args[0] + or_1 := or.Args[1] + for _i1 := 0; _i1 <= 1; _i1, or_0, or_1 = _i1+1, or_1, or_0 { + s0 := or_0 + if s0.Op != OpAMD64SHLQconst { + continue + } + j0 := s0.AuxInt + x0 := s0.Args[0] + if x0.Op != OpAMD64MOVBload || x0.AuxInt != i || x0.Aux != s { + continue + } + _ = x0.Args[1] + p0 := x0.Args[0] + if mem != x0.Args[1] { + continue + } + y := or_1 + if !(j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + continue + } + b = mergePoint(b, x0, x1, y) + v0 := b.NewValue0(x0.Pos, OpAMD64ORQ, v.Type) + v.copyOf(v0) + v1 := b.NewValue0(x0.Pos, OpAMD64SHLQconst, v.Type) + v1.AuxInt = j0 + v2 := b.NewValue0(x0.Pos, OpAMD64MOVWload, typ.UInt16) + v2.AuxInt = i + v2.Aux = s v2.AddArg2(p0, mem) v1.AddArg(v2) v0.AddArg2(v1, y) @@ -18988,9 +19064,9 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { } break } - // match: (ORQ s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p0 mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p1 mem)) y)) - // cond: i1 == i0+2 && j1 == j0+16 && j0 % 32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p0 mem)) y) + // match: (ORQ s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p mem)) y)) + // cond: i1 == i0+2 && j1 == j0+16 && j0 % 32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p mem)) y) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { s1 := v_0 @@ -19005,7 +19081,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i1 := x1.AuxInt s := x1.Aux mem := x1.Args[1] - p0 := x1.Args[0] + p := x1.Args[0] or := v_1 if or.Op != OpAMD64ORQ { continue @@ -19028,12 +19104,11 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x0.Args[1] - p1 := x0.Args[0] - if mem != x0.Args[1] { + if p != x0.Args[0] || mem != x0.Args[1] { continue } y := or_1 - if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { continue } b = mergePoint(b, x0, x1, y) @@ -19044,6 +19119,66 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v2 := b.NewValue0(x0.Pos, OpAMD64MOVLload, typ.UInt32) v2.AuxInt = i0 v2.Aux = s + v2.AddArg2(p, mem) + v1.AddArg(v2) + v0.AddArg2(v1, y) + return true + } + } + break + } + // match: (ORQ s1:(SHLQconst [j1] x1:(MOVWload [i] {s} p1 mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVWload [i] {s} p0 mem)) y)) + // cond: j1 == j0+16 && j0 % 32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i] {s} p0 mem)) y) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + s1 := v_0 + if s1.Op != OpAMD64SHLQconst { + continue + } + j1 := s1.AuxInt + x1 := s1.Args[0] + if x1.Op != OpAMD64MOVWload { + continue + } + i := x1.AuxInt + s := x1.Aux + mem := x1.Args[1] + p1 := x1.Args[0] + or := v_1 + if or.Op != OpAMD64ORQ { + continue + } + _ = or.Args[1] + or_0 := or.Args[0] + or_1 := or.Args[1] + for _i1 := 0; _i1 <= 1; _i1, or_0, or_1 = _i1+1, or_1, or_0 { + s0 := or_0 + if s0.Op != OpAMD64SHLQconst { + continue + } + j0 := s0.AuxInt + x0 := s0.Args[0] + if x0.Op != OpAMD64MOVWload || x0.AuxInt != i || x0.Aux != s { + continue + } + _ = x0.Args[1] + p0 := x0.Args[0] + if mem != x0.Args[1] { + continue + } + y := or_1 + if !(j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + continue + } + b = mergePoint(b, x0, x1, y) + v0 := b.NewValue0(x0.Pos, OpAMD64ORQ, v.Type) + v.copyOf(v0) + v1 := b.NewValue0(x0.Pos, OpAMD64SHLQconst, v.Type) + v1.AuxInt = j0 + v2 := b.NewValue0(x0.Pos, OpAMD64MOVLload, typ.UInt32) + v2.AuxInt = i + v2.Aux = s v2.AddArg2(p0, mem) v1.AddArg(v2) v0.AddArg2(v1, y) @@ -19052,9 +19187,9 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { } break } - // match: (ORQ x1:(MOVBload [i1] {s} p0 mem) sh:(SHLQconst [8] x0:(MOVBload [i0] {s} p1 mem))) - // cond: i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) - // result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p0 mem)) + // match: (ORQ x1:(MOVBload [i1] {s} p mem) sh:(SHLQconst [8] x0:(MOVBload [i0] {s} p mem))) + // cond: i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem)) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { x1 := v_0 @@ -19064,7 +19199,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i1 := x1.AuxInt s := x1.Aux mem := x1.Args[1] - p0 := x1.Args[0] + p := x1.Args[0] sh := v_1 if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 8 { continue @@ -19078,8 +19213,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x0.Args[1] - p1 := x0.Args[0] - if mem != x0.Args[1] || !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + if p != x0.Args[0] || mem != x0.Args[1] || !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -19089,15 +19223,54 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v1 := b.NewValue0(x0.Pos, OpAMD64MOVWload, typ.UInt16) v1.AuxInt = i0 v1.Aux = s + v1.AddArg2(p, mem) + v0.AddArg(v1) + return true + } + break + } + // match: (ORQ x1:(MOVBload [i] {s} p1 mem) sh:(SHLQconst [8] x0:(MOVBload [i] {s} p0 mem))) + // cond: x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh) + // result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i] {s} p0 mem)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + x1 := v_0 + if x1.Op != OpAMD64MOVBload { + continue + } + i := x1.AuxInt + s := x1.Aux + mem := x1.Args[1] + p1 := x1.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 8 { + continue + } + x0 := sh.Args[0] + if x0.Op != OpAMD64MOVBload || x0.AuxInt != i || x0.Aux != s { + continue + } + _ = x0.Args[1] + p0 := x0.Args[0] + if mem != x0.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, v.Type) + v.copyOf(v0) + v0.AuxInt = 8 + v1 := b.NewValue0(x0.Pos, OpAMD64MOVWload, typ.UInt16) + v1.AuxInt = i + v1.Aux = s v1.AddArg2(p0, mem) v0.AddArg(v1) return true } break } - // match: (ORQ r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p0 mem)) sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p1 mem)))) - // cond: i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) - // result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p0 mem)) + // match: (ORQ r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)) sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem)))) + // cond: i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) + // result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem)) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { r1 := v_0 @@ -19111,7 +19284,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i1 := x1.AuxInt s := x1.Aux mem := x1.Args[1] - p0 := x1.Args[0] + p := x1.Args[0] sh := v_1 if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 16 { continue @@ -19129,8 +19302,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x0.Args[1] - p1 := x0.Args[0] - if mem != x0.Args[1] || !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, r0, r1, sh)) { + if p != x0.Args[0] || mem != x0.Args[1] || !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, r0, r1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -19139,15 +19311,61 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v1 := b.NewValue0(x0.Pos, OpAMD64MOVLload, typ.UInt32) v1.AuxInt = i0 v1.Aux = s + v1.AddArg2(p, mem) + v0.AddArg(v1) + return true + } + break + } + // match: (ORQ r1:(ROLWconst [8] x1:(MOVWload [i] {s} p1 mem)) sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i] {s} p0 mem)))) + // cond: x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) + // result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i] {s} p0 mem)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + r1 := v_0 + if r1.Op != OpAMD64ROLWconst || r1.AuxInt != 8 { + continue + } + x1 := r1.Args[0] + if x1.Op != OpAMD64MOVWload { + continue + } + i := x1.AuxInt + s := x1.Aux + mem := x1.Args[1] + p1 := x1.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 16 { + continue + } + r0 := sh.Args[0] + if r0.Op != OpAMD64ROLWconst || r0.AuxInt != 8 { + continue + } + x0 := r0.Args[0] + if x0.Op != OpAMD64MOVWload || x0.AuxInt != i || x0.Aux != s { + continue + } + _ = x0.Args[1] + p0 := x0.Args[0] + if mem != x0.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, r0, r1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, v.Type) + v.copyOf(v0) + v1 := b.NewValue0(x0.Pos, OpAMD64MOVLload, typ.UInt32) + v1.AuxInt = i + v1.Aux = s v1.AddArg2(p0, mem) v0.AddArg(v1) return true } break } - // match: (ORQ r1:(BSWAPL x1:(MOVLload [i1] {s} p0 mem)) sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p1 mem)))) - // cond: i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) - // result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i0] {s} p0 mem)) + // match: (ORQ r1:(BSWAPL x1:(MOVLload [i1] {s} p mem)) sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p mem)))) + // cond: i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) + // result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i0] {s} p mem)) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { r1 := v_0 @@ -19161,7 +19379,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i1 := x1.AuxInt s := x1.Aux mem := x1.Args[1] - p0 := x1.Args[0] + p := x1.Args[0] sh := v_1 if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 32 { continue @@ -19179,8 +19397,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x0.Args[1] - p1 := x0.Args[0] - if mem != x0.Args[1] || !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, r0, r1, sh)) { + if p != x0.Args[0] || mem != x0.Args[1] || !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, r0, r1, sh)) { continue } b = mergePoint(b, x0, x1) @@ -19189,15 +19406,61 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v1 := b.NewValue0(x0.Pos, OpAMD64MOVQload, typ.UInt64) v1.AuxInt = i0 v1.Aux = s + v1.AddArg2(p, mem) + v0.AddArg(v1) + return true + } + break + } + // match: (ORQ r1:(BSWAPL x1:(MOVLload [i] {s} p1 mem)) sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i] {s} p0 mem)))) + // cond: x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 4) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, r0, r1, sh) + // result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i] {s} p0 mem)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + r1 := v_0 + if r1.Op != OpAMD64BSWAPL { + continue + } + x1 := r1.Args[0] + if x1.Op != OpAMD64MOVLload { + continue + } + i := x1.AuxInt + s := x1.Aux + mem := x1.Args[1] + p1 := x1.Args[0] + sh := v_1 + if sh.Op != OpAMD64SHLQconst || sh.AuxInt != 32 { + continue + } + r0 := sh.Args[0] + if r0.Op != OpAMD64BSWAPL { + continue + } + x0 := r0.Args[0] + if x0.Op != OpAMD64MOVLload || x0.AuxInt != i || x0.Aux != s { + continue + } + _ = x0.Args[1] + p0 := x0.Args[0] + if mem != x0.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p0, p1, 4) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, r0, r1, sh)) { + continue + } + b = mergePoint(b, x0, x1) + v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, v.Type) + v.copyOf(v0) + v1 := b.NewValue0(x0.Pos, OpAMD64MOVQload, typ.UInt64) + v1.AuxInt = i + v1.Aux = s v1.AddArg2(p0, mem) v0.AddArg(v1) return true } break } - // match: (ORQ s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p0 mem)) or:(ORQ s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p1 mem)) y)) - // cond: i1 == i0+1 && j1 == j0-8 && j1 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) - // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p0 mem))) y) + // match: (ORQ s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem)) or:(ORQ s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem)) y)) + // cond: i1 == i0+1 && j1 == j0-8 && j1 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { s0 := v_0 @@ -19212,7 +19475,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i0 := x0.AuxInt s := x0.Aux mem := x0.Args[1] - p0 := x0.Args[0] + p := x0.Args[0] or := v_1 if or.Op != OpAMD64ORQ { continue @@ -19235,12 +19498,74 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x1.Args[1] + if p != x1.Args[0] || mem != x1.Args[1] { + continue + } + y := or_1 + if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + continue + } + b = mergePoint(b, x0, x1, y) + v0 := b.NewValue0(x1.Pos, OpAMD64ORQ, v.Type) + v.copyOf(v0) + v1 := b.NewValue0(x1.Pos, OpAMD64SHLQconst, v.Type) + v1.AuxInt = j1 + v2 := b.NewValue0(x1.Pos, OpAMD64ROLWconst, typ.UInt16) + v2.AuxInt = 8 + v3 := b.NewValue0(x1.Pos, OpAMD64MOVWload, typ.UInt16) + v3.AuxInt = i0 + v3.Aux = s + v3.AddArg2(p, mem) + v2.AddArg(v3) + v1.AddArg(v2) + v0.AddArg2(v1, y) + return true + } + } + break + } + // match: (ORQ s0:(SHLQconst [j0] x0:(MOVBload [i] {s} p0 mem)) or:(ORQ s1:(SHLQconst [j1] x1:(MOVBload [i] {s} p1 mem)) y)) + // cond: j1 == j0-8 && j1 % 16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i] {s} p0 mem))) y) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + s0 := v_0 + if s0.Op != OpAMD64SHLQconst { + continue + } + j0 := s0.AuxInt + x0 := s0.Args[0] + if x0.Op != OpAMD64MOVBload { + continue + } + i := x0.AuxInt + s := x0.Aux + mem := x0.Args[1] + p0 := x0.Args[0] + or := v_1 + if or.Op != OpAMD64ORQ { + continue + } + _ = or.Args[1] + or_0 := or.Args[0] + or_1 := or.Args[1] + for _i1 := 0; _i1 <= 1; _i1, or_0, or_1 = _i1+1, or_1, or_0 { + s1 := or_0 + if s1.Op != OpAMD64SHLQconst { + continue + } + j1 := s1.AuxInt + x1 := s1.Args[0] + if x1.Op != OpAMD64MOVBload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] p1 := x1.Args[0] if mem != x1.Args[1] { continue } y := or_1 - if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { + if !(j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, s0, s1, or)) { continue } b = mergePoint(b, x0, x1, y) @@ -19251,7 +19576,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v2 := b.NewValue0(x1.Pos, OpAMD64ROLWconst, typ.UInt16) v2.AuxInt = 8 v3 := b.NewValue0(x1.Pos, OpAMD64MOVWload, typ.UInt16) - v3.AuxInt = i0 + v3.AuxInt = i v3.Aux = s v3.AddArg2(p0, mem) v2.AddArg(v3) @@ -19262,9 +19587,9 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { } break } - // match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p0 mem))) or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p1 mem))) y)) - // cond: i1 == i0+2 && j1 == j0-16 && j1 % 32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, r0, r1, s0, s1, or) - // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p0 mem))) y) + // match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))) or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))) y)) + // cond: i1 == i0+2 && j1 == j0-16 && j1 % 32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, r0, r1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p mem))) y) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { s0 := v_0 @@ -19283,7 +19608,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { i0 := x0.AuxInt s := x0.Aux mem := x0.Args[1] - p0 := x0.Args[0] + p := x0.Args[0] or := v_1 if or.Op != OpAMD64ORQ { continue @@ -19310,12 +19635,81 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { continue } _ = x1.Args[1] + if p != x1.Args[0] || mem != x1.Args[1] { + continue + } + y := or_1 + if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, r0, r1, s0, s1, or)) { + continue + } + b = mergePoint(b, x0, x1, y) + v0 := b.NewValue0(x1.Pos, OpAMD64ORQ, v.Type) + v.copyOf(v0) + v1 := b.NewValue0(x1.Pos, OpAMD64SHLQconst, v.Type) + v1.AuxInt = j1 + v2 := b.NewValue0(x1.Pos, OpAMD64BSWAPL, typ.UInt32) + v3 := b.NewValue0(x1.Pos, OpAMD64MOVLload, typ.UInt32) + v3.AuxInt = i0 + v3.Aux = s + v3.AddArg2(p, mem) + v2.AddArg(v3) + v1.AddArg(v2) + v0.AddArg2(v1, y) + return true + } + } + break + } + // match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i] {s} p0 mem))) or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i] {s} p1 mem))) y)) + // cond: j1 == j0-16 && j1 % 32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b,x0,x1,y) != nil && clobber(x0, x1, r0, r1, s0, s1, or) + // result: @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i] {s} p0 mem))) y) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + s0 := v_0 + if s0.Op != OpAMD64SHLQconst { + continue + } + j0 := s0.AuxInt + r0 := s0.Args[0] + if r0.Op != OpAMD64ROLWconst || r0.AuxInt != 8 { + continue + } + x0 := r0.Args[0] + if x0.Op != OpAMD64MOVWload { + continue + } + i := x0.AuxInt + s := x0.Aux + mem := x0.Args[1] + p0 := x0.Args[0] + or := v_1 + if or.Op != OpAMD64ORQ { + continue + } + _ = or.Args[1] + or_0 := or.Args[0] + or_1 := or.Args[1] + for _i1 := 0; _i1 <= 1; _i1, or_0, or_1 = _i1+1, or_1, or_0 { + s1 := or_0 + if s1.Op != OpAMD64SHLQconst { + continue + } + j1 := s1.AuxInt + r1 := s1.Args[0] + if r1.Op != OpAMD64ROLWconst || r1.AuxInt != 8 { + continue + } + x1 := r1.Args[0] + if x1.Op != OpAMD64MOVWload || x1.AuxInt != i || x1.Aux != s { + continue + } + _ = x1.Args[1] p1 := x1.Args[0] if mem != x1.Args[1] { continue } y := or_1 - if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && same(p0, p1, 1) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, r0, r1, s0, s1, or)) { + if !(j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && sequentialAddresses(p0, p1, 2) && mergePoint(b, x0, x1, y) != nil && clobber(x0, x1, r0, r1, s0, s1, or)) { continue } b = mergePoint(b, x0, x1, y) @@ -19325,7 +19719,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool { v1.AuxInt = j1 v2 := b.NewValue0(x1.Pos, OpAMD64BSWAPL, typ.UInt32) v3 := b.NewValue0(x1.Pos, OpAMD64MOVLload, typ.UInt32) - v3.AuxInt = i0 + v3.AuxInt = i v3.Aux = s v3.AddArg2(p0, mem) v2.AddArg(v3) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go b/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go index 40a7013744..6cdf8c89c2 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go @@ -7,20 +7,48 @@ func rewriteValueAMD64splitload(v *Value) bool { switch v.Op { case OpAMD64CMPBconstload: return rewriteValueAMD64splitload_OpAMD64CMPBconstload(v) + case OpAMD64CMPBconstloadidx1: + return rewriteValueAMD64splitload_OpAMD64CMPBconstloadidx1(v) case OpAMD64CMPBload: return rewriteValueAMD64splitload_OpAMD64CMPBload(v) + case OpAMD64CMPBloadidx1: + return rewriteValueAMD64splitload_OpAMD64CMPBloadidx1(v) case OpAMD64CMPLconstload: return rewriteValueAMD64splitload_OpAMD64CMPLconstload(v) + case OpAMD64CMPLconstloadidx1: + return rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx1(v) + case OpAMD64CMPLconstloadidx4: + return rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx4(v) case OpAMD64CMPLload: return rewriteValueAMD64splitload_OpAMD64CMPLload(v) + case OpAMD64CMPLloadidx1: + return rewriteValueAMD64splitload_OpAMD64CMPLloadidx1(v) + case OpAMD64CMPLloadidx4: + return rewriteValueAMD64splitload_OpAMD64CMPLloadidx4(v) case OpAMD64CMPQconstload: return rewriteValueAMD64splitload_OpAMD64CMPQconstload(v) + case OpAMD64CMPQconstloadidx1: + return rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx1(v) + case OpAMD64CMPQconstloadidx8: + return rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx8(v) case OpAMD64CMPQload: return rewriteValueAMD64splitload_OpAMD64CMPQload(v) + case OpAMD64CMPQloadidx1: + return rewriteValueAMD64splitload_OpAMD64CMPQloadidx1(v) + case OpAMD64CMPQloadidx8: + return rewriteValueAMD64splitload_OpAMD64CMPQloadidx8(v) case OpAMD64CMPWconstload: return rewriteValueAMD64splitload_OpAMD64CMPWconstload(v) + case OpAMD64CMPWconstloadidx1: + return rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx1(v) + case OpAMD64CMPWconstloadidx2: + return rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx2(v) case OpAMD64CMPWload: return rewriteValueAMD64splitload_OpAMD64CMPWload(v) + case OpAMD64CMPWloadidx1: + return rewriteValueAMD64splitload_OpAMD64CMPWloadidx1(v) + case OpAMD64CMPWloadidx2: + return rewriteValueAMD64splitload_OpAMD64CMPWloadidx2(v) } return false } @@ -46,6 +74,30 @@ func rewriteValueAMD64splitload_OpAMD64CMPBconstload(v *Value) bool { return true } } +func rewriteValueAMD64splitload_OpAMD64CMPBconstloadidx1(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPBconstloadidx1 {sym} [vo] ptr idx mem) + // result: (CMPBconst (MOVBloadidx1 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) + for { + vo := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + mem := v_2 + v.reset(OpAMD64CMPBconst) + v.AuxInt = valOnly(vo) + v0 := b.NewValue0(v.Pos, OpAMD64MOVBloadidx1, typ.UInt8) + v0.AuxInt = offOnly(vo) + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg(v0) + return true + } +} func rewriteValueAMD64splitload_OpAMD64CMPBload(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -69,6 +121,31 @@ func rewriteValueAMD64splitload_OpAMD64CMPBload(v *Value) bool { return true } } +func rewriteValueAMD64splitload_OpAMD64CMPBloadidx1(v *Value) bool { + v_3 := v.Args[3] + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPBloadidx1 {sym} [off] ptr idx x mem) + // result: (CMPB (MOVBloadidx1 {sym} [off] ptr idx mem) x) + for { + off := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + x := v_2 + mem := v_3 + v.reset(OpAMD64CMPB) + v0 := b.NewValue0(v.Pos, OpAMD64MOVBloadidx1, typ.UInt8) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg2(v0, x) + return true + } +} func rewriteValueAMD64splitload_OpAMD64CMPLconstload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -91,6 +168,54 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstload(v *Value) bool { return true } } +func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx1(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPLconstloadidx1 {sym} [vo] ptr idx mem) + // result: (CMPLconst (MOVLloadidx1 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) + for { + vo := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + mem := v_2 + v.reset(OpAMD64CMPLconst) + v.AuxInt = valOnly(vo) + v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32) + v0.AuxInt = offOnly(vo) + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg(v0) + return true + } +} +func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx4(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPLconstloadidx4 {sym} [vo] ptr idx mem) + // result: (CMPLconst (MOVLloadidx4 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) + for { + vo := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + mem := v_2 + v.reset(OpAMD64CMPLconst) + v.AuxInt = valOnly(vo) + v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx4, typ.UInt32) + v0.AuxInt = offOnly(vo) + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg(v0) + return true + } +} func rewriteValueAMD64splitload_OpAMD64CMPLload(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -114,6 +239,56 @@ func rewriteValueAMD64splitload_OpAMD64CMPLload(v *Value) bool { return true } } +func rewriteValueAMD64splitload_OpAMD64CMPLloadidx1(v *Value) bool { + v_3 := v.Args[3] + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPLloadidx1 {sym} [off] ptr idx x mem) + // result: (CMPL (MOVLloadidx1 {sym} [off] ptr idx mem) x) + for { + off := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + x := v_2 + mem := v_3 + v.reset(OpAMD64CMPL) + v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg2(v0, x) + return true + } +} +func rewriteValueAMD64splitload_OpAMD64CMPLloadidx4(v *Value) bool { + v_3 := v.Args[3] + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPLloadidx4 {sym} [off] ptr idx x mem) + // result: (CMPL (MOVLloadidx4 {sym} [off] ptr idx mem) x) + for { + off := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + x := v_2 + mem := v_3 + v.reset(OpAMD64CMPL) + v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx4, typ.UInt32) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg2(v0, x) + return true + } +} func rewriteValueAMD64splitload_OpAMD64CMPQconstload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -136,6 +311,54 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstload(v *Value) bool { return true } } +func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx1(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPQconstloadidx1 {sym} [vo] ptr idx mem) + // result: (CMPQconst (MOVQloadidx1 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) + for { + vo := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + mem := v_2 + v.reset(OpAMD64CMPQconst) + v.AuxInt = valOnly(vo) + v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64) + v0.AuxInt = offOnly(vo) + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg(v0) + return true + } +} +func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx8(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPQconstloadidx8 {sym} [vo] ptr idx mem) + // result: (CMPQconst (MOVQloadidx8 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) + for { + vo := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + mem := v_2 + v.reset(OpAMD64CMPQconst) + v.AuxInt = valOnly(vo) + v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx8, typ.UInt64) + v0.AuxInt = offOnly(vo) + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg(v0) + return true + } +} func rewriteValueAMD64splitload_OpAMD64CMPQload(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -159,6 +382,56 @@ func rewriteValueAMD64splitload_OpAMD64CMPQload(v *Value) bool { return true } } +func rewriteValueAMD64splitload_OpAMD64CMPQloadidx1(v *Value) bool { + v_3 := v.Args[3] + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPQloadidx1 {sym} [off] ptr idx x mem) + // result: (CMPQ (MOVQloadidx1 {sym} [off] ptr idx mem) x) + for { + off := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + x := v_2 + mem := v_3 + v.reset(OpAMD64CMPQ) + v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg2(v0, x) + return true + } +} +func rewriteValueAMD64splitload_OpAMD64CMPQloadidx8(v *Value) bool { + v_3 := v.Args[3] + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPQloadidx8 {sym} [off] ptr idx x mem) + // result: (CMPQ (MOVQloadidx8 {sym} [off] ptr idx mem) x) + for { + off := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + x := v_2 + mem := v_3 + v.reset(OpAMD64CMPQ) + v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx8, typ.UInt64) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg2(v0, x) + return true + } +} func rewriteValueAMD64splitload_OpAMD64CMPWconstload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -181,6 +454,54 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstload(v *Value) bool { return true } } +func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx1(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPWconstloadidx1 {sym} [vo] ptr idx mem) + // result: (CMPWconst (MOVWloadidx1 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) + for { + vo := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + mem := v_2 + v.reset(OpAMD64CMPWconst) + v.AuxInt = valOnly(vo) + v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16) + v0.AuxInt = offOnly(vo) + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg(v0) + return true + } +} +func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx2(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPWconstloadidx2 {sym} [vo] ptr idx mem) + // result: (CMPWconst (MOVWloadidx2 {sym} [offOnly(vo)] ptr idx mem) [valOnly(vo)]) + for { + vo := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + mem := v_2 + v.reset(OpAMD64CMPWconst) + v.AuxInt = valOnly(vo) + v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx2, typ.UInt16) + v0.AuxInt = offOnly(vo) + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg(v0) + return true + } +} func rewriteValueAMD64splitload_OpAMD64CMPWload(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] @@ -204,6 +525,56 @@ func rewriteValueAMD64splitload_OpAMD64CMPWload(v *Value) bool { return true } } +func rewriteValueAMD64splitload_OpAMD64CMPWloadidx1(v *Value) bool { + v_3 := v.Args[3] + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPWloadidx1 {sym} [off] ptr idx x mem) + // result: (CMPW (MOVWloadidx1 {sym} [off] ptr idx mem) x) + for { + off := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + x := v_2 + mem := v_3 + v.reset(OpAMD64CMPW) + v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg2(v0, x) + return true + } +} +func rewriteValueAMD64splitload_OpAMD64CMPWloadidx2(v *Value) bool { + v_3 := v.Args[3] + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (CMPWloadidx2 {sym} [off] ptr idx x mem) + // result: (CMPW (MOVWloadidx2 {sym} [off] ptr idx mem) x) + for { + off := v.AuxInt + sym := v.Aux + ptr := v_0 + idx := v_1 + x := v_2 + mem := v_3 + v.reset(OpAMD64CMPW) + v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx2, typ.UInt16) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg3(ptr, idx, mem) + v.AddArg2(v0, x) + return true + } +} func rewriteBlockAMD64splitload(b *Block) bool { switch b.Kind { } diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 13873b2ac8..5d954784e3 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -50,6 +50,14 @@ func rewriteValuegeneric(v *Value) bool { return rewriteValuegeneric_OpConstString(v) case OpConvert: return rewriteValuegeneric_OpConvert(v) + case OpCtz16: + return rewriteValuegeneric_OpCtz16(v) + case OpCtz32: + return rewriteValuegeneric_OpCtz32(v) + case OpCtz64: + return rewriteValuegeneric_OpCtz64(v) + case OpCtz8: + return rewriteValuegeneric_OpCtz8(v) case OpCvt32Fto32: return rewriteValuegeneric_OpCvt32Fto32(v) case OpCvt32Fto64: @@ -3983,7 +3991,7 @@ func rewriteValuegeneric_OpConvert(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (Convert (Add64 (Convert ptr mem) off) mem) - // result: (Add64 ptr off) + // result: (AddPtr ptr off) for { if v_0.Op != OpAdd64 { break @@ -4001,14 +4009,14 @@ func rewriteValuegeneric_OpConvert(v *Value) bool { if mem != v_1 { continue } - v.reset(OpAdd64) + v.reset(OpAddPtr) v.AddArg2(ptr, off) return true } break } // match: (Convert (Add32 (Convert ptr mem) off) mem) - // result: (Add32 ptr off) + // result: (AddPtr ptr off) for { if v_0.Op != OpAdd32 { break @@ -4026,7 +4034,7 @@ func rewriteValuegeneric_OpConvert(v *Value) bool { if mem != v_1 { continue } - v.reset(OpAdd32) + v.reset(OpAddPtr) v.AddArg2(ptr, off) return true } @@ -4048,6 +4056,150 @@ func rewriteValuegeneric_OpConvert(v *Value) bool { } return false } +func rewriteValuegeneric_OpCtz16(v *Value) bool { + v_0 := v.Args[0] + b := v.Block + config := b.Func.Config + // match: (Ctz16 (Const16 [c])) + // cond: config.PtrSize == 4 + // result: (Const32 [ntz16(c)]) + for { + if v_0.Op != OpConst16 { + break + } + c := v_0.AuxInt + if !(config.PtrSize == 4) { + break + } + v.reset(OpConst32) + v.AuxInt = ntz16(c) + return true + } + // match: (Ctz16 (Const16 [c])) + // cond: config.PtrSize == 8 + // result: (Const64 [ntz16(c)]) + for { + if v_0.Op != OpConst16 { + break + } + c := v_0.AuxInt + if !(config.PtrSize == 8) { + break + } + v.reset(OpConst64) + v.AuxInt = ntz16(c) + return true + } + return false +} +func rewriteValuegeneric_OpCtz32(v *Value) bool { + v_0 := v.Args[0] + b := v.Block + config := b.Func.Config + // match: (Ctz32 (Const32 [c])) + // cond: config.PtrSize == 4 + // result: (Const32 [ntz32(c)]) + for { + if v_0.Op != OpConst32 { + break + } + c := v_0.AuxInt + if !(config.PtrSize == 4) { + break + } + v.reset(OpConst32) + v.AuxInt = ntz32(c) + return true + } + // match: (Ctz32 (Const32 [c])) + // cond: config.PtrSize == 8 + // result: (Const64 [ntz32(c)]) + for { + if v_0.Op != OpConst32 { + break + } + c := v_0.AuxInt + if !(config.PtrSize == 8) { + break + } + v.reset(OpConst64) + v.AuxInt = ntz32(c) + return true + } + return false +} +func rewriteValuegeneric_OpCtz64(v *Value) bool { + v_0 := v.Args[0] + b := v.Block + config := b.Func.Config + // match: (Ctz64 (Const64 [c])) + // cond: config.PtrSize == 4 + // result: (Const32 [ntz(c)]) + for { + if v_0.Op != OpConst64 { + break + } + c := v_0.AuxInt + if !(config.PtrSize == 4) { + break + } + v.reset(OpConst32) + v.AuxInt = ntz(c) + return true + } + // match: (Ctz64 (Const64 [c])) + // cond: config.PtrSize == 8 + // result: (Const64 [ntz(c)]) + for { + if v_0.Op != OpConst64 { + break + } + c := v_0.AuxInt + if !(config.PtrSize == 8) { + break + } + v.reset(OpConst64) + v.AuxInt = ntz(c) + return true + } + return false +} +func rewriteValuegeneric_OpCtz8(v *Value) bool { + v_0 := v.Args[0] + b := v.Block + config := b.Func.Config + // match: (Ctz8 (Const8 [c])) + // cond: config.PtrSize == 4 + // result: (Const32 [ntz8(c)]) + for { + if v_0.Op != OpConst8 { + break + } + c := v_0.AuxInt + if !(config.PtrSize == 4) { + break + } + v.reset(OpConst32) + v.AuxInt = ntz8(c) + return true + } + // match: (Ctz8 (Const8 [c])) + // cond: config.PtrSize == 8 + // result: (Const64 [ntz8(c)]) + for { + if v_0.Op != OpConst8 { + break + } + c := v_0.AuxInt + if !(config.PtrSize == 8) { + break + } + v.reset(OpConst64) + v.AuxInt = ntz8(c) + return true + } + return false +} func rewriteValuegeneric_OpCvt32Fto32(v *Value) bool { v_0 := v.Args[0] // match: (Cvt32Fto32 (Const32F [c])) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index ef054c8938..a20a92d03d 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2694,15 +2694,15 @@ // Go module mirror run by Google and fall back to a direct connection // if the proxy reports that it does not have the module (HTTP error 404 or 410). // See https://proxy.golang.org/privacy for the service's privacy policy. -// If GOPROXY is set to the string "direct", downloads use a direct connection -// to source control servers. Setting GOPROXY to "off" disallows downloading -// modules from any source. Otherwise, GOPROXY is expected to be a comma-separated -// list of the URLs of module proxies, in which case the go command will fetch -// modules from those proxies. For each request, the go command tries each proxy -// in sequence, only moving to the next if the current proxy returns a 404 or 410 -// HTTP response. The string "direct" may appear in the proxy list, -// to cause a direct connection to be attempted at that point in the search. -// Any proxies listed after "direct" are never consulted. +// +// If GOPROXY is set to the string "direct", downloads use a direct connection to +// source control servers. Setting GOPROXY to "off" disallows downloading modules +// from any source. Otherwise, GOPROXY is expected to be list of module proxy URLs +// separated by either comma (,) or pipe (|) characters, which control error +// fallback behavior. For each request, the go command tries each proxy in +// sequence. If there is an error, the go command will try the next proxy in the +// list if the error is a 404 or 410 HTTP response or if the current proxy is +// followed by a pipe character, indicating it is safe to fall back on any error. // // The GOPRIVATE and GONOPROXY environment variables allow bypassing // the proxy for selected modules. See 'go help module-private' for details. diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 39e387b9e4..d446e457b5 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2662,7 +2662,7 @@ func TestBadCommandLines(t *testing.T) { tg.tempFile("src/-x/x.go", "package x\n") tg.setenv("GOPATH", tg.path(".")) tg.runFail("build", "--", "-x") - tg.grepStderr("invalid input directory name \"-x\"", "did not reject -x directory") + tg.grepStderr("invalid import path \"-x\"", "did not reject -x import path") tg.tempFile("src/-x/y/y.go", "package y\n") tg.setenv("GOPATH", tg.path(".")) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 21dcee1315..6aea54340d 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -318,16 +318,16 @@ func (p *Package) copyBuild(pp *build.Package) { // A PackageError describes an error loading information about a package. type PackageError struct { - ImportStack []string // shortest path from package named on command line to this one - Pos string // position of error - Err error // the error itself - IsImportCycle bool // the error is an import cycle - Hard bool // whether the error is soft or hard; soft errors are ignored in some places + ImportStack []string // shortest path from package named on command line to this one + Pos string // position of error + Err error // the error itself + IsImportCycle bool // the error is an import cycle + Hard bool // whether the error is soft or hard; soft errors are ignored in some places + alwaysPrintStack bool // whether to always print the ImportStack } func (p *PackageError) Error() string { - // Import cycles deserve special treatment. - if p.Pos != "" && !p.IsImportCycle { + if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) { // Omit import stack. The full path to the file where the error // is the most important thing. return p.Pos + ": " + p.Err.Error() @@ -339,15 +339,14 @@ func (p *PackageError) Error() string { // last path on the stack, we don't omit the path. An error like // "package A imports B: error loading C caused by B" would not be clearer // if "imports B" were omitted. - stack := p.ImportStack - var ierr ImportPathError - if len(stack) > 0 && errors.As(p.Err, &ierr) && ierr.ImportPath() == stack[len(stack)-1] { - stack = stack[:len(stack)-1] - } - if len(stack) == 0 { + if len(p.ImportStack) == 0 { return p.Err.Error() } - return "package " + strings.Join(stack, "\n\timports ") + ": " + p.Err.Error() + var optpos string + if p.Pos != "" { + optpos = "\n\t" + p.Pos + } + return "package " + strings.Join(p.ImportStack, "\n\timports ") + optpos + ": " + p.Err.Error() } func (p *PackageError) Unwrap() error { return p.Err } @@ -549,9 +548,6 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS panic("LoadImport called with empty package path") } - stk.Push(path) - defer stk.Pop() - var parentPath, parentRoot string parentIsStd := false if parent != nil { @@ -564,6 +560,11 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS pre.preloadImports(bp.Imports, bp) } if bp == nil { + if importErr, ok := err.(ImportPathError); !ok || importErr.ImportPath() != path { + // Only add path to the error's import stack if it's not already present on the error. + stk.Push(path) + defer stk.Pop() + } return &Package{ PackagePublic: PackagePublic{ ImportPath: path, @@ -578,7 +579,9 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS importPath := bp.ImportPath p := packageCache[importPath] if p != nil { + stk.Push(path) p = reusePackage(p, stk) + stk.Pop() } else { p = new(Package) p.Internal.Local = build.IsLocalImport(path) @@ -588,8 +591,11 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS // Load package. // loadPackageData may return bp != nil even if an error occurs, // in order to return partial information. - p.load(stk, bp, err) - if p.Error != nil && p.Error.Pos == "" { + p.load(path, stk, bp, err) + // Add position information unless this is a NoGoError or an ImportCycle error. + // Import cycles deserve special treatment. + var g *build.NoGoError + if p.Error != nil && p.Error.Pos == "" && !errors.As(err, &g) && !p.Error.IsImportCycle { p = setErrorPos(p, importPos) } @@ -608,7 +614,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS return setErrorPos(perr, importPos) } if mode&ResolveImport != 0 { - if perr := disallowVendor(srcDir, path, p, stk); perr != p { + if perr := disallowVendor(srcDir, path, parentPath, p, stk); perr != p { return setErrorPos(perr, importPos) } } @@ -1246,7 +1252,7 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p * // as if it were generated into the testing directory tree // (it's actually in a temporary directory outside any Go tree). // This cleans up a former kludge in passing functionality to the testing package. - if strings.HasPrefix(p.ImportPath, "testing/internal") && len(*stk) >= 2 && (*stk)[len(*stk)-2] == "testmain" { + if str.HasPathPrefix(p.ImportPath, "testing/internal") && importerPath == "testmain" { return p } @@ -1262,11 +1268,10 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p * return p } - // The stack includes p.ImportPath. - // If that's the only thing on the stack, we started + // importerPath is empty: we started // with a name given on the command line, not an // import. Anything listed on the command line is fine. - if len(*stk) == 1 { + if importerPath == "" { return p } @@ -1315,8 +1320,9 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p * // Internal is present, and srcDir is outside parent's tree. Not allowed. perr := *p perr.Error = &PackageError{ - ImportStack: stk.Copy(), - Err: ImportErrorf(p.ImportPath, "use of internal package "+p.ImportPath+" not allowed"), + alwaysPrintStack: true, + ImportStack: stk.Copy(), + Err: ImportErrorf(p.ImportPath, "use of internal package "+p.ImportPath+" not allowed"), } perr.Incomplete = true return &perr @@ -1344,16 +1350,15 @@ func findInternal(path string) (index int, ok bool) { // disallowVendor checks that srcDir is allowed to import p as path. // If the import is allowed, disallowVendor returns the original package p. // If not, it returns a new package containing just an appropriate error. -func disallowVendor(srcDir string, path string, p *Package, stk *ImportStack) *Package { - // The stack includes p.ImportPath. - // If that's the only thing on the stack, we started +func disallowVendor(srcDir string, path string, importerPath string, p *Package, stk *ImportStack) *Package { + // If the importerPath is empty, we started // with a name given on the command line, not an // import. Anything listed on the command line is fine. - if len(*stk) == 1 { + if importerPath == "" { return p } - if perr := disallowVendorVisibility(srcDir, p, stk); perr != p { + if perr := disallowVendorVisibility(srcDir, p, importerPath, stk); perr != p { return perr } @@ -1376,12 +1381,12 @@ func disallowVendor(srcDir string, path string, p *Package, stk *ImportStack) *P // is not subject to the rules, only subdirectories of vendor. // This allows people to have packages and commands named vendor, // for maximal compatibility with existing source trees. -func disallowVendorVisibility(srcDir string, p *Package, stk *ImportStack) *Package { - // The stack includes p.ImportPath. - // If that's the only thing on the stack, we started +func disallowVendorVisibility(srcDir string, p *Package, importerPath string, stk *ImportStack) *Package { + // The stack does not include p.ImportPath. + // If there's nothing on the stack, we started // with a name given on the command line, not an // import. Anything listed on the command line is fine. - if len(*stk) == 1 { + if importerPath == "" { return p } @@ -1525,7 +1530,8 @@ func (p *Package) DefaultExecName() string { // load populates p using information from bp, err, which should // be the result of calling build.Context.Import. -func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { +// stk contains the import stack, not including path itself. +func (p *Package) load(path string, stk *ImportStack, bp *build.Package, err error) { p.copyBuild(bp) // The localPrefix is the path we interpret ./ imports relative to. @@ -1548,7 +1554,16 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { if err != nil { p.Incomplete = true + // Report path in error stack unless err is an ImportPathError with path already set. + pushed := false + if e, ok := err.(ImportPathError); !ok || e.ImportPath() != path { + stk.Push(path) + pushed = true // Remember to pop after setError. + } setError(base.ExpandScanner(p.rewordError(err))) + if pushed { + stk.Pop() + } if _, isScanErr := err.(scanner.ErrorList); !isScanErr { return } @@ -1675,6 +1690,23 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { } } + // Check for case-insensitive collisions of import paths. + fold := str.ToFold(p.ImportPath) + if other := foldPath[fold]; other == "" { + foldPath[fold] = p.ImportPath + } else if other != p.ImportPath { + setError(ImportErrorf(p.ImportPath, "case-insensitive import collision: %q and %q", p.ImportPath, other)) + return + } + + if !SafeArg(p.ImportPath) { + setError(ImportErrorf(p.ImportPath, "invalid import path %q", p.ImportPath)) + return + } + + stk.Push(path) + defer stk.Pop() + // Check for case-insensitive collision of input files. // To avoid problems on case-insensitive files, we reject any package // where two different input files have equal names under a case-insensitive @@ -1703,10 +1735,6 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { setError(fmt.Errorf("invalid input directory name %q", name)) return } - if !SafeArg(p.ImportPath) { - setError(ImportErrorf(p.ImportPath, "invalid import path %q", p.ImportPath)) - return - } // Build list of imported packages and full dependency list. imports := make([]*Package, 0, len(p.Imports)) @@ -1770,15 +1798,6 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { return } - // Check for case-insensitive collisions of import paths. - fold := str.ToFold(p.ImportPath) - if other := foldPath[fold]; other == "" { - foldPath[fold] = p.ImportPath - } else if other != p.ImportPath { - setError(ImportErrorf(p.ImportPath, "case-insensitive import collision: %q and %q", p.ImportPath, other)) - return - } - if cfg.ModulesEnabled && p.Error == nil { mainPath := p.ImportPath if p.Internal.CmdlineFiles { @@ -2266,9 +2285,7 @@ func GoFilesPackage(gofiles []string) *Package { pkg := new(Package) pkg.Internal.Local = true pkg.Internal.CmdlineFiles = true - stk.Push("main") - pkg.load(&stk, bp, err) - stk.Pop() + pkg.load("command-line-arguments", &stk, bp, err) pkg.Internal.LocalPrefix = dirToImportPath(dir) pkg.ImportPath = "command-line-arguments" pkg.Target = "" diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index 866e0e567f..6465f46f4e 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -56,7 +56,6 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag } if len(p1.DepsErrors) > 0 { perr := p1.DepsErrors[0] - perr.Pos = "" // show full import stack err = perr break } diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go index dcea71adb3..67b06cbcd6 100644 --- a/src/cmd/go/internal/modfetch/proxy.go +++ b/src/cmd/go/internal/modfetch/proxy.go @@ -101,27 +101,51 @@ cached module versions with GOPROXY=https://example.com/proxy. var proxyOnce struct { sync.Once - list []string + list []proxySpec err error } -func proxyURLs() ([]string, error) { +type proxySpec struct { + // url is the proxy URL or one of "off", "direct", "noproxy". + url string + + // fallBackOnError is true if a request should be attempted on the next proxy + // in the list after any error from this proxy. If fallBackOnError is false, + // the request will only be attempted on the next proxy if the error is + // equivalent to os.ErrNotFound, which is true for 404 and 410 responses. + fallBackOnError bool +} + +func proxyList() ([]proxySpec, error) { proxyOnce.Do(func() { if cfg.GONOPROXY != "" && cfg.GOPROXY != "direct" { - proxyOnce.list = append(proxyOnce.list, "noproxy") + proxyOnce.list = append(proxyOnce.list, proxySpec{url: "noproxy"}) } - for _, proxyURL := range strings.Split(cfg.GOPROXY, ",") { - proxyURL = strings.TrimSpace(proxyURL) - if proxyURL == "" { + + goproxy := cfg.GOPROXY + for goproxy != "" { + var url string + fallBackOnError := false + if i := strings.IndexAny(goproxy, ",|"); i >= 0 { + url = goproxy[:i] + fallBackOnError = goproxy[i] == '|' + goproxy = goproxy[i+1:] + } else { + url = goproxy + goproxy = "" + } + + url = strings.TrimSpace(url) + if url == "" { continue } - if proxyURL == "off" { + if url == "off" { // "off" always fails hard, so can stop walking list. - proxyOnce.list = append(proxyOnce.list, "off") + proxyOnce.list = append(proxyOnce.list, proxySpec{url: "off"}) break } - if proxyURL == "direct" { - proxyOnce.list = append(proxyOnce.list, "direct") + if url == "direct" { + proxyOnce.list = append(proxyOnce.list, proxySpec{url: "direct"}) // For now, "direct" is the end of the line. We may decide to add some // sort of fallback behavior for them in the future, so ignore // subsequent entries for forward-compatibility. @@ -131,18 +155,21 @@ func proxyURLs() ([]string, error) { // Single-word tokens are reserved for built-in behaviors, and anything // containing the string ":/" or matching an absolute file path must be a // complete URL. For all other paths, implicitly add "https://". - if strings.ContainsAny(proxyURL, ".:/") && !strings.Contains(proxyURL, ":/") && !filepath.IsAbs(proxyURL) && !path.IsAbs(proxyURL) { - proxyURL = "https://" + proxyURL + if strings.ContainsAny(url, ".:/") && !strings.Contains(url, ":/") && !filepath.IsAbs(url) && !path.IsAbs(url) { + url = "https://" + url } // Check that newProxyRepo accepts the URL. // It won't do anything with the path. - _, err := newProxyRepo(proxyURL, "golang.org/x/text") - if err != nil { + if _, err := newProxyRepo(url, "golang.org/x/text"); err != nil { proxyOnce.err = err return } - proxyOnce.list = append(proxyOnce.list, proxyURL) + + proxyOnce.list = append(proxyOnce.list, proxySpec{ + url: url, + fallBackOnError: fallBackOnError, + }) } }) @@ -150,15 +177,16 @@ func proxyURLs() ([]string, error) { } // TryProxies iterates f over each configured proxy (including "noproxy" and -// "direct" if applicable) until f returns an error that is not -// equivalent to os.ErrNotExist. +// "direct" if applicable) until f returns no error or until f returns an +// error that is not equivalent to os.ErrNotExist on a proxy configured +// not to fall back on errors. // // TryProxies then returns that final error. // // If GOPROXY is set to "off", TryProxies invokes f once with the argument // "off". func TryProxies(f func(proxy string) error) error { - proxies, err := proxyURLs() + proxies, err := proxyList() if err != nil { return err } @@ -166,28 +194,39 @@ func TryProxies(f func(proxy string) error) error { return f("off") } - var lastAttemptErr error + // We try to report the most helpful error to the user. "direct" and "noproxy" + // errors are best, followed by proxy errors other than ErrNotExist, followed + // by ErrNotExist. Note that errProxyOff, errNoproxy, and errUseProxy are + // equivalent to ErrNotExist. + const ( + notExistRank = iota + proxyRank + directRank + ) + var bestErr error + bestErrRank := notExistRank for _, proxy := range proxies { - err = f(proxy) - if !errors.Is(err, os.ErrNotExist) { - lastAttemptErr = err - break + err := f(proxy.url) + if err == nil { + return nil + } + isNotExistErr := errors.Is(err, os.ErrNotExist) + + if proxy.url == "direct" || proxy.url == "noproxy" { + bestErr = err + bestErrRank = directRank + } else if bestErrRank <= proxyRank && !isNotExistErr { + bestErr = err + bestErrRank = proxyRank + } else if bestErrRank == notExistRank { + bestErr = err } - // The error indicates that the module does not exist. - // In general we prefer to report the last such error, - // because it indicates the error that occurs after all other - // options have been exhausted. - // - // However, for modules in the NOPROXY list, the most useful error occurs - // first (with proxy set to "noproxy"), and the subsequent errors are all - // errNoProxy (which is not particularly helpful). Do not overwrite a more - // useful error with errNoproxy. - if lastAttemptErr == nil || !errors.Is(err, errNoproxy) { - lastAttemptErr = err + if !proxy.fallBackOnError && !isNotExistErr { + break } } - return lastAttemptErr + return bestErr } type proxyRepo struct { diff --git a/src/cmd/go/internal/modfetch/sumdb.go b/src/cmd/go/internal/modfetch/sumdb.go index 1ed71dfb85..ff81ef687e 100644 --- a/src/cmd/go/internal/modfetch/sumdb.go +++ b/src/cmd/go/internal/modfetch/sumdb.go @@ -26,6 +26,7 @@ import ( "cmd/go/internal/lockedfile" "cmd/go/internal/str" "cmd/go/internal/web" + "golang.org/x/mod/module" "golang.org/x/mod/sumdb" "golang.org/x/mod/sumdb/note" @@ -146,49 +147,50 @@ func (c *dbClient) initBase() { } // Try proxies in turn until we find out how to connect to this database. - urls, err := proxyURLs() - if err != nil { - c.baseErr = err - return - } - for _, proxyURL := range urls { - if proxyURL == "noproxy" { - continue - } - if proxyURL == "direct" || proxyURL == "off" { - break - } - proxy, err := url.Parse(proxyURL) - if err != nil { - c.baseErr = err - return - } - // Quoting https://golang.org/design/25530-sumdb#proxying-a-checksum-database: - // - // Before accessing any checksum database URL using a proxy, - // the proxy client should first fetch <proxyURL>/sumdb/<sumdb-name>/supported. - // If that request returns a successful (HTTP 200) response, then the proxy supports - // proxying checksum database requests. In that case, the client should use - // the proxied access method only, never falling back to a direct connection to the database. - // If the /sumdb/<sumdb-name>/supported check fails with a “not found” (HTTP 404) - // or “gone” (HTTP 410) response, the proxy is unwilling to proxy the checksum database, - // and the client should connect directly to the database. - // Any other response is treated as the database being unavailable. - _, err = web.GetBytes(web.Join(proxy, "sumdb/"+c.name+"/supported")) - if err == nil { + // + // Before accessing any checksum database URL using a proxy, the proxy + // client should first fetch <proxyURL>/sumdb/<sumdb-name>/supported. + // + // If that request returns a successful (HTTP 200) response, then the proxy + // supports proxying checksum database requests. In that case, the client + // should use the proxied access method only, never falling back to a direct + // connection to the database. + // + // If the /sumdb/<sumdb-name>/supported check fails with a “not found” (HTTP + // 404) or “gone” (HTTP 410) response, or if the proxy is configured to fall + // back on errors, the client will try the next proxy. If there are no + // proxies left or if the proxy is "direct" or "off", the client should + // connect directly to that database. + // + // Any other response is treated as the database being unavailable. + // + // See https://golang.org/design/25530-sumdb#proxying-a-checksum-database. + err := TryProxies(func(proxy string) error { + switch proxy { + case "noproxy": + return errUseProxy + case "direct", "off": + return errProxyOff + default: + proxyURL, err := url.Parse(proxy) + if err != nil { + return err + } + if _, err := web.GetBytes(web.Join(proxyURL, "sumdb/"+c.name+"/supported")); err != nil { + return err + } // Success! This proxy will help us. - c.base = web.Join(proxy, "sumdb/"+c.name) - return - } - // If the proxy serves a non-404/410, give up. - if !errors.Is(err, os.ErrNotExist) { - c.baseErr = err - return + c.base = web.Join(proxyURL, "sumdb/"+c.name) + return nil } + }) + if errors.Is(err, os.ErrNotExist) { + // No proxies, or all proxies failed (with 404, 410, or were were allowed + // to fall back), or we reached an explicit "direct" or "off". + c.base = c.direct + } else if err != nil { + c.baseErr = err } - - // No proxies, or all proxies said 404, or we reached an explicit "direct". - c.base = c.direct } // ReadConfig reads the key from c.key diff --git a/src/cmd/go/internal/modload/help.go b/src/cmd/go/internal/modload/help.go index bd19bb43aa..d80206b194 100644 --- a/src/cmd/go/internal/modload/help.go +++ b/src/cmd/go/internal/modload/help.go @@ -363,15 +363,15 @@ variable (see 'go help env'). The default setting for GOPROXY is Go module mirror run by Google and fall back to a direct connection if the proxy reports that it does not have the module (HTTP error 404 or 410). See https://proxy.golang.org/privacy for the service's privacy policy. -If GOPROXY is set to the string "direct", downloads use a direct connection -to source control servers. Setting GOPROXY to "off" disallows downloading -modules from any source. Otherwise, GOPROXY is expected to be a comma-separated -list of the URLs of module proxies, in which case the go command will fetch -modules from those proxies. For each request, the go command tries each proxy -in sequence, only moving to the next if the current proxy returns a 404 or 410 -HTTP response. The string "direct" may appear in the proxy list, -to cause a direct connection to be attempted at that point in the search. -Any proxies listed after "direct" are never consulted. + +If GOPROXY is set to the string "direct", downloads use a direct connection to +source control servers. Setting GOPROXY to "off" disallows downloading modules +from any source. Otherwise, GOPROXY is expected to be list of module proxy URLs +separated by either comma (,) or pipe (|) characters, which control error +fallback behavior. For each request, the go command tries each proxy in +sequence. If there is an error, the go command will try the next proxy in the +list if the error is a 404 or 410 HTTP response or if the current proxy is +followed by a pipe character, indicating it is safe to fall back on any error. The GOPRIVATE and GONOPROXY environment variables allow bypassing the proxy for selected modules. See 'go help module-private' for details. diff --git a/src/cmd/go/testdata/script/mod_empty_err.txt b/src/cmd/go/testdata/script/mod_empty_err.txt index b309f634dd..982e6b2e51 100644 --- a/src/cmd/go/testdata/script/mod_empty_err.txt +++ b/src/cmd/go/testdata/script/mod_empty_err.txt @@ -10,7 +10,7 @@ go list -e -f {{.Error}} ./empty stdout 'no Go files in \$WORK[/\\]empty' go list -e -f {{.Error}} ./exclude -stdout 'package example.com/m/exclude: build constraints exclude all Go files in \$WORK[/\\]exclude' +stdout 'build constraints exclude all Go files in \$WORK[/\\]exclude' go list -e -f {{.Error}} ./missing stdout 'stat '$WORK'[/\\]missing: directory not found' diff --git a/src/cmd/go/testdata/script/mod_proxy_list.txt b/src/cmd/go/testdata/script/mod_proxy_list.txt index a48622814a..849cf2c476 100644 --- a/src/cmd/go/testdata/script/mod_proxy_list.txt +++ b/src/cmd/go/testdata/script/mod_proxy_list.txt @@ -10,17 +10,25 @@ stderr '404 Not Found' env GOPROXY=$proxy/404,$proxy/410,$proxy go get rsc.io/quote@v1.1.0 -# get should not walk past other 4xx errors. +# get should not walk past other 4xx errors if proxies are separated with ','. env GOPROXY=$proxy/403,$proxy ! go get rsc.io/quote@v1.2.0 stderr 'reading.*/403/rsc.io/.*: 403 Forbidden' -# get should not walk past non-4xx errors. +# get should not walk past non-4xx errors if proxies are separated with ','. env GOPROXY=$proxy/500,$proxy ! go get rsc.io/quote@v1.3.0 stderr 'reading.*/500/rsc.io/.*: 500 Internal Server Error' -# get should return the final 404/410 if that's all we have. +# get should walk past other 4xx errors if proxies are separated with '|'. +env GOPROXY=$proxy/403|https://0.0.0.0|$proxy +go get rsc.io/quote@v1.2.0 + +# get should walk past non-4xx errors if proxies are separated with '|'. +env GOPROXY=$proxy/500|https://0.0.0.0|$proxy +go get rsc.io/quote@v1.3.0 + +# get should return the final error if that's all we have. env GOPROXY=$proxy/404,$proxy/410 ! go get rsc.io/quote@v1.4.0 stderr 'reading.*/410/rsc.io/.*: 410 Gone' diff --git a/src/cmd/go/testdata/script/mod_sumdb_proxy.txt b/src/cmd/go/testdata/script/mod_sumdb_proxy.txt index 28166913fd..7bbc3f9e19 100644 --- a/src/cmd/go/testdata/script/mod_sumdb_proxy.txt +++ b/src/cmd/go/testdata/script/mod_sumdb_proxy.txt @@ -46,5 +46,22 @@ stderr '503 Service Unavailable' rm $GOPATH/pkg/mod/cache/download/sumdb rm go.sum +# the error from the last attempted proxy should be returned. +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-404,$proxy/sumdb-503 +! go get -d rsc.io/fortune@v1.0.0 +stderr '503 Service Unavailable' +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# if proxies are separated with '|', fallback is allowed on any error. +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-503|https://0.0.0.0|$proxy +go get -d rsc.io/fortune@v1.0.0 +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + -- go.mod.orig -- module m diff --git a/src/cmd/go/testdata/script/test_import_error_stack.txt b/src/cmd/go/testdata/script/test_import_error_stack.txt index 3b796053f7..c66c1213a4 100644 --- a/src/cmd/go/testdata/script/test_import_error_stack.txt +++ b/src/cmd/go/testdata/script/test_import_error_stack.txt @@ -1,6 +1,9 @@ ! go test testdep/p1 stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack +! go vet testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack + -- testdep/p1/p1.go -- package p1 -- testdep/p1/p1_test.go -- diff --git a/src/cmd/go/testdata/script/vet_internal.txt b/src/cmd/go/testdata/script/vet_internal.txt index 46e1ac7398..85f709302c 100644 --- a/src/cmd/go/testdata/script/vet_internal.txt +++ b/src/cmd/go/testdata/script/vet_internal.txt @@ -3,28 +3,28 @@ env GO111MODULE=off # Issue 36173. Verify that "go vet" prints line numbers on load errors. ! go vet a/a.go -stderr '^a[/\\]a.go:5:3: use of internal package' +stderr '^package command-line-arguments\n\ta[/\\]a.go:5:3: use of internal package' ! go vet a/a_test.go -stderr '^package command-line-arguments \(test\): use of internal package' # BUG +stderr '^package command-line-arguments \(test\)\n\ta[/\\]a_test.go:4:3: use of internal package' ! go vet a -stderr '^a[/\\]a.go:5:3: use of internal package' +stderr '^package a\n\ta[/\\]a.go:5:3: use of internal package' go vet b/b.go ! stderr 'use of internal package' ! go vet b/b_test.go -stderr '^package command-line-arguments \(test\): use of internal package' # BUG +stderr '^package command-line-arguments \(test\)\n\tb[/\\]b_test.go:4:3: use of internal package' ! go vet depends-on-a/depends-on-a.go -stderr '^a[/\\]a.go:5:3: use of internal package' +stderr '^package command-line-arguments\n\timports a\n\ta[/\\]a.go:5:3: use of internal package' ! go vet depends-on-a/depends-on-a_test.go -stderr '^package command-line-arguments \(test\)\n\timports a: use of internal package a/x/internal/y not allowed$' # BUG +stderr '^package command-line-arguments \(test\)\n\timports a\n\ta[/\\]a.go:5:3: use of internal package a/x/internal/y not allowed' ! go vet depends-on-a -stderr '^a[/\\]a.go:5:3: use of internal package' +stderr '^package depends-on-a\n\timports a\n\ta[/\\]a.go:5:3: use of internal package' -- a/a.go -- // A package with bad imports in both src and test diff --git a/src/cmd/internal/obj/riscv/anames.go b/src/cmd/internal/obj/riscv/anames.go index fa236d81e5..6581bb3402 100644 --- a/src/cmd/internal/obj/riscv/anames.go +++ b/src/cmd/internal/obj/riscv/anames.go @@ -226,6 +226,16 @@ var Anames = []string{ "HFENCEGVMA", "HFENCEVVMA", "WORD", + "BEQZ", + "BGEZ", + "BGT", + "BGTU", + "BGTZ", + "BLE", + "BLEU", + "BLEZ", + "BLTZ", + "BNEZ", "FNEGD", "FNEGS", "FNED", diff --git a/src/cmd/internal/obj/riscv/asm_test.go b/src/cmd/internal/obj/riscv/asm_test.go index 849a87b706..f8f7b4f2ce 100644 --- a/src/cmd/internal/obj/riscv/asm_test.go +++ b/src/cmd/internal/obj/riscv/asm_test.go @@ -12,6 +12,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "testing" ) @@ -131,3 +132,20 @@ TEXT _stub(SB),$0-0 t.Errorf("%v\n%s", err, out) } } + +func TestBranch(t *testing.T) { + if testing.Short() { + t.Skip("Skipping in short mode") + } + if runtime.GOARCH != "riscv64" { + t.Skip("Requires riscv64 to run") + } + + testenv.MustHaveGoBuild(t) + + cmd := exec.Command(testenv.GoToolPath(t), "test") + cmd.Dir = "testdata/testbranch" + if out, err := testenv.CleanCmdEnv(cmd).CombinedOutput(); err != nil { + t.Errorf("Branch test failed: %v\n%s", err, out) + } +} diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go index 76457dd8d2..482f9e0b6d 100644 --- a/src/cmd/internal/obj/riscv/cpu.go +++ b/src/cmd/internal/obj/riscv/cpu.go @@ -576,6 +576,16 @@ const ( // Pseudo-instructions. These get translated by the assembler into other // instructions, based on their operands. + ABEQZ + ABGEZ + ABGT + ABGTU + ABGTZ + ABLE + ABLEU + ABLEZ + ABLTZ + ABNEZ AFNEGD AFNEGS AFNED diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index ed5d533402..73fe8c284f 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -406,20 +406,40 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) { } // InvertBranch inverts the condition of a conditional branch. -func InvertBranch(i obj.As) obj.As { - switch i { +func InvertBranch(as obj.As) obj.As { + switch as { case ABEQ: return ABNE - case ABNE: - return ABEQ - case ABLT: - return ABGE + case ABEQZ: + return ABNEZ case ABGE: return ABLT - case ABLTU: - return ABGEU case ABGEU: return ABLTU + case ABGEZ: + return ABLTZ + case ABGT: + return ABLE + case ABGTU: + return ABLEU + case ABGTZ: + return ABLEZ + case ABLE: + return ABGT + case ABLEU: + return ABGTU + case ABLEZ: + return ABGTZ + case ABLT: + return ABGE + case ABLTU: + return ABGEU + case ABLTZ: + return ABGEZ + case ABNE: + return ABEQ + case ABNEZ: + return ABEQZ default: panic("InvertBranch: not a branch") } @@ -860,7 +880,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { for p := cursym.Func.Text; p != nil; p = p.Link { switch p.As { - case ABEQ, ABNE, ABLT, ABGE, ABLTU, ABGEU: + case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ: if p.To.Type != obj.TYPE_BRANCH { panic("assemble: instruction with branch-like opcode lacks destination") } @@ -917,7 +937,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { // instructions will break everything--don't do it! for p := cursym.Func.Text; p != nil; p = p.Link { switch p.As { - case AJAL, ABEQ, ABNE, ABLT, ABLTU, ABGE, ABGEU: + case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ, AJAL: switch p.To.Type { case obj.TYPE_BRANCH: p.To.Type, p.To.Offset = obj.TYPE_CONST, p.Pcond.Pc-p.Pc @@ -1778,7 +1798,29 @@ func instructionsForProg(p *obj.Prog) []*instruction { ins.rd, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE ins.imm = p.To.Offset - case ABEQ, ABNE, ABLT, ABGE, ABLTU, ABGEU: + case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ: + switch ins.as { + case ABEQZ: + ins.as, ins.rs1, ins.rs2 = ABEQ, REG_ZERO, uint32(p.From.Reg) + case ABGEZ: + ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg) + case ABGT: + ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.Reg), uint32(p.From.Reg) + case ABGTU: + ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.Reg), uint32(p.From.Reg) + case ABGTZ: + ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO + case ABLE: + ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.Reg), uint32(p.From.Reg) + case ABLEU: + ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.Reg), uint32(p.From.Reg) + case ABLEZ: + ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO + case ABLTZ: + ins.as, ins.rs1, ins.rs2 = ABLT, REG_ZERO, uint32(p.From.Reg) + case ABNEZ: + ins.as, ins.rs1, ins.rs2 = ABNE, REG_ZERO, uint32(p.From.Reg) + } ins.imm = p.To.Offset case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD: diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go new file mode 100644 index 0000000000..b0ab5f72aa --- /dev/null +++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go @@ -0,0 +1,94 @@ +// Copyright 2020 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. + +// +build riscv64 + +package testbranch + +import ( + "testing" +) + +func testBEQZ(a int64) (r bool) +func testBGEZ(a int64) (r bool) +func testBGT(a, b int64) (r bool) +func testBGTU(a, b int64) (r bool) +func testBGTZ(a int64) (r bool) +func testBLE(a, b int64) (r bool) +func testBLEU(a, b int64) (r bool) +func testBLEZ(a int64) (r bool) +func testBLTZ(a int64) (r bool) +func testBNEZ(a int64) (r bool) + +func TestBranchCondition(t *testing.T) { + tests := []struct{ + ins string + a int64 + b int64 + fn func(a, b int64) bool + want bool + }{ + {"BGT", 0, 1, testBGT, true}, + {"BGT", 0, 0, testBGT, false}, + {"BGT", 0, -1, testBGT, false}, + {"BGT", -1, 0, testBGT, true}, + {"BGT", 1, 0, testBGT, false}, + {"BGTU", 0, 1, testBGTU, true}, + {"BGTU", 0, -1, testBGTU, true}, + {"BGTU", -1, 0, testBGTU, false}, + {"BGTU", 1, 0, testBGTU, false}, + {"BLE", 0, 1, testBLE, false}, + {"BLE", 0, -1, testBLE, true}, + {"BLE", 0, 0, testBLE, true}, + {"BLE", -1, 0, testBLE, false}, + {"BLE", 1, 0, testBLE, true}, + {"BLEU", 0, 1, testBLEU, false}, + {"BLEU", 0, -1, testBLEU, false}, + {"BLEU", 0, 0, testBLEU, true}, + {"BLEU", -1, 0, testBLEU, true}, + {"BLEU", 1, 0, testBLEU, true}, + } + for _, test := range tests { + t.Run(test.ins, func(t *testing.T) { + if got := test.fn(test.a, test.b); got != test.want { + t.Errorf("%v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want) + } + }) + } +} + +func TestBranchZero(t *testing.T) { + tests := []struct{ + ins string + a int64 + fn func(a int64) bool + want bool + }{ + {"BEQZ", -1, testBEQZ, false}, + {"BEQZ", 0, testBEQZ, true}, + {"BEQZ", 1, testBEQZ, false}, + {"BGEZ", -1, testBGEZ, false}, + {"BGEZ", 0, testBGEZ, true}, + {"BGEZ", 1, testBGEZ, true}, + {"BGTZ", -1, testBGTZ, false}, + {"BGTZ", 0, testBGTZ, false}, + {"BGTZ", 1, testBGTZ, true}, + {"BLEZ", -1, testBLEZ, true}, + {"BLEZ", 0, testBLEZ, true}, + {"BLEZ", 1, testBLEZ, false}, + {"BLTZ", -1, testBLTZ, true}, + {"BLTZ", 0, testBLTZ, false}, + {"BLTZ", 1, testBLTZ, false}, + {"BNEZ", -1, testBNEZ, true}, + {"BNEZ", 0, testBNEZ, false}, + {"BNEZ", 1, testBNEZ, true}, + } + for _, test := range tests { + t.Run(test.ins, func(t *testing.T) { + if got := test.fn(test.a); got != test.want { + t.Errorf("%v %v = %v, want %v", test.ins, test.a, got, test.want) + } + }) + } +} diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s new file mode 100644 index 0000000000..6cff235848 --- /dev/null +++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s @@ -0,0 +1,111 @@ +// Copyright 2020 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. + +// +build riscv64 + +#include "textflag.h" + +// func testBEQZ(a int64) (r bool) +TEXT ·testBEQZ(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV $1, X6 + BEQZ X5, b + MOV $0, X6 +b: + MOV X6, r+8(FP) + RET + +// func testBGEZ(a int64) (r bool) +TEXT ·testBGEZ(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV $1, X6 + BGEZ X5, b + MOV $0, X6 +b: + MOV X6, r+8(FP) + RET + +// func testBGT(a, b int64) (r bool) +TEXT ·testBGT(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV b+8(FP), X6 + MOV $1, X7 + BGT X5, X6, b + MOV $0, X7 +b: + MOV X7, r+16(FP) + RET + +// func testBGTU(a, b int64) (r bool) +TEXT ·testBGTU(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV b+8(FP), X6 + MOV $1, X7 + BGTU X5, X6, b + MOV $0, X7 +b: + MOV X7, r+16(FP) + RET + +// func testBGTZ(a int64) (r bool) +TEXT ·testBGTZ(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV $1, X6 + BGTZ X5, b + MOV $0, X6 +b: + MOV X6, r+8(FP) + RET + +// func testBLE(a, b int64) (r bool) +TEXT ·testBLE(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV b+8(FP), X6 + MOV $1, X7 + BLE X5, X6, b + MOV $0, X7 +b: + MOV X7, r+16(FP) + RET + +// func testBLEU(a, b int64) (r bool) +TEXT ·testBLEU(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV b+8(FP), X6 + MOV $1, X7 + BLEU X5, X6, b + MOV $0, X7 +b: + MOV X7, r+16(FP) + RET + +// func testBLEZ(a int64) (r bool) +TEXT ·testBLEZ(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV $1, X6 + BLEZ X5, b + MOV $0, X6 +b: + MOV X6, r+8(FP) + RET + +// func testBLTZ(a int64) (r bool) +TEXT ·testBLTZ(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV $1, X6 + BLTZ X5, b + MOV $0, X6 +b: + MOV X6, r+8(FP) + RET + +// func testBNEZ(a int64) (r bool) +TEXT ·testBNEZ(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV $1, X6 + BNEZ X5, b + MOV $0, X6 +b: + MOV X6, r+8(FP) + RET diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go index 35cfd35d37..b5f1cd1632 100644 --- a/src/cmd/internal/objfile/disasm.go +++ b/src/cmd/internal/objfile/disasm.go @@ -187,7 +187,7 @@ func (fc *FileCache) Line(filename string, line int) ([]byte, error) { // If filter is non-nil, the disassembly only includes functions with names matching filter. // If printCode is true, the disassembly includs corresponding source lines. // The disassembly only includes functions that overlap the range [start, end). -func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool) { +func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool, gnuAsm bool) { if start < d.textStart { start = d.textStart } @@ -229,7 +229,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr var lastFile string var lastLine int - d.Decode(symStart, symEnd, relocs, func(pc, size uint64, file string, line int, text string) { + d.Decode(symStart, symEnd, relocs, gnuAsm, func(pc, size uint64, file string, line int, text string) { i := pc - d.textStart if printCode { @@ -266,7 +266,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr } // Decode disassembles the text segment range [start, end), calling f for each instruction. -func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint64, file string, line int, text string)) { +func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) { if start < d.textStart { start = d.textStart } @@ -277,7 +277,7 @@ func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint6 lookup := d.lookup for pc := start; pc < end; { i := pc - d.textStart - text, size := d.disasm(code[i:], pc, lookup, d.byteOrder) + text, size := d.disasm(code[i:], pc, lookup, d.byteOrder, gnuAsm) file, line, _ := d.pcln.PCToLine(pc) sep := "\t" for len(relocs) > 0 && relocs[0].Addr < i+uint64(size) { @@ -291,17 +291,17 @@ func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint6 } type lookupFunc = func(addr uint64) (sym string, base uint64) -type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder) (text string, size int) +type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder, _ bool) (text string, size int) -func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) { - return disasm_x86(code, pc, lookup, 32) +func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { + return disasm_x86(code, pc, lookup, 32, gnuAsm) } -func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) { - return disasm_x86(code, pc, lookup, 64) +func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { + return disasm_x86(code, pc, lookup, 64, gnuAsm) } -func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, int) { +func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int, gnuAsm bool) (string, int) { inst, err := x86asm.Decode(code, arch) var text string size := inst.Len @@ -309,7 +309,11 @@ func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, in size = 1 text = "?" } else { - text = x86asm.GoSyntax(inst, pc, lookup) + if gnuAsm { + text = fmt.Sprintf("%-36s // %s", x86asm.GoSyntax(inst, pc, lookup), x86asm.GNUSyntax(inst, pc, nil)) + } else { + text = x86asm.GoSyntax(inst, pc, lookup) + } } return text, size } @@ -334,31 +338,35 @@ func (r textReader) ReadAt(data []byte, off int64) (n int, err error) { return } -func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) { +func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { inst, err := armasm.Decode(code, armasm.ModeARM) var text string size := inst.Len if err != nil || size == 0 || inst.Op == 0 { size = 4 text = "?" + } else if gnuAsm { + text = fmt.Sprintf("%-36s // %s", armasm.GoSyntax(inst, pc, lookup, textReader{code, pc}), armasm.GNUSyntax(inst)) } else { text = armasm.GoSyntax(inst, pc, lookup, textReader{code, pc}) } return text, size } -func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder) (string, int) { +func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) { inst, err := arm64asm.Decode(code) var text string if err != nil || inst.Op == 0 { text = "?" + } else if gnuAsm { + text = fmt.Sprintf("%-36s // %s", arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}), arm64asm.GNUSyntax(inst)) } else { text = arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}) } return text, 4 } -func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder) (string, int) { +func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) { inst, err := ppc64asm.Decode(code, byteOrder) var text string size := inst.Len @@ -366,7 +374,11 @@ func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.By size = 4 text = "?" } else { - text = ppc64asm.GoSyntax(inst, pc, lookup) + if gnuAsm { + text = fmt.Sprintf("%-36s // %s", ppc64asm.GoSyntax(inst, pc, lookup), ppc64asm.GNUSyntax(inst, pc)) + } else { + text = ppc64asm.GoSyntax(inst, pc, lookup) + } } return text, size } diff --git a/src/cmd/link/internal/ld/errors.go b/src/cmd/link/internal/ld/errors.go index a156e67f95..e66c518b85 100644 --- a/src/cmd/link/internal/ld/errors.go +++ b/src/cmd/link/internal/ld/errors.go @@ -49,7 +49,7 @@ func (reporter *ErrorReporter) errorUnresolved(s *sym.Symbol, r *sym.Reloc) { if v == -1 { continue } - if rs := reporter.lookup(r.Sym.Name, v); rs != nil && rs.Type != sym.Sxxx { + if rs := reporter.lookup(r.Sym.Name, v); rs != nil && rs.Type != sym.Sxxx && rs.Type != sym.SXREF { haveABI = abi } } diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index ed2d3f4495..e665737cc3 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -172,6 +172,93 @@ main.x: relocation target main.zero not defined } } +func TestIssue33979(t *testing.T) { + testenv.MustHaveGoBuild(t) + testenv.MustHaveCGO(t) + + // Skip test on platforms that do not support cgo internal linking. + switch runtime.GOARCH { + case "mips", "mipsle", "mips64", "mips64le": + t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH) + } + if runtime.GOOS == "aix" { + t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH) + } + + tmpdir, err := ioutil.TempDir("", "unresolved-") + if err != nil { + t.Fatalf("failed to create temp dir: %v", err) + } + defer os.RemoveAll(tmpdir) + + write := func(name, content string) { + err := ioutil.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666) + if err != nil { + t.Fatal(err) + } + } + + run := func(name string, args ...string) string { + cmd := exec.Command(name, args...) + cmd.Dir = tmpdir + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("'go %s' failed: %v, output: %s", strings.Join(args, " "), err, out) + } + return string(out) + } + runGo := func(args ...string) string { + return run(testenv.GoToolPath(t), args...) + } + + // Test object with undefined reference that was not generated + // by Go, resulting in an SXREF symbol being loaded during linking. + // Because of issue #33979, the SXREF symbol would be found during + // error reporting, resulting in confusing error messages. + + write("main.go", `package main +func main() { + x() +} +func x() +`) + // The following assembly must work on all architectures. + write("x.s", ` +TEXT ·x(SB),0,$0 + CALL foo(SB) + RET +`) + write("x.c", ` +void undefined(); + +void foo() { + undefined(); +} +`) + + cc := strings.TrimSpace(runGo("env", "CC")) + cflags := strings.Fields(runGo("env", "GOGCCFLAGS")) + + // Compile, assemble and pack the Go and C code. + runGo("tool", "asm", "-gensymabis", "-o", "symabis", "x.s") + runGo("tool", "compile", "-symabis", "symabis", "-p", "main", "-o", "x1.o", "main.go") + runGo("tool", "asm", "-o", "x2.o", "x.s") + run(cc, append(cflags, "-c", "-o", "x3.o", "x.c")...) + runGo("tool", "pack", "c", "x.a", "x1.o", "x2.o", "x3.o") + + // Now attempt to link using the internal linker. + cmd := exec.Command(testenv.GoToolPath(t), "tool", "link", "-linkmode=internal", "x.a") + cmd.Dir = tmpdir + out, err := cmd.CombinedOutput() + if err == nil { + t.Fatalf("expected link to fail, but it succeeded") + } + re := regexp.MustCompile(`(?m)^main\(.*text\): relocation target undefined not defined$`) + if !re.Match(out) { + t.Fatalf("got:\n%q\nwant:\n%s", out, re) + } +} + func TestBuildForTvOS(t *testing.T) { testenv.MustHaveCGO(t) testenv.MustHaveGoBuild(t) diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go index 6a60697ebd..6605f8a60c 100644 --- a/src/cmd/objdump/main.go +++ b/src/cmd/objdump/main.go @@ -43,12 +43,13 @@ import ( "cmd/internal/objfile" ) -var printCode = flag.Bool("S", false, "print go code alongside assembly") +var printCode = flag.Bool("S", false, "print Go code alongside assembly") var symregexp = flag.String("s", "", "only dump symbols matching this regexp") +var gnuAsm = flag.Bool("gnu", false, "print GNU assembly next to Go assembly (where supported)") var symRE *regexp.Regexp func usage() { - fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-s symregexp] binary [start end]\n\n") + fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-gnu] [-s symregexp] binary [start end]\n\n") flag.PrintDefaults() os.Exit(2) } @@ -87,7 +88,7 @@ func main() { usage() case 1: // disassembly of entire object - dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode) + dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode, *gnuAsm) case 3: // disassembly of PC range @@ -99,6 +100,6 @@ func main() { if err != nil { log.Fatalf("invalid end PC: %v", err) } - dis.Print(os.Stdout, symRE, start, end, *printCode) + dis.Print(os.Stdout, symRE, start, end, *printCode, *gnuAsm) } } diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go index 7ed32cf3c2..c974d6707b 100644 --- a/src/cmd/objdump/objdump_test.go +++ b/src/cmd/objdump/objdump_test.go @@ -58,24 +58,54 @@ func buildObjdump() error { return nil } -var x86Need = []string{ +var x86Need = []string{ // for both 386 and AMD64 "JMP main.main(SB)", "CALL main.Println(SB)", "RET", } +var amd64GnuNeed = []string{ + "movq", + "callq", + "cmpb", +} + +var i386GnuNeed = []string{ + "mov", + "call", + "cmp", +} + var armNeed = []string{ "B main.main(SB)", "BL main.Println(SB)", "RET", } +var arm64Need = []string{ + "JMP main.main(SB)", + "CALL main.Println(SB)", + "RET", +} + +var armGnuNeed = []string{ // for both ARM and AMR64 + "ldr", + "bl", + "cmp", +} + var ppcNeed = []string{ "BR main.main(SB)", "CALL main.Println(SB)", "RET", } +var ppcGnuNeed = []string{ + "mflr", + "lbz", + "cmpw", +} + var target = flag.String("target", "", "test disassembly of `goos/goarch` binary") // objdump is fully cross platform: it can handle binaries @@ -87,7 +117,7 @@ var target = flag.String("target", "", "test disassembly of `goos/goarch` binary // binary for the current system (only) and test that objdump // can handle that one. -func testDisasm(t *testing.T, printCode bool, flags ...string) { +func testDisasm(t *testing.T, printCode bool, printGnuAsm bool, flags ...string) { t.Parallel() goarch := runtime.GOARCH if *target != "" { @@ -102,7 +132,7 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) { goarch = f[1] } - hash := md5.Sum([]byte(fmt.Sprintf("%v-%v", flags, printCode))) + hash := md5.Sum([]byte(fmt.Sprintf("%v-%v-%v", flags, printCode, printGnuAsm))) hello := filepath.Join(tmp, fmt.Sprintf("hello-%x.exe", hash)) args := []string{"build", "-o", hello} args = append(args, flags...) @@ -129,10 +159,24 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) { need = append(need, x86Need...) case "arm": need = append(need, armNeed...) + case "arm64": + need = append(need, arm64Need...) case "ppc64", "ppc64le": need = append(need, ppcNeed...) } + if printGnuAsm { + switch goarch { + case "amd64": + need = append(need, amd64GnuNeed...) + case "386": + need = append(need, i386GnuNeed...) + case "arm", "arm64": + need = append(need, armGnuNeed...) + case "ppc64", "ppc64le": + need = append(need, ppcGnuNeed...) + } + } args = []string{ "-s", "main.main", hello, @@ -142,6 +186,9 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) { args = append([]string{"-S"}, args...) } + if printGnuAsm { + args = append([]string{"-gnu"}, args...) + } cmd = exec.Command(exe, args...) cmd.Dir = "testdata" // "Bad line" bug #36683 is sensitive to being run in the source directory out, err = cmd.CombinedOutput() @@ -180,7 +227,7 @@ func TestDisasm(t *testing.T) { case "s390x": t.Skipf("skipping on %s, issue 15255", runtime.GOARCH) } - testDisasm(t, false) + testDisasm(t, false, false) } func TestDisasmCode(t *testing.T) { @@ -188,7 +235,15 @@ func TestDisasmCode(t *testing.T) { case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x": t.Skipf("skipping on %s, issue 19160", runtime.GOARCH) } - testDisasm(t, true) + testDisasm(t, true, false) +} + +func TestDisasmGnuAsm(t *testing.T) { + switch runtime.GOARCH { + case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x": + t.Skipf("skipping on %s, issue 19160", runtime.GOARCH) + } + testDisasm(t, false, true) } func TestDisasmExtld(t *testing.T) { @@ -209,7 +264,7 @@ func TestDisasmExtld(t *testing.T) { if !build.Default.CgoEnabled { t.Skip("skipping because cgo is not enabled") } - testDisasm(t, false, "-ldflags=-linkmode=external") + testDisasm(t, false, false, "-ldflags=-linkmode=external") } func TestDisasmGoobj(t *testing.T) { diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go index 42e310043d..903f9cc1db 100644 --- a/src/cmd/pprof/pprof.go +++ b/src/cmd/pprof/pprof.go @@ -177,7 +177,7 @@ func (t *objTool) Disasm(file string, start, end uint64) ([]driver.Inst, error) return nil, err } var asm []driver.Inst - d.Decode(start, end, nil, func(pc, size uint64, file string, line int, text string) { + d.Decode(start, end, nil, false, func(pc, size uint64, file string, line int, text string) { asm = append(asm, driver.Inst{Addr: pc, File: file, Line: line, Text: text}) }) return asm, nil diff --git a/src/context/context_test.go b/src/context/context_test.go index 98c6683335..6b392a29da 100644 --- a/src/context/context_test.go +++ b/src/context/context_test.go @@ -27,6 +27,7 @@ type testingT interface { Log(args ...interface{}) Logf(format string, args ...interface{}) Name() string + Parallel() Skip(args ...interface{}) SkipNow() Skipf(format string, args ...interface{}) @@ -284,6 +285,8 @@ func testDeadline(c Context, name string, t testingT) { } func XTestDeadline(t testingT) { + t.Parallel() + c, _ := WithDeadline(Background(), time.Now().Add(shortDuration)) if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { t.Errorf("c.String() = %q want prefix %q", got, prefix) @@ -307,6 +310,8 @@ func XTestDeadline(t testingT) { } func XTestTimeout(t testingT) { + t.Parallel() + c, _ := WithTimeout(Background(), shortDuration) if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { t.Errorf("c.String() = %q want prefix %q", got, prefix) @@ -417,9 +422,9 @@ func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func( gccgoLimit: 3, }, { - desc: "WithTimeout(bg, 15*time.Millisecond)", + desc: "WithTimeout(bg, 1*time.Nanosecond)", f: func() { - c, _ := WithTimeout(bg, 15*time.Millisecond) + c, _ := WithTimeout(bg, 1*time.Nanosecond) <-c.Done() }, limit: 12, @@ -545,7 +550,9 @@ func XTestLayersTimeout(t testingT) { } func testLayers(t testingT, seed int64, testTimeout bool) { - rand.Seed(seed) + t.Parallel() + + r := rand.New(rand.NewSource(seed)) errorf := func(format string, a ...interface{}) { t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...) } @@ -560,7 +567,7 @@ func testLayers(t testingT, seed int64, testTimeout bool) { ctx = Background() ) for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ { - switch rand.Intn(3) { + switch r.Intn(3) { case 0: v := new(value) ctx = WithValue(ctx, v, v) @@ -587,10 +594,12 @@ func testLayers(t testingT, seed int64, testTimeout bool) { } } } - select { - case <-ctx.Done(): - errorf("ctx should not be canceled yet") - default: + if !testTimeout { + select { + case <-ctx.Done(): + errorf("ctx should not be canceled yet") + default: + } } if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) { t.Errorf("ctx.String() = %q want prefix %q", s, prefix) @@ -608,7 +617,7 @@ func testLayers(t testingT, seed int64, testTimeout bool) { } checkValues("after timeout") } else { - cancel := cancels[rand.Intn(len(cancels))] + cancel := cancels[r.Intn(len(cancels))] cancel() select { case <-ctx.Done(): diff --git a/src/context/example_test.go b/src/context/example_test.go index b91a8acef3..72ac5d2e49 100644 --- a/src/context/example_test.go +++ b/src/context/example_test.go @@ -10,6 +10,8 @@ import ( "time" ) +const shortDuration = 1 * time.Millisecond // a reasonable duration to block in an example + // This example demonstrates the use of a cancelable context to prevent a // goroutine leak. By the end of the example function, the goroutine started // by gen will return without leaking. @@ -55,7 +57,7 @@ func ExampleWithCancel() { // This example passes a context with an arbitrary deadline to tell a blocking // function that it should abandon its work as soon as it gets to it. func ExampleWithDeadline() { - d := time.Now().Add(50 * time.Millisecond) + d := time.Now().Add(shortDuration) ctx, cancel := context.WithDeadline(context.Background(), d) // Even though ctx will be expired, it is good practice to call its @@ -79,7 +81,7 @@ func ExampleWithDeadline() { func ExampleWithTimeout() { // Pass a context with a timeout to tell a blocking function that it // should abandon its work after the timeout elapses. - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) + ctx, cancel := context.WithTimeout(context.Background(), shortDuration) defer cancel() select { diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go index 37790acb98..499242ffc5 100644 --- a/src/crypto/rsa/pkcs1v15.go +++ b/src/crypto/rsa/pkcs1v15.go @@ -277,6 +277,13 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) return ErrVerification } + // RFC 8017 Section 8.2.2: If the length of the signature S is not k + // octets (where k is the length in octets of the RSA modulus n), output + // "invalid signature" and stop. + if k != len(sig) { + return ErrVerification + } + c := new(big.Int).SetBytes(sig) m := encrypt(new(big.Int), pub, c) em := leftPad(m.Bytes(), k) diff --git a/src/crypto/rsa/pkcs1v15_test.go b/src/crypto/rsa/pkcs1v15_test.go index 7e62560a04..26b8c5f26f 100644 --- a/src/crypto/rsa/pkcs1v15_test.go +++ b/src/crypto/rsa/pkcs1v15_test.go @@ -9,6 +9,7 @@ import ( "crypto" "crypto/rand" "crypto/sha1" + "crypto/sha256" "encoding/base64" "encoding/hex" "io" @@ -296,3 +297,20 @@ var rsaPrivateKey = &PrivateKey{ fromBase10("94560208308847015747498523884063394671606671904944666360068158221458669711639"), }, } + +func TestShortPKCS1v15Signature(t *testing.T) { + pub := &PublicKey{ + E: 65537, + N: fromBase10("8272693557323587081220342447407965471608219912416565371060697606400726784709760494166080686904546560026343451112103559482851304715739629410219358933351333"), + } + sig, err := hex.DecodeString("193a310d0dcf64094c6e3a00c8219b80ded70535473acff72c08e1222974bb24a93a535b1dc4c59fc0e65775df7ba2007dd20e9193f4c4025a18a7070aee93") + if err != nil { + t.Fatalf("failed to decode signature: %s", err) + } + + h := sha256.Sum256([]byte("hello")) + err = VerifyPKCS1v15(pub, crypto.SHA256, h[:], sig) + if err == nil { + t.Fatal("VerifyPKCS1v15 accepted a truncated signature") + } +} diff --git a/src/crypto/tls/alert.go b/src/crypto/tls/alert.go index 22b3eca92f..4790b73724 100644 --- a/src/crypto/tls/alert.go +++ b/src/crypto/tls/alert.go @@ -15,63 +15,75 @@ const ( ) const ( - alertCloseNotify alert = 0 - alertUnexpectedMessage alert = 10 - alertBadRecordMAC alert = 20 - alertDecryptionFailed alert = 21 - alertRecordOverflow alert = 22 - alertDecompressionFailure alert = 30 - alertHandshakeFailure alert = 40 - alertBadCertificate alert = 42 - alertUnsupportedCertificate alert = 43 - alertCertificateRevoked alert = 44 - alertCertificateExpired alert = 45 - alertCertificateUnknown alert = 46 - alertIllegalParameter alert = 47 - alertUnknownCA alert = 48 - alertAccessDenied alert = 49 - alertDecodeError alert = 50 - alertDecryptError alert = 51 - alertProtocolVersion alert = 70 - alertInsufficientSecurity alert = 71 - alertInternalError alert = 80 - alertInappropriateFallback alert = 86 - alertUserCanceled alert = 90 - alertNoRenegotiation alert = 100 - alertMissingExtension alert = 109 - alertUnsupportedExtension alert = 110 - alertUnrecognizedName alert = 112 - alertNoApplicationProtocol alert = 120 + alertCloseNotify alert = 0 + alertUnexpectedMessage alert = 10 + alertBadRecordMAC alert = 20 + alertDecryptionFailed alert = 21 + alertRecordOverflow alert = 22 + alertDecompressionFailure alert = 30 + alertHandshakeFailure alert = 40 + alertBadCertificate alert = 42 + alertUnsupportedCertificate alert = 43 + alertCertificateRevoked alert = 44 + alertCertificateExpired alert = 45 + alertCertificateUnknown alert = 46 + alertIllegalParameter alert = 47 + alertUnknownCA alert = 48 + alertAccessDenied alert = 49 + alertDecodeError alert = 50 + alertDecryptError alert = 51 + alertExportRestriction alert = 60 + alertProtocolVersion alert = 70 + alertInsufficientSecurity alert = 71 + alertInternalError alert = 80 + alertInappropriateFallback alert = 86 + alertUserCanceled alert = 90 + alertNoRenegotiation alert = 100 + alertMissingExtension alert = 109 + alertUnsupportedExtension alert = 110 + alertCertificateUnobtainable alert = 111 + alertUnrecognizedName alert = 112 + alertBadCertificateStatusResponse alert = 113 + alertBadCertificateHashValue alert = 114 + alertUnknownPSKIdentity alert = 115 + alertCertificateRequired alert = 116 + alertNoApplicationProtocol alert = 120 ) var alertText = map[alert]string{ - alertCloseNotify: "close notify", - alertUnexpectedMessage: "unexpected message", - alertBadRecordMAC: "bad record MAC", - alertDecryptionFailed: "decryption failed", - alertRecordOverflow: "record overflow", - alertDecompressionFailure: "decompression failure", - alertHandshakeFailure: "handshake failure", - alertBadCertificate: "bad certificate", - alertUnsupportedCertificate: "unsupported certificate", - alertCertificateRevoked: "revoked certificate", - alertCertificateExpired: "expired certificate", - alertCertificateUnknown: "unknown certificate", - alertIllegalParameter: "illegal parameter", - alertUnknownCA: "unknown certificate authority", - alertAccessDenied: "access denied", - alertDecodeError: "error decoding message", - alertDecryptError: "error decrypting message", - alertProtocolVersion: "protocol version not supported", - alertInsufficientSecurity: "insufficient security level", - alertInternalError: "internal error", - alertInappropriateFallback: "inappropriate fallback", - alertUserCanceled: "user canceled", - alertNoRenegotiation: "no renegotiation", - alertMissingExtension: "missing extension", - alertUnsupportedExtension: "unsupported extension", - alertUnrecognizedName: "unrecognized name", - alertNoApplicationProtocol: "no application protocol", + alertCloseNotify: "close notify", + alertUnexpectedMessage: "unexpected message", + alertBadRecordMAC: "bad record MAC", + alertDecryptionFailed: "decryption failed", + alertRecordOverflow: "record overflow", + alertDecompressionFailure: "decompression failure", + alertHandshakeFailure: "handshake failure", + alertBadCertificate: "bad certificate", + alertUnsupportedCertificate: "unsupported certificate", + alertCertificateRevoked: "revoked certificate", + alertCertificateExpired: "expired certificate", + alertCertificateUnknown: "unknown certificate", + alertIllegalParameter: "illegal parameter", + alertUnknownCA: "unknown certificate authority", + alertAccessDenied: "access denied", + alertDecodeError: "error decoding message", + alertDecryptError: "error decrypting message", + alertExportRestriction: "export restriction", + alertProtocolVersion: "protocol version not supported", + alertInsufficientSecurity: "insufficient security level", + alertInternalError: "internal error", + alertInappropriateFallback: "inappropriate fallback", + alertUserCanceled: "user canceled", + alertNoRenegotiation: "no renegotiation", + alertMissingExtension: "missing extension", + alertUnsupportedExtension: "unsupported extension", + alertCertificateUnobtainable: "certificate unobtainable", + alertUnrecognizedName: "unrecognized name", + alertBadCertificateStatusResponse: "bad certificate status response", + alertBadCertificateHashValue: "bad certificate hash value", + alertUnknownPSKIdentity: "unknown PSK identity", + alertCertificateRequired: "certificate required", + alertNoApplicationProtocol: "no application protocol", } func (e alert) String() string { diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index 0c6747d28d..c2f110e87b 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -1806,7 +1806,7 @@ func TestMD5(t *testing.T) { } } -// certMissingRSANULL contains an RSA public key where the AlgorithmIdentifer +// certMissingRSANULL contains an RSA public key where the AlgorithmIdentifier // parameters are omitted rather than being an ASN.1 NULL. const certMissingRSANULL = ` -----BEGIN CERTIFICATE----- diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go index a2b844d71f..76f1bd3aa1 100644 --- a/src/database/sql/driver/driver.go +++ b/src/database/sql/driver/driver.go @@ -261,15 +261,15 @@ type SessionResetter interface { ResetSession(ctx context.Context) error } -// ConnectionValidator may be implemented by Conn to allow drivers to +// Validator may be implemented by Conn to allow drivers to // signal if a connection is valid or if it should be discarded. // // If implemented, drivers may return the underlying error from queries, // even if the connection should be discarded by the connection pool. -type ConnectionValidator interface { - // ValidConnection is called prior to placing the connection into the +type Validator interface { + // IsValid is called prior to placing the connection into the // connection pool. The connection will be discarded if false is returned. - ValidConnection() bool + IsValid() bool } // Result is the result of a query execution. diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go index 73dab101b7..b6e9a5707e 100644 --- a/src/database/sql/fakedb_test.go +++ b/src/database/sql/fakedb_test.go @@ -396,9 +396,9 @@ func (c *fakeConn) ResetSession(ctx context.Context) error { return nil } -var _ driver.ConnectionValidator = (*fakeConn)(nil) +var _ driver.Validator = (*fakeConn)(nil) -func (c *fakeConn) ValidConnection() bool { +func (c *fakeConn) IsValid() bool { return !c.isBad() } diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 95906b1318..4093ffe1bb 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -512,8 +512,8 @@ func (dc *driverConn) validateConnection(needsReset bool) bool { if needsReset { dc.needReset = true } - if cv, ok := dc.ci.(driver.ConnectionValidator); ok { - return cv.ValidConnection() + if cv, ok := dc.ci.(driver.Validator); ok { + return cv.IsValid() } return true } diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index 0fc994d0a1..f08eba93b3 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -1543,6 +1543,37 @@ func TestConnTx(t *testing.T) { } } +// TestConnIsValid verifies that a database connection that should be discarded, +// is actually discarded and does not re-enter the connection pool. +// If the IsValid method from *fakeConn is removed, this test will fail. +func TestConnIsValid(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + + db.SetMaxOpenConns(1) + + ctx := context.Background() + + c, err := db.Conn(ctx) + if err != nil { + t.Fatal(err) + } + + err = c.Raw(func(raw interface{}) error { + dc := raw.(*fakeConn) + dc.stickyBad = true + return nil + }) + if err != nil { + t.Fatal(err) + } + c.Close() + + if len(db.freeConn) > 0 && db.freeConn[0].ci.(*fakeConn).stickyBad { + t.Fatal("bad connection returned to pool; expected bad connection to be discarded") + } +} + // Tests fix for issue 2542, that we release a lock when querying on // a closed connection. func TestIssue2542Deadlock(t *testing.T) { diff --git a/src/go/internal/gccgoimporter/parser.go b/src/go/internal/gccgoimporter/parser.go index 9204b004f9..e2ef33f7ae 100644 --- a/src/go/internal/gccgoimporter/parser.go +++ b/src/go/internal/gccgoimporter/parser.go @@ -326,7 +326,7 @@ func (p *parser) parseConstValue(pkg *types.Package) (val constant.Value, typ ty if p.tok == '$' { p.next() if p.tok != scanner.Ident { - p.errorf("expected identifer after '$', got %s (%q)", scanner.TokenString(p.tok), p.lit) + p.errorf("expected identifier after '$', got %s (%q)", scanner.TokenString(p.tok), p.lit) } } diff --git a/src/internal/poll/fd_poll_runtime.go b/src/internal/poll/fd_poll_runtime.go index d32f4a0ddd..fd73166ac3 100644 --- a/src/internal/poll/fd_poll_runtime.go +++ b/src/internal/poll/fd_poll_runtime.go @@ -107,15 +107,24 @@ func (pd *pollDesc) pollable() bool { return pd.runtimeCtx != 0 } +// Error values returned by runtime_pollReset and runtime_pollWait. +// These must match the values in runtime/netpoll.go. +const ( + pollNoError = 0 + pollErrClosing = 1 + pollErrTimeout = 2 + pollErrNotPollable = 3 +) + func convertErr(res int, isFile bool) error { switch res { - case 0: + case pollNoError: return nil - case 1: + case pollErrClosing: return errClosing(isFile) - case 2: + case pollErrTimeout: return ErrTimeout - case 3: + case pollErrNotPollable: return ErrNotPollable } println("unreachable: ", res) diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go index 4b2623ea8f..1a0bdb34fe 100644 --- a/src/internal/poll/fd_windows.go +++ b/src/internal/poll/fd_windows.go @@ -999,7 +999,7 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er o := &fd.rop o.InitMsg(p, oob) o.rsa = new(syscall.RawSockaddrAny) - o.msg.Name = o.rsa + o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa)) n, err := execIO(o, func(o *operation) error { return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil) @@ -1030,7 +1030,7 @@ func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, err if err != nil { return 0, 0, err } - o.msg.Name = (*syscall.RawSockaddrAny)(rsa) + o.msg.Name = (syscall.Pointer)(rsa) o.msg.Namelen = len } n, err := execIO(o, func(o *operation) error { diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go index dc641116ba..f299adc45f 100644 --- a/src/internal/syscall/windows/syscall_windows.go +++ b/src/internal/syscall/windows/syscall_windows.go @@ -176,7 +176,7 @@ var sendRecvMsgFunc struct { } type WSAMsg struct { - Name *syscall.RawSockaddrAny + Name syscall.Pointer Namelen int32 Buffers *syscall.WSABuf BufferCount uint32 diff --git a/src/net/http/client.go b/src/net/http/client.go index 638ff500a4..3860d97d8f 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -269,7 +269,20 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, d return nil, didTimeout, fmt.Errorf("http: RoundTripper implementation (%T) returned a nil *Response with a nil error", rt) } if resp.Body == nil { - return nil, didTimeout, fmt.Errorf("http: RoundTripper implementation (%T) returned a *Response with a nil Body", rt) + // The documentation on the Body field says “The http Client and Transport + // guarantee that Body is always non-nil, even on responses without a body + // or responses with a zero-length body.” Unfortunately, we didn't document + // that same constraint for arbitrary RoundTripper implementations, and + // RoundTripper implementations in the wild (mostly in tests) assume that + // they can use a nil Body to mean an empty one (similar to Request.Body). + // (See https://golang.org/issue/38095.) + // + // If the ContentLength allows the Body to be empty, fill in an empty one + // here to ensure that it is non-nil. + if resp.ContentLength > 0 && req.Method != "HEAD" { + return nil, didTimeout, fmt.Errorf("http: RoundTripper implementation (%T) returned a *Response with content length %d but a nil Body", rt, resp.ContentLength) + } + resp.Body = ioutil.NopCloser(strings.NewReader("")) } if !deadline.IsZero() { resp.Body = &cancelTimerBody{ diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go index 2b4f53f802..80807fae7a 100644 --- a/src/net/http/client_test.go +++ b/src/net/http/client_test.go @@ -1991,3 +1991,38 @@ func testClientDoCanceledVsTimeout(t *testing.T, h2 bool) { }) } } + +type nilBodyRoundTripper struct{} + +func (nilBodyRoundTripper) RoundTrip(req *Request) (*Response, error) { + return &Response{ + StatusCode: StatusOK, + Status: StatusText(StatusOK), + Body: nil, + Request: req, + }, nil +} + +func TestClientPopulatesNilResponseBody(t *testing.T) { + c := &Client{Transport: nilBodyRoundTripper{}} + + resp, err := c.Get("http://localhost/anything") + if err != nil { + t.Fatalf("Client.Get rejected Response with nil Body: %v", err) + } + + if resp.Body == nil { + t.Fatalf("Client failed to provide a non-nil Body as documented") + } + defer func() { + if err := resp.Body.Close(); err != nil { + t.Fatalf("error from Close on substitute Response.Body: %v", err) + } + }() + + if b, err := ioutil.ReadAll(resp.Body); err != nil { + t.Errorf("read error from substitute Response.Body: %v", err) + } else if len(b) != 0 { + t.Errorf("substitute Response.Body was unexpectedly non-empty: %q", b) + } +} diff --git a/src/net/http/roundtrip_js.go b/src/net/http/roundtrip_js.go index 4dd99651a7..e14f3f7152 100644 --- a/src/net/http/roundtrip_js.go +++ b/src/net/http/roundtrip_js.go @@ -157,7 +157,7 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { }) defer success.Release() failure := js.FuncOf(func(this js.Value, args []js.Value) interface{} { - err := fmt.Errorf("net/http: fetch() failed: %s", args[0].String()) + err := fmt.Errorf("net/http: fetch() failed: %s", args[0].Get("message").String()) select { case errCh <- err: case <-req.Context().Done(): diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index 21ee7f33c8..9488821466 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -1057,16 +1057,13 @@ func TestIdentityResponse(t *testing.T) { t.Fatalf("error writing: %v", err) } - // The ReadAll will hang for a failing test, so use a Timer to - // fail explicitly. - goTimeout(t, 2*time.Second, func() { - got, _ := ioutil.ReadAll(conn) - expectedSuffix := "\r\n\r\ntoo short" - if !strings.HasSuffix(string(got), expectedSuffix) { - t.Errorf("Expected output to end with %q; got response body %q", - expectedSuffix, string(got)) - } - }) + // The ReadAll will hang for a failing test. + got, _ := ioutil.ReadAll(conn) + expectedSuffix := "\r\n\r\ntoo short" + if !strings.HasSuffix(string(got), expectedSuffix) { + t.Errorf("Expected output to end with %q; got response body %q", + expectedSuffix, string(got)) + } } func testTCPConnectionCloses(t *testing.T, req string, h Handler) { @@ -1438,13 +1435,13 @@ func TestTLSHandshakeTimeout(t *testing.T) { t.Fatalf("Dial: %v", err) } defer conn.Close() - goTimeout(t, 10*time.Second, func() { - var buf [1]byte - n, err := conn.Read(buf[:]) - if err == nil || n != 0 { - t.Errorf("Read = %d, %v; want an error and no bytes", n, err) - } - }) + + var buf [1]byte + n, err := conn.Read(buf[:]) + if err == nil || n != 0 { + t.Errorf("Read = %d, %v; want an error and no bytes", n, err) + } + select { case v := <-errc: if !strings.Contains(v, "timeout") && !strings.Contains(v, "TLS handshake") { @@ -1479,30 +1476,29 @@ func TestTLSServer(t *testing.T) { t.Fatalf("Dial: %v", err) } defer idleConn.Close() - goTimeout(t, 10*time.Second, func() { - if !strings.HasPrefix(ts.URL, "https://") { - t.Errorf("expected test TLS server to start with https://, got %q", ts.URL) - return - } - client := ts.Client() - res, err := client.Get(ts.URL) - if err != nil { - t.Error(err) - return - } - if res == nil { - t.Errorf("got nil Response") - return - } - defer res.Body.Close() - if res.Header.Get("X-TLS-Set") != "true" { - t.Errorf("expected X-TLS-Set response header") - return - } - if res.Header.Get("X-TLS-HandshakeComplete") != "true" { - t.Errorf("expected X-TLS-HandshakeComplete header") - } - }) + + if !strings.HasPrefix(ts.URL, "https://") { + t.Errorf("expected test TLS server to start with https://, got %q", ts.URL) + return + } + client := ts.Client() + res, err := client.Get(ts.URL) + if err != nil { + t.Error(err) + return + } + if res == nil { + t.Errorf("got nil Response") + return + } + defer res.Body.Close() + if res.Header.Get("X-TLS-Set") != "true" { + t.Errorf("expected X-TLS-Set response header") + return + } + if res.Header.Get("X-TLS-HandshakeComplete") != "true" { + t.Errorf("expected X-TLS-HandshakeComplete header") + } } func TestServeTLS(t *testing.T) { @@ -3629,21 +3625,6 @@ func TestHeaderToWire(t *testing.T) { } } -// goTimeout runs f, failing t if f takes more than ns to complete. -func goTimeout(t *testing.T, d time.Duration, f func()) { - ch := make(chan bool, 2) - timer := time.AfterFunc(d, func() { - t.Errorf("Timeout expired after %v", d) - ch <- true - }) - defer timer.Stop() - go func() { - defer func() { ch <- true }() - f() - }() - <-ch -} - type errorListener struct { errs []error } diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index 91dd0a41ac..9d6069093e 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -79,6 +79,13 @@ func helperCommandContext(t *testing.T, ctx context.Context, s ...string) (cmd * } else { cmd = exec.Command(os.Args[0], cs...) } + + // Temporary code to try to resolve #25628. + // TODO(iant): Remove this when we no longer need it. + if runtime.GOARCH == "386" && runtime.GOOS == "linux" && testenv.Builder() != "" && len(s) == 1 && s[0] == "read3" && ctx == nil { + cmd = exec.Command("/usr/bin/strace", append([]string{"-f", os.Args[0]}, cs...)...) + } + cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") return cmd } diff --git a/src/os/signal/signal.go b/src/os/signal/signal.go index 136dd9cc97..8e31aa2627 100644 --- a/src/os/signal/signal.go +++ b/src/os/signal/signal.go @@ -122,12 +122,6 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) { panic("os/signal: Notify using nil channel") } - watchSignalLoopOnce.Do(func() { - if watchSignalLoop != nil { - go watchSignalLoop() - } - }) - handlers.Lock() defer handlers.Unlock() @@ -148,6 +142,14 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) { h.set(n) if handlers.ref[n] == 0 { enableSignal(n) + + // The runtime requires that we enable a + // signal before starting the watcher. + watchSignalLoopOnce.Do(func() { + if watchSignalLoop != nil { + go watchSignalLoop() + } + }) } handlers.ref[n]++ } diff --git a/src/os/signal/signal_plan9.go b/src/os/signal/signal_plan9.go index 8408607c7f..7d4871518a 100644 --- a/src/os/signal/signal_plan9.go +++ b/src/os/signal/signal_plan9.go @@ -11,7 +11,7 @@ import ( var sigtab = make(map[os.Signal]int) -// In sig.s; jumps to runtime. +// Defined by the runtime package. func signal_disable(uint32) func signal_enable(uint32) func signal_ignore(uint32) @@ -19,8 +19,6 @@ func signal_ignored(uint32) bool func signal_recv() string func init() { - signal_enable(0) // first call - initialize - watchSignalLoop = loop } diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go index a4489ffd3e..e5dcda4a2b 100644 --- a/src/os/signal/signal_test.go +++ b/src/os/signal/signal_test.go @@ -22,21 +22,10 @@ import ( "time" ) -var testDeadline time.Time - -func TestMain(m *testing.M) { - flag.Parse() - - // TODO(golang.org/issue/28135): Remove this setup and use t.Deadline instead. - timeoutFlag := flag.Lookup("test.timeout") - if timeoutFlag != nil { - if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 { - testDeadline = time.Now().Add(d) - } - } - - os.Exit(m.Run()) -} +// settleTime is an upper bound on how long we expect signals to take to be +// delivered. Lower values make the test faster, but also flakier — especially +// on heavily loaded systems. +const settleTime = 100 * time.Millisecond func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) { waitSig1(t, c, sig, false) @@ -48,27 +37,45 @@ func waitSigAll(t *testing.T, c <-chan os.Signal, sig os.Signal) { func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) { // Sleep multiple times to give the kernel more tries to // deliver the signal. - for i := 0; i < 10; i++ { + start := time.Now() + timer := time.NewTimer(settleTime / 10) + defer timer.Stop() + // If the caller notified for all signals on c, filter out SIGURG, + // which is used for runtime preemption and can come at unpredictable times. + // General user code should filter out all unexpected signals instead of just + // SIGURG, but since os/signal is tightly coupled to the runtime it seems + // appropriate to be stricter here. + for time.Since(start) < settleTime { select { case s := <-c: - // If the caller notified for all signals on - // c, filter out SIGURG, which is used for - // runtime preemption and can come at - // unpredictable times. - if all && s == syscall.SIGURG { - continue + if s == sig { + return } - if s != sig { + if !all || s != syscall.SIGURG { t.Fatalf("signal was %v, want %v", s, sig) } - return - - case <-time.After(100 * time.Millisecond): + case <-timer.C: + timer.Reset(settleTime / 10) } } t.Fatalf("timeout waiting for %v", sig) } +// quiesce waits until we can be reasonably confident that all pending signals +// have been delivered by the OS. +func quiesce() { + // The kernel will deliver a signal as a thread returns + // from a syscall. If the only active thread is sleeping, + // and the system is busy, the kernel may not get around + // to waking up a thread to catch the signal. + // We try splitting up the sleep to give the kernel + // many chances to deliver the signal. + start := time.Now() + for time.Since(start) < settleTime { + time.Sleep(settleTime / 10) + } +} + // Test that basic signal handling works. func TestSignal(t *testing.T) { // Ask for SIGHUP @@ -112,50 +119,39 @@ func TestStress(t *testing.T) { dur = 100 * time.Millisecond } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) - done := make(chan bool) - finished := make(chan bool) - go func() { - sig := make(chan os.Signal, 1) - Notify(sig, syscall.SIGUSR1) - defer Stop(sig) - Loop: - for { - select { - case <-sig: - case <-done: - break Loop - } - } - finished <- true - }() + + sig := make(chan os.Signal, 1) + Notify(sig, syscall.SIGUSR1) + go func() { - Loop: + stop := time.After(dur) for { select { - case <-done: - break Loop + case <-stop: + // Allow enough time for all signals to be delivered before we stop + // listening for them. + quiesce() + Stop(sig) + // According to its documentation, “[w]hen Stop returns, it in + // guaranteed that c will receive no more signals.” So we can safely + // close sig here: if there is a send-after-close race here, that is a + // bug in Stop and we would like to detect it. + close(sig) + return + default: syscall.Kill(syscall.Getpid(), syscall.SIGUSR1) runtime.Gosched() } } - finished <- true }() - time.Sleep(dur) - close(done) - <-finished - <-finished - // When run with 'go test -cpu=1,2,4' SIGUSR1 from this test can slip - // into subsequent TestSignal() causing failure. - // Sleep for a while to reduce the possibility of the failure. - time.Sleep(10 * time.Millisecond) + + for range sig { + // Receive signals until the sender closes sig. + } } func testCancel(t *testing.T, ignore bool) { - // Send SIGWINCH. By default this signal should be ignored. - syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) - time.Sleep(100 * time.Millisecond) - // Ask to be notified on c1 when a SIGWINCH is received. c1 := make(chan os.Signal, 1) Notify(c1, syscall.SIGWINCH) @@ -175,25 +171,16 @@ func testCancel(t *testing.T, ignore bool) { waitSig(t, c2, syscall.SIGHUP) // Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP. + // Either way, this should undo both calls to Notify above. if ignore { Ignore(syscall.SIGWINCH, syscall.SIGHUP) + // Don't bother deferring a call to Reset: it is documented to undo Notify, + // but its documentation says nothing about Ignore, and (as of the time of + // writing) it empirically does not undo an Ignore. } else { Reset(syscall.SIGWINCH, syscall.SIGHUP) } - // At this point we do not expect any further signals on c1. - // However, it is just barely possible that the initial SIGWINCH - // at the start of this function was delivered after we called - // Notify on c1. In that case the waitSig for SIGWINCH may have - // picked up that initial SIGWINCH, and the second SIGWINCH may - // then have been delivered on the channel. This sequence of events - // may have caused issue 15661. - // So, read any possible signal from the channel now. - select { - case <-c1: - default: - } - // Send this process a SIGWINCH. It should be ignored. syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) @@ -202,22 +189,28 @@ func testCancel(t *testing.T, ignore bool) { syscall.Kill(syscall.Getpid(), syscall.SIGHUP) } + quiesce() + select { case s := <-c1: - t.Fatalf("unexpected signal %v", s) - case <-time.After(100 * time.Millisecond): + t.Errorf("unexpected signal %v", s) + default: // nothing to read - good } select { case s := <-c2: - t.Fatalf("unexpected signal %v", s) - case <-time.After(100 * time.Millisecond): + t.Errorf("unexpected signal %v", s) + default: // nothing to read - good } - // Reset the signal handlers for all signals. - Reset() + // One or both of the signals may have been blocked for this process + // by the calling process. + // Discard any queued signals now to avoid interfering with other tests. + Notify(c1, syscall.SIGWINCH) + Notify(c2, syscall.SIGHUP) + quiesce() } // Test that Reset cancels registration for listed signals on all channels. @@ -289,7 +282,10 @@ func TestDetectNohup(t *testing.T) { } } -var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop") +var ( + sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop") + dieFromSighup = flag.Bool("die_from_sighup", false, "wait to die from uncaught SIGHUP") +) // Test that Stop cancels the channel's registrations. func TestStop(t *testing.T) { @@ -300,59 +296,74 @@ func TestStop(t *testing.T) { } for _, sig := range sigs { - // Send the signal. - // If it's SIGWINCH, we should not see it. - // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. - if sig == syscall.SIGWINCH || (sig == syscall.SIGHUP && *sendUncaughtSighup == 1) { - syscall.Kill(syscall.Getpid(), sig) - } - - // The kernel will deliver a signal as a thread returns - // from a syscall. If the only active thread is sleeping, - // and the system is busy, the kernel may not get around - // to waking up a thread to catch the signal. - // We try splitting up the sleep to give the kernel - // another chance to deliver the signal. - time.Sleep(50 * time.Millisecond) - time.Sleep(50 * time.Millisecond) - - // Ask for signal - c := make(chan os.Signal, 1) - Notify(c, sig) - defer Stop(c) + sig := sig + t.Run(fmt.Sprint(sig), func(t *testing.T) { + // When calling Notify with a specific signal, + // independent signals should not interfere with each other, + // and we end up needing to wait for signals to quiesce a lot. + // Test the three different signals concurrently. + t.Parallel() + + // If the signal is not ignored, send the signal before registering a + // channel to verify the behavior of the default Go handler. + // If it's SIGWINCH or SIGUSR1 we should not see it. + // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. + mayHaveBlockedSignal := false + if !Ignored(sig) && (sig != syscall.SIGHUP || *sendUncaughtSighup == 1) { + syscall.Kill(syscall.Getpid(), sig) + quiesce() + + // We don't know whether sig is blocked for this process; see + // https://golang.org/issue/38165. Assume that it could be. + mayHaveBlockedSignal = true + } - // Send this process that signal - syscall.Kill(syscall.Getpid(), sig) - waitSig(t, c, sig) + // Ask for signal + c := make(chan os.Signal, 1) + Notify(c, sig) - Stop(c) - time.Sleep(50 * time.Millisecond) - select { - case s := <-c: - t.Fatalf("unexpected signal %v", s) - case <-time.After(50 * time.Millisecond): - // nothing to read - good - } - - // Send the signal. - // If it's SIGWINCH, we should not see it. - // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. - if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 { + // Send this process the signal again. syscall.Kill(syscall.Getpid(), sig) - } + waitSig(t, c, sig) + + if mayHaveBlockedSignal { + // We may have received a queued initial signal in addition to the one + // that we sent after Notify. If so, waitSig may have observed that + // initial signal instead of the second one, and we may need to wait for + // the second signal to clear. Do that now. + quiesce() + select { + case <-c: + default: + } + } - time.Sleep(50 * time.Millisecond) - select { - case s := <-c: - t.Fatalf("unexpected signal %v", s) - case <-time.After(50 * time.Millisecond): - // nothing to read - good - } + // Stop watching for the signal and send it again. + // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. + Stop(c) + if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 { + syscall.Kill(syscall.Getpid(), sig) + quiesce() + + select { + case s := <-c: + t.Errorf("unexpected signal %v", s) + default: + // nothing to read - good + } + + // If we're going to receive a signal, it has almost certainly been + // received by now. However, it may have been blocked for this process — + // we don't know. Explicitly unblock it and wait for it to clear now. + Notify(c, sig) + quiesce() + Stop(c) + } + }) } } -// Test that when run under nohup, an uncaught SIGHUP does not kill the program, -// but a +// Test that when run under nohup, an uncaught SIGHUP does not kill the program. func TestNohup(t *testing.T) { // Ugly: ask for SIGHUP so that child will not have no-hup set // even if test is running under nohup environment. @@ -371,12 +382,38 @@ func TestNohup(t *testing.T) { // // Both should fail without nohup and succeed with nohup. + var subTimeout time.Duration + + var wg sync.WaitGroup + wg.Add(2) + if deadline, ok := t.Deadline(); ok { + subTimeout = time.Until(deadline) + subTimeout -= subTimeout / 10 // Leave 10% headroom for propagating output. + } for i := 1; i <= 2; i++ { - out, err := exec.Command(os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput() - if err == nil { - t.Fatalf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out) - } + i := i + go t.Run(fmt.Sprintf("uncaught-%d", i), func(t *testing.T) { + defer wg.Done() + + args := []string{ + "-test.v", + "-test.run=TestStop", + "-send_uncaught_sighup=" + strconv.Itoa(i), + "-die_from_sighup", + } + if subTimeout != 0 { + args = append(args, fmt.Sprintf("-test.timeout=%v", subTimeout)) + } + out, err := exec.Command(os.Args[0], args...).CombinedOutput() + + if err == nil { + t.Errorf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out) + } else { + t.Logf("test with -send_uncaught_sighup=%d failed as expected.\nError: %v\nOutput:\n%s", i, err, out) + } + }) } + wg.Wait() Stop(c) @@ -387,21 +424,46 @@ func TestNohup(t *testing.T) { } // Again, this time with nohup, assuming we can find it. - _, err := os.Stat("/usr/bin/nohup") + _, err := exec.LookPath("nohup") if err != nil { t.Skip("cannot find nohup; skipping second half of test") } + wg.Add(2) + if deadline, ok := t.Deadline(); ok { + subTimeout = time.Until(deadline) + subTimeout -= subTimeout / 10 // Leave 10% headroom for propagating output. + } for i := 1; i <= 2; i++ { - os.Remove("nohup.out") - out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput() + i := i + go t.Run(fmt.Sprintf("nohup-%d", i), func(t *testing.T) { + defer wg.Done() - data, _ := ioutil.ReadFile("nohup.out") - os.Remove("nohup.out") - if err != nil { - t.Fatalf("ran test with -send_uncaught_sighup=%d under nohup and it failed: expected success.\nError: %v\nOutput:\n%s%s", i, err, out, data) - } + // POSIX specifies that nohup writes to a file named nohup.out if standard + // output is a terminal. However, for an exec.Command, standard output is + // not a terminal — so we don't need to read or remove that file (and, + // indeed, cannot even create it if the current user is unable to write to + // GOROOT/src, such as when GOROOT is installed and owned by root). + + args := []string{ + os.Args[0], + "-test.v", + "-test.run=TestStop", + "-send_uncaught_sighup=" + strconv.Itoa(i), + } + if subTimeout != 0 { + args = append(args, fmt.Sprintf("-test.timeout=%v", subTimeout)) + } + out, err := exec.Command("nohup", args...).CombinedOutput() + + if err != nil { + t.Errorf("ran test with -send_uncaught_sighup=%d under nohup and it failed: expected success.\nError: %v\nOutput:\n%s", i, err, out) + } else { + t.Logf("ran test with -send_uncaught_sighup=%d under nohup.\nOutput:\n%s", i, out) + } + }) } + wg.Wait() } // Test that SIGCONT works (issue 8953). @@ -416,7 +478,7 @@ func TestSIGCONT(t *testing.T) { // Test race between stopping and receiving a signal (issue 14571). func TestAtomicStop(t *testing.T) { if os.Getenv("GO_TEST_ATOMIC_STOP") != "" { - atomicStopTestProgram() + atomicStopTestProgram(t) t.Fatal("atomicStopTestProgram returned") } @@ -438,8 +500,8 @@ func TestAtomicStop(t *testing.T) { const execs = 10 for i := 0; i < execs; i++ { timeout := "0" - if !testDeadline.IsZero() { - timeout = testDeadline.Sub(time.Now()).String() + if deadline, ok := t.Deadline(); ok { + timeout = time.Until(deadline).String() } cmd := exec.Command(os.Args[0], "-test.run=TestAtomicStop", "-test.timeout="+timeout) cmd.Env = append(os.Environ(), "GO_TEST_ATOMIC_STOP=1") @@ -478,7 +540,7 @@ func TestAtomicStop(t *testing.T) { // atomicStopTestProgram is run in a subprocess by TestAtomicStop. // It tries to trigger a signal delivery race. This function should // either catch a signal or die from it. -func atomicStopTestProgram() { +func atomicStopTestProgram(t *testing.T) { // This test won't work if SIGINT is ignored here. if Ignored(syscall.SIGINT) { fmt.Println("SIGINT is ignored") @@ -488,10 +550,10 @@ func atomicStopTestProgram() { const tries = 10 timeout := 2 * time.Second - if !testDeadline.IsZero() { + if deadline, ok := t.Deadline(); ok { // Give each try an equal slice of the deadline, with one slice to spare for // cleanup. - timeout = testDeadline.Sub(time.Now()) / (tries + 1) + timeout = time.Until(deadline) / (tries + 1) } pid := syscall.Getpid() @@ -541,43 +603,45 @@ func TestTime(t *testing.T) { dur = 100 * time.Millisecond } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) - done := make(chan bool) - finished := make(chan bool) - go func() { - sig := make(chan os.Signal, 1) - Notify(sig, syscall.SIGUSR1) - defer Stop(sig) - Loop: - for { - select { - case <-sig: - case <-done: - break Loop - } - } - finished <- true - }() + + sig := make(chan os.Signal, 1) + Notify(sig, syscall.SIGUSR1) + + stop := make(chan struct{}) go func() { - Loop: for { select { - case <-done: - break Loop + case <-stop: + // Allow enough time for all signals to be delivered before we stop + // listening for them. + quiesce() + Stop(sig) + // According to its documentation, “[w]hen Stop returns, it in + // guaranteed that c will receive no more signals.” So we can safely + // close sig here: if there is a send-after-close race, that is a bug in + // Stop and we would like to detect it. + close(sig) + return + default: syscall.Kill(syscall.Getpid(), syscall.SIGUSR1) runtime.Gosched() } } - finished <- true }() + + done := make(chan struct{}) + go func() { + for range sig { + // Receive signals until the sender closes sig. + } + close(done) + }() + t0 := time.Now() for t1 := t0; t1.Sub(t0) < dur; t1 = time.Now() { } // hammering on getting time - close(done) - <-finished - <-finished - // When run with 'go test -cpu=1,2,4' SIGUSR1 from this test can slip - // into subsequent TestSignal() causing failure. - // Sleep for a while to reduce the possibility of the failure. - time.Sleep(10 * time.Millisecond) + + close(stop) + <-done } diff --git a/src/os/signal/signal_unix.go b/src/os/signal/signal_unix.go index 89ee2d9e18..90a1eca156 100644 --- a/src/os/signal/signal_unix.go +++ b/src/os/signal/signal_unix.go @@ -25,8 +25,6 @@ func loop() { } func init() { - signal_enable(0) // first call - initialize - watchSignalLoop = loop } diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 00c18104eb..66d9661aeb 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4163,6 +4163,37 @@ func TestConvert(t *testing.T) { } } +var gFloat32 float32 + +func TestConvertNaNs(t *testing.T) { + const snan uint32 = 0x7f800001 + + // Test to see if a store followed by a load of a signaling NaN + // maintains the signaling bit. The only platform known to fail + // this test is 386,GO386=387. The real test below will always fail + // if the platform can't even store+load a float without mucking + // with the bits. + gFloat32 = math.Float32frombits(snan) + runtime.Gosched() // make sure we don't optimize the store/load away + r := math.Float32bits(gFloat32) + if r != snan { + // This should only happen on 386,GO386=387. We have no way to + // test for 387, so we just make sure we're at least on 386. + if runtime.GOARCH != "386" { + t.Errorf("store/load of sNaN not faithful") + } + t.Skip("skipping test, float store+load not faithful") + } + + type myFloat32 float32 + x := V(myFloat32(math.Float32frombits(snan))) + y := x.Convert(TypeOf(float32(0))) + z := y.Interface().(float32) + if got := math.Float32bits(z); got != snan { + t.Errorf("signaling nan conversion got %x, want %x", got, snan) + } +} + type ComparableStruct struct { X int } diff --git a/src/reflect/value.go b/src/reflect/value.go index 51e7d195fe..08f0d259de 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -2541,6 +2541,14 @@ func makeFloat(f flag, v float64, t Type) Value { return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} } +// makeFloat returns a Value of type t equal to v, where t is a float32 type. +func makeFloat32(f flag, v float32, t Type) Value { + typ := t.common() + ptr := unsafe_New(typ) + *(*float32)(ptr) = v + return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} +} + // makeComplex returns a Value of type t equal to v (possibly truncated to complex64), // where t is a complex64 or complex128 type. func makeComplex(f flag, v complex128, t Type) Value { @@ -2613,6 +2621,12 @@ func cvtUintFloat(v Value, t Type) Value { // convertOp: floatXX -> floatXX func cvtFloat(v Value, t Type) Value { + if v.Type().Kind() == Float32 && t.Kind() == Float32 { + // Don't do any conversion if both types have underlying type float32. + // This avoids converting to float64 and back, which will + // convert a signaling NaN to a quiet NaN. See issue 36400. + return makeFloat32(v.flag.ro(), *(*float32)(v.ptr), t) + } return makeFloat(v.flag.ro(), v.Float(), t) } diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index b872b8834d..ed7cec7233 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -1475,6 +1475,55 @@ flush: MOVQ 96(SP), R15 JMP ret +// gcWriteBarrierCX is gcWriteBarrier, but with args in DI and CX. +TEXT runtime·gcWriteBarrierCX(SB),NOSPLIT,$0 + XCHGQ CX, AX + CALL runtime·gcWriteBarrier(SB) + XCHGQ CX, AX + RET + +// gcWriteBarrierDX is gcWriteBarrier, but with args in DI and DX. +TEXT runtime·gcWriteBarrierDX(SB),NOSPLIT,$0 + XCHGQ DX, AX + CALL runtime·gcWriteBarrier(SB) + XCHGQ DX, AX + RET + +// gcWriteBarrierBX is gcWriteBarrier, but with args in DI and BX. +TEXT runtime·gcWriteBarrierBX(SB),NOSPLIT,$0 + XCHGQ BX, AX + CALL runtime·gcWriteBarrier(SB) + XCHGQ BX, AX + RET + +// gcWriteBarrierBP is gcWriteBarrier, but with args in DI and BP. +TEXT runtime·gcWriteBarrierBP(SB),NOSPLIT,$0 + XCHGQ BP, AX + CALL runtime·gcWriteBarrier(SB) + XCHGQ BP, AX + RET + +// gcWriteBarrierSI is gcWriteBarrier, but with args in DI and SI. +TEXT runtime·gcWriteBarrierSI(SB),NOSPLIT,$0 + XCHGQ SI, AX + CALL runtime·gcWriteBarrier(SB) + XCHGQ SI, AX + RET + +// gcWriteBarrierR8 is gcWriteBarrier, but with args in DI and R8. +TEXT runtime·gcWriteBarrierR8(SB),NOSPLIT,$0 + XCHGQ R8, AX + CALL runtime·gcWriteBarrier(SB) + XCHGQ R8, AX + RET + +// gcWriteBarrierR9 is gcWriteBarrier, but with args in DI and R9. +TEXT runtime·gcWriteBarrierR9(SB),NOSPLIT,$0 + XCHGQ R9, AX + CALL runtime·gcWriteBarrier(SB) + XCHGQ R9, AX + RET + DATA debugCallFrameTooLarge<>+0x00(SB)/20, $"call frame too large" GLOBL debugCallFrameTooLarge<>(SB), RODATA, $20 // Size duplicated below diff --git a/src/runtime/duff_ppc64x.s b/src/runtime/duff_ppc64x.s index 0c62d0afe9..d6b89ba940 100644 --- a/src/runtime/duff_ppc64x.s +++ b/src/runtime/duff_ppc64x.s @@ -137,7 +137,5 @@ TEXT runtime·duffzero(SB), NOSPLIT|NOFRAME, $0-0 MOVDU R0, 8(R3) RET -// TODO: Implement runtime·duffcopy. -TEXT runtime·duffcopy(SB),NOSPLIT|NOFRAME,$0-0 - MOVD R0, 0(R0) - RET +TEXT runtime·duffcopy(SB), NOSPLIT|NOFRAME, $0-0 + UNDEF diff --git a/src/runtime/map.go b/src/runtime/map.go index e456c32556..399c1b071f 100644 --- a/src/runtime/map.go +++ b/src/runtime/map.go @@ -66,7 +66,7 @@ const ( bucketCnt = 1 << bucketCntBits // Maximum average load of a bucket that triggers growth is 6.5. - // Represent as loadFactorNum/loadFactDen, to allow integer math. + // Represent as loadFactorNum/loadFactorDen, to allow integer math. loadFactorNum = 13 loadFactorDen = 2 diff --git a/src/runtime/mkduff.go b/src/runtime/mkduff.go index 6ac5e7da44..6c7a4cf8dc 100644 --- a/src/runtime/mkduff.go +++ b/src/runtime/mkduff.go @@ -194,7 +194,9 @@ func zeroPPC64x(w io.Writer) { } func copyPPC64x(w io.Writer) { - fmt.Fprintln(w, "// TODO: Implement runtime·duffcopy.") + // duffcopy is not used on PPC64. + fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT|NOFRAME, $0-0") + fmt.Fprintln(w, "\tUNDEF") } func tagsMIPS64x(w io.Writer) { diff --git a/src/runtime/mpagealloc.go b/src/runtime/mpagealloc.go index bb751f1f8e..60926fbebf 100644 --- a/src/runtime/mpagealloc.go +++ b/src/runtime/mpagealloc.go @@ -724,7 +724,7 @@ nextLevel: // is what the final level represents. ci := chunkIdx(i) j, searchIdx := s.chunkOf(ci).find(npages, 0) - if j < 0 { + if j == ^uint(0) { // We couldn't find any space in this chunk despite the summaries telling // us it should be there. There's likely a bug, so dump some state and throw. sum := s.summary[len(s.summary)-1][i] @@ -766,7 +766,7 @@ func (s *pageAlloc) alloc(npages uintptr) (addr uintptr, scav uintptr) { i := chunkIndex(s.searchAddr) if max := s.summary[len(s.summary)-1][i].max(); max >= uint(npages) { j, searchIdx := s.chunkOf(i).find(npages, chunkPageIndex(s.searchAddr)) - if j < 0 { + if j == ^uint(0) { print("runtime: max = ", max, ", npages = ", npages, "\n") print("runtime: searchIdx = ", chunkPageIndex(s.searchAddr), ", s.searchAddr = ", hex(s.searchAddr), "\n") throw("bad summary data") diff --git a/src/runtime/mpagecache.go b/src/runtime/mpagecache.go index 9fc338bd8e..5b679d357d 100644 --- a/src/runtime/mpagecache.go +++ b/src/runtime/mpagecache.go @@ -115,7 +115,7 @@ func (s *pageAlloc) allocToCache() pageCache { // Fast path: there's free pages at or near the searchAddr address. chunk := s.chunkOf(ci) j, _ := chunk.find(1, chunkPageIndex(s.searchAddr)) - if j < 0 { + if j == ^uint(0) { throw("bad summary data") } c = pageCache{ diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go index 3852598b7e..a332045342 100644 --- a/src/runtime/netpoll.go +++ b/src/runtime/netpoll.go @@ -33,6 +33,15 @@ import ( // func netpollIsPollDescriptor(fd uintptr) bool // Reports whether fd is a file descriptor used by the poller. +// Error codes returned by runtime_pollReset and runtime_pollWait. +// These must match the values in internal/poll/fd_poll_runtime.go. +const ( + pollNoError = 0 // no error + pollErrClosing = 1 // descriptor is closed + pollErrTimeout = 2 // I/O timeout + pollErrNotPollable = 3 // general error polling descriptor +) + // pollDesc contains 2 binary semaphores, rg and wg, to park reader and writer // goroutines respectively. The semaphore can be in the following states: // pdReady - io readiness notification is pending; @@ -176,40 +185,47 @@ func (c *pollCache) free(pd *pollDesc) { unlock(&c.lock) } +// poll_runtime_pollReset, which is internal/poll.runtime_pollReset, +// prepares a descriptor for polling in mode, which is 'r' or 'w'. +// This returns an error code; the codes are defined above. //go:linkname poll_runtime_pollReset internal/poll.runtime_pollReset func poll_runtime_pollReset(pd *pollDesc, mode int) int { - err := netpollcheckerr(pd, int32(mode)) - if err != 0 { - return err + errcode := netpollcheckerr(pd, int32(mode)) + if errcode != pollNoError { + return errcode } if mode == 'r' { pd.rg = 0 } else if mode == 'w' { pd.wg = 0 } - return 0 + return pollNoError } +// poll_runtime_pollWait, which is internal/poll.runtime_pollWait, +// waits for a descriptor to be ready for reading or writing, +// according to mode, which is 'r' or 'w'. +// This returns an error code; the codes are defined above. //go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait func poll_runtime_pollWait(pd *pollDesc, mode int) int { - err := netpollcheckerr(pd, int32(mode)) - if err != 0 { - return err + errcode := netpollcheckerr(pd, int32(mode)) + if errcode != pollNoError { + return errcode } // As for now only Solaris, illumos, and AIX use level-triggered IO. if GOOS == "solaris" || GOOS == "illumos" || GOOS == "aix" { netpollarm(pd, mode) } for !netpollblock(pd, int32(mode), false) { - err = netpollcheckerr(pd, int32(mode)) - if err != 0 { - return err + errcode = netpollcheckerr(pd, int32(mode)) + if errcode != pollNoError { + return errcode } // Can happen if timeout has fired and unblocked us, // but before we had a chance to run, timeout has been reset. // Pretend it has not happened and retry. } - return 0 + return pollNoError } //go:linkname poll_runtime_pollWaitCanceled internal/poll.runtime_pollWaitCanceled @@ -359,18 +375,18 @@ func netpollready(toRun *gList, pd *pollDesc, mode int32) { func netpollcheckerr(pd *pollDesc, mode int32) int { if pd.closing { - return 1 // ErrFileClosing or ErrNetClosing + return pollErrClosing } if (mode == 'r' && pd.rd < 0) || (mode == 'w' && pd.wd < 0) { - return 2 // ErrTimeout + return pollErrTimeout } // Report an event scanning error only on a read event. // An error on a write event will be captured in a subsequent // write call that is able to report a more specific error. if mode == 'r' && pd.everr { - return 3 // ErrNotPollable + return pollErrNotPollable } - return 0 + return pollNoError } func netpollblockcommit(gp *g, gpp unsafe.Pointer) bool { @@ -447,7 +463,7 @@ func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g { new = pdReady } if atomic.Casuintptr(gpp, old, new) { - if old == pdReady || old == pdWait { + if old == pdWait { old = 0 } return (*g)(unsafe.Pointer(old)) diff --git a/src/runtime/netpoll_aix.go b/src/runtime/netpoll_aix.go index c936fbb70f..3c1f70874d 100644 --- a/src/runtime/netpoll_aix.go +++ b/src/runtime/netpoll_aix.go @@ -4,7 +4,10 @@ package runtime -import "unsafe" +import ( + "runtime/internal/atomic" + "unsafe" +) // This is based on the former libgo/runtime/netpoll_select.c implementation // except that it uses poll instead of select and is written in Go. @@ -41,6 +44,8 @@ var ( rdwake int32 wrwake int32 pendingUpdates int32 + + netpollWakeSig uintptr // used to avoid duplicate calls of netpollBreak ) func netpollinit() { @@ -130,7 +135,10 @@ func netpollarm(pd *pollDesc, mode int) { // netpollBreak interrupts a poll. func netpollBreak() { - netpollwakeup() + if atomic.Casuintptr(&netpollWakeSig, 0, 1) { + b := [1]byte{0} + write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1) + } } // netpoll checks for ready network connections. @@ -184,6 +192,7 @@ retry: var b [1]byte for read(rdwake, unsafe.Pointer(&b[0]), 1) == 1 { } + atomic.Storeuintptr(&netpollWakeSig, 0) } // Still look at the other fds even if the mode may have // changed, as netpollBreak might have been called. diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 5bfc3b6134..83b3152d68 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -1172,6 +1172,18 @@ func TestTryAdd(t *testing.T) { {Value: []int64{20, 20 * period}, Location: []*profile.Location{{ID: 1}}}, }, }, { + name: "bug38096", + input: []uint64{ + 3, 0, 500, // hz = 500. Must match the period. + // count (data[2]) == 0 && len(stk) == 1 is an overflow + // entry. The "stk" entry is actually the count. + 4, 0, 0, 4242, + }, + wantLocs: [][]string{{"runtime/pprof.lostProfileEvent"}}, + wantSamples: []*profile.Sample{ + {Value: []int64{4242, 4242 * period}, Location: []*profile.Location{{ID: 1}}}, + }, + }, { // If a function is called recursively then it must not be // inlined in the caller. // diff --git a/src/runtime/pprof/proto.go b/src/runtime/pprof/proto.go index 416ace7ab2..bb63153a70 100644 --- a/src/runtime/pprof/proto.go +++ b/src/runtime/pprof/proto.go @@ -322,7 +322,10 @@ func (b *profileBuilder) addCPUData(data []uint64, tags []unsafe.Pointer) error // overflow record count = uint64(stk[0]) stk = []uint64{ - uint64(funcPC(lostProfileEvent)), + // gentraceback guarantees that PCs in the + // stack can be unconditionally decremented and + // still be valid, so we must do the same. + uint64(funcPC(lostProfileEvent)+1), } } b.m.lookup(stk, tag).count += int64(count) diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 79b4621614..5dbe4bf88a 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -41,6 +41,8 @@ func checkGdbEnvironment(t *testing.T) { if testing.Short() { t.Skip("skipping gdb tests on AIX; see https://golang.org/issue/35710") } + case "plan9": + t.Skip("there is no gdb on Plan 9") } if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final { t.Skip("gdb test can fail with GOROOT_FINAL pending") diff --git a/src/runtime/sigqueue.go b/src/runtime/sigqueue.go index b2ebb2b457..3bf07cb5a6 100644 --- a/src/runtime/sigqueue.go +++ b/src/runtime/sigqueue.go @@ -192,16 +192,13 @@ func signalWaitUntilIdle() { //go:linkname signal_enable os/signal.signal_enable func signal_enable(s uint32) { if !sig.inuse { - // The first call to signal_enable is for us - // to use for initialization. It does not pass - // signal information in m. + // This is the first call to signal_enable. Initialize. sig.inuse = true // enable reception of signals; cannot disable if GOOS == "darwin" { sigNoteSetup(&sig.note) - return + } else { + noteclear(&sig.note) } - noteclear(&sig.note) - return } if s >= uint32(len(sig.wanted)*32) { diff --git a/src/runtime/sigqueue_plan9.go b/src/runtime/sigqueue_plan9.go index 934742a1f4..d5fe8f8b35 100644 --- a/src/runtime/sigqueue_plan9.go +++ b/src/runtime/sigqueue_plan9.go @@ -134,12 +134,9 @@ func signalWaitUntilIdle() { //go:linkname signal_enable os/signal.signal_enable func signal_enable(s uint32) { if !sig.inuse { - // The first call to signal_enable is for us - // to use for initialization. It does not pass - // signal information in m. + // This is the first call to signal_enable. Initialize. sig.inuse = true // enable reception of signals; cannot disable noteclear(&sig.note) - return } } diff --git a/src/runtime/stubs_amd64.go b/src/runtime/stubs_amd64.go index 5b79d66762..8c14bc2271 100644 --- a/src/runtime/stubs_amd64.go +++ b/src/runtime/stubs_amd64.go @@ -4,6 +4,15 @@ package runtime +// Called from compiled code; declared for vet; do NOT call from Go. +func gcWriteBarrierCX() +func gcWriteBarrierDX() +func gcWriteBarrierBX() +func gcWriteBarrierBP() +func gcWriteBarrierSI() +func gcWriteBarrierR8() +func gcWriteBarrierR9() + // stackcheck checks that SP is in range [g->stack.lo, g->stack.hi). func stackcheck() diff --git a/src/strings/strings.go b/src/strings/strings.go index 6d78b9ef16..314e2276d4 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -828,7 +828,7 @@ func makeCutsetFunc(cutset string) func(rune) bool { // Trim returns a slice of the string s with all leading and // trailing Unicode code points contained in cutset removed. -func Trim(s string, cutset string) string { +func Trim(s, cutset string) string { if s == "" || cutset == "" { return s } @@ -839,7 +839,7 @@ func Trim(s string, cutset string) string { // Unicode code points contained in cutset removed. // // To remove a prefix, use TrimPrefix instead. -func TrimLeft(s string, cutset string) string { +func TrimLeft(s, cutset string) string { if s == "" || cutset == "" { return s } @@ -850,7 +850,7 @@ func TrimLeft(s string, cutset string) string { // Unicode code points contained in cutset removed. // // To remove a suffix, use TrimSuffix instead. -func TrimRight(s string, cutset string) string { +func TrimRight(s, cutset string) string { if s == "" || cutset == "" { return s } diff --git a/src/sync/atomic/atomic_test.go b/src/sync/atomic/atomic_test.go index 286eadc6cd..83e7c8d763 100644 --- a/src/sync/atomic/atomic_test.go +++ b/src/sync/atomic/atomic_test.go @@ -153,6 +153,21 @@ func TestSwapUintptr(t *testing.T) { } } +var global [1024]byte + +func testPointers() []unsafe.Pointer { + var pointers []unsafe.Pointer + // globals + for i := 0; i < 10; i++ { + pointers = append(pointers, unsafe.Pointer(&global[1<<i-1])) + } + // heap + pointers = append(pointers, unsafe.Pointer(new(byte))) + // nil + pointers = append(pointers, nil) + return pointers +} + func TestSwapPointer(t *testing.T) { var x struct { before uintptr @@ -163,13 +178,14 @@ func TestSwapPointer(t *testing.T) { magicptr := uintptr(m) x.before = magicptr x.after = magicptr - var j uintptr - for delta := uintptr(1 << 16); delta+delta > delta; delta += delta { - k := SwapPointer(&x.i, unsafe.Pointer(delta)) - if uintptr(x.i) != delta || uintptr(k) != j { - t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) + var j unsafe.Pointer + + for _, p := range testPointers() { + k := SwapPointer(&x.i, p) + if x.i != p || k != j { + t.Fatalf("p=%p i=%p j=%p k=%p", p, x.i, j, k) } - j = delta + j = p } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) @@ -456,20 +472,20 @@ func TestCompareAndSwapPointer(t *testing.T) { magicptr := uintptr(m) x.before = magicptr x.after = magicptr - for val := uintptr(1 << 16); val+val > val; val += val { - x.i = unsafe.Pointer(val) - if !CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+1)) { - t.Fatalf("should have swapped %#x %#x", val, val+1) + q := unsafe.Pointer(new(byte)) + for _, p := range testPointers() { + x.i = p + if !CompareAndSwapPointer(&x.i, p, q) { + t.Fatalf("should have swapped %p %p", p, q) } - if x.i != unsafe.Pointer(val+1) { - t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) + if x.i != q { + t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i, q) } - x.i = unsafe.Pointer(val + 1) - if CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+2)) { - t.Fatalf("should not have swapped %#x %#x", val, val+2) + if CompareAndSwapPointer(&x.i, p, nil) { + t.Fatalf("should not have swapped %p nil", p) } - if x.i != unsafe.Pointer(val+1) { - t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) + if x.i != q { + t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i, q) } } if x.before != magicptr || x.after != magicptr { @@ -595,12 +611,12 @@ func TestLoadPointer(t *testing.T) { magicptr := uintptr(m) x.before = magicptr x.after = magicptr - for delta := uintptr(1 << 16); delta+delta > delta; delta += delta { + for _, p := range testPointers() { + x.i = p k := LoadPointer(&x.i) - if k != x.i { - t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) + if k != p { + t.Fatalf("p=%x k=%x", p, k) } - x.i = unsafe.Pointer(uintptr(x.i) + delta) } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) @@ -730,13 +746,11 @@ func TestStorePointer(t *testing.T) { magicptr := uintptr(m) x.before = magicptr x.after = magicptr - v := unsafe.Pointer(uintptr(0)) - for delta := uintptr(1 << 16); delta+delta > delta; delta += delta { - StorePointer(&x.i, unsafe.Pointer(v)) - if x.i != v { - t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) + for _, p := range testPointers() { + StorePointer(&x.i, p) + if x.i != p { + t.Fatalf("x.i=%p p=%p", x.i, p) } - v = unsafe.Pointer(uintptr(v) + delta) } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index 950c281e4d..922cf2cb2e 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -871,11 +871,19 @@ func Shutdown(fd Handle, how int) (err error) { } func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (err error) { - rsa, l, err := to.sockaddr() + rsa, len, err := to.sockaddr() if err != nil { return err } - return WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine) + r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = EINVAL + } + } + return err } func LoadGetAddrInfo() error { diff --git a/src/time/time.go b/src/time/time.go index 3f632dbc3e..3d242f2541 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -287,25 +287,10 @@ const ( December ) -var months = [...]string{ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", -} - // String returns the English name of the month ("January", "February", ...). func (m Month) String() string { if January <= m && m <= December { - return months[m-1] + return longMonthNames[m-1] } buf := make([]byte, 20) n := fmtInt(buf, uint64(m)) @@ -325,20 +310,10 @@ const ( Saturday ) -var days = [...]string{ - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", -} - // String returns the English name of the day ("Sunday", "Monday", ...). func (d Weekday) String() string { if Sunday <= d && d <= Saturday { - return days[d] + return longDayNames[d] } buf := make([]byte, 20) n := fmtInt(buf, uint64(d)) diff --git a/test/blank1.go b/test/blank1.go index 1a9f012464..c9a8e6a290 100644 --- a/test/blank1.go +++ b/test/blank1.go @@ -4,7 +4,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Test that incorrect uses of the blank identifer are caught. +// Test that incorrect uses of the blank identifier are caught. // Does not compile. package _ // ERROR "invalid package name" diff --git a/test/chanlinear.go b/test/chanlinear.go index 55fee4ab9b..4d55586dc8 100644 --- a/test/chanlinear.go +++ b/test/chanlinear.go @@ -5,7 +5,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Test that dequeueing from a pending channel doesn't +// Test that dequeuing from a pending channel doesn't // take linear time. package main diff --git a/test/codegen/memcombine.go b/test/codegen/memcombine.go index e2d703cb0c..6ad9514557 100644 --- a/test/codegen/memcombine.go +++ b/test/codegen/memcombine.go @@ -160,14 +160,14 @@ func load_le_byte8_uint64_inv(s []byte) uint64 { func load_be_byte2_uint16(s []byte) uint16 { // arm64:`MOVHU\t\(R[0-9]+\)`,`REV16W`,-`ORR`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // amd64:`MOVWLZX\s\([A-Z]+\)`,`ROLW`,-`MOVB`,-`OR` // ppc64le:`MOVHBR\t\(R[0-9]+\)`,-`MOVBZ` return uint16(s[0])<<8 | uint16(s[1]) } func load_be_byte2_uint16_inv(s []byte) uint16 { // arm64:`MOVHU\t\(R[0-9]+\)`,`REV16W`,-`ORR`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // amd64:`MOVWLZX\s\([A-Z]+\)`,`ROLW`,-`MOVB`,-`OR` // ppc64le:`MOVHBR\t\(R[0-9]+\)`,-`MOVBZ` return uint16(s[1]) | uint16(s[0])<<8 } @@ -179,7 +179,7 @@ func load_be_byte4_uint32(s []byte) uint32 { func load_be_byte4_uint32_inv(s []byte) uint32 { // arm64:`MOVWU\t\(R[0-9]+\)`,`REVW`,-`ORR`,-`REV16W`,-`MOV[BH]` - // amd64:`MOVL\s\([A-Z]+\)`,-`MOV[BW]`,-`OR` + // amd64:`MOVL\s\([A-Z]+\)`,`BSWAPL`,-`MOV[BW]`,-`OR` return uint32(s[3]) | uint32(s[2])<<8 | uint32(s[1])<<16 | uint32(s[0])<<24 } @@ -191,7 +191,7 @@ func load_be_byte8_uint64(s []byte) uint64 { func load_be_byte8_uint64_inv(s []byte) uint64 { // arm64:`MOVD\t\(R[0-9]+\)`,`REV`,-`ORR`,-`REVW`,-`REV16W`,-`MOV[BHW]` - // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+`,-`MOV[BWL]\t[^$]`,-`OR` + // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+`,`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR` // ppc64le:`MOVDBR\t\(R[0-9]+\)`,-`MOV[BHW]Z` return uint64(s[7]) | uint64(s[6])<<8 | uint64(s[5])<<16 | uint64(s[4])<<24 | uint64(s[3])<<32 | uint64(s[2])<<40 | uint64(s[1])<<48 | uint64(s[0])<<56 } diff --git a/test/codegen/memops.go b/test/codegen/memops.go index 9d18153a29..bf5ffb6c4f 100644 --- a/test/codegen/memops.go +++ b/test/codegen/memops.go @@ -99,46 +99,61 @@ func compMem3(x, y *int) (int, bool) { func idxInt8(x, y []int8, i int) { var t int8 // amd64: `MOVBL[SZ]X\t1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*` + // 386: `MOVBL[SZ]X\t1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*` t = x[i+1] // amd64: `MOVB\t[A-Z]+[0-9]*, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + // 386: `MOVB\t[A-Z]+[0-9]*, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` y[i+1] = t // amd64: `MOVB\t[$]77, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + // 386: `MOVB\t[$]77, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` x[i+1] = 77 } func idxInt16(x, y []int16, i int) { var t int16 // amd64: `MOVWL[SZ]X\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*` + // 386: `MOVWL[SZ]X\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*` t = x[i+1] // amd64: `MOVW\t[A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + // 386: `MOVW\t[A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` y[i+1] = t // amd64: `MOVWL[SZ]X\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*` + // 386: `MOVWL[SZ]X\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*` t = x[16*i+1] // amd64: `MOVW\t[A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)` + // 386: `MOVW\t[A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)` y[16*i+1] = t // amd64: `MOVW\t[$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + // 386: `MOVW\t[$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` x[i+1] = 77 // amd64: `MOVW\t[$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)` + // 386: `MOVW\t[$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)` x[16*i+1] = 77 } func idxInt32(x, y []int32, i int) { var t int32 // amd64: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + // 386: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` t = x[i+1] // amd64: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + // 386: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` y[i+1] = t // amd64: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` t = x[2*i+1] // amd64: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` y[2*i+1] = t // amd64: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*` + // 386: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*` t = x[16*i+1] // amd64: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + // 386: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` y[16*i+1] = t // amd64: `MOVL\t[$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + // 386: `MOVL\t[$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` x[i+1] = 77 // amd64: `MOVL\t[$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + // 386: `MOVL\t[$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` x[16*i+1] = 77 } @@ -160,24 +175,131 @@ func idxInt64(x, y []int64, i int) { func idxFloat32(x, y []float32, i int) { var t float32 - // amd64: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+` + // amd64: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+` + // 386/sse2: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+` t = x[i+1] - // amd64: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + // amd64: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + // 386/sse2: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` y[i+1] = t - // amd64: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), X[0-9]+` + // amd64: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), X[0-9]+` + // 386/sse2: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), X[0-9]+` t = x[16*i+1] - // amd64: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + // amd64: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + // 386/sse2: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` y[16*i+1] = t } func idxFloat64(x, y []float64, i int) { var t float64 - // amd64: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+` + // amd64: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+` + // 386/sse2: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+` t = x[i+1] - // amd64: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + // amd64: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + // 386/sse2: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` y[i+1] = t - // amd64: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), X[0-9]+` + // amd64: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), X[0-9]+` + // 386/sse2: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), X[0-9]+` t = x[16*i+1] - // amd64: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)` + // amd64: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)` + // 386/sse2: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)` y[16*i+1] = t } + +func idxLoadPlusOp(x []int32, i int) int32 { + s := x[0] + // 386: `ADDL\t4\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + s += x[i+1] + // 386: `SUBL\t8\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + s -= x[i+2] + // 386: `IMULL\t12\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + s *= x[i+3] + // 386: `ANDL\t16\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + s &= x[i+4] + // 386: `ORL\t20\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + s |= x[i+5] + // 386: `XORL\t24\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + s ^= x[i+6] + return s +} + +func idxStorePlusOp(x []int32, i int, v int32) { + // 386: `ADDL\t[A-Z]+, 4\([A-Z]+\)\([A-Z]+\*4\)` + x[i+1] += v + // 386: `SUBL\t[A-Z]+, 8\([A-Z]+\)\([A-Z]+\*4\)` + x[i+2] -= v + // 386: `ANDL\t[A-Z]+, 12\([A-Z]+\)\([A-Z]+\*4\)` + x[i+3] &= v + // 386: `ORL\t[A-Z]+, 16\([A-Z]+\)\([A-Z]+\*4\)` + x[i+4] |= v + // 386: `XORL\t[A-Z]+, 20\([A-Z]+\)\([A-Z]+\*4\)` + x[i+5] ^= v + + // 386: `ADDL\t[$]77, 24\([A-Z]+\)\([A-Z]+\*4\)` + x[i+6] += 77 + // 386: `ANDL\t[$]77, 28\([A-Z]+\)\([A-Z]+\*4\)` + x[i+7] &= 77 + // 386: `ORL\t[$]77, 32\([A-Z]+\)\([A-Z]+\*4\)` + x[i+8] |= 77 + // 386: `XORL\t[$]77, 36\([A-Z]+\)\([A-Z]+\*4\)` + x[i+9] ^= 77 +} + +func idxCompare(i int) int { + // amd64: `CMPB\t1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*` + if x8[i+1] < x8[0] { + return 0 + } + // amd64: `CMPW\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*` + if x16[i+1] < x16[0] { + return 0 + } + // amd64: `CMPW\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*` + if x16[16*i+1] < x16[0] { + return 0 + } + // amd64: `CMPL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + if x32[i+1] < x32[0] { + return 0 + } + // amd64: `CMPL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*` + if x32[16*i+1] < x32[0] { + return 0 + } + // amd64: `CMPQ\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + if x64[i+1] < x64[0] { + return 0 + } + // amd64: `CMPQ\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), [A-Z]+[0-9]*` + if x64[16*i+1] < x64[0] { + return 0 + } + // amd64: `CMPB\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), \$77` + if x8[i+2] < 77 { + return 0 + } + // amd64: `CMPW\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), \$77` + if x16[i+2] < 77 { + return 0 + } + // amd64: `CMPW\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), \$77` + if x16[16*i+2] < 77 { + return 0 + } + // amd64: `CMPL\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), \$77` + if x32[i+2] < 77 { + return 0 + } + // amd64: `CMPL\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), \$77` + if x32[16*i+2] < 77 { + return 0 + } + // amd64: `CMPQ\t16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), \$77` + if x64[i+2] < 77 { + return 0 + } + // amd64: `CMPQ\t16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), \$77` + if x64[16*i+2] < 77 { + return 0 + } + return 1 +} diff --git a/test/codegen/structs.go b/test/codegen/structs.go index b81ad67c44..9eddc5b16e 100644 --- a/test/codegen/structs.go +++ b/test/codegen/structs.go @@ -28,7 +28,7 @@ type Z2 struct { func Zero2(t *Z2) { // amd64:`XORPS\tX., X`,`MOVUPS\tX., \(.*\)`,`MOVQ\t\$0, 16\(.*\)` - // amd64:`.*runtime[.]gcWriteBarrier\(SB\)` + // amd64:`.*runtime[.]gcWriteBarrier.*\(SB\)` *t = Z2{} } diff --git a/test/escape_slice.go b/test/escape_slice.go index 03053cf326..d2cdaa6a01 100644 --- a/test/escape_slice.go +++ b/test/escape_slice.go @@ -18,28 +18,28 @@ var sink interface{} func slice0() { var s []*int // BAD: i should not escape - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s = append(s, &i) _ = s } func slice1() *int { var s []*int - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s = append(s, &i) return s[0] } func slice2() []*int { var s []*int - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s = append(s, &i) return s } func slice3() *int { var s []*int - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s = append(s, &i) for _, p := range s { return p @@ -48,7 +48,7 @@ func slice3() *int { } func slice4(s []*int) { // ERROR "s does not escape" - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s[0] = &i } @@ -56,14 +56,14 @@ func slice5(s []*int) { // ERROR "s does not escape" if s != nil { s = make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape" } - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s[0] = &i } func slice6() { s := make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape" // BAD: i should not escape - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s[0] = &i _ = s } @@ -93,6 +93,14 @@ func slice10() []*int { return s } +func slice11() { + i := 2 + s := make([]int, 2, 3) // ERROR "make\(\[\]int, 2, 3\) does not escape" + s = make([]int, i, 3) // ERROR "make\(\[\]int, i, 3\) does not escape" + s = make([]int, i, 1) // ERROR "make\(\[\]int, i, 1\) does not escape" + _ = s +} + func envForDir(dir string) []string { // ERROR "dir does not escape" env := os.Environ() return mergeEnvLists([]string{"PWD=" + dir}, env) // ERROR ".PWD=. \+ dir escapes to heap" "\[\]string literal does not escape" diff --git a/test/fixedbugs/issue35073.go b/test/fixedbugs/issue35073.go new file mode 100644 index 0000000000..dc8ce3a987 --- /dev/null +++ b/test/fixedbugs/issue35073.go @@ -0,0 +1,23 @@ +// run -gcflags=-d=checkptr + +// Copyright 2020 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. + +// Test that reflect.Value.UnsafeAddr/Pointer is handled +// correctly by -d=checkptr + +package main + +import ( + "reflect" + "unsafe" +) + +func main() { + n := 10 + m := make(map[string]string) + + _ = unsafe.Pointer(reflect.ValueOf(&n).Elem().UnsafeAddr()) + _ = unsafe.Pointer(reflect.ValueOf(&m).Elem().Pointer()) +} diff --git a/test/fixedbugs/issue37975.go b/test/fixedbugs/issue37975.go new file mode 100644 index 0000000000..a4e8f1f14a --- /dev/null +++ b/test/fixedbugs/issue37975.go @@ -0,0 +1,54 @@ +// run + +// Copyright 2020 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. + +// Make sure runtime.panicmakeslice* are called. + +package main + +import "strings" + +func main() { + // Test typechecking passes if len is valid + // but cap is out of range for len's type. + var x byte + _ = make([]int, x, 300) + + capOutOfRange := func() { + i := 2 + s := make([]int, i, 1) + s[0] = 1 + } + lenOutOfRange := func() { + i := -1 + s := make([]int, i, 3) + s[0] = 1 + } + + tests := []struct { + f func() + panicStr string + }{ + {capOutOfRange, "cap out of range"}, + {lenOutOfRange, "len out of range"}, + } + + for _, tc := range tests { + shouldPanic(tc.panicStr, tc.f) + } + +} + +func shouldPanic(str string, f func()) { + defer func() { + err := recover() + runtimeErr := err.(error).Error() + if !strings.Contains(runtimeErr, str) { + panic("got panic " + runtimeErr + ", want " + str) + } + }() + + f() +} diff --git a/test/fixedbugs/issue38117.go b/test/fixedbugs/issue38117.go new file mode 100644 index 0000000000..11edef7f25 --- /dev/null +++ b/test/fixedbugs/issue38117.go @@ -0,0 +1,17 @@ +// errorcheck + +// Copyright 2020 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. + +// cmd/compile erroneously rejected conversions of constant values +// between int/float and complex types. + +package p + +const ( + _ = int(complex64(int(0))) + _ = float64(complex128(float64(0))) + + _ = int8(complex128(1000)) // ERROR "overflow" +) diff --git a/test/fixedbugs/issue9521.go b/test/fixedbugs/issue9521.go index 4e4a55f1e1..a33f0483f3 100644 --- a/test/fixedbugs/issue9521.go +++ b/test/fixedbugs/issue9521.go @@ -4,7 +4,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Test that an incorrect use of the blank identifer is caught. +// Test that an incorrect use of the blank identifier is caught. // Does not compile. package main |