From a91f860d7d8e36354e606bbc22bd2c2713e17c55 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Wed, 22 Jul 2026 10:28:30 -0400 Subject: [PATCH 01/21] cmd/compile/internal/ssa: remove HTMLWriter from Func This will make it easier to move the Func type into a separate package by removing the dependency from the Func onto the HTMLWriter. The HTMLWriter is just passed around by the ssagen/compile functions. For #80409 Change-Id: I25e2227d197d4b192194ba12f5ac2e086a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/804260 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Cherry Mui Reviewed-by: Keith Randall Reviewed-by: Michael Matloob --- src/cmd/compile/internal/ssa/compile.go | 16 ++++++------- src/cmd/compile/internal/ssa/func.go | 7 +++--- src/cmd/compile/internal/ssa/html.go | 8 +++++++ src/cmd/compile/internal/ssa/shift_test.go | 4 ++-- src/cmd/compile/internal/ssagen/pgen.go | 4 ++-- src/cmd/compile/internal/ssagen/ssa.go | 26 ++++++++++++---------- 6 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index d2657d7acdd9c0..480da486090804 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -30,7 +30,7 @@ import ( // - the order of f.Blocks is the order to emit the Blocks // - the order of b.Values is the order to emit the Values in each Block // - f has a non-nil regAlloc field -func Compile(f *Func) { +func Compile(f *Func, htmlWriter *HTMLWriter) { // TODO: debugging - set flags to control verbosity of compiler, // which phases to dump IR before/after, etc. if f.Log() { @@ -51,8 +51,8 @@ func Compile(f *Func) { stack := make([]byte, 16384) n := runtime.Stack(stack, false) stack = stack[:n] - if f.HTMLWriter != nil { - f.HTMLWriter.flushPhases() + if htmlWriter != nil { + htmlWriter.flushPhases() } f.Fatalf("panic during %s while compiling %s:\n\n%v\n\n%s\n", phaseName, f.Name, err, stack) } @@ -62,7 +62,7 @@ func Compile(f *Func) { if f.Log() { printFunc(f) } - f.HTMLWriter.WritePhase("start", "start") + htmlWriter.WritePhase("start", "start") if BuildDump[f.Name] { f.dumpFile("build") } @@ -101,7 +101,7 @@ func Compile(f *Func) { tEnd := time.Now() // Need something less crude than "Log the whole intermediate result". - if f.Log() || f.HTMLWriter != nil { + if f.Log() || htmlWriter != nil { time := tEnd.Sub(tStart).Nanoseconds() var stats string if logMemStats { @@ -118,7 +118,7 @@ func Compile(f *Func) { f.Logf(" pass %s end %s\n", p.name, stats) printFunc(f) } - f.HTMLWriter.WritePhase(phaseName, fmt.Sprintf("%s %s", phaseName, stats)) + htmlWriter.WritePhase(phaseName, fmt.Sprintf("%s %s", phaseName, stats)) } if p.time || p.mem { // Surround timing information w/ enough context to allow comparisons. @@ -143,9 +143,9 @@ func Compile(f *Func) { } } - if f.HTMLWriter != nil { + if htmlWriter != nil { // Ensure we write any pending phases to the html - f.HTMLWriter.flushPhases() + htmlWriter.flushPhases() } if f.ruleMatches != nil { diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 65e4e46872fb54..40c291e69c8be8 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -35,7 +35,7 @@ type Func struct { bid idAlloc // block ID allocator vid idAlloc // value ID allocator - HTMLWriter *HTMLWriter // html writer, for debugging + FatalCleanup func() // cleanup function to run before reporting a fatal error PrintOrHtmlSSA bool // true if GOSSAFUNC matches, true even if fe.Log() (spew phase results to stdout) is false. There's an odd dependence on this in debug.go for method logf. ruleMatches map[string]int // number of times countRule was called during compilation for any given string ABI0 *abi.ABIConfig // ABI configuration for ABI0 @@ -759,9 +759,8 @@ func (f *Func) Fatalf(msg string, args ...any) { f.Logf(" pass %s end %s\n", f.pass.name, stats) printFunc(f) } - if f.HTMLWriter != nil { - f.HTMLWriter.WritePhase(f.pass.name, fmt.Sprintf("%s %s", f.pass.name, stats)) - f.HTMLWriter.flushPhases() + if f.FatalCleanup != nil { + f.FatalCleanup() } f.fe.Fatalf(f.Entry.Pos, msg, args...) } diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index accb558cdbbfff..7af6386a7e743c 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -804,6 +804,14 @@ func (w *HTMLWriter) WritePhase(phase, title string) { w.prevHash = hash } +// FatalCleanup should be called to do cleanup if the complation is exiting early due to +// a fatal error. +func (w *HTMLWriter) FatalCleanup() { + const stats = "crashed" + w.WritePhase(w.Func.pass.name, fmt.Sprintf("%s %s", w.Func.pass.name, stats)) + w.flushPhases() +} + // flushPhases collects any pending phases and titles, writes them to the html, and resets the pending slices. func (w *HTMLWriter) flushPhases() { phaseLen := len(w.pendingPhases) diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index 06c2f6720ff7ff..3ec4dca76a8ff4 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -43,7 +43,7 @@ func makeConstShiftFunc(c *Conf, amount int64, op Op, typ *types.Type) fun { Valu("shift", op, typ, 0, nil, "load", "c"), Valu("store", OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "shift", "mem"), Exit("store"))) - Compile(fun.f) + Compile(fun.f, nil) return fun } @@ -102,6 +102,6 @@ func makeShiftExtensionFunc(c *Conf, amount int64, lshift, rshift Op, typ *types Valu("rshift", rshift, typ, 0, nil, "lshift", "c"), Valu("store", OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "rshift", "mem"), Exit("store"))) - Compile(fun.f) + Compile(fun.f, nil) return fun } diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 0a2010363f8d04..58401927dd1c0f 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -301,7 +301,7 @@ const maxStackSize = 1 << 30 // and flushes that plist to machine code. // worker indicates which of the backend workers is doing the processing. func Compile(fn *ir.Func, worker int, profile *pgoir.Profile) { - f := buildssa(fn, worker, inline.IsPgoHotFunc(fn, profile) || inline.HasPgoHotInline(fn)) + f, htmlWriter := buildssa(fn, worker, inline.IsPgoHotFunc(fn, profile) || inline.HasPgoHotInline(fn)) // Note: check arg size to fix issue 25507. if f.Frontend().(*ssafn).stksize >= maxStackSize || f.OwnAux.ArgWidth() >= maxStackSize { largeStackFramesMu.Lock() @@ -311,7 +311,7 @@ func Compile(fn *ir.Func, worker int, profile *pgoir.Profile) { } pp := objw.NewProgs(fn, worker) defer pp.Free() - genssa(f, pp) + genssa(htmlWriter, f, pp) // Check frame size again. // The check above included only the space needed for local variables. // After genssa, the space needed includes local variables and the callee arg region. diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index f08c15f5317e0d..b6a9ed53d381d9 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -295,7 +295,7 @@ func (s *state) emitOpenDeferInfo() { // buildssa builds an SSA function for fn. // worker indicates which of the backend workers is doing the processing. -func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { +func buildssa(fn *ir.Func, worker int, isPgoHot bool) (*ssa.Func, *ssa.HTMLWriter) { name := ir.FuncName(fn) abiSelf := abiForFunc(fn, ssaConfig.ABI0, ssaConfig.ABI1) @@ -378,6 +378,7 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { s.f.Entry = s.f.NewBlock(block.BlockPlain) s.f.Entry.Pos = fn.Pos() s.f.IsPgoHot = isPgoHot + var htmlWriter *ssa.HTMLWriter if printssa { ssaDF := ssaDumpFile @@ -386,10 +387,11 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { ssaD := filepath.Dir(ssaDF) os.MkdirAll(ssaD, 0755) } - s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDF, s.f, ssaDumpCFG) + htmlWriter = ssa.NewHTMLWriter(ssaDF, s.f, ssaDumpCFG) // TODO: generate and print a mapping from nodes to values and blocks - dumpSourcesColumn(s.f.HTMLWriter, fn) - s.f.HTMLWriter.WriteAST("AST", astBuf) + dumpSourcesColumn(htmlWriter, fn) + htmlWriter.WriteAST("AST", astBuf) + s.f.FatalCleanup = htmlWriter.FatalCleanup } // Allocate starting values @@ -589,12 +591,12 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { } } - s.f.HTMLWriter.WritePhase("before insert phis", "before insert phis") + htmlWriter.WritePhase("before insert phis", "before insert phis") s.insertPhis() // Main call to ssa package to compile function - ssa.Compile(s.f) + ssa.Compile(s.f, htmlWriter) fe.AllocFrame(s.f) @@ -620,7 +622,7 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { } } - return s.f + return s.f, htmlWriter } func (s *state) storeParameterRegsToStack(abi *abi.ABIConfig, paramAssignment *abi.ABIParamAssignment, n *ir.Name, addr *ssa.Value, pointersOnly bool) { @@ -6981,7 +6983,7 @@ func emitWrappedFuncInfo(e *ssafn, pp *objw.Progs) { } // genssa appends entries to pp for each instruction in f. -func genssa(f *ssa.Func, pp *objw.Progs) { +func genssa(htmlWriter *ssa.HTMLWriter, f *ssa.Func, pp *objw.Progs) { var s State s.ABI = f.OwnAux.Fn.ABI() @@ -7433,7 +7435,7 @@ func genssa(f *ssa.Func, pp *objw.Progs) { f.Logf(" %-6s\t%.5d (%s)\t%s\n", s, p.Pc, p.InnermostLineNumber(), p.InstructionString()) } } - if f.HTMLWriter != nil { // spew to ssa.html + if htmlWriter != nil { // spew to ssa.html var buf strings.Builder buf.WriteString("") buf.WriteString("
") @@ -7482,7 +7484,7 @@ func genssa(f *ssa.Func, pp *objw.Progs) { } buf.WriteString("
") buf.WriteString("
") - f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String()) + htmlWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String()) } if ssa.GenssaDump[f.Name] { fi := f.DumpFileForPhase("genssa") @@ -7533,8 +7535,8 @@ func genssa(f *ssa.Func, pp *objw.Progs) { } } - f.HTMLWriter.Close() - f.HTMLWriter = nil + htmlWriter.Close() + htmlWriter = nil } func defframe(s *State, e *ssafn, f *ssa.Func) { From 59758157e384f457c266063bd38c156d2d71d02a Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Fri, 24 Jul 2026 14:12:39 -0400 Subject: [PATCH 02/21] cmd/compile/internal/ssa: remove test dependence on Compile This change adds a simple helper for running passes in a test without doing a full compile. This will allow splitting ssa.Compile into a separate package, ssacompile, in the next cl. For #80409 Change-Id: I17b7be7cfb0502184c6a3636e52952c06a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/806161 Reviewed-by: Keith Randall Reviewed-by: Michael Matloob Reviewed-by: Cherry Mui LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/cmd/compile/internal/ssa/shift_test.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index 3ec4dca76a8ff4..08c6cd8a638185 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -43,7 +43,7 @@ func makeConstShiftFunc(c *Conf, amount int64, op Op, typ *types.Type) fun { Valu("shift", op, typ, 0, nil, "load", "c"), Valu("store", OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "shift", "mem"), Exit("store"))) - Compile(fun.f, nil) + runPasses(fun.f) return fun } @@ -102,6 +102,19 @@ func makeShiftExtensionFunc(c *Conf, amount int64, lshift, rshift Op, typ *types Valu("rshift", rshift, typ, 0, nil, "lshift", "c"), Valu("store", OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "rshift", "mem"), Exit("store"))) - Compile(fun.f, nil) + runPasses(fun.f) return fun } + +// runPasses is a simplified version of Compile that runs the passes +// for the tests in this file. +func runPasses(f *Func) { + for i := range passes { + p := &passes[i] + if !f.Config.optimize && !p.required || p.disabled { + continue + } + f.pass = p + p.fn(f) + } +} From 63bf1f763dc299951bbcc1db482f67984c8e52a6 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Fri, 31 Jul 2026 11:41:35 -0400 Subject: [PATCH 03/21] crypto/x509: use FIPS140 helper for x509-limbo skip In the x509-limbo path-building tests rather than checking fips140.Version() directly, let's use cryptotest.MustMinimumFIPS140ModuleVersion() with the module version that added ML-DSA support. Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest Change-Id: I96b5b74b5c9a0a4b69ab2484a5a650aa5dc3a862 Reviewed-on: https://go-review.googlesource.com/c/go/+/808540 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Mark Freeman Auto-Submit: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: Filippo Valsorda --- src/crypto/x509/x509limbo_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/crypto/x509/x509limbo_test.go b/src/crypto/x509/x509limbo_test.go index dd67ab4acb148b..86578561af805a 100644 --- a/src/crypto/x509/x509limbo_test.go +++ b/src/crypto/x509/x509limbo_test.go @@ -5,7 +5,6 @@ package x509 import ( - "crypto/fips140" "crypto/internal/cryptotest" "crypto/internal/cryptotest/x509limbo" "encoding/json" @@ -206,8 +205,8 @@ func TestX509Limbo(t *testing.T) { t.Skipf("name constraints for DirectoryNames are not supported") } - if slices.Contains(tc.Features, x509limbo.FeatureHasMldsa) && fips140.Version() == "v1.0.0" { - t.Skipf("ML-DSA is not available in FIPS 140-3 module v1.0.0") + if slices.Contains(tc.Features, x509limbo.FeatureHasMldsa) { + cryptotest.MustMinimumFIPS140ModuleVersion(t, "v1.26.0") } if len(tc.SignatureAlgorithms) != 0 { From 422cc1b8a7645c5685be7326d240edd070ead231 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Mon, 27 Jul 2026 11:03:24 -0400 Subject: [PATCH 04/21] crypto/x509: update go-jsonschema, simplify time handling This commit updates the crypto/internal/cryptotest modules that generate Go code from JSON schemas to use the latest atombender/go-jsonschema release instead of a replace fork. Previously we had this pointed at a PR branch with a bugfix that has since been merged. The updated tooling handles time fields better so after regenerating the x509-limbo schema we can simplify some TestX509Limbo logic. The Wycheproof generated code is 1:1 across tooling updates. Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest Change-Id: I66d7a0dcb8b69ad8fac79648c4d2a78a0ddd4b97 Reviewed-on: https://go-review.googlesource.com/c/go/+/809460 Reviewed-by: Filippo Valsorda Reviewed-by: Mark Freeman LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Roland Shoemaker --- .../internal/cryptotest/wycheproof/_schema/go.mod | 4 +--- .../internal/cryptotest/wycheproof/_schema/go.sum | 4 ++-- .../internal/cryptotest/x509limbo/_schema/go.mod | 2 +- .../internal/cryptotest/x509limbo/_schema/go.sum | 4 ++-- src/crypto/internal/cryptotest/x509limbo/schema.go | 4 +--- src/crypto/x509/x509limbo_test.go | 10 +--------- 6 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod b/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod index d7c20ce6f6d307..f5d0b8da2d315b 100644 --- a/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod +++ b/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod @@ -3,7 +3,7 @@ module crypto/internal/cryptotest/wycheproof/_schema go 1.26.4 require ( - github.com/atombender/go-jsonschema v0.23.1 + github.com/atombender/go-jsonschema v0.24.1 github.com/c2sp/wycheproof v0.0.0-20260625212325-ee7b4f7e6119 ) @@ -15,5 +15,3 @@ require ( github.com/sanity-io/litter v1.5.8 // indirect github.com/sosodev/duration v1.4.0 // indirect ) - -replace github.com/atombender/go-jsonschema => github.com/filippo-claude/go-jsonschema v0.23.2-0.20260625215234-f867483bec31 diff --git a/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum b/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum index 5ad2f74b721e16..386610162f409b 100644 --- a/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum +++ b/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum @@ -1,12 +1,12 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/atombender/go-jsonschema v0.24.1 h1:Vb2JHFA0AxtMl8F1ecrpMQ3uQ2Cxm0HgpX1ZyInY0Lc= +github.com/atombender/go-jsonschema v0.24.1/go.mod h1:yYMQVvK3WlxXJIpciA84rKg/xf2VCxIsxNt9I7Ugvmw= github.com/c2sp/wycheproof v0.0.0-20260625212325-ee7b4f7e6119 h1:jOCu6erj86P93+eFn8Qxp6XLwftn1nW0C9RUx7xZwZg= github.com/c2sp/wycheproof v0.0.0-20260625212325-ee7b4f7e6119/go.mod h1:/5JsOpi3fKmnnig5BQ2mz49TNtnrD308VfTVHcbr5x4= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/filippo-claude/go-jsonschema v0.23.2-0.20260625215234-f867483bec31 h1:c2W1mlsq9K/W+GPQWycHmGxTq4/RkWgDHOY99K+rtaw= -github.com/filippo-claude/go-jsonschema v0.23.2-0.20260625215234-f867483bec31/go.mod h1:4SrgNrwGKijxhewvpPQ8HKEbin5Q2N4Tk+pFKW77HEk= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= diff --git a/src/crypto/internal/cryptotest/x509limbo/_schema/go.mod b/src/crypto/internal/cryptotest/x509limbo/_schema/go.mod index bfb3d5ce6bca92..e67e1c6e4d85a2 100644 --- a/src/crypto/internal/cryptotest/x509limbo/_schema/go.mod +++ b/src/crypto/internal/cryptotest/x509limbo/_schema/go.mod @@ -2,7 +2,7 @@ module crypto/internal/cryptotest/x509limbo/_schema go 1.26 -require github.com/atombender/go-jsonschema v0.23.1 +require github.com/atombender/go-jsonschema v0.24.1 require ( dario.cat/mergo v1.0.2 // indirect diff --git a/src/crypto/internal/cryptotest/x509limbo/_schema/go.sum b/src/crypto/internal/cryptotest/x509limbo/_schema/go.sum index fef1f2b29fb0b3..5c491c89cd3ada 100644 --- a/src/crypto/internal/cryptotest/x509limbo/_schema/go.sum +++ b/src/crypto/internal/cryptotest/x509limbo/_schema/go.sum @@ -1,7 +1,7 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= -github.com/atombender/go-jsonschema v0.23.1 h1:hpj94ehS+gpVvd1NJSTE0BMtWIpab06ObCz57rwo37c= -github.com/atombender/go-jsonschema v0.23.1/go.mod h1:4SrgNrwGKijxhewvpPQ8HKEbin5Q2N4Tk+pFKW77HEk= +github.com/atombender/go-jsonschema v0.24.1 h1:Vb2JHFA0AxtMl8F1ecrpMQ3uQ2Cxm0HgpX1ZyInY0Lc= +github.com/atombender/go-jsonschema v0.24.1/go.mod h1:yYMQVvK3WlxXJIpciA84rKg/xf2VCxIsxNt9I7Ugvmw= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/src/crypto/internal/cryptotest/x509limbo/schema.go b/src/crypto/internal/cryptotest/x509limbo/schema.go index 2b0a1c440b0b06..28958061138ba9 100644 --- a/src/crypto/internal/cryptotest/x509limbo/schema.go +++ b/src/crypto/internal/cryptotest/x509limbo/schema.go @@ -462,7 +462,7 @@ type Testcase struct { ValidationKind ValidationKind `json:"validation_kind"` // The time at which to perform the validation - ValidationTime interface{} `json:"validation_time,omitempty,omitzero"` + ValidationTime *time.Time `json:"validation_time,omitempty,omitzero"` } // For server (i.e. client-side) validation: the expected peer name, if any @@ -501,8 +501,6 @@ type TestcaseMaxChainDepth_0 *int type TestcasePeerCertificateKey_0 *string -type TestcaseValidationTime_0 *time.Time - // UnmarshalJSON implements json.Unmarshaler. func (j *Testcase) UnmarshalJSON(value []byte) error { var raw map[string]interface{} diff --git a/src/crypto/x509/x509limbo_test.go b/src/crypto/x509/x509limbo_test.go index 86578561af805a..c1fcee42bf93bc 100644 --- a/src/crypto/x509/x509limbo_test.go +++ b/src/crypto/x509/x509limbo_test.go @@ -267,15 +267,7 @@ func TestX509Limbo(t *testing.T) { validationTime := time.Now() if tc.ValidationTime != nil { - vtStr, ok := tc.ValidationTime.(string) - if !ok { - t.Fatalf("validation time is not a string: %T %v", tc.ValidationTime, tc.ValidationTime) - } - parsed, err := time.Parse(time.RFC3339, vtStr) - if err != nil { - t.Fatalf("invalid validation time %q: %v", vtStr, err) - } - validationTime = parsed + validationTime = *tc.ValidationTime } var ekus []ExtKeyUsage From c1da31bba100561ecde96bf66fe0a730fd1aada5 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 22 Jul 2026 13:07:05 +0200 Subject: [PATCH 05/21] crypto/tls: check FIPS 140-3 compliance of leaf even with InsecureSkipVerify Fixes #80074 Change-Id: I5c619a090293a7668e26699c29b194a56a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/804200 Reviewed-by: Daniel McCarney Auto-Submit: Filippo Valsorda Reviewed-by: Mark Freeman LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Cherry Mui --- src/crypto/tls/fips140_test.go | 52 ++++++++++++++++++++++++++++++ src/crypto/tls/handshake_client.go | 6 ++++ src/crypto/tls/handshake_server.go | 6 ++++ 3 files changed, 64 insertions(+) diff --git a/src/crypto/tls/fips140_test.go b/src/crypto/tls/fips140_test.go index c3f6ec917b5632..571fe896e1d408 100644 --- a/src/crypto/tls/fips140_test.go +++ b/src/crypto/tls/fips140_test.go @@ -570,6 +570,58 @@ func TestFIPSCertAlgs(t *testing.T) { } } +func TestFIPSCertificateWithoutVerification(t *testing.T) { + badCert := fipsCert(t, "L", fipsRSAKey(t, 1024), nil, fipsCertLeaf) + + serverCert := func(t *testing.T, version uint16) (clientErr, serverErr error) { + clientConfig := testConfigFIPS140.Clone() + clientConfig.InsecureSkipVerify = true + clientConfig.MinVersion = version + clientConfig.MaxVersion = version + serverConfig := testConfigFIPS140.Clone() + serverConfig.Certificates = []Certificate{{Certificate: [][]byte{badCert.der}, PrivateKey: badCert.key}} + serverConfig.MinVersion = version + serverConfig.MaxVersion = version + return fipsHandshake(t, clientConfig, serverConfig) + } + + clientCert := func(t *testing.T, version uint16) (clientErr, serverErr error) { + clientConfig := testConfigFIPS140.Clone() + clientConfig.InsecureSkipVerify = true + clientConfig.Certificates = []Certificate{{Certificate: [][]byte{badCert.der}, PrivateKey: badCert.key}} + clientConfig.MinVersion = version + clientConfig.MaxVersion = version + serverConfig := testConfigFIPS140.Clone() + serverConfig.ClientAuth = RequireAnyClientCert + serverConfig.MinVersion = version + serverConfig.MaxVersion = version + return fipsHandshake(t, clientConfig, serverConfig) + } + + for _, version := range []uint16{VersionTLS12, VersionTLS13} { + t.Run(VersionName(version), func(t *testing.T) { + runWithFIPSDisabled(t, func(t *testing.T) { + if clientErr, serverErr := serverCert(t, version); clientErr != nil { + t.Errorf("server cert: expected success; client error: %v; server error: %v", clientErr, serverErr) + } + if clientErr, serverErr := clientCert(t, version); serverErr != nil { + t.Errorf("client cert: expected success; client error: %v; server error: %v", clientErr, serverErr) + } + }) + + runWithFIPSEnabled(t, func(t *testing.T) { + const want = "not allowed in FIPS 140-3 mode" + if clientErr, _ := serverCert(t, version); clientErr == nil || !strings.Contains(clientErr.Error(), want) { + t.Errorf("server cert: got client error %v, want error containing %q", clientErr, want) + } + if _, serverErr := clientCert(t, version); serverErr == nil || !strings.Contains(serverErr.Error(), want) { + t.Errorf("client cert: got server error %v, want error containing %q", serverErr, want) + } + }) + }) + } +} + const ( fipsCertCA = iota fipsCertLeaf diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index 74389458f5b214..8bdef57bb42463 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -1174,6 +1174,12 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { } } + if fips140tls.Required() && !isCertificateAllowedFIPS(certs[0]) { + c.sendAlert(alertBadCertificate) + err := errors.New("server's certificate is not allowed in FIPS 140-3 mode") + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + switch certs[0].PublicKey.(type) { case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: case *mldsa.PublicKey: diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index a05d6c896bf02f..3991f212c1f8a1 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -1003,6 +1003,12 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error { c.scts = certificate.SignedCertificateTimestamps if len(certs) > 0 { + if fips140tls.Required() && !isCertificateAllowedFIPS(certs[0]) { + c.sendAlert(alertBadCertificate) + err := errors.New("client's certificate is not allowed in FIPS 140-3 mode") + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + switch certs[0].PublicKey.(type) { case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey: case *mldsa.PublicKey: From de08649b3352b647f7f5358e505a717baabc0ddd Mon Sep 17 00:00:00 2001 From: cuishuang Date: Tue, 28 Jul 2026 10:30:15 +0800 Subject: [PATCH 06/21] net/rpc: remove unused sort.Interface methods The RPC debug handler now uses slices.SortFunc to sort services and methods. The Len, Less, and Swap methods on serviceArray and methodArray are no longer used. Remove the obsolete sorting methods. This change does not affect the sorting behavior. Change-Id: I8293beb388efb24594d0baf2217fa0d58491112d Reviewed-on: https://go-review.googlesource.com/c/go/+/806660 Reviewed-by: Cherry Mui Auto-Submit: Sean Liao LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Mark Freeman Reviewed-by: Sean Liao --- src/net/rpc/debug.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/net/rpc/debug.go b/src/net/rpc/debug.go index 81d4ea368563e4..b1ec2f785bb825 100644 --- a/src/net/rpc/debug.go +++ b/src/net/rpc/debug.go @@ -57,14 +57,6 @@ type debugService struct { type serviceArray []debugService -func (s serviceArray) Len() int { return len(s) } -func (s serviceArray) Less(i, j int) bool { return s[i].Name < s[j].Name } -func (s serviceArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func (m methodArray) Len() int { return len(m) } -func (m methodArray) Less(i, j int) bool { return m[i].Name < m[j].Name } -func (m methodArray) Swap(i, j int) { m[i], m[j] = m[j], m[i] } - type debugHTTP struct { *Server } From 78f2c18ad22613bcdc611266606c1237ec7e6bd8 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Tue, 28 Jul 2026 15:20:19 +0800 Subject: [PATCH 07/21] net/mail: use B encoding for display names containing backslash Address.String uses MIME Q encoding for non-ASCII display names unless the name contains a character that cannot appear unencoded in an encoded-word in a phrase. A backslash was missing from this set. mime.QEncoding leaves backslashes unencoded, so Address.String could produce output that ParseAddress could not parse. Select B encoding for display names containing a backslash, and add a round-trip test. Fixes golang/go#80592 Change-Id: I53f8fab709bace922914b579c283bb71877c6be7 Reviewed-on: https://go-review.googlesource.com/c/go/+/806681 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Auto-Submit: Sean Liao Reviewed-by: Mark Freeman Reviewed-by: Sean Liao Reviewed-by: Cherry Mui --- src/net/mail/message.go | 2 +- src/net/mail/message_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/net/mail/message.go b/src/net/mail/message.go index 81acf018edd039..94553c193a6139 100644 --- a/src/net/mail/message.go +++ b/src/net/mail/message.go @@ -321,7 +321,7 @@ func (a *Address) String() string { // Text in an encoded-word in a display-name must not contain certain // characters like quotes or parentheses (see RFC 2047 section 5.3). // When this is the case encode the name using base64 encoding. - if strings.ContainsAny(a.Name, "\"#$%&'(),.:;<>@[]^`{|}~") { + if strings.ContainsAny(a.Name, "\\\"#$%&'(),.:;<>@[]^`{|}~") { return mime.BEncoding.Encode("utf-8", a.Name) + " " + s } return mime.QEncoding.Encode("utf-8", a.Name) + " " + s diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go index 2c1198a698cf4a..c606dd930411e5 100644 --- a/src/net/mail/message_test.go +++ b/src/net/mail/message_test.go @@ -1260,6 +1260,7 @@ func TestAddressFormattingAndParsing(t *testing.T) { {Name: "Böb ???", Address: "bob@example.com"}, {Name: "Böb (Jacöb)", Address: "bob@example.com"}, {Name: "à#$%&'(),.:;<>@[]^`{|}~'", Address: "bob@example.com"}, + {Name: `é\`, Address: "user@example.com"}, // https://golang.org/issue/11292 {Name: "\"\\\x1f,\"", Address: "0@0"}, // https://golang.org/issue/12782 From 921529fd83a0629b33d63e6defa1f05a4eb98d3f Mon Sep 17 00:00:00 2001 From: harjoth Date: Tue, 28 Jul 2026 08:54:42 -0700 Subject: [PATCH 08/21] cmd/go: allow dashes in pkg-config variable values The pkg-config --define-variable flag carries its value inside a single argument. Its validator rejects '-' or '@' anywhere in that value, so it also rejects valid values such as paths containing hyphens, which worked before the pkg-config flag allowlist was added. Allow '-' and '@' after the first character, following the pattern used for --with-path. A leading '-' or '@' is still rejected, since a .pc file may pass the value on to another program, where it could be read as a flag or as a response file. Add direct validator coverage and a script test that exercises the complete cgo build path with a fake pkg-config tool. Fixes #79330 Change-Id: I64d9f5ca9104ee3da73848aa77f6e5d1d684ee1f Reviewed-on: https://go-review.googlesource.com/c/go/+/806860 Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Mark Freeman Reviewed-by: Cherry Mui --- src/cmd/go/internal/work/security.go | 2 +- src/cmd/go/internal/work/security_test.go | 27 +++++++++++++++ .../script/cgo_pkgconfig_define_variable.txt | 33 +++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/cgo_pkgconfig_define_variable.txt diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index be3f1a25336bef..1398f123c92672 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -260,7 +260,7 @@ var validPkgConfigFlags = []*lazyregexp.Regexp{ re(`--cflags-only-I`), re(`--cflags`), re(`--define-prefix`), - re(`--define-variable=[A-Za-z_][A-Za-z0-9_]*=[^@\-]*`), + re(`--define-variable=[A-Za-z_][A-Za-z0-9_]*=[^@\-].*`), re(`--digraph`), re(`--dont-define-prefix`), re(`--dont-relocate-paths`), diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index 68f0ea3770fe56..0b8219b5dc74f5 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -308,6 +308,33 @@ func TestCheckLinkerFlags(t *testing.T) { } } +func TestCheckPkgConfigFlags(t *testing.T) { + good := [][]string{ + {"--define-variable=A=b-c"}, + {"--define-variable=A=b@c"}, + {"--define-variable=prefix=/opt/my-pkg/lib"}, + } + for _, f := range good { + if err := checkPkgConfigFlags("test", "test", f); err != nil { + t.Errorf("unexpected error for %q: %v", f, err) + } + } + + bad := [][]string{ + {"--define-variable=A=-b"}, + {"--define-variable=A=@b"}, + {"--define-variable=A="}, + {"--define-variable=1A=b"}, + {"--define-variable=A"}, + {"--log-file=/tmp/log"}, + } + for _, f := range bad { + if err := checkPkgConfigFlags("test", "test", f); err == nil { + t.Errorf("missing error for %q", f) + } + } +} + func TestCheckFlagAllowDisallow(t *testing.T) { if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil { t.Fatalf("missing error for -disallow") diff --git a/src/cmd/go/testdata/script/cgo_pkgconfig_define_variable.txt b/src/cmd/go/testdata/script/cgo_pkgconfig_define_variable.txt new file mode 100644 index 00000000000000..89a400b0bf9fa7 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_pkgconfig_define_variable.txt @@ -0,0 +1,33 @@ +[!cgo] skip +[short] skip + +go build -o $WORK/pkg-config$GOEXE ./pkgconfig +env PKG_CONFIG=$WORK/pkg-config$GOEXE +go build ./p + +-- go.mod -- +module example + +go 1.27 +-- pkgconfig/main.go -- +package main + +import ( + "fmt" + "os" +) + +func main() { + for _, arg := range os.Args { + if arg == "--define-variable=A=b-c" { + return + } + } + fmt.Fprintln(os.Stderr, "missing --define-variable argument") + os.Exit(1) +} +-- p/p.go -- +package p + +// #cgo pkg-config: --define-variable=A=b-c example +import "C" From e1943591f0958466506b2bd360658122b656571b Mon Sep 17 00:00:00 2001 From: dorbmon Date: Tue, 28 Jul 2026 16:28:43 -0400 Subject: [PATCH 09/21] bytes, strings: remove redundant DecodeRune fast paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CL 699675 made utf8.DecodeRune and utf8.DecodeRuneInString inlineable, including their ASCII fast paths. The manual ASCII decoding fast paths added in CL 793620 are therefore redundant. Call the UTF-8 decoding functions directly. On linux/amd64, using benchstat over 10 runs: goos: linux goarch: amd64 pkg: bytes cpu: Intel(R) Core(TM) i7-14700KF │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ TrimSpace/SomeNonASCII-20 22.44n ± 1% 22.38n ± 1% ~ (p=0.171 n=10) TrimSpace/JustNonASCII-20 28.37n ± 1% 28.39n ± 1% ~ (p=0.839 n=10) geomean 25.23n 25.21n -0.08% pkg: strings │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ TrimSpace/SomeNonASCII-20 25.41n ± 1% 25.38n ± 1% ~ (p=0.305 n=10) TrimSpace/JustNonASCII-20 31.81n ± 1% 31.82n ± 0% ~ (p=0.813 n=10) geomean 28.44n 28.42n -0.05% Change-Id: I317e5bd6d1dcf3a3aed58c8303d1002b71004507 Reviewed-on: https://go-review.googlesource.com/c/go/+/807060 Auto-Submit: Sean Liao LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Cherry Mui Reviewed-by: Mark Freeman Reviewed-by: Sean Liao --- src/bytes/bytes.go | 5 +---- src/strings/strings.go | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go index 669d5b01b9ffc7..c46b92fd0d1141 100644 --- a/src/bytes/bytes.go +++ b/src/bytes/bytes.go @@ -1109,10 +1109,7 @@ func trimRightUnicode(s []byte, cutset string) []byte { func trimSpaceUnicode(s []byte) []byte { for len(s) > 0 { - r, n := rune(s[0]), 1 - if r >= utf8.RuneSelf { - r, n = utf8.DecodeRune(s) - } + r, n := utf8.DecodeRune(s) if !stringslite.IsSpace(r) { break } diff --git a/src/strings/strings.go b/src/strings/strings.go index d366d52e1e6610..8cb1f0e115b03f 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -1085,10 +1085,7 @@ func trimRightUnicode(s, cutset string) string { func trimSpaceUnicode(s string) string { for len(s) > 0 { - r, n := rune(s[0]), 1 - if r >= utf8.RuneSelf { - r, n = utf8.DecodeRuneInString(s) - } + r, n := utf8.DecodeRuneInString(s) if !stringslite.IsSpace(r) { break } From 94cfdcfbac1d5475ff3623ab69dc12b4bd09277e Mon Sep 17 00:00:00 2001 From: Archana Ravindar Date: Wed, 29 Jul 2026 15:34:27 +0530 Subject: [PATCH 10/21] internal/stringslite: fix performance regression in index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix performance regression by restoring original behavior of index function of selecting IndexString vs IndexRabinKarp by introducing guard n>bytealg.MaxLen. At present, the condition else if fails >= 4+i>>4 is reachable when n <= bytealg.MaxLen, which was structurally impossible in 1.26.5, this ends up calling IndexRabinKarp almost all the time leading to slower performance. Regression bisected to the following change https://go-review.googlesource.com/c/go/+/741340 which tried to combine two duplicate loops, adding the guard n > bytealg.MaxLen restores the original behavior while keeping the loops combined. Multiple strings tests improve, none of them regress, pasting performance of a subset of tests that improve the maximum. The change should create similar improvements on other platforms too as it increases the frequency of calling vectorized assembly for index computation. Fixes #80638 goos: linux goarch: amd64 pkg: strings cpu: 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz │ baseline.txt │ new.txt │ │ sec/op │ sec/op vs base │ CountHard1-8 1157.30µ ± 1% 82.65µ ± 6% -92.86% (p=0.000 n=10) CountHard2-8 1159.5µ ± 2% 116.8µ ± 5% -89.93% (p=0.000 n=10) CountHard3-8 1172.3µ ± 2% 373.1µ ± 2% -68.17% (p=0.000 n=10) geomean 1.163m 153.3µ -86.82% Change-Id: Ia9d1b094273751e25bbd2e536ac169363228e7e1 Reviewed-on: https://go-review.googlesource.com/c/go/+/807360 Auto-Submit: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Mark Freeman Reviewed-by: Keith Randall LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/internal/stringslite/strings.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/stringslite/strings.go b/src/internal/stringslite/strings.go index c74eb961237758..5f5839f66cdd1a 100644 --- a/src/internal/stringslite/strings.go +++ b/src/internal/stringslite/strings.go @@ -65,7 +65,7 @@ func Index(s, substr string) int { return r + i } return -1 - } else if fails >= 4+i>>4 && i < t { + } else if n > bytealg.MaxLen && fails >= 4+i>>4 && i < t { // See comment in ../bytes/bytes.go. j := bytealg.IndexRabinKarp(s[i:], substr) if j < 0 { From d53d7a4f3325db43e2423973fa6a524250bba37b Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Thu, 30 Jul 2026 19:00:03 +1000 Subject: [PATCH 11/21] test/codegen: add XSubXandYAndn code generation tests for arm64 and riscv64 Note that ANDN is generated on all riscv64 profiles - the assembler synthesises ANDN in the case the instruction cannot be used directly. Change-Id: I8c6492a24eaa82b30cc631f0ef091fd4c794e774 Reviewed-on: https://go-review.googlesource.com/c/go/+/807900 Reviewed-by: Jorropo Auto-Submit: Joel Sing Reviewed-by: Julian Zhu Reviewed-by: Cherry Mui LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Mark Freeman Auto-Submit: Jorropo --- test/codegen/bmi.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/codegen/bmi.go b/test/codegen/bmi.go index 3c00dd328bd5b9..e9ae079ce437ef 100644 --- a/test/codegen/bmi.go +++ b/test/codegen/bmi.go @@ -211,11 +211,15 @@ func shlrx32_load(x []uint32, i int, s uint32) uint32 { func XSubXandYAndn64(x, y uint64) uint64 { // amd64/v1:"ANDQ" "NOTQ" -"SUBQ" // amd64/v3:"ANDNQ" -"SUBQ" -"ANDQ" + // arm64:"BIC" -"SUB" -"AND" + // riscv64:"ANDN" -"SUB" -"AND " return x - (x & y) } func XSubXandYAndn32(x, y uint32) uint32 { // amd64/v1:"ANDL" "NOTL" -"SUBL" // amd64/v3:"ANDNL" -"SUBL" -"ANDL" + // arm64:"BIC" -"SUB" -"AND" + // riscv64:"ANDN" -"SUB" -"AND " return x - (x & y) } From 40fd497af5a5eb360e63393d87b12622c6fc788e Mon Sep 17 00:00:00 2001 From: Nick Ripley Date: Fri, 31 Jul 2026 12:59:40 -0400 Subject: [PATCH 12/21] runtime: fix frame pointer adjustment around injected calls This CL addresses two bugs related to moving goroutine stacks during injected function calls. The runtime injects calls during asynchronous preemption, when handling signals that get turned into panics (sigpanic), and for calls injected by a debugger. If a function triggers a sigpanic, and there is no way to resume execution in the function (such as through a deferred function), then that function's call frame is skipped during stack copying. The reasoning is that its locals, arguments, etc are dead. However, the call frame might contain a frame pointer. We can visit that frame pointer with the execution tracer or block/mutex profilers. If we visit that frame pointer after stack movement, it can point into the old stack. Following it will crash. This CL fixes this by adjusting the frame pointer if there is one. But it still skips the rest of the work, which is unnecessary. For arm64, there is an additonal frame pointer adjustment we're missing. Injected call frames are placed 16 bytes below the stack pointer at the point of call injection. This gap is needed both to avoid clobbering the frame pointer saved below the original function's call frame, and to have space to save the link register so it can be restored when the injected call returns. Normally when function A calls function B, the frame pointer saved below function A's frame is fixed when adjusting function B's frame. But because of the gap in the case of injection, the frame pointer saved by the original function isn't inside any call frame. We need to fix it when visiting the injected call frame. The regression test uses stackPoisonCopy so that the old stack is filled with garbage and frame pointer unwinding will reliably crash. Otherwise we'd only see a crash if something else happens to reuse the old stack space. Fixes #73664 Change-Id: I600d7942521e90852c67e379679b07e96a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/730200 Reviewed-by: Mark Freeman LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Cherry Mui --- src/runtime/callers_test.go | 24 +++++++++++++++++++ src/runtime/export_test.go | 10 ++++++++ src/runtime/stack.go | 47 ++++++++++++++++++++++++++++++------- src/runtime/traceback.go | 6 ++++- 4 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/runtime/callers_test.go b/src/runtime/callers_test.go index 9429442fc08d39..5a7369be2d5ce2 100644 --- a/src/runtime/callers_test.go +++ b/src/runtime/callers_test.go @@ -487,3 +487,27 @@ func TestFPUnwindAfterRecovery(t *testing.T) { }() panic(1) } + +//go:noinline +func deref() int { + var i *int + runtime.KeepAlive(&i) + return *i +} + +func TestFPUnwindStackGrowthAfterRecovery(t *testing.T) { + if !runtime.FramePointerEnabled { + t.Skip("frame pointers not supported for this architecture") + } + state := runtime.StackPoisonCopy() + defer state.Restore() + defer func() { + if recover() == nil { + t.Fatal("did not recover from panic") + } + growStack(nil) + var pcs [32]uintptr + runtime.FPCallers(pcs[:]) + }() + deref() +} diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 1239bfabbf2c04..ae5c5168502f0c 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -453,6 +453,16 @@ func ShrinkStackAndVerifyFramePointers() { FPCallers(make([]uintptr, 1024)) } +type StackPoisonCopyRestore int + +func (s StackPoisonCopyRestore) Restore() { stackPoisonCopy = int(s) } + +func StackPoisonCopy() StackPoisonCopyRestore { + before := stackPoisonCopy + stackPoisonCopy = 1 + return StackPoisonCopyRestore(before) +} + // BlockOnSystemStack switches to the system stack, prints "x\n" to // stderr, and blocks in a stack containing // "runtime.blockOnSystemStackInternal". diff --git a/src/runtime/stack.go b/src/runtime/stack.go index 6f89cc142c39f0..838090067a1769 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -699,15 +699,6 @@ func adjustpointers(scanp unsafe.Pointer, bv *bitvector, adjinfo *adjustinfo, f // Note: the argument/return area is adjusted by the callee. func adjustframe(frame *stkframe, adjinfo *adjustinfo) { - if frame.continpc == 0 { - // Frame is dead. - return - } - f := frame.fn - if stackDebug >= 2 { - print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n") - } - // Adjust saved frame pointer if there is one. if (goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.ARM64) && frame.argp-frame.varp == 2*goarch.PtrSize { if stackDebug >= 3 { @@ -729,6 +720,44 @@ func adjustframe(frame *stkframe, adjinfo *adjustinfo) { // by the caller in its frame (one word below its SP). adjustpointer(adjinfo, unsafe.Pointer(frame.varp)) } + if goarch.ArchFamily == goarch.ARM64 && isInjectedCall(frame.fn.funcID) { + // If this is an injected call on arm64, then we need to adjust + // the frame pointer saved by the original function into which + // the call was injected. Normally this would be handled when + // adjusting the callee's frame or in adjustctxt. But when a + // call is injected, the frame is placed 16 bytes below the + // original stack pointer to make room to save the link + // register, and the frame pointer saved by the original + // function isn't inside any call frame. We can adjust that + // saved frame pointer here by looking just above frame.fp. + // + // ^ original call ^ + // | frame above... | + // +-------------------+ <- stack pointer at the time of injection + // : FP saved by : + // : original func : + // :···················: <- frame pointer register from original function + // : LR saved during : + // : injection : + // +-------------------+ <- frame.fp (injection decrements SP by 16 bytes) + // | FP saved | + // | during injection | + // +-------------------+ + // | injected call | + // V frame below... V + adjustpointer(adjinfo, unsafe.Pointer(frame.fp+goarch.PtrSize)) + } + + if frame.continpc == 0 { + // Frame is dead. The program might still see the frame pointer + // saved in the frame, adjusted above, but we don't need to + // adjust the rest of the frame. + return + } + f := frame.fn + if stackDebug >= 2 { + print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n") + } locals, args, objs := frame.getStackMap(true) diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index e05075432df93a..58161dee06bddb 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -438,6 +438,10 @@ func (u *unwinder) resolveInternal(innermost, isSyscall bool) { } } +func isInjectedCall(id abi.FuncID) bool { + return id == abi.FuncID_sigpanic || id == abi.FuncID_asyncPreempt || id == abi.FuncID_debugCallV2 +} + func (u *unwinder) next() { frame := &u.frame f := frame.fn @@ -482,7 +486,7 @@ func (u *unwinder) next() { throw("traceback stuck") } - injectedCall := f.funcID == abi.FuncID_sigpanic || f.funcID == abi.FuncID_asyncPreempt || f.funcID == abi.FuncID_debugCallV2 + injectedCall := isInjectedCall(f.funcID) if injectedCall { u.flags |= unwindTrap } else { From 50f76abc2693286ae66ce531a5a8d8582ea706b8 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sat, 23 May 2026 00:15:51 +0200 Subject: [PATCH 13/21] crypto/x509: add ML-KEM support to PKIX/PKCS#8 parsing and marshaling Fixes #79225 Change-Id: I51cf9587969af8273a6ebb479f7a0c7f6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/781844 Reviewed-by: Cherry Mui Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Mark Freeman --- src/crypto/x509/parser.go | 14 + src/crypto/x509/pkcs8.go | 58 +++- src/crypto/x509/x509.go | 26 +- src/crypto/x509/x509_test.go | 556 +++++++++++++++++++++++++++++++++++ 4 files changed, 647 insertions(+), 7 deletions(-) diff --git a/src/crypto/x509/parser.go b/src/crypto/x509/parser.go index 4a1416e314d811..34bc6006c8a4b5 100644 --- a/src/crypto/x509/parser.go +++ b/src/crypto/x509/parser.go @@ -11,6 +11,7 @@ import ( "crypto/ecdsa" "crypto/ed25519" "crypto/mldsa" + "crypto/mlkem" "crypto/rsa" "crypto/x509/pkix" "encoding/asn1" @@ -379,6 +380,19 @@ func parsePublicKey(keyData *publicKeyInfo) (any, error) { return nil, errors.New("x509: X25519 key encoded with illegal parameters") } return ecdh.X25519().NewPublicKey(data) + case oid.Equal(oidPublicKeyMLKEM768): + // RFC 9935, Section 3 + // > The parameters field of the AlgorithmIdentifier for the ML-KEM + // > public key MUST be absent. + if len(params.FullBytes) != 0 { + return nil, errors.New("x509: ML-KEM-768 key encoded with illegal parameters") + } + return mlkem.NewEncapsulationKey768(data) + case oid.Equal(oidPublicKeyMLKEM1024): + if len(params.FullBytes) != 0 { + return nil, errors.New("x509: ML-KEM-1024 key encoded with illegal parameters") + } + return mlkem.NewEncapsulationKey1024(data) case oid.Equal(oidPublicKeyDSA): der := cryptobyte.String(data) y := new(big.Int) diff --git a/src/crypto/x509/pkcs8.go b/src/crypto/x509/pkcs8.go index 1c2f2172bb2cf7..808b33184c34bf 100644 --- a/src/crypto/x509/pkcs8.go +++ b/src/crypto/x509/pkcs8.go @@ -9,6 +9,7 @@ import ( "crypto/ecdsa" "crypto/ed25519" "crypto/mldsa" + "crypto/mlkem" "crypto/rsa" "crypto/x509/pkix" "encoding/asn1" @@ -28,9 +29,10 @@ type pkcs8 struct { // ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form. // -// It returns a *[rsa.PrivateKey], an *[ecdsa.PrivateKey], an [ed25519.PrivateKey] (not -// a pointer), a *[mldsa.PrivateKey], or an *[ecdh.PrivateKey] (for X25519). -// More types might be supported in the future. +// It returns a *[rsa.PrivateKey], an *[ecdsa.PrivateKey], an [ed25519.PrivateKey] +// (not a pointer), a *[mldsa.PrivateKey], an *[ecdh.PrivateKey] (for X25519), a +// *[mlkem.DecapsulationKey768], or a *[mlkem.DecapsulationKey1024]. More types +// might be supported in the future. // // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY". // @@ -120,6 +122,41 @@ func ParsePKCS8PrivateKey(der []byte) (key any, err error) { } return ecdh.X25519().NewPrivateKey(curvePrivateKey) + case privKey.Algo.Algorithm.Equal(oidPublicKeyMLKEM768), + privKey.Algo.Algorithm.Equal(oidPublicKeyMLKEM1024): + // RFC 9935, Section 3 + // > The parameters field of the AlgorithmIdentifier for the ML-KEM + // > public key MUST be absent. + if l := len(privKey.Algo.Parameters.FullBytes); l != 0 { + return nil, errors.New("x509: invalid ML-KEM private key parameters") + } + // RFC 9935, Section 6 defines a CHOICE between a seed (IMPLICIT [0] + // OCTET STRING), an expandedKey (OCTET STRING), and a SEQUENCE + // containing both. Only the seed-only format is supported. + if l := len(privKey.PrivateKey); l == 0 { + return nil, fmt.Errorf("x509: invalid ML-KEM private key length: %d", l) + } + switch privKey.PrivateKey[0] { + case 0x80: // IMPLICIT [0] OCTET STRING (seed) + case 0x04: // OCTET STRING (expandedKey) + return nil, errors.New("x509: expanded ML-KEM private keys without seed are not supported") + case 0x30: // SEQUENCE (both) + return nil, errors.New(`x509: ML-KEM private keys with both seed and expanded key are not supported, use e.g. "openssl pkey -provparam ml-kem.output_formats=seed-only" to convert to a seed-only key`) + default: + return nil, fmt.Errorf("x509: invalid ML-KEM private key: invalid ASN.1 tag %02x", privKey.PrivateKey[0]) + } + if l := len(privKey.PrivateKey); l != 2+mlkem.SeedSize { + return nil, fmt.Errorf("x509: invalid ML-KEM private key length: %d", l) + } + if privKey.PrivateKey[1] != mlkem.SeedSize { + return nil, errors.New("x509: invalid ML-KEM private key ASN.1 encoding") + } + seed := privKey.PrivateKey[2:] + if privKey.Algo.Algorithm.Equal(oidPublicKeyMLKEM768) { + return mlkem.NewDecapsulationKey768(seed) + } + return mlkem.NewDecapsulationKey1024(seed) + default: return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) } @@ -129,7 +166,8 @@ func ParsePKCS8PrivateKey(der []byte) (key any, err error) { // // The following key types are currently supported: *[rsa.PrivateKey], // *[ecdsa.PrivateKey], [ed25519.PrivateKey] (not a pointer), *[mldsa.PrivateKey], -// and *[ecdh.PrivateKey]. Unsupported key types result in an error. +// *[ecdh.PrivateKey], *[mlkem.DecapsulationKey768], and +// *[mlkem.DecapsulationKey1024]. Unsupported key types result in an error. // // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY". // @@ -188,6 +226,18 @@ func MarshalPKCS8PrivateKey(key any) ([]byte, error) { } privKey.PrivateKey = append([]byte{0x80, mldsa.PrivateKeySize}, k.Bytes()...) + case *mlkem.DecapsulationKey768: + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyMLKEM768, + } + privKey.PrivateKey = append([]byte{0x80, mlkem.SeedSize}, k.Bytes()...) + + case *mlkem.DecapsulationKey1024: + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyMLKEM1024, + } + privKey.PrivateKey = append([]byte{0x80, mlkem.SeedSize}, k.Bytes()...) + case *ecdh.PrivateKey: if k.Curve() == ecdh.X25519() { privKey.Algo = pkix.AlgorithmIdentifier{ diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 755007f543b332..fa219b53454631 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -29,6 +29,7 @@ import ( "crypto/elliptic" "crypto/fips140" "crypto/mldsa" + "crypto/mlkem" "crypto/rsa" "crypto/sha1" "crypto/sha256" @@ -67,8 +68,9 @@ type pkixPublicKey struct { // public key is a SubjectPublicKeyInfo structure (see RFC 5280, Section 4.1). // // It returns a *[rsa.PublicKey], *[dsa.PublicKey], *[ecdsa.PublicKey], -// [ed25519.PublicKey] (not a pointer), *[mldsa.PublicKey], or *[ecdh.PublicKey] -// (for X25519). More types might be supported in the future. +// [ed25519.PublicKey] (not a pointer), *[mldsa.PublicKey], *[ecdh.PublicKey] +// (for X25519), *[mlkem.EncapsulationKey768], or *[mlkem.EncapsulationKey1024]. +// More types might be supported in the future. // // This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". func ParsePKIXPublicKey(derBytes []byte) (pub any, err error) { @@ -141,6 +143,12 @@ func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.A } publicKeyAlgorithm.Parameters.FullBytes = paramBytes } + case *mlkem.EncapsulationKey768: + publicKeyBytes = pub.Bytes() + publicKeyAlgorithm.Algorithm = oidPublicKeyMLKEM768 + case *mlkem.EncapsulationKey1024: + publicKeyBytes = pub.Bytes() + publicKeyAlgorithm.Algorithm = oidPublicKeyMLKEM1024 default: return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", pub) } @@ -154,7 +162,8 @@ func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.A // // The following key types are currently supported: *[rsa.PublicKey], // *[ecdsa.PublicKey], [ed25519.PublicKey] (not a pointer), *[mldsa.PublicKey], -// and *[ecdh.PublicKey]. Unsupported key types result in an error. +// *[ecdh.PublicKey], *[mlkem.EncapsulationKey768], and +// *[mlkem.EncapsulationKey1024]. Unsupported key types result in an error. // // This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". func MarshalPKIXPublicKey(pub any) ([]byte, error) { @@ -530,6 +539,17 @@ var ( oidPublicKeyMLDSA44 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 17} oidPublicKeyMLDSA65 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 18} oidPublicKeyMLDSA87 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 19} + // RFC 9935, Section 3 + // + // id-alg-ml-kem-768 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + // country(16) us(840) organization(1) gov(101) csor(3) + // nistAlgorithm(4) kems(4) id-alg-ml-kem-768(2) } + // + // id-alg-ml-kem-1024 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + // country(16) us(840) organization(1) gov(101) csor(3) + // nistAlgorithm(4) kems(4) id-alg-ml-kem-1024(3) } + oidPublicKeyMLKEM768 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 4, 2} + oidPublicKeyMLKEM1024 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 4, 3} ) // getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index 53735bdd8e8825..acca2bfebc9dad 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -15,6 +15,7 @@ import ( "crypto/fips140" "crypto/internal/cryptotest" "crypto/mldsa" + "crypto/mlkem" "crypto/rand" "crypto/rsa" _ "crypto/sha256" @@ -4719,6 +4720,110 @@ func testMLDSA(t *testing.T, privateKeyPEM, publicKeyPEM, certPEM string) { } } +func TestMLKEM(t *testing.T) { + t.Run("ML-KEM-768", func(t *testing.T) { + testMLKEM[*mlkem.DecapsulationKey768](t, + rfc9935ExamplePrivateKeyMLKEM768, + rfc9935ExamplePublicKeyMLKEM768, + rfc9935ExampleCertificateMLKEM768) + }) + t.Run("ML-KEM-1024", func(t *testing.T) { + testMLKEM[*mlkem.DecapsulationKey1024](t, + rfc9935ExamplePrivateKeyMLKEM1024, + rfc9935ExamplePublicKeyMLKEM1024, + rfc9935ExampleCertificateMLKEM1024) + }) + + key, err := ParsePKCS8PrivateKey(pemDecode(t, rfc9935ExamplePrivateKeyMLKEM768Expanded)) + if key != nil || err == nil || !strings.Contains(err.Error(), "supported") { + t.Fatalf("ParsePKCS8PrivateKey should fail when parsing expanded ML-KEM-768 private key: got key %v, err %v", key, err) + } + key, err = ParsePKCS8PrivateKey(pemDecode(t, rfc9935ExamplePrivateKeyMLKEM768Both)) + if key != nil || err == nil || !strings.Contains(err.Error(), "supported") { + t.Fatalf("ParsePKCS8PrivateKey should fail when parsing ML-KEM-768 private key with both seed and expanded: got key %v, err %v", key, err) + } + + // CreateCertificate must reject ML-KEM subject public keys. + dk, err := mlkem.GenerateKey768() + if err != nil { + t.Fatalf("GenerateKey768: %v", err) + } + caPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("ecdsa.GenerateKey: %v", err) + } + tmpl := &Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{CommonName: "ML-KEM-768"}, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour), + } + if _, err := CreateCertificate(rand.Reader, tmpl, tmpl, dk.EncapsulationKey(), caPriv); err == nil { + t.Fatal("CreateCertificate with ML-KEM subject public key should fail") + } +} + +func testMLKEM[DK interface { + Bytes() []byte + EncapsulationKey() EK +}, EK interface { + Bytes() []byte +}](t *testing.T, privateKeyPEM, publicKeyPEM, certPEM string) { + privKey, err := ParsePKCS8PrivateKey(pemDecode(t, privateKeyPEM)) + if err != nil { + t.Fatalf("ParsePKCS8PrivateKey failed: %s", err) + } + dk, ok := privKey.(DK) + if !ok { + t.Fatalf("ParsePKCS8PrivateKey returned wrong type: got %T, want %T", privKey, *new(DK)) + } + // All the example private keys in RFC 9935, Appendix C.1 use this seed. + if hex.EncodeToString(dk.Bytes()) != "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" { + t.Fatal("ParsePKCS8PrivateKey returned wrong private key value") + } + + got, err := MarshalPKCS8PrivateKey(privKey) + if err != nil { + t.Fatalf("MarshalPKCS8PrivateKey failed: %s", err) + } + if !bytes.Equal(got, pemDecode(t, privateKeyPEM)) { + t.Fatal("MarshalPKCS8PrivateKey did not return original DER bytes") + } + + pubKey, err := ParsePKIXPublicKey(pemDecode(t, publicKeyPEM)) + if err != nil { + t.Fatalf("ParsePKIXPublicKey failed: %s", err) + } + ek, ok := pubKey.(EK) + if !ok { + t.Fatalf("ParsePKIXPublicKey returned wrong type: got %T, want %T", pubKey, *new(EK)) + } + if !bytes.Equal(ek.Bytes(), dk.EncapsulationKey().Bytes()) { + t.Fatal("ParsePKIXPublicKey returned public key that does not match private key") + } + + got, err = MarshalPKIXPublicKey(pubKey) + if err != nil { + t.Fatalf("MarshalPKIXPublicKey failed: %s", err) + } + if !bytes.Equal(got, pemDecode(t, publicKeyPEM)) { + t.Fatal("MarshalPKIXPublicKey did not return original DER bytes") + } + + // We don't support ML-KEM certificates, ParseCertificate must leave + // PublicKey nil and report UnknownPublicKeyAlgorithm. + cert, err := ParseCertificate(pemDecode(t, certPEM)) + if err != nil { + t.Fatalf("ParseCertificate failed: %s", err) + } + if cert.PublicKey != nil { + t.Errorf("ParseCertificate returned non-nil PublicKey for ML-KEM certificate: %T", cert.PublicKey) + } + if cert.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm { + t.Errorf("ParseCertificate returned PublicKeyAlgorithm %v, want UnknownPublicKeyAlgorithm", cert.PublicKeyAlgorithm) + } +} + func pemDecode(t *testing.T, pemStr string) []byte { b, _ := pem.Decode([]byte(pemStr)) if b == nil { @@ -5457,3 +5562,454 @@ func TestIPv4MappedIPsConstraintCreate(t *testing.T) { t.Fatalf("unexpected success creating certificate with IPv4-mapped IPv6 address constraint") } } + +// RFC 9935, Appendix C.1.2.1. +var rfc9935ExamplePrivateKeyMLKEM768 = testingKey(` +-----BEGIN TESTING KEY----- +MFQCAQAwCwYJYIZIAWUDBAQCBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ +GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8= +-----END TESTING KEY----- +`) + +// RFC 9935, Appendix C.1.3.1. +var rfc9935ExamplePrivateKeyMLKEM1024 = testingKey(` +-----BEGIN TESTING KEY----- +MFQCAQAwCwYJYIZIAWUDBAQDBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ +GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8= +-----END TESTING KEY----- +`) + +// RFC 9935, Appendix C.1.2.2. +var rfc9935ExamplePrivateKeyMLKEM768Expanded = testingKey(` +-----BEGIN TESTING KEY----- +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 +JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw== +-----END TESTING KEY----- +`) + +// RFC 9935, Appendix C.1.2.3. +var rfc9935ExamplePrivateKeyMLKEM768Both = testingKey(` +-----BEGIN TESTING KEY----- +MIIJvgIBADALBglghkgBZQMEBAIEggmqMIIJpgRAAAECAwQFBgcICQoLDA0ODxAR +EhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+PwSC +CWAn0qd/M3VvYSCO8ROr6CWVhz1KvHMOW11nlSm/akzrY4NCcjGoYS9BVQUVrLpS +5I6ti5QoM7vmhl0T0Up50sXD4H8KBW2N56rfyroFjEk8gLN8q4xWJ1O7O6a27IKX ++IXqp1QNUwAVqEQG5VsTZrV34jbOWKJtih61pE1UIyPCFn2b9KR/mFaZygW65DuN +7GF/AjgKOJCv1LjH7H7eJlU6Al885bxdemITAwQjXLGtSDa1ZrW4Y72b20WihEpw +R7bI04PkSFJeBAtNyKK0jGw3yW1i1D8/2I4ogcQKIFyeJI9lK1kngad5+GiA8qFH +tnhj85HMGlqQjACV4HISKR4u+KNuuanAxgcyJbNHA6SvBJOCxHVz2mj96SRa1ETj +Gx+9tSHx9h83vAzvKSBn5nDSih/9kE9vEZCplpGKEwN6bKvzw3O/gpbNN6szundG +gJzD+K3hs2Ob1Xv8xpZQqq8d4Zj8TARjKZ5SxGF4DMQo/F0EpcUYUMumwqUnQ0Bn +V5PdoJvkTCnmOVxl+F0qCnxt9BHmkRsfLLbDUc0uh19Rtji+d2CX6T4vKy+D2gvu +9KqFup52OrZFAqDKUiLp6rWztwiO1SBg6Mgmm5Q6casK4cWxtofS4BnPgDa8+b9u +e6w6qjbkFmD6pFQPJkjNk6GJ7Fwt6nC6yqpP/JBvkIEOobZ78k8seM9rqIGq6mHA +ZSv/lbG65EJtF3O5zCyoLCHjjGNuOxxSMkSYawvoqD9d1c8tVHYvs8Xr9ZuOiFMC +sc5HAz7fdg9OApvkC21WaxnddYrNXHQSh4ExJE+QFyxT8mZjwh2QUwHUi6+RyRfM +d3np2IAswQ2Jo3BQmaKtOjqIlnQ8EURpgJO+JX2stm3HhSKLkSyNll0Uqig0LDrE +qT/vpTKyCUXdwQIBOcFNY4uQjE3d6aBkW5Wy5EFNQLt58EQTgw8VqHPCi7cFnCdB +ACAV8gQI8FjnFbC/mVtTgLfdMloFarl+ZZor4M32wzcxxoOmNLdx6MkqE5ruS7Dk +nHB3Mh1C/BmffB8pjKYl0iOlwmOgPMSBWbeBJmW3hjfk4YcgssKaa5n0J2aky8Tc +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 +Pj8= +-----END TESTING KEY----- +`) + +// RFC 9935, Appendix C.2. +var rfc9935ExamplePublicKeyMLKEM768 = ` +-----BEGIN PUBLIC KEY----- +MIIEsjALBglghkgBZQMEBAIDggShACmKoQ1CPI3aBp0CvFnmzfA6CWuLPaTKubgM +pKFJB2cszvHsT68jSgvFt+nUc/KzEzs7JqHRdctnp4BZGWmcAvdlMbmcX4kYBwS7 +TKRTXFuJcmecZgoHxeUUuHAJyGLrj1FXaV77P8QKne9rgcHMAqJJrk8JStDZvTSF +wcHGgIBSCnyMYyAyzuc4FU5cUXbAfaVgJHdqQw/nbqz2ZaP3uDIQIhW8gvEJOcg1 +VwQzao+sHYHkuwSFql18dNa1m75cXpcqDYusQRtVtdVVfNaAoaj3G064a8SMmgUJ +cxpUvZ1ykLJ5Y+Q3Lcmxmc/crAsBrNKKYjlREuTENkjWIsSMgjTQFEDozDdskn8j +pa/JrAR0xmInTkJFJchVLs47P+JlFt6QG8fVFb3olVjmJslcgLkzQvgBAATznmxs +lIccXjRMqzlmyDX5qWpZr9McQChrOLHBp4RwurlHUYk0RTzoZzapGfH1ptUQqG9U +VPw5gMtcdlvSvV97NrFBDWY1yM60fE3aDXaijqyTnHHDAkgEhmxxYmZYRCFjwsIh +F+UKzvzmN4qYVlIwKk7wws4Mxxa3eW4ray43d9+hrD2iWaMbWptTD4y2OKgaYqww +GEmrr5WnMBvaMAaJCb/bfmfbzLs4pVUaJbGjoPaFdIrVdT2IgPABbGJ0hhZjhMVX +H+I2WQA2TQODEeLYdds2ZoaTK17GAkMKNp6Hpu9cM4eGZXglvUwFes65I+sJNeaQ +XmO0ztf4CFenc91ksVDSZhLqmsEgUtsgF78YQ8y0sygbaQ3HKK36hcACgbjjwJKH +M1+Fa0/CiS9povV5Ia2gGRTECYhmLVd2lmKnhjUbm2ZJPat5WU2YbeIQDWW6D/Tq +WLgVONJKRDWiWPrCVASqf0H2WLE4UGXhWNy2ARVzJyD0BFmqrBXkBpU6kKxSmX0c +zQcAYO/GXbnmUzVEZ/rVbscTyG51QMQjrPJmn1L6b0rGiI2HHvPoR8ApqKr7uS4X +skqgebH0GbphdbRCr7EZCdSla3CgM1soc5IYqnyTSOLDwvPrPRWkHmQXwN2Uv+sh +QZsxGnuxOhgLvoMyGKmmsXRHzIXyJYWVh6cwdwSay8/UTQ8CVDjhXRU4Jw1Ybhv4 +MZKpRZz2PA6XL4UpdnmDHs8SFQmFHLg0D28Qew+hoO/Rs2qBibwIXE9ct4TlU/Qb +kY+AOXzhlW94W+43fKmqi+aZitowwmt8PYxrVSVMyWIDsgxCruCsTh67QI5JqeP4 +edCrB4XrcCVCXRMFoimcAV4SDRY7DhlJTOVyU9AkbRgnRcuBl6t0OLPBu3lyvsWj +BuujVnhVwBRpn+9lrlTHcKDYXBhADPZCrtxmB3e6SxOFAr1aeBL2IfhKSClrmN1D +IrbxWCi4qPDgCoukSlPDqLFDVxsHQKvVZ9rxzenHnCBLbV4lnRdmoxu7y05qBc9F +AhdrMBwcL0Ekd1AVe87IXoCbMKTWDXdHzdD1uZqoyCaYdRd5OqqAgKCxJKhVjfcr +vje3X07btr6CFtbGM/srIoDiURPYaV5DSBw+6zl+sZJQUim2eiAeqJPD4ssy2ovD +QvpN6gV4 +-----END PUBLIC KEY----- +` + +// RFC 9935, Appendix C.2. +var rfc9935ExamplePublicKeyMLKEM1024 = ` +-----BEGIN PUBLIC KEY----- +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 +uYOILhF1 +-----END PUBLIC KEY----- +` + +// RFC 9935, Appendix C.3. +var rfc9935ExampleCertificateMLKEM768 = ` +-----BEGIN CERTIFICATE----- +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 +AAAAAAAAAAAAAAAFDBUZHyU= +-----END CERTIFICATE----- +` + +// RFC 9935, Appendix C.3. +var rfc9935ExampleCertificateMLKEM1024 = ` +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- +` From 2d782633ac996161fe473c9a74425bec0f4fcef6 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Sat, 13 Jun 2026 21:40:08 +0800 Subject: [PATCH 14/21] mime: reject duplicate formatted parameter names FormatMediaType lower-cases parameter names when serializing. If the input map contains keys that differ only by case, it can emit duplicate parameter names such as "name=foo; name=bar", which ParseMediaType rejects. Return an empty string in this case, matching FormatMediaType's documented behavior for invalid output. Change-Id: I6d0890bf608da8c3a18af60a36b1825f8dc88ce9 Reviewed-on: https://go-review.googlesource.com/c/go/+/790400 Reviewed-by: shuang cui Reviewed-by: Sean Liao Reviewed-by: Michael Pratt Reviewed-by: Mark Freeman Auto-Submit: Sean Liao LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/mime/mediatype.go | 8 +++++++- src/mime/mediatype_test.go | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go index c6006b614f319e..520bcb724abbb8 100644 --- a/src/mime/mediatype.go +++ b/src/mime/mediatype.go @@ -34,6 +34,7 @@ func FormatMediaType(t string, param map[string]string) string { b.WriteString(strings.ToLower(sub)) } + seenAttrs := make(map[string]struct{}, len(param)) for _, attribute := range slices.Sorted(maps.Keys(param)) { value := param[attribute] b.WriteByte(';') @@ -41,7 +42,12 @@ func FormatMediaType(t string, param map[string]string) string { if !isToken(attribute) { return "" } - b.WriteString(strings.ToLower(attribute)) + attribute = strings.ToLower(attribute) + if _, ok := seenAttrs[attribute]; ok { + return "" + } + seenAttrs[attribute] = struct{}{} + b.WriteString(attribute) needEnc := needsEncoding(value) if needEnc { diff --git a/src/mime/mediatype_test.go b/src/mime/mediatype_test.go index da8d64de7a3f0c..343beb863da892 100644 --- a/src/mime/mediatype_test.go +++ b/src/mime/mediatype_test.go @@ -531,6 +531,7 @@ var formatTests = []formatTest{ {"foo/BAR", map[string]string{"both": `With \backslash and "quote`}, `foo/bar; both="With \\backslash and \"quote"`}, {"foo/BAR", map[string]string{"": "empty attribute"}, ""}, {"foo/BAR", map[string]string{"bad attribute": "baz"}, ""}, + {"foo/BAR", map[string]string{"Name": "foo", "name": "bar"}, ""}, {"foo/BAR", map[string]string{"nonascii": "not an ascii character: ä"}, "foo/bar; nonascii*=utf-8''not%20an%20ascii%20character%3A%20%C3%A4"}, {"foo/BAR", map[string]string{"ctl": "newline: \n nil: \000"}, "foo/bar; ctl*=utf-8''newline%3A%20%0A%20nil%3A%20%00"}, {"foo/bar", map[string]string{"a": "av", "b": "bv", "c": "cv"}, "foo/bar; a=av; b=bv; c=cv"}, From 1a474e96baf18bb70921b49f4dab05574055bd21 Mon Sep 17 00:00:00 2001 From: Salih Muhammed Date: Thu, 2 Jul 2026 22:16:20 +0000 Subject: [PATCH 15/21] encoding/base64: make decoder errors independent of read chunking The stream decoder decoded each buffered chunk with a stateless call to Decode, so validity and error offsets depended on how the underlying reader happened to chunk the input. A padded group followed by more input was accepted whenever a chunk boundary fell right after the padding, even though decoding the same input as a whole rejects it, and CorruptInputError offsets were relative to the current chunk rather than the whole stream. Track how much input has been consumed and whether a padded group has been seen: reject any input that follows a padded group, and rebase error offsets so they refer to positions in the whole input stream. Fixes #31626 Change-Id: I2f8c19ac9796fb938430fbcb3df1123583be4a6b GitHub-Last-Rev: a9acf71d0ee4af94bbd81634e180cb4e6cd9ae2d GitHub-Pull-Request: golang/go#80245 Reviewed-on: https://go-review.googlesource.com/c/go/+/796680 Reviewed-by: Sean Liao Auto-Submit: Sean Liao Reviewed-by: Michael Pratt LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Mark Freeman --- src/encoding/base64/base64.go | 26 ++++++++++++++++++++++++++ src/encoding/base64/base64_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go index 952cf0c6f859a3..d0eee1a5eae82a 100644 --- a/src/encoding/base64/base64.go +++ b/src/encoding/base64/base64.go @@ -441,12 +441,23 @@ type decoder struct { readErr error // error from r.Read enc *Encoding r io.Reader + end bool // saw a padded group: no more input may follow + total int64 // input consumed so far, excluding filtered newlines buf [1024]byte // leftover input nbuf int out []byte // leftover decoded output outbuf [1024 / 4 * 3]byte } +// rebaseError updates the offset of a CorruptInputError returned by decoding +// d.buf so that it refers to a position in the whole input stream. +func (d *decoder) rebaseError(err error) error { + if e, ok := err.(CorruptInputError); ok { + return CorruptInputError(int64(e) + d.total) + } + return err +} + func (d *decoder) Read(p []byte) (n int, err error) { // Use leftover decoded output from last read. if len(d.out) > 0 { @@ -474,11 +485,19 @@ func (d *decoder) Read(p []byte) (n int, err error) { d.nbuf += nn } + // A padded group must end the stream: decoding the same input as a whole + // reports any input after it as garbage. + if d.end && d.nbuf > 0 { + d.err = CorruptInputError(d.total) + return 0, d.err + } + if d.nbuf < 4 { if d.enc.padChar == NoPadding && d.nbuf > 0 { // Decode final fragment, without padding. var nw int nw, d.err = d.enc.Decode(d.outbuf[:], d.buf[:d.nbuf]) + d.err = d.rebaseError(d.err) d.nbuf = 0 d.out = d.outbuf[:nw] n = copy(p, d.out) @@ -508,6 +527,13 @@ func (d *decoder) Read(p []byte) (n int, err error) { } else { n, d.err = d.enc.Decode(p, d.buf[:nr]) } + if d.err != nil { + d.err = d.rebaseError(d.err) + } else if d.enc.padChar != NoPadding && d.buf[nr-1] == byte(d.enc.padChar) { + // The decoded chunk ended with a padded group. + d.end = true + } + d.total += int64(nr) d.nbuf -= nr copy(d.buf[:d.nbuf], d.buf[nr:]) return n, d.err diff --git a/src/encoding/base64/base64_test.go b/src/encoding/base64/base64_test.go index bc67413cc7ca85..88d4ccf9ccf30f 100644 --- a/src/encoding/base64/base64_test.go +++ b/src/encoding/base64/base64_test.go @@ -197,6 +197,36 @@ func TestDecoder(t *testing.T) { } } +func TestDecoderChunking(t *testing.T) { + // The decoder must behave identically to decoding the whole input at + // once, regardless of how the underlying reader chunks the input. + // See golang.org/issue/31626. + tests := []struct { + enc *Encoding + in string + }{ + {StdEncoding, "Rw==bw=="}, // padding inside the stream + {StdEncoding, "AAAA####"}, // error offset must not reset per chunk + {StdEncoding, "Rw==x"}, // trailing garbage after a padded group + {StdEncoding, "Rw===="}, // extra padding after a padded group + {StdEncoding, "AAAABBBBCCCC"}, // valid input + {StdEncoding, "AAAABB=="}, // valid input with padding + {RawStdEncoding, "AAAABB"}, // valid input, no padding + {RawStdEncoding, "AAAA#B"}, // invalid byte in final fragment + } + for _, tt := range tests { + want, wantErr := tt.enc.DecodeString(tt.in) + for i := 0; i <= len(tt.in); i++ { + r := io.MultiReader(strings.NewReader(tt.in[:i]), strings.NewReader(tt.in[i:])) + got, gotErr := io.ReadAll(NewDecoder(tt.enc, r)) + if !bytes.Equal(got, want) || gotErr != wantErr { + t.Errorf("Decode(%q) with split at %d = %q, %v; want %q, %v", + tt.in, i, got, gotErr, want, wantErr) + } + } + } +} + func TestDecoderBuffering(t *testing.T) { for bs := 1; bs <= 12; bs++ { decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded)) From 655a713cda939618d56b179ed44d1257858b775c Mon Sep 17 00:00:00 2001 From: Ruihao Chen Date: Thu, 23 Jul 2026 05:37:07 +0000 Subject: [PATCH 16/21] compress/flate: do not emit the preset dictionary into the output When using a dictionary, fillWindow was not setting blockStart, which caused a non-compressed block in first position to write the dictionary. This mixup can happen because window stores both the look back window and the block we are about to write. Set blockStart to skip over the dictionary if we have to write the window. Fixes #80538 Change-Id: I6e6784696f29591f2819fc3c9c461d73d3d6335b GitHub-Last-Rev: 469f26bdac32aaf87cfc3b9723673e8de9506f6d GitHub-Pull-Request: golang/go#80539 Reviewed-on: https://go-review.googlesource.com/c/go/+/804680 Auto-Submit: Jorropo LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Cherry Mui Reviewed-by: Jorropo Reviewed-by: Mark Freeman --- src/compress/flate/deflate.go | 1 + src/compress/flate/deflate_test.go | 34 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go index fcd9d8c8d57ecd..f7e58e8dfc2f5c 100644 --- a/src/compress/flate/deflate.go +++ b/src/compress/flate/deflate.go @@ -250,6 +250,7 @@ func (d *compressor) fillWindow(b []byte) { // Update window information. d.windowEnd += n s.index = n + d.blockStart = d.windowEnd } // findMatch finds the longest match starting at pos in the hash chain starting diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go index 47ef8f0da087d3..073c63a5eef550 100644 --- a/src/compress/flate/deflate_test.go +++ b/src/compress/flate/deflate_test.go @@ -494,6 +494,40 @@ func TestWriterDict(t *testing.T) { } } +// TestNonCompressedBlockDoesntLeakDict checks that the dictionary isn't sent when +// sending a non-compressed block. See https://go.dev/issue/80538 +func TestNonCompressedBlockDoesntLeakDict(t *testing.T) { + data := make([]byte, 763) + rand.New(rand.NewSource(42)).Read(data) + dict := []byte("0123456789abcdefghij") + for l := range BestCompression + 1 { + t.Run(fmt.Sprintf("level=%d", l), func(t *testing.T) { + var b bytes.Buffer + w, err := NewWriterDict(&b, l, dict) + if err != nil { + t.Fatalf("NewWriterDict: %v", err) + } + if _, err := w.Write(data); err != nil { + t.Fatalf("Write: %v", err) + } + if err := w.Close(); err != nil { + t.Fatalf("Close: %v", err) + } + got, err := io.ReadAll(NewReaderDict(&b, dict)) + if err != nil { + t.Fatalf("NewReaderDict: %v", err) + } + if !bytes.Equal(got, data) { + t.Errorf("round trip mismatch: got %d bytes, want %d (dictionary emitted: %v)", + len(got), len(data), bytes.HasPrefix(got, dict)) + } + if b.Len() != 0 { + t.Errorf("compressed stream not fully consumed: %d bytes left", b.Len()) + } + }) + } +} + // See https://golang.org/issue/2508 func TestRegression2508(t *testing.T) { if testing.Short() { From e8285ccd6e7610ee18ec7c9b8c46605a9b97a119 Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Sun, 26 Jul 2026 22:13:34 +0300 Subject: [PATCH 17/21] cmd/compile/internal/ssa: make zero-upper-bits a declared op attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ZeroUpper32/48/56Bits kept a hand-maintained per-opcode fact — "this op's result has the upper N bits zero" — in three parallel switches in rewrite.go, far from the op definitions it describes. Every new op had to be added to the right subset of the three lists by hand, which is exactly how MOVBQZX and MOVWQZX ended up missing from the 32-bit list. Declare the fact as a zeroUpperBits attribute on the op definition instead, at the op's strongest valid level; the predicates keep only the value-dependent cases. With the fact at the definition point, an audit of the full op tables extends coverage well beyond the old lists: the flags-to-bool pseudos, the atomics whose result register is written only at load width or by CSET, and value-bounded ops such as CLZ and POPCNT. Codegen validated by diffing -S output of std against the previous commit: on amd64 51 functions improve; on arm64 a net 285 instructions (-848 bytes of text) of re-extensions of atomic results and CSET booleans fold away. Change-Id: I3f2c8b41d19a06f8e027325cc8d64d75e35f9427 Reviewed-on: https://go-review.googlesource.com/c/go/+/806140 Reviewed-by: Keith Randall Reviewed-by: Keith Randall Auto-Submit: Keith Randall LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Mark Freeman --- src/cmd/compile/internal/amd64/ssa.go | 5 +- src/cmd/compile/internal/arm64/ssa.go | 13 + src/cmd/compile/internal/ssa/_gen/AMD64Ops.go | 392 ++-- .../internal/ssa/_gen/AMD64latelower.rules | 6 +- src/cmd/compile/internal/ssa/_gen/ARM64.rules | 8 +- src/cmd/compile/internal/ssa/_gen/ARM64Ops.go | 314 +-- .../internal/ssa/_gen/ARM64latelower.rules | 6 +- src/cmd/compile/internal/ssa/_gen/main.go | 9 + src/cmd/compile/internal/ssa/op.go | 1 + src/cmd/compile/internal/ssa/opGen.go | 1790 +++++++++-------- src/cmd/compile/internal/ssa/rewrite.go | 217 +- .../internal/ssa/rewriteAMD64latelower.go | 12 +- src/cmd/compile/internal/ssa/rewriteARM64.go | 32 +- .../internal/ssa/rewriteARM64latelower.go | 12 +- test/codegen/noextend.go | 40 + 15 files changed, 1494 insertions(+), 1363 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 4e6f54370d7037..29301ac83334c3 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -1251,7 +1251,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { } if x != y { width := v.Type.Size() - if width == 8 && isGPReg(y) && ssa.ZeroUpper32Bits(arg, 3) { + if width == 8 && isGPReg(y) && ssa.ZeroUpper32Bits(arg) { // The source was naturally zext-ed from 32 to 64 bits, // but we are asked to do a full 64-bit copy. // Save the REX prefix byte in I-CACHE by using a 32-bit move, @@ -1288,6 +1288,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Reg = r ssagen.AddrAuto(&p.To, v) case ssa.OpAMD64LoweredHasCPUFeature: + // If this load changes width, update zeroUpperBits in AMD64Ops.go. p := s.Prog(x86.AMOVBLZX) p.From.Type = obj.TYPE_MEM ssagen.AddAux(&p.From, v) @@ -1669,6 +1670,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // LOCK CMPXCHGQ tmp, (addr) : note that AX is implicit old value to compare against // JNE loop // : result in AX + // + // If the width written to AX changes, update zeroUpperBits in AMD64Ops.go. mov := x86.AMOVQ op := x86.AANDQ cmpxchg := x86.ACMPXCHGQ diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index c75e0e5e65b764..394c9336af42c6 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -1042,6 +1042,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // LDAXR (Rarg0), Rout // STLXR Rarg1, (Rarg0), Rtmp // CBNZ Rtmp, -2(PC) + // + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. var ld, st obj.As switch v.Op { case ssa.OpARM64LoweredAtomicExchange8: @@ -1076,6 +1078,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpARM64LoweredAtomicExchange64Variant, ssa.OpARM64LoweredAtomicExchange32Variant, ssa.OpARM64LoweredAtomicExchange8Variant: + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. var swap obj.As switch v.Op { case ssa.OpARM64LoweredAtomicExchange8Variant: @@ -1163,6 +1166,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // STLXR Rarg2, (Rarg0), Rtmp // CBNZ Rtmp, -4(PC) // CSET EQ, Rout + // + // If Rout stops being written only by CSET, update zeroUpperBits in ARM64Ops.go. ld := arm64.ALDAXR st := arm64.ASTLXR cmp := arm64.ACMP @@ -1212,6 +1217,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // CASAL Rtmp, (Rarg0), Rarg2 // CMP Rarg1, Rtmp // CSET EQ, Rout + // + // If Rout stops being written only by CSET, update zeroUpperBits in ARM64Ops.go. cas := arm64.ACASALD cmp := arm64.ACMP mov := arm64.AMOVD @@ -1263,6 +1270,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // AND/OR Rarg1, Rout, tmp1 // STLXR[BW] tmp1, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) + // + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. ld := arm64.ALDAXR st := arm64.ASTLXR if v.Op == ssa.OpARM64LoweredAtomicAnd32 || v.Op == ssa.OpARM64LoweredAtomicOr32 { @@ -1303,6 +1312,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpARM64LoweredAtomicAnd8Variant, ssa.OpARM64LoweredAtomicAnd32Variant, ssa.OpARM64LoweredAtomicAnd64Variant: + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. atomic_clear := arm64.ALDCLRALD if v.Op == ssa.OpARM64LoweredAtomicAnd32Variant { atomic_clear = arm64.ALDCLRALW @@ -1332,6 +1342,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpARM64LoweredAtomicOr8Variant, ssa.OpARM64LoweredAtomicOr32Variant, ssa.OpARM64LoweredAtomicOr64Variant: + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. atomic_or := arm64.ALDORALD if v.Op == ssa.OpARM64LoweredAtomicOr32Variant { atomic_or = arm64.ALDORALW @@ -1870,6 +1881,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpARM64LessThanNoov, ssa.OpARM64GreaterEqualNoov: // generate boolean values using CSET + // + // If the result stops being a 0/1-producing CSET, update zeroUpperBits in ARM64Ops.go. p := s.Prog(arm64.ACSET) p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset condCode := condBits[v.Op] diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go index fc06f3e40cdc0f..0615866c273671 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go @@ -362,24 +362,24 @@ func init() { // constmodify versions compute *(arg0+ValAndOff(AuxInt).Off().aux) OP= ValAndOff(AuxInt).Val(), arg1 = mem // x==L operations zero the upper 4 bytes of the destination register (not meaningful for constmodify versions). {name: "ADDQ", argLength: 2, reg: gp21sp, asm: "ADDQ", commutative: true, clobberFlags: true, earlyOk: true}, - {name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true, clobberFlags: true, earlyOk: true}, + {name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "ADDQconst", argLength: 1, reg: gp11sp, asm: "ADDQ", aux: "Int32", typ: "UInt64", clobberFlags: true, earlyOk: true}, - {name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32", clobberFlags: true, earlyOk: true}, + {name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32", clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "ADDQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ADDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "SUBQ", argLength: 2, reg: gp21sp2, asm: "SUBQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SUBQconst", argLength: 1, reg: gp11, asm: "SUBQ", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "MULQ", argLength: 2, reg: gp21, asm: "IMULQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "MULQconst", argLength: 1, reg: gp11, asm: "IMUL3Q", aux: "Int32", clobberFlags: true, earlyOk: true}, - {name: "MULLconst", argLength: 1, reg: gp11, asm: "IMUL3L", aux: "Int32", clobberFlags: true, earlyOk: true}, + {name: "MULLconst", argLength: 1, reg: gp11, asm: "IMUL3L", aux: "Int32", clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // Let x = arg0*arg1 (full 32x32->64 unsigned multiply). Returns uint32(x), and flags set to overflow if uint32(x) != x. - {name: "MULLU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, regMask{}}, clobbers: dx}, typ: "(UInt32,Flags)", asm: "MULL", commutative: true, clobberFlags: true}, + {name: "MULLU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, regMask{}}, clobbers: dx}, typ: "(UInt32,Flags)", asm: "MULL", commutative: true, clobberFlags: true, zeroUpperBits: 32}, // Let x = arg0*arg1 (full 64x64->128 unsigned multiply). Returns uint64(x), and flags set to overflow if uint64(x) != x. {name: "MULQU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, regMask{}}, clobbers: dx}, typ: "(UInt64,Flags)", asm: "MULQ", commutative: true, clobberFlags: true}, @@ -390,9 +390,9 @@ func init() { // This is because they have asymmetric register requirements. // There are rewrite rules to try to place arguments in preferable slots. {name: "HMULQ", argLength: 2, reg: gp21hmul, asm: "IMULQ", clobberFlags: true, earlyOk: true}, - {name: "HMULL", argLength: 2, reg: gp21hmul, asm: "IMULL", clobberFlags: true, earlyOk: true}, + {name: "HMULL", argLength: 2, reg: gp21hmul, asm: "IMULL", clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "HMULQU", argLength: 2, reg: gp21hmul, asm: "MULQ", clobberFlags: true, earlyOk: true}, - {name: "HMULLU", argLength: 2, reg: gp21hmul, asm: "MULL", clobberFlags: true, earlyOk: true}, + {name: "HMULLU", argLength: 2, reg: gp21hmul, asm: "MULL", clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // (arg0 + arg1) / 2 as unsigned, all 64 result bits {name: "AVGQU", argLength: 2, reg: gp21, commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, @@ -400,19 +400,19 @@ func init() { // DIVx[U] computes [arg0 / arg1, arg0 % arg1] // For signed versions, AuxInt non-zero means that the divisor has been proved to be not -1. {name: "DIVQ", argLength: 2, reg: gp11div, typ: "(Int64,Int64)", asm: "IDIVQ", aux: "Bool", clobberFlags: true}, - {name: "DIVL", argLength: 2, reg: gp11div, typ: "(Int32,Int32)", asm: "IDIVL", aux: "Bool", clobberFlags: true}, + {name: "DIVL", argLength: 2, reg: gp11div, typ: "(Int32,Int32)", asm: "IDIVL", aux: "Bool", clobberFlags: true, zeroUpperBits: 32}, {name: "DIVW", argLength: 2, reg: gp11div, typ: "(Int16,Int16)", asm: "IDIVW", aux: "Bool", clobberFlags: true}, {name: "DIVQU", argLength: 2, reg: gp11div, typ: "(UInt64,UInt64)", asm: "DIVQ", clobberFlags: true}, - {name: "DIVLU", argLength: 2, reg: gp11div, typ: "(UInt32,UInt32)", asm: "DIVL", clobberFlags: true}, + {name: "DIVLU", argLength: 2, reg: gp11div, typ: "(UInt32,UInt32)", asm: "DIVL", clobberFlags: true, zeroUpperBits: 32}, {name: "DIVWU", argLength: 2, reg: gp11div, typ: "(UInt16,UInt16)", asm: "DIVW", clobberFlags: true}, // computes -arg0, flags set for 0-arg0. - {name: "NEGLflags", argLength: 1, reg: gp11flags, typ: "(UInt32,Flags)", asm: "NEGL", resultInArg0: true}, + {name: "NEGLflags", argLength: 1, reg: gp11flags, typ: "(UInt32,Flags)", asm: "NEGL", resultInArg0: true, zeroUpperBits: 32}, // compute arg0+auxint. flags set for arg0+auxint. // NOTE: we pretend the CF/OF flags are undefined for these instructions, // so we can use INC/DEC instead of ADDQconst if auxint is +/-1. (INC/DEC don't modify CF.) {name: "ADDQconstflags", argLength: 1, reg: gp11flags, aux: "Int32", asm: "ADDQ", resultInArg0: true}, - {name: "ADDLconstflags", argLength: 1, reg: gp11flags, aux: "Int32", asm: "ADDL", resultInArg0: true}, + {name: "ADDLconstflags", argLength: 1, reg: gp11flags, aux: "Int32", asm: "ADDL", resultInArg0: true, zeroUpperBits: 32}, // The following 4 add opcodes return the low 64 bits of the sum in the first result and // the carry (the 65th bit) in the carry flag. @@ -439,23 +439,23 @@ func init() { {name: "DIVQU2", argLength: 3, reg: regInfo{inputs: []regMask{dx, ax, gpsp}, outputs: []regMask{ax, dx}}, asm: "DIVQ", clobberFlags: true}, // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r) {name: "ANDQ", argLength: 2, reg: gp21, asm: "ANDQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 & arg1 - {name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 & arg1 + {name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 & arg1 {name: "ANDQconst", argLength: 1, reg: gp11, asm: "ANDQ", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 & auxint - {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 & auxint + {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 & auxint {name: "ANDQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "ANDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 | arg1 - {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 | arg1 + {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 | arg1 {name: "ORQconst", argLength: 1, reg: gp11, asm: "ORQ", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 | auxint - {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 | auxint + {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 | auxint {name: "ORQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "ORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 ^ arg1 - {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 ^ arg1 + {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 ^ arg1 {name: "XORQconst", argLength: 1, reg: gp11, asm: "XORQ", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 ^ auxint - {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 ^ auxint + {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 ^ auxint {name: "XORQconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "XORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem @@ -507,19 +507,19 @@ func init() { {name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // bit test/set/clear operations - {name: "BTL", argLength: 2, reg: gp2flags, asm: "BTL", typ: "Flags"}, // test whether bit arg0%32 in arg1 is set - {name: "BTQ", argLength: 2, reg: gp2flags, asm: "BTQ", typ: "Flags"}, // test whether bit arg0%64 in arg1 is set - {name: "BTCL", argLength: 2, reg: gp21, asm: "BTCL", resultInArg0: true, clobberFlags: true, earlyOk: true}, // complement bit arg1%32 in arg0 - {name: "BTCQ", argLength: 2, reg: gp21, asm: "BTCQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // complement bit arg1%64 in arg0 - {name: "BTRL", argLength: 2, reg: gp21, asm: "BTRL", resultInArg0: true, clobberFlags: true, earlyOk: true}, // reset bit arg1%32 in arg0 - {name: "BTRQ", argLength: 2, reg: gp21, asm: "BTRQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // reset bit arg1%64 in arg0 - {name: "BTSL", argLength: 2, reg: gp21, asm: "BTSL", resultInArg0: true, clobberFlags: true, earlyOk: true}, // set bit arg1%32 in arg0 - {name: "BTSQ", argLength: 2, reg: gp21, asm: "BTSQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // set bit arg1%64 in arg0 - {name: "BTLconst", argLength: 1, reg: gp1flags, asm: "BTL", typ: "Flags", aux: "Int8", earlyOk: true}, // test whether bit auxint in arg0 is set, 0 <= auxint < 32 - {name: "BTQconst", argLength: 1, reg: gp1flags, asm: "BTQ", typ: "Flags", aux: "Int8", earlyOk: true}, // test whether bit auxint in arg0 is set, 0 <= auxint < 64 - {name: "BTCQconst", argLength: 1, reg: gp11, asm: "BTCQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // complement bit auxint in arg0, 31 <= auxint < 64 - {name: "BTRQconst", argLength: 1, reg: gp11, asm: "BTRQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // reset bit auxint in arg0, 31 <= auxint < 64 - {name: "BTSQconst", argLength: 1, reg: gp11, asm: "BTSQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // set bit auxint in arg0, 31 <= auxint < 64 + {name: "BTL", argLength: 2, reg: gp2flags, asm: "BTL", typ: "Flags"}, // test whether bit arg0%32 in arg1 is set + {name: "BTQ", argLength: 2, reg: gp2flags, asm: "BTQ", typ: "Flags"}, // test whether bit arg0%64 in arg1 is set + {name: "BTCL", argLength: 2, reg: gp21, asm: "BTCL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // complement bit arg1%32 in arg0 + {name: "BTCQ", argLength: 2, reg: gp21, asm: "BTCQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // complement bit arg1%64 in arg0 + {name: "BTRL", argLength: 2, reg: gp21, asm: "BTRL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // reset bit arg1%32 in arg0 + {name: "BTRQ", argLength: 2, reg: gp21, asm: "BTRQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // reset bit arg1%64 in arg0 + {name: "BTSL", argLength: 2, reg: gp21, asm: "BTSL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // set bit arg1%32 in arg0 + {name: "BTSQ", argLength: 2, reg: gp21, asm: "BTSQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // set bit arg1%64 in arg0 + {name: "BTLconst", argLength: 1, reg: gp1flags, asm: "BTL", typ: "Flags", aux: "Int8", earlyOk: true}, // test whether bit auxint in arg0 is set, 0 <= auxint < 32 + {name: "BTQconst", argLength: 1, reg: gp1flags, asm: "BTQ", typ: "Flags", aux: "Int8", earlyOk: true}, // test whether bit auxint in arg0 is set, 0 <= auxint < 64 + {name: "BTCQconst", argLength: 1, reg: gp11, asm: "BTCQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // complement bit auxint in arg0, 31 <= auxint < 64 + {name: "BTRQconst", argLength: 1, reg: gp11, asm: "BTRQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // reset bit auxint in arg0, 31 <= auxint < 64 + {name: "BTSQconst", argLength: 1, reg: gp11, asm: "BTSQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // set bit auxint in arg0, 31 <= auxint < 64 // BT[SRC]Qconstmodify // @@ -560,25 +560,25 @@ func init() { // (Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!) // For *const versions, use auxint instead of arg1 as the shift amount. auxint must be in the range 0 to (Q=63,L=31,W=15,B=7) inclusive. {name: "SHLQ", argLength: 2, reg: gp21shift, asm: "SHLQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SHLQconst", argLength: 1, reg: gp11, asm: "SHLQ", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, @@ -589,15 +589,15 @@ func init() { // x==L versions zero the upper 32 bits of the destination register. // x==W and x==B versions leave the upper bits unspecified. {name: "ROLQ", argLength: 2, reg: gp21shift, asm: "ROLQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "ROLL", argLength: 2, reg: gp21shift, asm: "ROLL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "ROLL", argLength: 2, reg: gp21shift, asm: "ROLL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "ROLW", argLength: 2, reg: gp21shift, asm: "ROLW", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "ROLB", argLength: 2, reg: gp21shift, asm: "ROLB", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "RORQ", argLength: 2, reg: gp21shift, asm: "RORQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "RORL", argLength: 2, reg: gp21shift, asm: "RORL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "RORL", argLength: 2, reg: gp21shift, asm: "RORL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "RORW", argLength: 2, reg: gp21shift, asm: "RORW", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "RORB", argLength: 2, reg: gp21shift, asm: "RORB", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "ROLQconst", argLength: 1, reg: gp11, asm: "ROLQ", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "ROLBconst", argLength: 1, reg: gp11, asm: "ROLB", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, @@ -605,44 +605,44 @@ func init() { // L = int32, Q = int64 // x==L operations zero the upper 4 bytes of the destination register. // computes arg0 op *(arg1+auxint+aux), arg2=mem - {name: "ADDLload", argLength: 3, reg: gp21load, asm: "ADDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ADDLload", argLength: 3, reg: gp21load, asm: "ADDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ADDQload", argLength: 3, reg: gp21load, asm: "ADDQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, {name: "SUBQload", argLength: 3, reg: gp21load, asm: "SUBQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, - {name: "SUBLload", argLength: 3, reg: gp21load, asm: "SUBL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ANDLload", argLength: 3, reg: gp21load, asm: "ANDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, + {name: "SUBLload", argLength: 3, reg: gp21load, asm: "SUBL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ANDLload", argLength: 3, reg: gp21load, asm: "ANDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ANDQload", argLength: 3, reg: gp21load, asm: "ANDQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, {name: "ORQload", argLength: 3, reg: gp21load, asm: "ORQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ORLload", argLength: 3, reg: gp21load, asm: "ORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ORLload", argLength: 3, reg: gp21load, asm: "ORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "XORQload", argLength: 3, reg: gp21load, asm: "XORQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, - {name: "XORLload", argLength: 3, reg: gp21load, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, + {name: "XORLload", argLength: 3, reg: gp21load, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, // integer indexed load/op combo // L = int32, Q = int64 // L operations zero the upper 4 bytes of the destination register. // computes arg0 op *(arg1+scale*arg2+auxint+aux), arg3=mem - {name: "ADDLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ADDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ADDLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ADDLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ADDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ADDLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ADDQloadidx1", argLength: 4, reg: gp21loadidx, asm: "ADDQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "ADDQloadidx8", argLength: 4, reg: gp21loadidx, asm: "ADDQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "SUBLloadidx1", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "SUBLloadidx4", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "SUBLloadidx8", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "SUBLloadidx1", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "SUBLloadidx4", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "SUBLloadidx8", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "SUBQloadidx1", argLength: 4, reg: gp21loadidx, asm: "SUBQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "SUBQloadidx8", argLength: 4, reg: gp21loadidx, asm: "SUBQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ANDLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ANDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ANDLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ANDLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ANDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ANDLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ANDQloadidx1", argLength: 4, reg: gp21loadidx, asm: "ANDQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "ANDQloadidx8", argLength: 4, reg: gp21loadidx, asm: "ANDQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ORLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ORLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ORLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ORLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ORQloadidx1", argLength: 4, reg: gp21loadidx, asm: "ORQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "ORQloadidx8", argLength: 4, reg: gp21loadidx, asm: "ORQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "XORLloadidx1", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "XORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "XORLloadidx8", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "XORLloadidx1", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "XORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "XORLloadidx8", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "XORQloadidx1", argLength: 4, reg: gp21loadidx, asm: "XORQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "XORQloadidx8", argLength: 4, reg: gp21loadidx, asm: "XORQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, @@ -716,9 +716,9 @@ func init() { // L = int32, Q = int64 // L operations zero the upper 4 bytes of the destination register. {name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "NOTQ", argLength: 1, reg: gp11, asm: "NOTQ", resultInArg0: true, earlyOk: true}, - {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true, earlyOk: true}, + {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, // BS{F,R}Q returns a tuple [result, flags] // result is undefined if the input is zero. @@ -742,16 +742,16 @@ func init() { {name: "CMOVQCC", argLength: 3, reg: gp21, asm: "CMOVQCC", resultInArg0: true, earlyOk: true}, {name: "CMOVQCS", argLength: 3, reg: gp21, asm: "CMOVQCS", resultInArg0: true, earlyOk: true}, - {name: "CMOVLEQ", argLength: 3, reg: gp21, asm: "CMOVLEQ", resultInArg0: true, earlyOk: true}, - {name: "CMOVLNE", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, earlyOk: true}, - {name: "CMOVLLT", argLength: 3, reg: gp21, asm: "CMOVLLT", resultInArg0: true, earlyOk: true}, - {name: "CMOVLGT", argLength: 3, reg: gp21, asm: "CMOVLGT", resultInArg0: true, earlyOk: true}, - {name: "CMOVLLE", argLength: 3, reg: gp21, asm: "CMOVLLE", resultInArg0: true, earlyOk: true}, - {name: "CMOVLGE", argLength: 3, reg: gp21, asm: "CMOVLGE", resultInArg0: true, earlyOk: true}, - {name: "CMOVLLS", argLength: 3, reg: gp21, asm: "CMOVLLS", resultInArg0: true, earlyOk: true}, - {name: "CMOVLHI", argLength: 3, reg: gp21, asm: "CMOVLHI", resultInArg0: true, earlyOk: true}, - {name: "CMOVLCC", argLength: 3, reg: gp21, asm: "CMOVLCC", resultInArg0: true, earlyOk: true}, - {name: "CMOVLCS", argLength: 3, reg: gp21, asm: "CMOVLCS", resultInArg0: true, earlyOk: true}, + {name: "CMOVLEQ", argLength: 3, reg: gp21, asm: "CMOVLEQ", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLNE", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLLT", argLength: 3, reg: gp21, asm: "CMOVLLT", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLGT", argLength: 3, reg: gp21, asm: "CMOVLGT", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLLE", argLength: 3, reg: gp21, asm: "CMOVLLE", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLGE", argLength: 3, reg: gp21, asm: "CMOVLGE", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLLS", argLength: 3, reg: gp21, asm: "CMOVLLS", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLHI", argLength: 3, reg: gp21, asm: "CMOVLHI", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLCC", argLength: 3, reg: gp21, asm: "CMOVLCC", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLCS", argLength: 3, reg: gp21, asm: "CMOVLCS", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, {name: "CMOVWEQ", argLength: 3, reg: gp21, asm: "CMOVWEQ", resultInArg0: true, earlyOk: true}, {name: "CMOVWNE", argLength: 3, reg: gp21, asm: "CMOVWNE", resultInArg0: true, earlyOk: true}, @@ -772,10 +772,10 @@ func init() { {name: "CMOVQNEF", argLength: 3, reg: gp21, asm: "CMOVQNE", resultInArg0: true, earlyOk: true}, {name: "CMOVQGTF", argLength: 3, reg: gp21, asm: "CMOVQHI", resultInArg0: true, earlyOk: true}, {name: "CMOVQGEF", argLength: 3, reg: gp21, asm: "CMOVQCC", resultInArg0: true, earlyOk: true}, - {name: "CMOVLEQF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, needIntTemp: true, earlyOk: true}, - {name: "CMOVLNEF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, earlyOk: true}, - {name: "CMOVLGTF", argLength: 3, reg: gp21, asm: "CMOVLHI", resultInArg0: true, earlyOk: true}, - {name: "CMOVLGEF", argLength: 3, reg: gp21, asm: "CMOVLCC", resultInArg0: true, earlyOk: true}, + {name: "CMOVLEQF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, needIntTemp: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLNEF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLGTF", argLength: 3, reg: gp21, asm: "CMOVLHI", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLGEF", argLength: 3, reg: gp21, asm: "CMOVLCC", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, {name: "CMOVWEQF", argLength: 3, reg: gp21, asm: "CMOVWNE", resultInArg0: true, needIntTemp: true, earlyOk: true}, {name: "CMOVWNEF", argLength: 3, reg: gp21, asm: "CMOVWNE", resultInArg0: true, earlyOk: true}, {name: "CMOVWGTF", argLength: 3, reg: gp21, asm: "CMOVWHI", resultInArg0: true, earlyOk: true}, @@ -785,13 +785,13 @@ func init() { // Q: abcdefgh -> hgfedcba // L: abcdefgh -> 0000hgfe (L zeros the upper 4 bytes) {name: "BSWAPQ", argLength: 1, reg: gp11, asm: "BSWAPQ", resultInArg0: true, earlyOk: true}, - {name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true, earlyOk: true}, + {name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, // POPCNTx counts the number of set bits in the low-order (L=32,Q=64) bits of arg0. // POPCNTx instructions are only guaranteed to be available if GOAMD64>=v2. // For GOAMD64 condition from arg0 {name: "SETGEF", argLength: 1, reg: flagsgp, asm: "SETCC", earlyOk: true}, // extract floating >= condition from arg0 - {name: "MOVBQSX", argLength: 1, reg: gp11, asm: "MOVBQSX", earlyOk: true}, // sign extend arg0 from int8 to int64 - {name: "MOVBQZX", argLength: 1, reg: gp11, asm: "MOVBLZX", earlyOk: true}, // zero extend arg0 from int8 to int64 - {name: "MOVWQSX", argLength: 1, reg: gp11, asm: "MOVWQSX", earlyOk: true}, // sign extend arg0 from int16 to int64 - {name: "MOVWQZX", argLength: 1, reg: gp11, asm: "MOVWLZX", earlyOk: true}, // zero extend arg0 from int16 to int64 - {name: "MOVLQSX", argLength: 1, reg: gp11, asm: "MOVLQSX", earlyOk: true}, // sign extend arg0 from int32 to int64 - {name: "MOVLQZX", argLength: 1, reg: gp11, asm: "MOVL", earlyOk: true}, // zero extend arg0 from int32 to int64 - - {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true, earlyOk: true}, // 32 low bits of auxint (upper 32 are zeroed) - {name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true, earlyOk: true}, // auxint - - {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL", earlyOk: true}, // convert float64 to int32 - {name: "CVTTSD2SQ", argLength: 1, reg: fpgp, asm: "CVTTSD2SQ", earlyOk: true}, // convert float64 to int64 - {name: "CVTTSS2SL", argLength: 1, reg: fpgp, asm: "CVTTSS2SL", earlyOk: true}, // convert float32 to int32 - {name: "CVTTSS2SQ", argLength: 1, reg: fpgp, asm: "CVTTSS2SQ", earlyOk: true}, // convert float32 to int64 - {name: "CVTSL2SS", argLength: 1, reg: gpfp, asm: "CVTSL2SS", earlyOk: true}, // convert int32 to float32 - {name: "CVTSL2SD", argLength: 1, reg: gpfp, asm: "CVTSL2SD", earlyOk: true}, // convert int32 to float64 - {name: "CVTSQ2SS", argLength: 1, reg: gpfp, asm: "CVTSQ2SS", earlyOk: true}, // convert int64 to float32 - {name: "CVTSQ2SD", argLength: 1, reg: gpfp, asm: "CVTSQ2SD", earlyOk: true}, // convert int64 to float64 - {name: "CVTSD2SS", argLength: 1, reg: fp11, asm: "CVTSD2SS", earlyOk: true}, // convert float64 to float32 - {name: "CVTSS2SD", argLength: 1, reg: fp11, asm: "CVTSS2SD", earlyOk: true}, // convert float32 to float64 + {name: "MOVBQSX", argLength: 1, reg: gp11, asm: "MOVBQSX", earlyOk: true}, // sign extend arg0 from int8 to int64 + {name: "MOVBQZX", argLength: 1, reg: gp11, asm: "MOVBLZX", earlyOk: true, zeroUpperBits: 56}, // zero extend arg0 from int8 to int64 + {name: "MOVWQSX", argLength: 1, reg: gp11, asm: "MOVWQSX", earlyOk: true}, // sign extend arg0 from int16 to int64 + {name: "MOVWQZX", argLength: 1, reg: gp11, asm: "MOVWLZX", earlyOk: true, zeroUpperBits: 48}, // zero extend arg0 from int16 to int64 + {name: "MOVLQSX", argLength: 1, reg: gp11, asm: "MOVLQSX", earlyOk: true}, // sign extend arg0 from int32 to int64 + {name: "MOVLQZX", argLength: 1, reg: gp11, asm: "MOVL", earlyOk: true, zeroUpperBits: 32}, // zero extend arg0 from int32 to int64 + + {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true, earlyOk: true, zeroUpperBits: 32}, // 32 low bits of auxint (upper 32 are zeroed) + {name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true, earlyOk: true}, // auxint + + {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL", earlyOk: true, zeroUpperBits: 32}, // convert float64 to int32 + {name: "CVTTSD2SQ", argLength: 1, reg: fpgp, asm: "CVTTSD2SQ", earlyOk: true}, // convert float64 to int64 + {name: "CVTTSS2SL", argLength: 1, reg: fpgp, asm: "CVTTSS2SL", earlyOk: true, zeroUpperBits: 32}, // convert float32 to int32 + {name: "CVTTSS2SQ", argLength: 1, reg: fpgp, asm: "CVTTSS2SQ", earlyOk: true}, // convert float32 to int64 + {name: "CVTSL2SS", argLength: 1, reg: gpfp, asm: "CVTSL2SS", earlyOk: true}, // convert int32 to float32 + {name: "CVTSL2SD", argLength: 1, reg: gpfp, asm: "CVTSL2SD", earlyOk: true}, // convert int32 to float64 + {name: "CVTSQ2SS", argLength: 1, reg: gpfp, asm: "CVTSQ2SS", earlyOk: true}, // convert int64 to float32 + {name: "CVTSQ2SD", argLength: 1, reg: gpfp, asm: "CVTSQ2SD", earlyOk: true}, // convert int64 to float64 + {name: "CVTSD2SS", argLength: 1, reg: fp11, asm: "CVTSD2SS", earlyOk: true}, // convert float64 to float32 + {name: "CVTSS2SD", argLength: 1, reg: fp11, asm: "CVTSS2SD", earlyOk: true}, // convert float32 to float64 // Move values between int and float registers, with no conversion. // TODO: should we have generic versions of these? - {name: "MOVQi2f", argLength: 1, reg: gpfp, typ: "Float64", earlyOk: true}, // move 64 bits from int to float reg - {name: "MOVQf2i", argLength: 1, reg: fpgp, typ: "UInt64", earlyOk: true}, // move 64 bits from float to int reg - {name: "MOVLi2f", argLength: 1, reg: gpfp, typ: "Float32", earlyOk: true}, // move 32 bits from int to float reg - {name: "MOVLf2i", argLength: 1, reg: fpgp, typ: "UInt32", earlyOk: true}, // move 32 bits from float to int reg, zero extend + {name: "MOVQi2f", argLength: 1, reg: gpfp, typ: "Float64", earlyOk: true}, // move 64 bits from int to float reg + {name: "MOVQf2i", argLength: 1, reg: fpgp, typ: "UInt64", earlyOk: true}, // move 64 bits from float to int reg + {name: "MOVLi2f", argLength: 1, reg: gpfp, typ: "Float32", earlyOk: true}, // move 32 bits from int to float reg + {name: "MOVLf2i", argLength: 1, reg: fpgp, typ: "UInt32", earlyOk: true, zeroUpperBits: 32}, // move 32 bits from float to int reg, zero extend {name: "PXOR", argLength: 2, reg: fp21, asm: "PXOR", commutative: true, resultInArg0: true, earlyOk: true}, // exclusive or, applied to X regs (for float negation). {name: "POR", argLength: 2, reg: fp21, asm: "POR", commutative: true, resultInArg0: true, earlyOk: true}, // inclusive or, applied to X regs (for float min/max). - {name: "LEAQ", argLength: 1, reg: gp11sb, asm: "LEAQ", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux - {name: "LEAL", argLength: 1, reg: gp11sb, asm: "LEAL", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux - {name: "LEAW", argLength: 1, reg: gp11sb, asm: "LEAW", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux + {name: "LEAQ", argLength: 1, reg: gp11sb, asm: "LEAQ", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux + {name: "LEAL", argLength: 1, reg: gp11sb, asm: "LEAL", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + auxint + offset encoded in aux + {name: "LEAW", argLength: 1, reg: gp11sb, asm: "LEAW", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux // LEAxn computes arg0 + n*arg1 + auxint + aux // x==L zeroes the upper 4 bytes. - {name: "LEAQ1", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux - {name: "LEAL1", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux - {name: "LEAW1", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux - {name: "LEAQ2", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux - {name: "LEAL2", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux - {name: "LEAW2", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux - {name: "LEAQ4", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux - {name: "LEAL4", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux - {name: "LEAW4", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux - {name: "LEAQ8", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux - {name: "LEAL8", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux - {name: "LEAW8", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux + {name: "LEAQ1", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux + {name: "LEAL1", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + arg1 + auxint + aux + {name: "LEAW1", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux + {name: "LEAQ2", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux + {name: "LEAL2", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + 2*arg1 + auxint + aux + {name: "LEAW2", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux + {name: "LEAQ4", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux + {name: "LEAL4", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + 4*arg1 + auxint + aux + {name: "LEAW4", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux + {name: "LEAQ8", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux + {name: "LEAL8", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + 8*arg1 + auxint + aux + {name: "LEAW8", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux // Note: LEAx{1,2,4,8} must not have OpSB as either argument. // MOVxload: loads // Load (Q=8,L=4,W=2,B=1) bytes from (arg0+auxint+aux), arg1=mem. // "+auxint+aux" == add auxint and the offset of the symbol in aux (if any) to the effective address // Standard versions zero extend the result. SX versions sign extend the result. - {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, + {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 56}, {name: "MOVBQSXload", argLength: 2, reg: gpload, asm: "MOVBQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, - {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, + {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 48}, {name: "MOVWQSXload", argLength: 2, reg: gpload, asm: "MOVWQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, - {name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, + {name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, {name: "MOVLQSXload", argLength: 2, reg: gpload, asm: "MOVLQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, {name: "MOVQload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, @@ -955,12 +955,12 @@ func init() { // MOVxloadidx: indexed loads // load (Q=8,L=4,W=2,B=1) bytes from (arg0+scale*arg1+auxint+aux), arg2=mem. // Results are zero-extended. (TODO: sign-extending indexed loads) - {name: "MOVBloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBLZX", scale: 1, aux: "SymOff", typ: "UInt8", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, - {name: "MOVWloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWLZX", scale: 1, aux: "SymOff", typ: "UInt16", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, - {name: "MOVWloadidx2", argLength: 3, reg: gploadidx, asm: "MOVWLZX", scale: 2, aux: "SymOff", typ: "UInt16", symEffect: "Read", addrSinkArg0: true}, - {name: "MOVLloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVL", scale: 1, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, - {name: "MOVLloadidx4", argLength: 3, reg: gploadidx, asm: "MOVL", scale: 4, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true}, - {name: "MOVLloadidx8", argLength: 3, reg: gploadidx, asm: "MOVL", scale: 8, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true}, + {name: "MOVBloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBLZX", scale: 1, aux: "SymOff", typ: "UInt8", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 56}, + {name: "MOVWloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWLZX", scale: 1, aux: "SymOff", typ: "UInt16", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 48}, + {name: "MOVWloadidx2", argLength: 3, reg: gploadidx, asm: "MOVWLZX", scale: 2, aux: "SymOff", typ: "UInt16", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 48}, + {name: "MOVLloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVL", scale: 1, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 32}, + {name: "MOVLloadidx4", argLength: 3, reg: gploadidx, asm: "MOVL", scale: 4, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, + {name: "MOVLloadidx8", argLength: 3, reg: gploadidx, asm: "MOVL", scale: 8, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, {name: "MOVQloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVQ", scale: 1, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, {name: "MOVQloadidx8", argLength: 3, reg: gploadidx, asm: "MOVQ", scale: 8, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true}, @@ -1141,7 +1141,7 @@ func init() { // Returns a pointer to a write barrier buffer in R11. {name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gp.union(g)), outputs: []regMask{buildReg("R11")}}, clobberFlags: true, aux: "Int64"}, - {name: "LoweredHasCPUFeature", argLength: 0, reg: gp01, rematerializeable: true, typ: "UInt64", aux: "Sym", symEffect: "None"}, + {name: "LoweredHasCPUFeature", argLength: 0, reg: gp01, rematerializeable: true, typ: "UInt64", aux: "Sym", symEffect: "None", zeroUpperBits: 56}, // LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail. // the RC and CR versions are used when one of the arguments is a constant. CC is used @@ -1170,7 +1170,7 @@ func init() { // so they can be properly ordered with other loads. // load from arg0+auxint+aux. arg1=mem. {name: "MOVBatomicload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, - {name: "MOVLatomicload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, + {name: "MOVLatomicload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read", zeroUpperBits: 32}, {name: "MOVQatomicload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // Atomic stores and exchanges. Stores use XCHG to get the right memory ordering semantics. @@ -1178,14 +1178,14 @@ func init() { // These ops return a tuple of . // Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)! {name: "XCHGB", argLength: 3, reg: gpstorexchg, asm: "XCHGB", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, - {name: "XCHGL", argLength: 3, reg: gpstorexchg, asm: "XCHGL", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, + {name: "XCHGL", argLength: 3, reg: gpstorexchg, asm: "XCHGL", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr", zeroUpperBits: 32}, {name: "XCHGQ", argLength: 3, reg: gpstorexchg, asm: "XCHGQ", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, // Atomic adds. // *(arg1+auxint+aux) += arg0. arg2=mem. // Returns a tuple of . // Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)! - {name: "XADDLlock", argLength: 3, reg: gpstorexchg, asm: "XADDL", typ: "(UInt32,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, + {name: "XADDLlock", argLength: 3, reg: gpstorexchg, asm: "XADDL", typ: "(UInt32,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr", zeroUpperBits: 32}, {name: "XADDQlock", argLength: 3, reg: gpstorexchg, asm: "XADDQ", typ: "(UInt64,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, {name: "AddTupleFirst32", argLength: 2}, // arg1=tuple . Returns . {name: "AddTupleFirst64", argLength: 2}, // arg1=tuple . Returns . @@ -1225,9 +1225,9 @@ func init() { // *(arg0+auxint+aux) op= arg1. arg2=mem. // New style that returns a tuple of . {name: "LoweredAtomicAnd64", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ANDQ", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicAnd32", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ANDL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true}, + {name: "LoweredAtomicAnd32", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ANDL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true, zeroUpperBits: 32}, {name: "LoweredAtomicOr64", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ORQ", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicOr32", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ORL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true}, + {name: "LoweredAtomicOr32", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ORL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true, zeroUpperBits: 32}, // Prefetch instructions // Do prefetch arg0 address. arg0=addr, arg1=memory. Instruction variant selects locality hint @@ -1235,16 +1235,22 @@ func init() { {name: "PrefetchNTA", argLength: 2, reg: prefreg, asm: "PREFETCHNTA", hasSideEffects: true}, // CPUID feature: BMI1. - {name: "ANDNQ", argLength: 2, reg: gp21, asm: "ANDNQ", clobberFlags: true}, // arg0 &^ arg1 - {name: "ANDNL", argLength: 2, reg: gp21, asm: "ANDNL", clobberFlags: true}, // arg0 &^ arg1 - {name: "BLSIQ", argLength: 1, reg: gp11, asm: "BLSIQ", clobberFlags: true}, // arg0 & -arg0 - {name: "BLSIL", argLength: 1, reg: gp11, asm: "BLSIL", clobberFlags: true}, // arg0 & -arg0 - {name: "BLSMSKQ", argLength: 1, reg: gp11, asm: "BLSMSKQ", clobberFlags: true}, // arg0 ^ (arg0 - 1) - {name: "BLSMSKL", argLength: 1, reg: gp11, asm: "BLSMSKL", clobberFlags: true}, // arg0 ^ (arg0 - 1) - {name: "BLSRQ", argLength: 1, reg: gp11flags, asm: "BLSRQ", typ: "(UInt64,Flags)"}, // arg0 & (arg0 - 1) - {name: "BLSRL", argLength: 1, reg: gp11flags, asm: "BLSRL", typ: "(UInt32,Flags)"}, // arg0 & (arg0 - 1) + {name: "ANDNQ", argLength: 2, reg: gp21, asm: "ANDNQ", clobberFlags: true}, // arg0 &^ arg1 + {name: "ANDNL", argLength: 2, reg: gp21, asm: "ANDNL", clobberFlags: true, zeroUpperBits: 32}, // arg0 &^ arg1 + {name: "BLSIQ", argLength: 1, reg: gp11, asm: "BLSIQ", clobberFlags: true}, // arg0 & -arg0 + {name: "BLSIL", argLength: 1, reg: gp11, asm: "BLSIL", clobberFlags: true, zeroUpperBits: 32}, // arg0 & -arg0 + {name: "BLSMSKQ", argLength: 1, reg: gp11, asm: "BLSMSKQ", clobberFlags: true}, // arg0 ^ (arg0 - 1) + {name: "BLSMSKL", argLength: 1, reg: gp11, asm: "BLSMSKL", clobberFlags: true, zeroUpperBits: 32}, // arg0 ^ (arg0 - 1) + {name: "BLSRQ", argLength: 1, reg: gp11flags, asm: "BLSRQ", typ: "(UInt64,Flags)"}, // arg0 & (arg0 - 1) + {name: "BLSRL", argLength: 1, reg: gp11flags, asm: "BLSRL", typ: "(UInt32,Flags)", zeroUpperBits: 32}, // arg0 & (arg0 - 1) // count the number of trailing zero bits, prefer TZCNTQ over BSFQ, as TZCNTQ(0)==64 // and BSFQ(0) is undefined. Same for TZCNTL(0)==32 + // + // TZCNT/LZCNT deliberately carry no zeroUpperBits: their result is + // bounded only as long as every rule producing them stays gated on + // GOAMD64 >= 3. On older parts their REP BSF/BSR encodings silently + // decode as legacy BSF/BSR, which leave the destination unmodified + // on zero input — a guarantee too easy to break silently. {name: "TZCNTQ", argLength: 1, reg: gp11, asm: "TZCNTQ", clobberFlags: true}, {name: "TZCNTL", argLength: 1, reg: gp11, asm: "TZCNTL", clobberFlags: true}, @@ -1255,17 +1261,17 @@ func init() { // CPUID feature: MOVBE // MOVBEWload does not satisfy zero extended, so only use MOVBEWstore - {name: "MOVBEWstore", argLength: 3, reg: gpstore, asm: "MOVBEW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem - {name: "MOVBELload", argLength: 2, reg: gpload, asm: "MOVBEL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load and swap 4 bytes from arg0+auxint+aux. arg1=mem. Zero extend. - {name: "MOVBELstore", argLength: 3, reg: gpstore, asm: "MOVBEL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem - {name: "MOVBEQload", argLength: 2, reg: gpload, asm: "MOVBEQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load and swap 8 bytes from arg0+auxint+aux. arg1=mem - {name: "MOVBEQstore", argLength: 3, reg: gpstore, asm: "MOVBEQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVBEWstore", argLength: 3, reg: gpstore, asm: "MOVBEW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVBELload", argLength: 2, reg: gpload, asm: "MOVBEL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // load and swap 4 bytes from arg0+auxint+aux. arg1=mem. Zero extend. + {name: "MOVBELstore", argLength: 3, reg: gpstore, asm: "MOVBEL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVBEQload", argLength: 2, reg: gpload, asm: "MOVBEQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load and swap 8 bytes from arg0+auxint+aux. arg1=mem + {name: "MOVBEQstore", argLength: 3, reg: gpstore, asm: "MOVBEQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem // indexed MOVBE loads - {name: "MOVBELloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBEL", scale: 1, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, // load and swap 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Zero extend. - {name: "MOVBELloadidx4", argLength: 3, reg: gploadidx, asm: "MOVBEL", scale: 4, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true}, // load and swap 4 bytes from arg0+4*arg1+auxint+aux. arg2=mem. Zero extend. - {name: "MOVBELloadidx8", argLength: 3, reg: gploadidx, asm: "MOVBEL", scale: 8, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true}, // load and swap 4 bytes from arg0+8*arg1+auxint+aux. arg2=mem. Zero extend. - {name: "MOVBEQloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBEQ", scale: 1, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, // load and swap 8 bytes from arg0+arg1+auxint+aux. arg2=mem - {name: "MOVBEQloadidx8", argLength: 3, reg: gploadidx, asm: "MOVBEQ", scale: 8, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true}, // load and swap 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem + {name: "MOVBELloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBEL", scale: 1, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 32}, // load and swap 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Zero extend. + {name: "MOVBELloadidx4", argLength: 3, reg: gploadidx, asm: "MOVBEL", scale: 4, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // load and swap 4 bytes from arg0+4*arg1+auxint+aux. arg2=mem. Zero extend. + {name: "MOVBELloadidx8", argLength: 3, reg: gploadidx, asm: "MOVBEL", scale: 8, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // load and swap 4 bytes from arg0+8*arg1+auxint+aux. arg2=mem. Zero extend. + {name: "MOVBEQloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBEQ", scale: 1, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, // load and swap 8 bytes from arg0+arg1+auxint+aux. arg2=mem + {name: "MOVBEQloadidx8", argLength: 3, reg: gploadidx, asm: "MOVBEQ", scale: 8, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true}, // load and swap 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem // indexed MOVBE stores {name: "MOVBEWstoreidx1", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVBEW", scale: 1, aux: "SymOff", symEffect: "Write", addrSinkArg0: true, addrSinkArg1: true}, // swap and store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem {name: "MOVBEWstoreidx2", argLength: 4, reg: gpstoreidx, asm: "MOVBEW", scale: 2, aux: "SymOff", symEffect: "Write", addrSinkArg0: true}, // swap and store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem @@ -1276,35 +1282,35 @@ func init() { {name: "MOVBEQstoreidx8", argLength: 4, reg: gpstoreidx, asm: "MOVBEQ", scale: 8, aux: "SymOff", symEffect: "Write", addrSinkArg0: true}, // swap and store 8 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem // CPUID feature: BMI2. - {name: "SARXQ", argLength: 2, reg: gp21, asm: "SARXQ"}, // signed arg0 >> arg1, shift amount is mod 64 - {name: "SARXL", argLength: 2, reg: gp21, asm: "SARXL"}, // signed int32(arg0) >> arg1, shift amount is mod 32 - {name: "SHLXQ", argLength: 2, reg: gp21, asm: "SHLXQ"}, // arg0 << arg1, shift amount is mod 64 - {name: "SHLXL", argLength: 2, reg: gp21, asm: "SHLXL"}, // arg0 << arg1, shift amount is mod 32 - {name: "SHRXQ", argLength: 2, reg: gp21, asm: "SHRXQ"}, // unsigned arg0 >> arg1, shift amount is mod 64 - {name: "SHRXL", argLength: 2, reg: gp21, asm: "SHRXL"}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32 - - {name: "SARXLload", argLength: 3, reg: gp21shxload, asm: "SARXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 32 - {name: "SARXQload", argLength: 3, reg: gp21shxload, asm: "SARXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 64 - {name: "SHLXLload", argLength: 3, reg: gp21shxload, asm: "SHLXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 32 - {name: "SHLXQload", argLength: 3, reg: gp21shxload, asm: "SHLXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 64 - {name: "SHRXLload", argLength: 3, reg: gp21shxload, asm: "SHRXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 32 - {name: "SHRXQload", argLength: 3, reg: gp21shxload, asm: "SHRXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 64 - - {name: "SARXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SARXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+4*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SARXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SARXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SARXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 - {name: "SARXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SARXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 - {name: "SHLXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 - {name: "SHLXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+4*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 - {name: "SHLXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 - {name: "SHLXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64 - {name: "SHLXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64 - {name: "SHRXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SHRXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+4*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SHRXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SHRXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 - {name: "SHRXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 + {name: "SARXQ", argLength: 2, reg: gp21, asm: "SARXQ"}, // signed arg0 >> arg1, shift amount is mod 64 + {name: "SARXL", argLength: 2, reg: gp21, asm: "SARXL", zeroUpperBits: 32}, // signed int32(arg0) >> arg1, shift amount is mod 32 + {name: "SHLXQ", argLength: 2, reg: gp21, asm: "SHLXQ"}, // arg0 << arg1, shift amount is mod 64 + {name: "SHLXL", argLength: 2, reg: gp21, asm: "SHLXL", zeroUpperBits: 32}, // arg0 << arg1, shift amount is mod 32 + {name: "SHRXQ", argLength: 2, reg: gp21, asm: "SHRXQ"}, // unsigned arg0 >> arg1, shift amount is mod 64 + {name: "SHRXL", argLength: 2, reg: gp21, asm: "SHRXL", zeroUpperBits: 32}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32 + + {name: "SARXLload", argLength: 3, reg: gp21shxload, asm: "SARXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // signed *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 32 + {name: "SARXQload", argLength: 3, reg: gp21shxload, asm: "SARXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 64 + {name: "SHLXLload", argLength: 3, reg: gp21shxload, asm: "SHLXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 32 + {name: "SHLXQload", argLength: 3, reg: gp21shxload, asm: "SHLXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 64 + {name: "SHRXLload", argLength: 3, reg: gp21shxload, asm: "SHRXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 32 + {name: "SHRXQload", argLength: 3, reg: gp21shxload, asm: "SHRXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 64 + + {name: "SARXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // signed *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SARXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // signed *(arg0+4*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SARXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // signed *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SARXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SARXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 + {name: "SARXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SARXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 + {name: "SHLXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 + {name: "SHLXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // *(arg0+4*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 + {name: "SHLXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 + {name: "SHLXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64 + {name: "SHLXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64 + {name: "SHRXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SHRXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // unsigned *(arg0+4*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SHRXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SHRXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 + {name: "SHRXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 // Unpack bytes, low 64-bits. // @@ -1358,7 +1364,7 @@ func init() { // Input treated as [16]uint8. Output is [16]bit (uint16 bitmap). // // output[i] = (input[i] >> 7) & 1 - {name: "PMOVMSKB", argLength: 1, reg: fpgp, asm: "PMOVMSKB"}, + {name: "PMOVMSKB", argLength: 1, reg: fpgp, asm: "PMOVMSKB", zeroUpperBits: 48}, // SIMD ops {name: "VMOVDQUload128", argLength: 2, reg: vload, asm: "VMOVDQU", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0+auxint+aux, arg1 = mem @@ -1425,12 +1431,12 @@ func init() { {name: "VPMOVVec64x8ToM", argLength: 1, reg: wk, asm: "VPMOVQ2M"}, // AVX1/2 moves from int-vector to bitmask (extracting sign bits) - {name: "VPMOVMSKB128", argLength: 1, reg: vgp, asm: "VPMOVMSKB"}, - {name: "VPMOVMSKB256", argLength: 1, reg: vgp, asm: "VPMOVMSKB"}, - {name: "VMOVMSKPS128", argLength: 1, reg: vgp, asm: "VMOVMSKPS"}, - {name: "VMOVMSKPS256", argLength: 1, reg: vgp, asm: "VMOVMSKPS"}, - {name: "VMOVMSKPD128", argLength: 1, reg: vgp, asm: "VMOVMSKPD"}, - {name: "VMOVMSKPD256", argLength: 1, reg: vgp, asm: "VMOVMSKPD"}, + {name: "VPMOVMSKB128", argLength: 1, reg: vgp, asm: "VPMOVMSKB", zeroUpperBits: 48}, + {name: "VPMOVMSKB256", argLength: 1, reg: vgp, asm: "VPMOVMSKB", zeroUpperBits: 32}, + {name: "VMOVMSKPS128", argLength: 1, reg: vgp, asm: "VMOVMSKPS", zeroUpperBits: 56}, + {name: "VMOVMSKPS256", argLength: 1, reg: vgp, asm: "VMOVMSKPS", zeroUpperBits: 56}, + {name: "VMOVMSKPD128", argLength: 1, reg: vgp, asm: "VMOVMSKPD", zeroUpperBits: 56}, + {name: "VMOVMSKPD256", argLength: 1, reg: vgp, asm: "VMOVMSKPD", zeroUpperBits: 56}, // X15 is the zero register up to 128-bit. For larger values, we zero it on the fly. {name: "Zero128", argLength: 0, reg: x15only, zeroWidth: true, fixedReg: true}, @@ -1477,9 +1483,9 @@ func init() { {name: "KMOVWk", argLength: 1, reg: gpk, asm: "KMOVW"}, {name: "KMOVBk", argLength: 1, reg: gpk, asm: "KMOVB"}, {name: "KMOVQi", argLength: 1, reg: kgp, asm: "KMOVQ"}, - {name: "KMOVDi", argLength: 1, reg: kgp, asm: "KMOVD"}, - {name: "KMOVWi", argLength: 1, reg: kgp, asm: "KMOVW"}, - {name: "KMOVBi", argLength: 1, reg: kgp, asm: "KMOVB"}, + {name: "KMOVDi", argLength: 1, reg: kgp, asm: "KMOVD", zeroUpperBits: 32}, + {name: "KMOVWi", argLength: 1, reg: kgp, asm: "KMOVW", zeroUpperBits: 48}, + {name: "KMOVBi", argLength: 1, reg: kgp, asm: "KMOVB", zeroUpperBits: 56}, // Mask logical operations {name: "KANDB", argLength: 2, reg: k2k, asm: "KANDB", typ: "Mask"}, diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules b/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules index 9bdb5f8d803bdb..04070889aa876f 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules @@ -8,6 +8,6 @@ (SHR(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SHRX(Q|L) x y) // See comments in ARM64latelower.rules for why these are here. -(MOVLQZX x) && ZeroUpper32Bits(x,3) => x -(MOVWQZX x) && ZeroUpper48Bits(x,3) => x -(MOVBQZX x) && ZeroUpper56Bits(x,3) => x +(MOVLQZX x) && ZeroUpper32Bits(x) => x +(MOVWQZX x) && ZeroUpper48Bits(x) => x +(MOVBQZX x) && ZeroUpper56Bits(x) => x diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64.rules b/src/cmd/compile/internal/ssa/_gen/ARM64.rules index 8189f1583b9627..b5a50f1081dd7a 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/_gen/ARM64.rules @@ -657,10 +657,10 @@ // against 128 (=2^7) is a bit-7 test, for both compare widths and both // signednesses: with the value in [0,255] the signed and unsigned orderings // against 128 coincide. -((UGE|ULT) (CMPWconst [128] x) yes no) && ZeroUpper56Bits(x, 3) => ((TBNZ|TBZ) [7] x yes no) -((UGE|ULT) (CMPconst [128] x) yes no) && ZeroUpper56Bits(x, 3) => ((TBNZ|TBZ) [7] x yes no) -((GE|LT) (CMPWconst [128] x) yes no) && ZeroUpper56Bits(x, 3) => ((TBNZ|TBZ) [7] x yes no) -((GE|LT) (CMPconst [128] x) yes no) && ZeroUpper56Bits(x, 3) => ((TBNZ|TBZ) [7] x yes no) +((UGE|ULT) (CMPWconst [128] x) yes no) && ZeroUpper56Bits(x) => ((TBNZ|TBZ) [7] x yes no) +((UGE|ULT) (CMPconst [128] x) yes no) && ZeroUpper56Bits(x) => ((TBNZ|TBZ) [7] x yes no) +((GE|LT) (CMPWconst [128] x) yes no) && ZeroUpper56Bits(x) => ((TBNZ|TBZ) [7] x yes no) +((GE|LT) (CMPconst [128] x) yes no) && ZeroUpper56Bits(x) => ((TBNZ|TBZ) [7] x yes no) // fold offset into address (ADDconst [off1] (MOVDaddr [off2] {sym} ptr)) && is32Bit(off1+int64(off2)) => diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go index 0da3151acd3e7c..4c29e410f19ea9 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go @@ -195,32 +195,32 @@ func init() { ) ops := []opData{ // binary ops - {name: "ADCSflags", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "ADCS", commutative: true}, // arg0+arg1+carry, set flags. - {name: "ADCzerocarry", argLength: 1, reg: gp0flags1, typ: "UInt64", asm: "ADC", earlyOk: true}, // ZR+ZR+carry - {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true, earlyOk: true}, // arg0 + arg1 - {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int64", earlyOk: true}, // arg0 + auxInt - {name: "ADDSconstflags", argLength: 1, reg: gp11flags, typ: "(UInt64,Flags)", asm: "ADDS", aux: "Int64"}, // arg0+auxint, set flags. - {name: "ADDSflags", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "ADDS", commutative: true}, // arg0+arg1, set flags. - {name: "SUB", argLength: 2, reg: gp21, asm: "SUB", earlyOk: true}, // arg0 - arg1 - {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int64", earlyOk: true}, // arg0 - auxInt - {name: "SBCSflags", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "SBCS"}, // arg0-(arg1+borrowing), set flags. - {name: "SUBSflags", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "SUBS"}, // arg0 - arg1, set flags. - {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true, earlyOk: true}, // arg0 * arg1 - {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true, earlyOk: true}, // arg0 * arg1, 32-bit - {name: "MNEG", argLength: 2, reg: gp21, asm: "MNEG", commutative: true, earlyOk: true}, // -arg0 * arg1 - {name: "MNEGW", argLength: 2, reg: gp21, asm: "MNEGW", commutative: true, earlyOk: true}, // -arg0 * arg1, 32-bit - {name: "MULH", argLength: 2, reg: gp21, asm: "SMULH", commutative: true, earlyOk: true}, // (arg0 * arg1) >> 64, signed - {name: "UMULH", argLength: 2, reg: gp21, asm: "UMULH", commutative: true, earlyOk: true}, // (arg0 * arg1) >> 64, unsigned - {name: "MULL", argLength: 2, reg: gp21, asm: "SMULL", commutative: true, earlyOk: true}, // arg0 * arg1, signed, 32-bit mult results in 64-bit - {name: "UMULL", argLength: 2, reg: gp21, asm: "UMULL", commutative: true, earlyOk: true}, // arg0 * arg1, unsigned, 32-bit mult results in 64-bit - {name: "DIV", argLength: 2, reg: gp21, asm: "SDIV", earlyOk: true}, // arg0 / arg1, signed - {name: "UDIV", argLength: 2, reg: gp21, asm: "UDIV", earlyOk: true}, // arg0 / arg1, unsigned - {name: "DIVW", argLength: 2, reg: gp21, asm: "SDIVW", earlyOk: true}, // arg0 / arg1, signed, 32 bit - {name: "UDIVW", argLength: 2, reg: gp21, asm: "UDIVW", earlyOk: true}, // arg0 / arg1, unsigned, 32 bit - {name: "MOD", argLength: 2, reg: gp21, asm: "REM", earlyOk: true}, // arg0 % arg1, signed - {name: "UMOD", argLength: 2, reg: gp21, asm: "UREM", earlyOk: true}, // arg0 % arg1, unsigned - {name: "MODW", argLength: 2, reg: gp21, asm: "REMW", earlyOk: true}, // arg0 % arg1, signed, 32 bit - {name: "UMODW", argLength: 2, reg: gp21, asm: "UREMW", earlyOk: true}, // arg0 % arg1, unsigned, 32 bit + {name: "ADCSflags", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "ADCS", commutative: true}, // arg0+arg1+carry, set flags. + {name: "ADCzerocarry", argLength: 1, reg: gp0flags1, typ: "UInt64", asm: "ADC", earlyOk: true, zeroUpperBits: 56}, // ZR+ZR+carry + {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true, earlyOk: true}, // arg0 + arg1 + {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int64", earlyOk: true}, // arg0 + auxInt + {name: "ADDSconstflags", argLength: 1, reg: gp11flags, typ: "(UInt64,Flags)", asm: "ADDS", aux: "Int64"}, // arg0+auxint, set flags. + {name: "ADDSflags", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "ADDS", commutative: true}, // arg0+arg1, set flags. + {name: "SUB", argLength: 2, reg: gp21, asm: "SUB", earlyOk: true}, // arg0 - arg1 + {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int64", earlyOk: true}, // arg0 - auxInt + {name: "SBCSflags", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "SBCS"}, // arg0-(arg1+borrowing), set flags. + {name: "SUBSflags", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "SUBS"}, // arg0 - arg1, set flags. + {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true, earlyOk: true}, // arg0 * arg1 + {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true, earlyOk: true, zeroUpperBits: 32}, // arg0 * arg1, 32-bit + {name: "MNEG", argLength: 2, reg: gp21, asm: "MNEG", commutative: true, earlyOk: true}, // -arg0 * arg1 + {name: "MNEGW", argLength: 2, reg: gp21, asm: "MNEGW", commutative: true, earlyOk: true, zeroUpperBits: 32}, // -arg0 * arg1, 32-bit + {name: "MULH", argLength: 2, reg: gp21, asm: "SMULH", commutative: true, earlyOk: true}, // (arg0 * arg1) >> 64, signed + {name: "UMULH", argLength: 2, reg: gp21, asm: "UMULH", commutative: true, earlyOk: true}, // (arg0 * arg1) >> 64, unsigned + {name: "MULL", argLength: 2, reg: gp21, asm: "SMULL", commutative: true, earlyOk: true}, // arg0 * arg1, signed, 32-bit mult results in 64-bit + {name: "UMULL", argLength: 2, reg: gp21, asm: "UMULL", commutative: true, earlyOk: true}, // arg0 * arg1, unsigned, 32-bit mult results in 64-bit + {name: "DIV", argLength: 2, reg: gp21, asm: "SDIV", earlyOk: true}, // arg0 / arg1, signed + {name: "UDIV", argLength: 2, reg: gp21, asm: "UDIV", earlyOk: true}, // arg0 / arg1, unsigned + {name: "DIVW", argLength: 2, reg: gp21, asm: "SDIVW", earlyOk: true, zeroUpperBits: 32}, // arg0 / arg1, signed, 32 bit + {name: "UDIVW", argLength: 2, reg: gp21, asm: "UDIVW", earlyOk: true, zeroUpperBits: 32}, // arg0 / arg1, unsigned, 32 bit + {name: "MOD", argLength: 2, reg: gp21, asm: "REM", earlyOk: true}, // arg0 % arg1, signed + {name: "UMOD", argLength: 2, reg: gp21, asm: "UREM", earlyOk: true}, // arg0 % arg1, unsigned + {name: "MODW", argLength: 2, reg: gp21, asm: "REMW", earlyOk: true, zeroUpperBits: 32}, // arg0 % arg1, signed, 32 bit + {name: "UMODW", argLength: 2, reg: gp21, asm: "UREMW", earlyOk: true, zeroUpperBits: 32}, // arg0 % arg1, unsigned, 32 bit {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true, earlyOk: true}, // arg0 + arg1 {name: "FADDD", argLength: 2, reg: fp21, asm: "FADDD", commutative: true, earlyOk: true}, // arg0 + arg1 @@ -259,45 +259,45 @@ func init() { {name: "FMAXD", argLength: 2, reg: fp21, asm: "FMAXD", earlyOk: true}, // max(arg0, arg1) {name: "FMAXS", argLength: 2, reg: fp21, asm: "FMAXS", earlyOk: true}, // max(arg0, arg1) {name: "REV", argLength: 1, reg: gp11, asm: "REV", earlyOk: true}, // byte reverse, 64-bit - {name: "REVW", argLength: 1, reg: gp11, asm: "REVW", earlyOk: true}, // byte reverse, 32-bit + {name: "REVW", argLength: 1, reg: gp11, asm: "REVW", earlyOk: true, zeroUpperBits: 32}, // byte reverse, 32-bit {name: "REV16", argLength: 1, reg: gp11, asm: "REV16", earlyOk: true}, // byte reverse in each 16-bit halfword, 64-bit - {name: "REV16W", argLength: 1, reg: gp11, asm: "REV16W", earlyOk: true}, // byte reverse in each 16-bit halfword, 32-bit + {name: "REV16W", argLength: 1, reg: gp11, asm: "REV16W", earlyOk: true, zeroUpperBits: 32}, // byte reverse in each 16-bit halfword, 32-bit {name: "RBIT", argLength: 1, reg: gp11, asm: "RBIT", earlyOk: true}, // bit reverse, 64-bit - {name: "RBITW", argLength: 1, reg: gp11, asm: "RBITW", earlyOk: true}, // bit reverse, 32-bit - {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ", earlyOk: true}, // count leading zero, 64-bit - {name: "CLZW", argLength: 1, reg: gp11, asm: "CLZW", earlyOk: true}, // count leading zero, 32-bit + {name: "RBITW", argLength: 1, reg: gp11, asm: "RBITW", earlyOk: true, zeroUpperBits: 32}, // bit reverse, 32-bit + {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ", earlyOk: true, zeroUpperBits: 56}, // count leading zero, 64-bit + {name: "CLZW", argLength: 1, reg: gp11, asm: "CLZW", earlyOk: true, zeroUpperBits: 56}, // count leading zero, 32-bit {name: "VCNT", argLength: 1, reg: fp11, asm: "VCNT", earlyOk: true}, // count set bits for each 8-bit unit and store the result in each 8-bit unit {name: "VUADDLV", argLength: 1, reg: fp11, asm: "VUADDLV", earlyOk: true}, // unsigned sum of eight bytes in a 64-bit value, zero extended to 64-bit. {name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true, earlyOk: true}, {name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true, earlyOk: true}, // 3-operand, the addend comes first - {name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS", earlyOk: true}, // +arg0 + (arg1 * arg2) - {name: "FMADDD", argLength: 3, reg: fp31, asm: "FMADDD", earlyOk: true}, // +arg0 + (arg1 * arg2) - {name: "FNMADDS", argLength: 3, reg: fp31, asm: "FNMADDS", earlyOk: true}, // -arg0 - (arg1 * arg2) - {name: "FNMADDD", argLength: 3, reg: fp31, asm: "FNMADDD", earlyOk: true}, // -arg0 - (arg1 * arg2) - {name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS", earlyOk: true}, // +arg0 - (arg1 * arg2) - {name: "FMSUBD", argLength: 3, reg: fp31, asm: "FMSUBD", earlyOk: true}, // +arg0 - (arg1 * arg2) - {name: "FNMSUBS", argLength: 3, reg: fp31, asm: "FNMSUBS", earlyOk: true}, // -arg0 + (arg1 * arg2) - {name: "FNMSUBD", argLength: 3, reg: fp31, asm: "FNMSUBD", earlyOk: true}, // -arg0 + (arg1 * arg2) - {name: "MADD", argLength: 3, reg: gp31, asm: "MADD", earlyOk: true}, // +arg0 + (arg1 * arg2) - {name: "MADDW", argLength: 3, reg: gp31, asm: "MADDW", earlyOk: true}, // +arg0 + (arg1 * arg2), 32-bit - {name: "MSUB", argLength: 3, reg: gp31, asm: "MSUB", earlyOk: true}, // +arg0 - (arg1 * arg2) - {name: "MSUBW", argLength: 3, reg: gp31, asm: "MSUBW", earlyOk: true}, // +arg0 - (arg1 * arg2), 32-bit + {name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS", earlyOk: true}, // +arg0 + (arg1 * arg2) + {name: "FMADDD", argLength: 3, reg: fp31, asm: "FMADDD", earlyOk: true}, // +arg0 + (arg1 * arg2) + {name: "FNMADDS", argLength: 3, reg: fp31, asm: "FNMADDS", earlyOk: true}, // -arg0 - (arg1 * arg2) + {name: "FNMADDD", argLength: 3, reg: fp31, asm: "FNMADDD", earlyOk: true}, // -arg0 - (arg1 * arg2) + {name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS", earlyOk: true}, // +arg0 - (arg1 * arg2) + {name: "FMSUBD", argLength: 3, reg: fp31, asm: "FMSUBD", earlyOk: true}, // +arg0 - (arg1 * arg2) + {name: "FNMSUBS", argLength: 3, reg: fp31, asm: "FNMSUBS", earlyOk: true}, // -arg0 + (arg1 * arg2) + {name: "FNMSUBD", argLength: 3, reg: fp31, asm: "FNMSUBD", earlyOk: true}, // -arg0 + (arg1 * arg2) + {name: "MADD", argLength: 3, reg: gp31, asm: "MADD", earlyOk: true}, // +arg0 + (arg1 * arg2) + {name: "MADDW", argLength: 3, reg: gp31, asm: "MADDW", earlyOk: true, zeroUpperBits: 32}, // +arg0 + (arg1 * arg2), 32-bit + {name: "MSUB", argLength: 3, reg: gp31, asm: "MSUB", earlyOk: true}, // +arg0 - (arg1 * arg2) + {name: "MSUBW", argLength: 3, reg: gp31, asm: "MSUBW", earlyOk: true, zeroUpperBits: 32}, // +arg0 - (arg1 * arg2), 32-bit // shifts - {name: "SLL", argLength: 2, reg: gp21, asm: "LSL", earlyOk: true}, // arg0 << arg1, shift amount is mod 64 - {name: "SLLconst", argLength: 1, reg: gp11, asm: "LSL", aux: "Int64", earlyOk: true}, // arg0 << auxInt, auxInt should be in the range 0 to 63. - {name: "SRL", argLength: 2, reg: gp21, asm: "LSR", earlyOk: true}, // arg0 >> arg1, unsigned, shift amount is mod 64 - {name: "SRLconst", argLength: 1, reg: gp11, asm: "LSR", aux: "Int64", earlyOk: true}, // arg0 >> auxInt, unsigned, auxInt should be in the range 0 to 63. - {name: "SRA", argLength: 2, reg: gp21, asm: "ASR", earlyOk: true}, // arg0 >> arg1, signed, shift amount is mod 64 - {name: "SRAconst", argLength: 1, reg: gp11, asm: "ASR", aux: "Int64", earlyOk: true}, // arg0 >> auxInt, signed, auxInt should be in the range 0 to 63. - {name: "ROR", argLength: 2, reg: gp21, asm: "ROR", earlyOk: true}, // arg0 right rotate by (arg1 mod 64) bits - {name: "RORW", argLength: 2, reg: gp21, asm: "RORW", earlyOk: true}, // arg0 right rotate by (arg1 mod 32) bits - {name: "RORconst", argLength: 1, reg: gp11, asm: "ROR", aux: "Int64", earlyOk: true}, // arg0 right rotate by auxInt bits, auxInt should be in the range 0 to 63. - {name: "RORWconst", argLength: 1, reg: gp11, asm: "RORW", aux: "Int64", earlyOk: true}, // uint32(arg0) right rotate by auxInt bits, auxInt should be in the range 0 to 31. - {name: "EXTRconst", argLength: 2, reg: gp21, asm: "EXTR", aux: "Int64", earlyOk: true}, // extract 64 bits from arg0:arg1 starting at lsb auxInt, auxInt should be in the range 0 to 63. - {name: "EXTRWconst", argLength: 2, reg: gp21, asm: "EXTRW", aux: "Int64", earlyOk: true}, // extract 32 bits from arg0[31:0]:arg1[31:0] starting at lsb auxInt and zero top 32 bits, auxInt should be in the range 0 to 31. + {name: "SLL", argLength: 2, reg: gp21, asm: "LSL", earlyOk: true}, // arg0 << arg1, shift amount is mod 64 + {name: "SLLconst", argLength: 1, reg: gp11, asm: "LSL", aux: "Int64", earlyOk: true}, // arg0 << auxInt, auxInt should be in the range 0 to 63. + {name: "SRL", argLength: 2, reg: gp21, asm: "LSR", earlyOk: true}, // arg0 >> arg1, unsigned, shift amount is mod 64 + {name: "SRLconst", argLength: 1, reg: gp11, asm: "LSR", aux: "Int64", earlyOk: true}, // arg0 >> auxInt, unsigned, auxInt should be in the range 0 to 63. + {name: "SRA", argLength: 2, reg: gp21, asm: "ASR", earlyOk: true}, // arg0 >> arg1, signed, shift amount is mod 64 + {name: "SRAconst", argLength: 1, reg: gp11, asm: "ASR", aux: "Int64", earlyOk: true}, // arg0 >> auxInt, signed, auxInt should be in the range 0 to 63. + {name: "ROR", argLength: 2, reg: gp21, asm: "ROR", earlyOk: true}, // arg0 right rotate by (arg1 mod 64) bits + {name: "RORW", argLength: 2, reg: gp21, asm: "RORW", earlyOk: true, zeroUpperBits: 32}, // arg0 right rotate by (arg1 mod 32) bits + {name: "RORconst", argLength: 1, reg: gp11, asm: "ROR", aux: "Int64", earlyOk: true}, // arg0 right rotate by auxInt bits, auxInt should be in the range 0 to 63. + {name: "RORWconst", argLength: 1, reg: gp11, asm: "RORW", aux: "Int64", earlyOk: true, zeroUpperBits: 32}, // uint32(arg0) right rotate by auxInt bits, auxInt should be in the range 0 to 31. + {name: "EXTRconst", argLength: 2, reg: gp21, asm: "EXTR", aux: "Int64", earlyOk: true}, // extract 64 bits from arg0:arg1 starting at lsb auxInt, auxInt should be in the range 0 to 63. + {name: "EXTRWconst", argLength: 2, reg: gp21, asm: "EXTRW", aux: "Int64", earlyOk: true, zeroUpperBits: 32}, // extract 32 bits from arg0[31:0]:arg1[31:0] starting at lsb auxInt and zero top 32 bits, auxInt should be in the range 0 to 31. // comparisons {name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1 @@ -388,16 +388,16 @@ func init() { {name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP").union(buildReg("SB"))}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB - {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "FMOVQload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVQ", typ: "Vec128", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 56}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 48}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "FMOVQload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVQ", typ: "Vec128", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. // LDP instructions load the contents of two adjacent locations in memory into registers. // Address to start loading is addr = arg0 + auxInt + aux. @@ -405,32 +405,32 @@ func init() { // y := *(*T)(addr+sizeof(T)) // arg1=mem // Returns the tuple . - {name: "LDP", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDP", typ: "(UInt64,UInt64)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int64 (gp reg destination) - {name: "LDPW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPW", typ: "(UInt32,UInt32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int32 (gp reg destination) unsigned extension - {name: "LDPSW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPSW", typ: "(Int32,Int32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int32 (gp reg destination) signed extension - {name: "FLDPD", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPD", typ: "(Float64,Float64)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=float64 (fp reg destination) - {name: "FLDPS", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPS", typ: "(Float32,Float32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=float32 (fp reg destination) - {name: "FLDPQ", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPQ", typ: "(Vec128,Vec128)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=vec128 (fp reg destination) + {name: "LDP", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDP", typ: "(UInt64,UInt64)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int64 (gp reg destination) + {name: "LDPW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPW", typ: "(UInt32,UInt32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // T=int32 (gp reg destination) unsigned extension + {name: "LDPSW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPSW", typ: "(Int32,Int32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int32 (gp reg destination) signed extension + {name: "FLDPD", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPD", typ: "(Float64,Float64)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=float64 (fp reg destination) + {name: "FLDPS", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPS", typ: "(Float32,Float32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=float32 (fp reg destination) + {name: "FLDPQ", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPQ", typ: "(Vec128,Vec128)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=vec128 (fp reg destination) // register indexed load - {name: "MOVDloadidx", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64", addrSinkArg0: true, addrSinkArg1: true}, // load 64-bit dword from arg0 + arg1, arg2 = mem. - {name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. - {name: "MOVWUloadidx", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. - {name: "MOVHloadidx", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16", addrSinkArg0: true, addrSinkArg1: true}, // load 16-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. - {name: "MOVHUloadidx", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16", addrSinkArg0: true, addrSinkArg1: true}, // load 16-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. - {name: "MOVBloadidx", argLength: 3, reg: gp2load, asm: "MOVB", typ: "Int8", addrSinkArg0: true, addrSinkArg1: true}, // load 8-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. - {name: "MOVBUloadidx", argLength: 3, reg: gp2load, asm: "MOVBU", typ: "UInt8", addrSinkArg0: true, addrSinkArg1: true}, // load 8-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. - {name: "FMOVSloadidx", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit float from arg0 + arg1, arg2=mem. - {name: "FMOVDloadidx", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64", addrSinkArg0: true, addrSinkArg1: true}, // load 64-bit float from arg0 + arg1, arg2=mem. + {name: "MOVDloadidx", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64", addrSinkArg0: true, addrSinkArg1: true}, // load 64-bit dword from arg0 + arg1, arg2 = mem. + {name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. + {name: "MOVWUloadidx", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 32}, // load 32-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "MOVHloadidx", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16", addrSinkArg0: true, addrSinkArg1: true}, // load 16-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. + {name: "MOVHUloadidx", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 48}, // load 16-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "MOVBloadidx", argLength: 3, reg: gp2load, asm: "MOVB", typ: "Int8", addrSinkArg0: true, addrSinkArg1: true}, // load 8-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. + {name: "MOVBUloadidx", argLength: 3, reg: gp2load, asm: "MOVBU", typ: "UInt8", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 56}, // load 8-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "FMOVSloadidx", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit float from arg0 + arg1, arg2=mem. + {name: "FMOVDloadidx", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64", addrSinkArg0: true, addrSinkArg1: true}, // load 64-bit float from arg0 + arg1, arg2=mem. // shifted register indexed load - {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16", addrSinkArg0: true}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem. - {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16", addrSinkArg0: true}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem. - {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32", addrSinkArg0: true}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem. - {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32", addrSinkArg0: true}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem. - {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64", addrSinkArg0: true}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem. - {name: "FMOVSloadidx4", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32", addrSinkArg0: true}, // load 32-bit float from arg0 + arg1*4, arg2 = mem. - {name: "FMOVDloadidx8", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64", addrSinkArg0: true}, // load 64-bit float from arg0 + arg1*8, arg2 = mem. + {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16", addrSinkArg0: true}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem. + {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16", addrSinkArg0: true, zeroUpperBits: 48}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem. + {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32", addrSinkArg0: true}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem. + {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32", addrSinkArg0: true, zeroUpperBits: 32}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem. + {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64", addrSinkArg0: true}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem. + {name: "FMOVSloadidx4", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32", addrSinkArg0: true}, // load 32-bit float from arg0 + arg1*4, arg2 = mem. + {name: "FMOVDloadidx8", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64", addrSinkArg0: true}, // load 64-bit float from arg0 + arg1*8, arg2 = mem. {name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. @@ -466,40 +466,40 @@ func init() { {name: "FMOVSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "FMOVS", typ: "Mem", addrSinkArg0: true}, // store 32-bit float of arg2 to arg0 + arg1*4, arg3=mem. {name: "FMOVDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "FMOVD", typ: "Mem", addrSinkArg0: true}, // store 64-bit float of arg2 to arg0 + arg1*8, arg3=mem. - {name: "FMOVDgpfp", argLength: 1, reg: gpfp, asm: "FMOVD", earlyOk: true}, // move int64 to float64 (no conversion) - {name: "FMOVDfpgp", argLength: 1, reg: fpgp, asm: "FMOVD", earlyOk: true}, // move float64 to int64 (no conversion) - {name: "FMOVSgpfp", argLength: 1, reg: gpfp, asm: "FMOVS", earlyOk: true}, // move 32bits from int to float reg (no conversion) - {name: "FMOVSfpgp", argLength: 1, reg: fpgp, asm: "FMOVS", earlyOk: true}, // move 32bits from float to int reg, zero extend (no conversion) + {name: "FMOVDgpfp", argLength: 1, reg: gpfp, asm: "FMOVD", earlyOk: true}, // move int64 to float64 (no conversion) + {name: "FMOVDfpgp", argLength: 1, reg: fpgp, asm: "FMOVD", earlyOk: true}, // move float64 to int64 (no conversion) + {name: "FMOVSgpfp", argLength: 1, reg: gpfp, asm: "FMOVS", earlyOk: true}, // move 32bits from int to float reg (no conversion) + {name: "FMOVSfpgp", argLength: 1, reg: fpgp, asm: "FMOVS", earlyOk: true, zeroUpperBits: 32}, // move 32bits from float to int reg, zero extend (no conversion) // conversions - {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", earlyOk: true}, // move from arg0, sign-extended from byte - {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU", earlyOk: true}, // move from arg0, unsign-extended from byte - {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", earlyOk: true}, // move from arg0, sign-extended from half - {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU", earlyOk: true}, // move from arg0, unsign-extended from half - {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", earlyOk: true}, // move from arg0, sign-extended from word - {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU", earlyOk: true}, // move from arg0, unsign-extended from word - {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOVD", earlyOk: true}, // move from arg0 + {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", earlyOk: true}, // move from arg0, sign-extended from byte + {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU", earlyOk: true, zeroUpperBits: 56}, // move from arg0, unsign-extended from byte + {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", earlyOk: true}, // move from arg0, sign-extended from half + {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU", earlyOk: true, zeroUpperBits: 48}, // move from arg0, unsign-extended from half + {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", earlyOk: true}, // move from arg0, sign-extended from word + {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU", earlyOk: true, zeroUpperBits: 32}, // move from arg0, unsign-extended from word + {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOVD", earlyOk: true}, // move from arg0 {name: "MOVDnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true, earlyOk: true}, // nop, return arg0 in same register - {name: "SCVTFWS", argLength: 1, reg: gpfp, asm: "SCVTFWS", earlyOk: true}, // int32 -> float32 - {name: "SCVTFWD", argLength: 1, reg: gpfp, asm: "SCVTFWD", earlyOk: true}, // int32 -> float64 - {name: "UCVTFWS", argLength: 1, reg: gpfp, asm: "UCVTFWS", earlyOk: true}, // uint32 -> float32 - {name: "UCVTFWD", argLength: 1, reg: gpfp, asm: "UCVTFWD", earlyOk: true}, // uint32 -> float64 - {name: "SCVTFS", argLength: 1, reg: gpfp, asm: "SCVTFS", earlyOk: true}, // int64 -> float32 - {name: "SCVTFD", argLength: 1, reg: gpfp, asm: "SCVTFD", earlyOk: true}, // int64 -> float64 - {name: "UCVTFS", argLength: 1, reg: gpfp, asm: "UCVTFS", earlyOk: true}, // uint64 -> float32 - {name: "UCVTFD", argLength: 1, reg: gpfp, asm: "UCVTFD", earlyOk: true}, // uint64 -> float64 - {name: "FCVTZSSW", argLength: 1, reg: fpgp, asm: "FCVTZSSW", earlyOk: true}, // float32 -> int32 - {name: "FCVTZSDW", argLength: 1, reg: fpgp, asm: "FCVTZSDW", earlyOk: true}, // float64 -> int32 - {name: "FCVTZUSW", argLength: 1, reg: fpgp, asm: "FCVTZUSW", earlyOk: true}, // float32 -> uint32 - {name: "FCVTZUDW", argLength: 1, reg: fpgp, asm: "FCVTZUDW", earlyOk: true}, // float64 -> uint32 - {name: "FCVTZSS", argLength: 1, reg: fpgp, asm: "FCVTZSS", earlyOk: true}, // float32 -> int64 - {name: "FCVTZSD", argLength: 1, reg: fpgp, asm: "FCVTZSD", earlyOk: true}, // float64 -> int64 - {name: "FCVTZUS", argLength: 1, reg: fpgp, asm: "FCVTZUS", earlyOk: true}, // float32 -> uint64 - {name: "FCVTZUD", argLength: 1, reg: fpgp, asm: "FCVTZUD", earlyOk: true}, // float64 -> uint64 - {name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD", earlyOk: true}, // float32 -> float64 - {name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS", earlyOk: true}, // float64 -> float32 + {name: "SCVTFWS", argLength: 1, reg: gpfp, asm: "SCVTFWS", earlyOk: true}, // int32 -> float32 + {name: "SCVTFWD", argLength: 1, reg: gpfp, asm: "SCVTFWD", earlyOk: true}, // int32 -> float64 + {name: "UCVTFWS", argLength: 1, reg: gpfp, asm: "UCVTFWS", earlyOk: true}, // uint32 -> float32 + {name: "UCVTFWD", argLength: 1, reg: gpfp, asm: "UCVTFWD", earlyOk: true}, // uint32 -> float64 + {name: "SCVTFS", argLength: 1, reg: gpfp, asm: "SCVTFS", earlyOk: true}, // int64 -> float32 + {name: "SCVTFD", argLength: 1, reg: gpfp, asm: "SCVTFD", earlyOk: true}, // int64 -> float64 + {name: "UCVTFS", argLength: 1, reg: gpfp, asm: "UCVTFS", earlyOk: true}, // uint64 -> float32 + {name: "UCVTFD", argLength: 1, reg: gpfp, asm: "UCVTFD", earlyOk: true}, // uint64 -> float64 + {name: "FCVTZSSW", argLength: 1, reg: fpgp, asm: "FCVTZSSW", earlyOk: true, zeroUpperBits: 32}, // float32 -> int32 + {name: "FCVTZSDW", argLength: 1, reg: fpgp, asm: "FCVTZSDW", earlyOk: true, zeroUpperBits: 32}, // float64 -> int32 + {name: "FCVTZUSW", argLength: 1, reg: fpgp, asm: "FCVTZUSW", earlyOk: true, zeroUpperBits: 32}, // float32 -> uint32 + {name: "FCVTZUDW", argLength: 1, reg: fpgp, asm: "FCVTZUDW", earlyOk: true, zeroUpperBits: 32}, // float64 -> uint32 + {name: "FCVTZSS", argLength: 1, reg: fpgp, asm: "FCVTZSS", earlyOk: true}, // float32 -> int64 + {name: "FCVTZSD", argLength: 1, reg: fpgp, asm: "FCVTZSD", earlyOk: true}, // float64 -> int64 + {name: "FCVTZUS", argLength: 1, reg: fpgp, asm: "FCVTZUS", earlyOk: true}, // float32 -> uint64 + {name: "FCVTZUD", argLength: 1, reg: fpgp, asm: "FCVTZUD", earlyOk: true}, // float64 -> uint64 + {name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD", earlyOk: true}, // float32 -> float64 + {name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS", earlyOk: true}, // float64 -> float32 // 64-bit floating-point round to integers in 64-bit FP format {name: "FRINTAD", argLength: 1, reg: fp11, asm: "FRINTAD", earlyOk: true}, // Round (ties Away from zero; 0.5 -> 1, -0.5 -> -1) @@ -550,26 +550,26 @@ func init() { {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem. {name: "LoweredMemEq", argLength: 4, reg: regInfo{inputs: []regMask{buildReg("R0"), buildReg("R1"), buildReg("R2")}, outputs: []regMask{buildReg("R0")}, clobbers: callerSave}, typ: "Bool", faultOnNilArg0: true, faultOnNilArg1: true, clobberFlags: true, call: true}, // arg0, arg1 - pointers to memory, arg2=size, arg3=mem. - {name: "Equal", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode x==y false otherwise. - {name: "NotEqual", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode x!=y false otherwise. - {name: "LessThan", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode signed xy false otherwise. - {name: "GreaterEqual", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode signed x>=y false otherwise. - {name: "LessThanU", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode unsigned xy false otherwise. - {name: "GreaterEqualU", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode unsigned x>=y false otherwise. - {name: "LessThanF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point xy false otherwise. - {name: "GreaterEqualF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x>=y false otherwise. - {name: "NotLessThanF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x>=y || x is unordered with y, false otherwise. - {name: "NotLessEqualF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x>y || x is unordered with y, false otherwise. - {name: "NotGreaterThanF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x<=y || x is unordered with y, false otherwise. - {name: "NotGreaterEqualF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x=y but without honoring overflow, false otherwise. + {name: "Equal", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode x==y false otherwise. + {name: "NotEqual", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode x!=y false otherwise. + {name: "LessThan", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode signed xy false otherwise. + {name: "GreaterEqual", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode signed x>=y false otherwise. + {name: "LessThanU", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode unsigned xy false otherwise. + {name: "GreaterEqualU", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode unsigned x>=y false otherwise. + {name: "LessThanF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point xy false otherwise. + {name: "GreaterEqualF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x>=y false otherwise. + {name: "NotLessThanF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x>=y || x is unordered with y, false otherwise. + {name: "NotLessEqualF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x>y || x is unordered with y, false otherwise. + {name: "NotGreaterThanF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x<=y || x is unordered with y, false otherwise. + {name: "NotGreaterEqualF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x=y but without honoring overflow, false otherwise. // medium zeroing // arg0 = address of memory to zero @@ -676,8 +676,8 @@ func init() { // load from arg0. arg1=mem. auxint must be zero. // returns so they can be properly ordered with other loads. {name: "LDAR", argLength: 2, reg: gpload, asm: "LDAR", faultOnNilArg0: true}, - {name: "LDARB", argLength: 2, reg: gpload, asm: "LDARB", faultOnNilArg0: true}, - {name: "LDARW", argLength: 2, reg: gpload, asm: "LDARW", faultOnNilArg0: true}, + {name: "LDARB", argLength: 2, reg: gpload, asm: "LDARB", faultOnNilArg0: true, zeroUpperBits: 56}, + {name: "LDARW", argLength: 2, reg: gpload, asm: "LDARW", faultOnNilArg0: true, zeroUpperBits: 32}, // atomic stores. // store arg1 to arg0. arg2=mem. returns memory. auxint must be zero. @@ -691,15 +691,15 @@ func init() { // STLXR Rarg1, (Rarg0), Rtmp // CBNZ Rtmp, -2(PC) {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicExchange8", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, + {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 32}, + {name: "LoweredAtomicExchange8", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, // atomic exchange variant. // store arg1 to arg0. arg2=mem. returns . auxint must be zero. // SWPALD Rarg1, (Rarg0), Rout {name: "LoweredAtomicExchange64Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, - {name: "LoweredAtomicExchange32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, - {name: "LoweredAtomicExchange8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, + {name: "LoweredAtomicExchange32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, zeroUpperBits: 32}, + {name: "LoweredAtomicExchange8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, // atomic add. // *arg0 += arg1. arg2=mem. returns . auxint must be zero. @@ -707,6 +707,8 @@ func init() { // ADD Rarg1, Rout // STLXR Rout, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) + // Unlike the other 32-bit atomics, no zeroUpperBits: the final write + // to Rout is the 64-bit ADD. {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, @@ -731,8 +733,8 @@ func init() { // STLXR Rarg2, (Rarg0), Rtmp // CBNZ Rtmp, -4(PC) // CSET EQ, Rout - {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, + {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, + {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, // atomic compare and swap variant. // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero. @@ -746,8 +748,8 @@ func init() { // CASAL Rtmp, (Rarg0), Rarg2 // CMP Rarg1, Rtmp // CSET EQ, Rout - {name: "LoweredAtomicCas64Variant", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicCas32Variant", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, + {name: "LoweredAtomicCas64Variant", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, + {name: "LoweredAtomicCas32Variant", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, // atomic and/or. // *arg0 &= (|=) arg1. arg2=mem. returns . auxint must be zero. @@ -755,12 +757,12 @@ func init() { // AND/OR Rarg1, Rout, tempReg // STLXR tempReg, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) - {name: "LoweredAtomicAnd8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicOr8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, + {name: "LoweredAtomicAnd8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true, zeroUpperBits: 56}, + {name: "LoweredAtomicOr8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true, zeroUpperBits: 56}, {name: "LoweredAtomicAnd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, {name: "LoweredAtomicOr64", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicAnd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicOr32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, + {name: "LoweredAtomicAnd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true, zeroUpperBits: 32}, + {name: "LoweredAtomicOr32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true, zeroUpperBits: 32}, // atomic and/or variant. // *arg0 &= (|=) arg1. arg2=mem. returns . auxint must be zero. @@ -769,12 +771,12 @@ func init() { // LDANDALB Rtemp, (Rarg0), Rout // OR: // LDORALB Rarg1, (Rarg0), Rout - {name: "LoweredAtomicAnd8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicOr8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicAnd8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, + {name: "LoweredAtomicOr8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, zeroUpperBits: 56}, {name: "LoweredAtomicAnd64Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, {name: "LoweredAtomicOr64Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, - {name: "LoweredAtomicAnd32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicOr32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicAnd32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 32}, + {name: "LoweredAtomicOr32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, zeroUpperBits: 32}, // LoweredWB invokes runtime.gcWriteBarrier. arg0=mem, auxint=# of buffer entries needed // It saves all GP registers if necessary, @@ -798,8 +800,8 @@ func init() { {name: "PRFM", argLength: 2, aux: "Int64", reg: prefreg, asm: "PRFM", hasSideEffects: true}, // Publication barrier - {name: "DMB", argLength: 1, aux: "Int64", asm: "DMB", hasSideEffects: true}, // Do data barrier. arg0=memory, aux=option. - {name: "ZERO", zeroWidth: true, fixedReg: true, earlyOk: true}, // reads-as-zero register + {name: "DMB", argLength: 1, aux: "Int64", asm: "DMB", hasSideEffects: true}, // Do data barrier. arg0=memory, aux=option. + {name: "ZERO", zeroWidth: true, fixedReg: true, earlyOk: true, zeroUpperBits: 56}, // reads-as-zero register // Broadcast constant to each lane of a SIMD register. aux=constant. // TODO: add the other arrangements after assembler supports them, to be used in simdgen-generated opt rules. diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64latelower.rules b/src/cmd/compile/internal/ssa/_gen/ARM64latelower.rules index 3372fb1bd0e730..963a58d83d3647 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64latelower.rules +++ b/src/cmd/compile/internal/ssa/_gen/ARM64latelower.rules @@ -29,9 +29,9 @@ (MOVBUreg x:((Equal|NotEqual|LessThan|LessThanU|LessThanF|LessEqual|LessEqualU|LessEqualF|GreaterThan|GreaterThanU|GreaterThanF|GreaterEqual|GreaterEqualU|GreaterEqualF) _)) => x // omit unsigned extension -(MOVBUreg x) && ZeroUpper56Bits(x, 3) => x -(MOVHUreg x) && ZeroUpper48Bits(x, 3) => x -(MOVWUreg x) && ZeroUpper32Bits(x, 3) => x +(MOVBUreg x) && ZeroUpper56Bits(x) => x +(MOVHUreg x) && ZeroUpper48Bits(x) => x +(MOVWUreg x) && ZeroUpper32Bits(x) => x // don't extend after proper load (MOVBreg x:(MOVBload _ _)) => (MOVDreg x) diff --git a/src/cmd/compile/internal/ssa/_gen/main.go b/src/cmd/compile/internal/ssa/_gen/main.go index d87150a039bc07..46bb6a40f730bb 100644 --- a/src/cmd/compile/internal/ssa/_gen/main.go +++ b/src/cmd/compile/internal/ssa/_gen/main.go @@ -77,6 +77,7 @@ type opData struct { addrSinkArg1 bool // the address in arg1 does not propagate to the result symEffect string // effect this op has on symbol in aux scale uint8 // amd64/386 indexed load scale + zeroUpperBits uint8 // the op writes a 64-bit GPR whose upper N bits are always zero (0, 32, 48 or 56); for a tuple op, this holds for every integer result } type blockData struct { @@ -451,6 +452,14 @@ func genOp() { if v.scale != 0 { fmt.Fprintf(w, "scale: %d,\n", v.scale) } + if v.zeroUpperBits != 0 { + switch v.zeroUpperBits { + case 32, 48, 56: + default: + log.Fatalf("%s: zeroUpperBits must be 0, 32, 48 or 56, have %d", v.name, v.zeroUpperBits) + } + fmt.Fprintf(w, "zeroUpperBits: %d,\n", v.zeroUpperBits) + } fmt.Fprintln(w, "reg:regInfo{") // Compute input allocation order. We allocate from the diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 79c76dd71662e9..5ff3d3202c3bf0 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -51,6 +51,7 @@ type opInfo struct { addrSinkArg1 bool // the address in arg1 does not propagate to the result symEffect SymEffect // effect this op has on symbol in aux scale uint8 // amd64/386 indexed load scale + zeroUpperBits uint8 // the op writes a 64-bit GPR whose upper N bits are always zero (0, 32, 48 or 56); for a tuple op, this holds for every integer result } type inputInfo struct { diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index c0516e67ca3588..5c9748d3828c03 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -12845,12 +12845,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDL", - argLen: 2, - commutative: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AADDL, + name: "ADDL", + argLen: 2, + commutative: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -12878,12 +12879,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLconst", - auxType: auxInt32, - argLen: 1, - clobberFlags: true, - earlyOk: true, - asm: x86.AADDL, + name: "ADDLconst", + auxType: auxInt32, + argLen: 1, + clobberFlags: true, + earlyOk: true, + asm: x86.AADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -12941,12 +12943,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASUBL, + name: "SUBL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASUBL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -12975,13 +12978,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBLconst", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASUBL, + name: "SUBLconst", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASUBL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13010,13 +13014,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULL", - argLen: 2, - commutative: true, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AIMULL, + name: "MULL", + argLen: 2, + commutative: true, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AIMULL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13044,12 +13049,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULLconst", - auxType: auxInt32, - argLen: 1, - clobberFlags: true, - earlyOk: true, - asm: x86.AIMUL3L, + name: "MULLconst", + auxType: auxInt32, + argLen: 1, + clobberFlags: true, + earlyOk: true, + asm: x86.AIMUL3L, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13060,11 +13066,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULLU", - argLen: 2, - commutative: true, - clobberFlags: true, - asm: x86.AMULL, + name: "MULLU", + argLen: 2, + commutative: true, + clobberFlags: true, + asm: x86.AMULL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13113,11 +13120,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "HMULL", - argLen: 2, - clobberFlags: true, - earlyOk: true, - asm: x86.AIMULL, + name: "HMULL", + argLen: 2, + clobberFlags: true, + earlyOk: true, + asm: x86.AIMULL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13147,11 +13155,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "HMULLU", - argLen: 2, - clobberFlags: true, - earlyOk: true, - asm: x86.AMULL, + name: "HMULLU", + argLen: 2, + clobberFlags: true, + earlyOk: true, + asm: x86.AMULL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13198,11 +13207,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DIVL", - auxType: auxBool, - argLen: 2, - clobberFlags: true, - asm: x86.AIDIVL, + name: "DIVL", + auxType: auxBool, + argLen: 2, + clobberFlags: true, + asm: x86.AIDIVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13248,10 +13258,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DIVLU", - argLen: 2, - clobberFlags: true, - asm: x86.ADIVL, + name: "DIVLU", + argLen: 2, + clobberFlags: true, + asm: x86.ADIVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13280,10 +13291,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NEGLflags", - argLen: 1, - resultInArg0: true, - asm: x86.ANEGL, + name: "NEGLflags", + argLen: 1, + resultInArg0: true, + asm: x86.ANEGL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13311,11 +13323,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLconstflags", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - asm: x86.AADDL, + name: "ADDLconstflags", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + asm: x86.AADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13526,13 +13539,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDL", - argLen: 2, - commutative: true, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AANDL, + name: "ANDL", + argLen: 2, + commutative: true, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AANDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13561,13 +13575,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDLconst", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AANDL, + name: "ANDLconst", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AANDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13626,13 +13641,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORL", - argLen: 2, - commutative: true, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AORL, + name: "ORL", + argLen: 2, + commutative: true, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13661,13 +13677,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORLconst", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AORL, + name: "ORLconst", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13726,13 +13743,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORL", - argLen: 2, - commutative: true, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AXORL, + name: "XORL", + argLen: 2, + commutative: true, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AXORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13761,13 +13779,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORLconst", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AXORL, + name: "XORLconst", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AXORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14289,12 +14308,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BTCL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ABTCL, + name: "BTCL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ABTCL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14323,12 +14343,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BTRL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ABTRL, + name: "BTRL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ABTRL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14357,12 +14378,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BTSL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ABTSL, + name: "BTSL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ABTSL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14620,12 +14642,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASHLL, + name: "SHLL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASHLL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -14654,13 +14677,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLLconst", - auxType: auxInt8, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASHLL, + name: "SHLLconst", + auxType: auxInt8, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASHLL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14688,12 +14712,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASHRL, + name: "SHRL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASHRL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -14756,13 +14781,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRLconst", - auxType: auxInt8, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASHRL, + name: "SHRLconst", + auxType: auxInt8, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASHRL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14824,12 +14850,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASARL, + name: "SARL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASARL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -14892,13 +14919,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARLconst", - auxType: auxInt8, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASARL, + name: "SARLconst", + auxType: auxInt8, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASARL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14960,12 +14988,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ROLL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AROLL, + name: "ROLL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AROLL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -15028,12 +15057,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "RORL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ARORL, + name: "RORL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ARORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -15096,13 +15126,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ROLLconst", - auxType: auxInt8, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AROLL, + name: "ROLLconst", + auxType: auxInt8, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AROLL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15156,6 +15187,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.AADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15216,6 +15248,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.ASUBL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15236,6 +15269,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.AANDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15296,6 +15330,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.AORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15336,6 +15371,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.AXORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15347,15 +15383,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AADDL, - scale: 1, + name: "ADDLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AADDL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15368,15 +15405,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AADDL, - scale: 4, + name: "ADDLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AADDL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15389,15 +15427,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AADDL, - scale: 8, + name: "ADDLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AADDL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15452,15 +15491,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.ASUBL, - scale: 1, + name: "SUBLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.ASUBL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15473,15 +15513,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.ASUBL, - scale: 4, + name: "SUBLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.ASUBL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15494,15 +15535,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.ASUBL, - scale: 8, + name: "SUBLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.ASUBL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15557,15 +15599,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AANDL, - scale: 1, + name: "ANDLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AANDL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15578,15 +15621,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AANDL, - scale: 4, + name: "ANDLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AANDL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15599,15 +15643,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AANDL, - scale: 8, + name: "ANDLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AANDL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15662,15 +15707,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AORL, - scale: 1, + name: "ORLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AORL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15683,15 +15729,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AORL, - scale: 4, + name: "ORLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AORL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15704,15 +15751,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AORL, - scale: 8, + name: "ORLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AORL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15767,15 +15815,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AXORL, - scale: 1, + name: "XORLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AXORL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15788,15 +15837,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AXORL, - scale: 4, + name: "XORLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AXORL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15809,15 +15859,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AXORL, - scale: 8, + name: "XORLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AXORL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -16793,12 +16844,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NEGL", - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ANEGL, + name: "NEGL", + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ANEGL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -16824,11 +16876,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NOTL", - argLen: 1, - resultInArg0: true, - earlyOk: true, - asm: x86.ANOTL, + name: "NOTL", + argLen: 1, + resultInArg0: true, + earlyOk: true, + asm: x86.ANOTL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17059,11 +17112,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLEQ", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLEQ, + name: "CMOVLEQ", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLEQ, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17075,11 +17129,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLNE", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLNE, + name: "CMOVLNE", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLNE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17091,11 +17146,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLLT", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLLT, + name: "CMOVLLT", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLLT, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17107,11 +17163,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLGT", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLGT, + name: "CMOVLGT", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLGT, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17123,11 +17180,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLLE", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLLE, + name: "CMOVLLE", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLLE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17139,11 +17197,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLGE", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLGE, + name: "CMOVLGE", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLGE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17155,11 +17214,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLLS", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLLS, + name: "CMOVLLS", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLLS, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17171,11 +17231,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLHI", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLHI, + name: "CMOVLHI", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLHI, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17187,11 +17248,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLCC", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLCC, + name: "CMOVLCC", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLCC, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17203,11 +17265,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLCS", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLCS, + name: "CMOVLCS", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLCS, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17444,12 +17507,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLEQF", - argLen: 3, - resultInArg0: true, - needIntTemp: true, - earlyOk: true, - asm: x86.ACMOVLNE, + name: "CMOVLEQF", + argLen: 3, + resultInArg0: true, + needIntTemp: true, + earlyOk: true, + asm: x86.ACMOVLNE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17461,11 +17525,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLNEF", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLNE, + name: "CMOVLNEF", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLNE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17477,11 +17542,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLGTF", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLHI, + name: "CMOVLGTF", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLHI, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17493,11 +17559,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLGEF", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLCC, + name: "CMOVLGEF", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLCC, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17589,11 +17656,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BSWAPL", - argLen: 1, - resultInArg0: true, - earlyOk: true, - asm: x86.ABSWAPL, + name: "BSWAPL", + argLen: 1, + resultInArg0: true, + earlyOk: true, + asm: x86.ABSWAPL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17604,10 +17672,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "POPCNTQ", - argLen: 1, - clobberFlags: true, - asm: x86.APOPCNTQ, + name: "POPCNTQ", + argLen: 1, + clobberFlags: true, + asm: x86.APOPCNTQ, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17618,10 +17687,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "POPCNTL", - argLen: 1, - clobberFlags: true, - asm: x86.APOPCNTL, + name: "POPCNTL", + argLen: 1, + clobberFlags: true, + asm: x86.APOPCNTL, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17857,10 +17927,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SBBLcarrymask", - argLen: 1, - earlyOk: true, - asm: x86.ASBBL, + name: "SBBLcarrymask", + argLen: 1, + earlyOk: true, + asm: x86.ASBBL, + zeroUpperBits: 32, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18383,10 +18454,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBQZX", - argLen: 1, - earlyOk: true, - asm: x86.AMOVBLZX, + name: "MOVBQZX", + argLen: 1, + earlyOk: true, + asm: x86.AMOVBLZX, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18411,10 +18483,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWQZX", - argLen: 1, - earlyOk: true, - asm: x86.AMOVWLZX, + name: "MOVWQZX", + argLen: 1, + earlyOk: true, + asm: x86.AMOVWLZX, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18439,10 +18512,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLQZX", - argLen: 1, - earlyOk: true, - asm: x86.AMOVL, + name: "MOVLQZX", + argLen: 1, + earlyOk: true, + asm: x86.AMOVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18459,6 +18533,7 @@ var opcodeTable = [...]opInfo{ rematerializeable: true, earlyOk: true, asm: x86.AMOVL, + zeroUpperBits: 32, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18479,10 +18554,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CVTTSD2SL", - argLen: 1, - earlyOk: true, - asm: x86.ACVTTSD2SL, + name: "CVTTSD2SL", + argLen: 1, + earlyOk: true, + asm: x86.ACVTTSD2SL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -18507,10 +18583,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CVTTSS2SL", - argLen: 1, - earlyOk: true, - asm: x86.ACVTTSS2SL, + name: "CVTTSS2SL", + argLen: 1, + earlyOk: true, + asm: x86.ACVTTSS2SL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -18658,9 +18735,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLf2i", - argLen: 1, - earlyOk: true, + name: "MOVLf2i", + argLen: 1, + earlyOk: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -18729,6 +18807,7 @@ var opcodeTable = [...]opInfo{ earlyOk: true, symEffect: SymAddr, asm: x86.ALEAL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -18775,14 +18854,15 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAL1", - auxType: auxSymOff, - argLen: 2, - commutative: true, - earlyOk: true, - symEffect: SymAddr, - asm: x86.ALEAL, - scale: 1, + name: "LEAL1", + auxType: auxSymOff, + argLen: 2, + commutative: true, + earlyOk: true, + symEffect: SymAddr, + asm: x86.ALEAL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18831,13 +18911,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAL2", - auxType: auxSymOff, - argLen: 2, - earlyOk: true, - symEffect: SymAddr, - asm: x86.ALEAL, - scale: 2, + name: "LEAL2", + auxType: auxSymOff, + argLen: 2, + earlyOk: true, + symEffect: SymAddr, + asm: x86.ALEAL, + scale: 2, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18885,13 +18966,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAL4", - auxType: auxSymOff, - argLen: 2, - earlyOk: true, - symEffect: SymAddr, - asm: x86.ALEAL, - scale: 4, + name: "LEAL4", + auxType: auxSymOff, + argLen: 2, + earlyOk: true, + symEffect: SymAddr, + asm: x86.ALEAL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18939,13 +19021,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAL8", - auxType: auxSymOff, - argLen: 2, - earlyOk: true, - symEffect: SymAddr, - asm: x86.ALEAL, - scale: 8, + name: "LEAL8", + auxType: auxSymOff, + argLen: 2, + earlyOk: true, + symEffect: SymAddr, + asm: x86.ALEAL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18982,6 +19065,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.AMOVBLZX, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -19016,6 +19100,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.AMOVWLZX, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -19050,6 +19135,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.AMOVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -19186,15 +19272,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBloadidx1", - auxType: auxSymOff, - argLen: 3, - commutative: true, - addrSinkArg0: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AMOVBLZX, - scale: 1, + name: "MOVBloadidx1", + auxType: auxSymOff, + argLen: 3, + commutative: true, + addrSinkArg0: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AMOVBLZX, + scale: 1, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19206,15 +19293,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWloadidx1", - auxType: auxSymOff, - argLen: 3, - commutative: true, - addrSinkArg0: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AMOVWLZX, - scale: 1, + name: "MOVWloadidx1", + auxType: auxSymOff, + argLen: 3, + commutative: true, + addrSinkArg0: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AMOVWLZX, + scale: 1, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19226,13 +19314,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWloadidx2", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVWLZX, - scale: 2, + name: "MOVWloadidx2", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVWLZX, + scale: 2, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19244,15 +19333,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLloadidx1", - auxType: auxSymOff, - argLen: 3, - commutative: true, - addrSinkArg0: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AMOVL, - scale: 1, + name: "MOVLloadidx1", + auxType: auxSymOff, + argLen: 3, + commutative: true, + addrSinkArg0: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AMOVL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19264,13 +19354,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLloadidx4", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVL, - scale: 4, + name: "MOVLloadidx4", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19282,13 +19373,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLloadidx8", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVL, - scale: 8, + name: "MOVLloadidx8", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19885,6 +19977,7 @@ var opcodeTable = [...]opInfo{ argLen: 0, rematerializeable: true, symEffect: SymNone, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19980,6 +20073,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, symEffect: SymRead, asm: x86.AMOVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -20033,6 +20127,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, symEffect: SymRdWr, asm: x86.AXCHGL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20072,6 +20167,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, symEffect: SymRdWr, asm: x86.AXADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20287,6 +20383,7 @@ var opcodeTable = [...]opInfo{ unsafePoint: true, symEffect: SymRdWr, asm: x86.AANDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49134, v2: 0}}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20333,6 +20430,7 @@ var opcodeTable = [...]opInfo{ unsafePoint: true, symEffect: SymRdWr, asm: x86.AORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49134, v2: 0}}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20382,10 +20480,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDNL", - argLen: 2, - clobberFlags: true, - asm: x86.AANDNL, + name: "ANDNL", + argLen: 2, + clobberFlags: true, + asm: x86.AANDNL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20411,10 +20510,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BLSIL", - argLen: 1, - clobberFlags: true, - asm: x86.ABLSIL, + name: "BLSIL", + argLen: 1, + clobberFlags: true, + asm: x86.ABLSIL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20439,10 +20539,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BLSMSKL", - argLen: 1, - clobberFlags: true, - asm: x86.ABLSMSKL, + name: "BLSMSKL", + argLen: 1, + clobberFlags: true, + asm: x86.ABLSMSKL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20467,9 +20568,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BLSRL", - argLen: 1, - asm: x86.ABLSRL, + name: "BLSRL", + argLen: 1, + asm: x86.ABLSRL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20559,6 +20661,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.AMOVBEL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -20616,15 +20719,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBELloadidx1", - auxType: auxSymOff, - argLen: 3, - commutative: true, - addrSinkArg0: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AMOVBEL, - scale: 1, + name: "MOVBELloadidx1", + auxType: auxSymOff, + argLen: 3, + commutative: true, + addrSinkArg0: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AMOVBEL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20636,13 +20740,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBELloadidx4", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVBEL, - scale: 4, + name: "MOVBELloadidx4", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVBEL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20654,13 +20759,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBELloadidx8", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVBEL, - scale: 8, + name: "MOVBELloadidx8", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVBEL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20842,9 +20948,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARXL", - argLen: 2, - asm: x86.ASARXL, + name: "SARXL", + argLen: 2, + asm: x86.ASARXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20870,9 +20977,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLXL", - argLen: 2, - asm: x86.ASHLXL, + name: "SHLXL", + argLen: 2, + asm: x86.ASHLXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20898,9 +21006,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRXL", - argLen: 2, - asm: x86.ASHRXL, + name: "SHRXL", + argLen: 2, + asm: x86.ASHRXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20919,6 +21028,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.ASARXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20955,6 +21065,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.ASHLXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20991,6 +21102,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.ASHRXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21028,6 +21140,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASARXL, scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21048,6 +21161,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASARXL, scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21068,6 +21182,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASARXL, scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21128,6 +21243,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHLXL, scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21148,6 +21264,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHLXL, scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21168,6 +21285,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHLXL, scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21228,6 +21346,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHRXL, scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21248,6 +21367,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHRXL, scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21268,6 +21388,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHRXL, scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21407,9 +21528,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "PMOVMSKB", - argLen: 1, - asm: x86.APMOVMSKB, + name: "PMOVMSKB", + argLen: 1, + asm: x86.APMOVMSKB, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22078,9 +22200,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VPMOVMSKB128", - argLen: 1, - asm: x86.AVPMOVMSKB, + name: "VPMOVMSKB128", + argLen: 1, + asm: x86.AVPMOVMSKB, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22091,9 +22214,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VPMOVMSKB256", - argLen: 1, - asm: x86.AVPMOVMSKB, + name: "VPMOVMSKB256", + argLen: 1, + asm: x86.AVPMOVMSKB, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22104,9 +22228,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VMOVMSKPS128", - argLen: 1, - asm: x86.AVMOVMSKPS, + name: "VMOVMSKPS128", + argLen: 1, + asm: x86.AVMOVMSKPS, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22117,9 +22242,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VMOVMSKPS256", - argLen: 1, - asm: x86.AVMOVMSKPS, + name: "VMOVMSKPS256", + argLen: 1, + asm: x86.AVMOVMSKPS, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22130,9 +22256,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VMOVMSKPD128", - argLen: 1, - asm: x86.AVMOVMSKPD, + name: "VMOVMSKPD128", + argLen: 1, + asm: x86.AVMOVMSKPD, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22143,9 +22270,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VMOVMSKPD256", - argLen: 1, - asm: x86.AVMOVMSKPD, + name: "VMOVMSKPD256", + argLen: 1, + asm: x86.AVMOVMSKPD, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22528,9 +22656,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "KMOVDi", - argLen: 1, - asm: x86.AKMOVD, + name: "KMOVDi", + argLen: 1, + asm: x86.AKMOVD, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 71494644084506624, v2: 0}}, // K1 K2 K3 K4 K5 K6 K7 @@ -22541,9 +22670,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "KMOVWi", - argLen: 1, - asm: x86.AKMOVW, + name: "KMOVWi", + argLen: 1, + asm: x86.AKMOVW, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 71494644084506624, v2: 0}}, // K1 K2 K3 K4 K5 K6 K7 @@ -22554,9 +22684,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "KMOVBi", - argLen: 1, - asm: x86.AKMOVB, + name: "KMOVBi", + argLen: 1, + asm: x86.AKMOVB, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 71494644084506624, v2: 0}}, // K1 K2 K3 K4 K5 K6 K7 @@ -74979,10 +75110,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADCzerocarry", - argLen: 1, - earlyOk: true, - asm: arm64.AADC, + name: "ADCzerocarry", + argLen: 1, + earlyOk: true, + asm: arm64.AADC, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -75128,11 +75260,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULW", - argLen: 2, - commutative: true, - earlyOk: true, - asm: arm64.AMULW, + name: "MULW", + argLen: 2, + commutative: true, + earlyOk: true, + asm: arm64.AMULW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75160,11 +75293,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MNEGW", - argLen: 2, - commutative: true, - earlyOk: true, - asm: arm64.AMNEGW, + name: "MNEGW", + argLen: 2, + commutative: true, + earlyOk: true, + asm: arm64.AMNEGW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75270,10 +75404,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DIVW", - argLen: 2, - earlyOk: true, - asm: arm64.ASDIVW, + name: "DIVW", + argLen: 2, + earlyOk: true, + asm: arm64.ASDIVW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75285,10 +75420,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "UDIVW", - argLen: 2, - earlyOk: true, - asm: arm64.AUDIVW, + name: "UDIVW", + argLen: 2, + earlyOk: true, + asm: arm64.AUDIVW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75330,10 +75466,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MODW", - argLen: 2, - earlyOk: true, - asm: arm64.AREMW, + name: "MODW", + argLen: 2, + earlyOk: true, + asm: arm64.AREMW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75345,10 +75482,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "UMODW", - argLen: 2, - earlyOk: true, - asm: arm64.AUREMW, + name: "UMODW", + argLen: 2, + earlyOk: true, + asm: arm64.AUREMW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75865,10 +76003,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "REVW", - argLen: 1, - earlyOk: true, - asm: arm64.AREVW, + name: "REVW", + argLen: 1, + earlyOk: true, + asm: arm64.AREVW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75893,10 +76032,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "REV16W", - argLen: 1, - earlyOk: true, - asm: arm64.AREV16W, + name: "REV16W", + argLen: 1, + earlyOk: true, + asm: arm64.AREV16W, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75921,10 +76061,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "RBITW", - argLen: 1, - earlyOk: true, - asm: arm64.ARBITW, + name: "RBITW", + argLen: 1, + earlyOk: true, + asm: arm64.ARBITW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75935,10 +76076,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CLZ", - argLen: 1, - earlyOk: true, - asm: arm64.ACLZ, + name: "CLZ", + argLen: 1, + earlyOk: true, + asm: arm64.ACLZ, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75949,10 +76091,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CLZW", - argLen: 1, - earlyOk: true, - asm: arm64.ACLZW, + name: "CLZW", + argLen: 1, + earlyOk: true, + asm: arm64.ACLZW, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76165,10 +76308,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MADDW", - argLen: 3, - earlyOk: true, - asm: arm64.AMADDW, + name: "MADDW", + argLen: 3, + earlyOk: true, + asm: arm64.AMADDW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76197,10 +76341,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MSUBW", - argLen: 3, - earlyOk: true, - asm: arm64.AMSUBW, + name: "MSUBW", + argLen: 3, + earlyOk: true, + asm: arm64.AMSUBW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76318,10 +76463,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "RORW", - argLen: 2, - earlyOk: true, - asm: arm64.ARORW, + name: "RORW", + argLen: 2, + earlyOk: true, + asm: arm64.ARORW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76348,11 +76494,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "RORWconst", - auxType: auxInt64, - argLen: 1, - earlyOk: true, - asm: arm64.ARORW, + name: "RORWconst", + auxType: auxInt64, + argLen: 1, + earlyOk: true, + asm: arm64.ARORW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76379,11 +76526,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "EXTRWconst", - auxType: auxInt64, - argLen: 2, - earlyOk: true, - asm: arm64.AEXTRW, + name: "EXTRWconst", + auxType: auxInt64, + argLen: 2, + earlyOk: true, + asm: arm64.AEXTRW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77452,6 +77600,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: arm64.AMOVBU, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -77486,6 +77635,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: arm64.AMOVHU, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -77520,6 +77670,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: arm64.AMOVWU, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -77623,6 +77774,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: arm64.ALDPW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -77738,11 +77890,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWUloadidx", - argLen: 3, - addrSinkArg0: true, - addrSinkArg1: true, - asm: arm64.AMOVWU, + name: "MOVWUloadidx", + argLen: 3, + addrSinkArg0: true, + addrSinkArg1: true, + asm: arm64.AMOVWU, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77770,11 +77923,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVHUloadidx", - argLen: 3, - addrSinkArg0: true, - addrSinkArg1: true, - asm: arm64.AMOVHU, + name: "MOVHUloadidx", + argLen: 3, + addrSinkArg0: true, + addrSinkArg1: true, + asm: arm64.AMOVHU, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77802,11 +77956,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBUloadidx", - argLen: 3, - addrSinkArg0: true, - addrSinkArg1: true, - asm: arm64.AMOVBU, + name: "MOVBUloadidx", + argLen: 3, + addrSinkArg0: true, + addrSinkArg1: true, + asm: arm64.AMOVBU, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77865,10 +78020,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVHUloadidx2", - argLen: 3, - addrSinkArg0: true, - asm: arm64.AMOVHU, + name: "MOVHUloadidx2", + argLen: 3, + addrSinkArg0: true, + asm: arm64.AMOVHU, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77895,10 +78051,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWUloadidx4", - argLen: 3, - addrSinkArg0: true, - asm: arm64.AMOVWU, + name: "MOVWUloadidx4", + argLen: 3, + addrSinkArg0: true, + asm: arm64.AMOVWU, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -78331,10 +78488,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FMOVSfpgp", - argLen: 1, - earlyOk: true, - asm: arm64.AFMOVS, + name: "FMOVSfpgp", + argLen: 1, + earlyOk: true, + asm: arm64.AFMOVS, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -78359,10 +78517,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBUreg", - argLen: 1, - earlyOk: true, - asm: arm64.AMOVBU, + name: "MOVBUreg", + argLen: 1, + earlyOk: true, + asm: arm64.AMOVBU, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -78387,10 +78546,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVHUreg", - argLen: 1, - earlyOk: true, - asm: arm64.AMOVHU, + name: "MOVHUreg", + argLen: 1, + earlyOk: true, + asm: arm64.AMOVHU, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -78415,10 +78575,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWUreg", - argLen: 1, - earlyOk: true, - asm: arm64.AMOVWU, + name: "MOVWUreg", + argLen: 1, + earlyOk: true, + asm: arm64.AMOVWU, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -78569,10 +78730,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FCVTZSSW", - argLen: 1, - earlyOk: true, - asm: arm64.AFCVTZSSW, + name: "FCVTZSSW", + argLen: 1, + earlyOk: true, + asm: arm64.AFCVTZSSW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -78583,10 +78745,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FCVTZSDW", - argLen: 1, - earlyOk: true, - asm: arm64.AFCVTZSDW, + name: "FCVTZSDW", + argLen: 1, + earlyOk: true, + asm: arm64.AFCVTZSDW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -78597,10 +78760,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FCVTZUSW", - argLen: 1, - earlyOk: true, - asm: arm64.AFCVTZUSW, + name: "FCVTZUSW", + argLen: 1, + earlyOk: true, + asm: arm64.AFCVTZUSW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -78611,10 +78775,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FCVTZUDW", - argLen: 1, - earlyOk: true, - asm: arm64.AFCVTZUDW, + name: "FCVTZUDW", + argLen: 1, + earlyOk: true, + asm: arm64.AFCVTZUDW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -79124,9 +79289,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "Equal", - argLen: 1, - earlyOk: true, + name: "Equal", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79134,9 +79300,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotEqual", - argLen: 1, - earlyOk: true, + name: "NotEqual", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79144,9 +79311,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessThan", - argLen: 1, - earlyOk: true, + name: "LessThan", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79154,9 +79322,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessEqual", - argLen: 1, - earlyOk: true, + name: "LessEqual", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79164,9 +79333,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterThan", - argLen: 1, - earlyOk: true, + name: "GreaterThan", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79174,9 +79344,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterEqual", - argLen: 1, - earlyOk: true, + name: "GreaterEqual", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79184,9 +79355,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessThanU", - argLen: 1, - earlyOk: true, + name: "LessThanU", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79194,9 +79366,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessEqualU", - argLen: 1, - earlyOk: true, + name: "LessEqualU", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79204,9 +79377,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterThanU", - argLen: 1, - earlyOk: true, + name: "GreaterThanU", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79214,9 +79388,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterEqualU", - argLen: 1, - earlyOk: true, + name: "GreaterEqualU", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79224,9 +79399,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessThanF", - argLen: 1, - earlyOk: true, + name: "LessThanF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79234,9 +79410,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessEqualF", - argLen: 1, - earlyOk: true, + name: "LessEqualF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79244,9 +79421,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterThanF", - argLen: 1, - earlyOk: true, + name: "GreaterThanF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79254,9 +79432,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterEqualF", - argLen: 1, - earlyOk: true, + name: "GreaterEqualF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79264,9 +79443,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotLessThanF", - argLen: 1, - earlyOk: true, + name: "NotLessThanF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79274,9 +79454,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotLessEqualF", - argLen: 1, - earlyOk: true, + name: "NotLessEqualF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79284,9 +79465,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotGreaterThanF", - argLen: 1, - earlyOk: true, + name: "NotGreaterThanF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79294,9 +79476,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotGreaterEqualF", - argLen: 1, - earlyOk: true, + name: "NotGreaterEqualF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79304,9 +79487,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessThanNoov", - argLen: 1, - earlyOk: true, + name: "LessThanNoov", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79314,9 +79498,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterEqualNoov", - argLen: 1, - earlyOk: true, + name: "GreaterEqualNoov", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79443,6 +79628,7 @@ var opcodeTable = [...]opInfo{ argLen: 2, faultOnNilArg0: true, asm: arm64.ALDARB, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -79457,6 +79643,7 @@ var opcodeTable = [...]opInfo{ argLen: 2, faultOnNilArg0: true, asm: arm64.ALDARW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -79529,6 +79716,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79546,6 +79734,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79578,6 +79767,7 @@ var opcodeTable = [...]opInfo{ resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79595,6 +79785,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79679,6 +79870,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79698,6 +79890,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79717,6 +79910,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79736,6 +79930,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79756,6 +79951,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, unsafePoint: true, asm: arm64.AAND, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79775,6 +79971,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, unsafePoint: true, asm: arm64.AORR, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79832,6 +80029,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, unsafePoint: true, asm: arm64.AAND, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79851,6 +80049,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, unsafePoint: true, asm: arm64.AORR, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79868,6 +80067,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79884,6 +80084,7 @@ var opcodeTable = [...]opInfo{ resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79934,6 +80135,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79950,6 +80152,7 @@ var opcodeTable = [...]opInfo{ resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -80034,12 +80237,13 @@ var opcodeTable = [...]opInfo{ reg: regInfo{}, }, { - name: "ZERO", - argLen: 0, - zeroWidth: true, - fixedReg: true, - earlyOk: true, - reg: regInfo{}, + name: "ZERO", + argLen: 0, + zeroWidth: true, + fixedReg: true, + earlyOk: true, + zeroUpperBits: 56, + reg: regInfo{}, }, { name: "VMOVI16B", diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 2597106f09aa5f..4245145cefd0c0 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -1384,210 +1384,63 @@ func overlap(offset1, size1, offset2, size2 int64) bool { return false } -// check if value zeroes out upper 32-bit of 64-bit register. +// ZeroUpper32Bits checks if value zeroes out upper 32-bit of 64-bit register. // depth limits recursion depth. In AMD64.rules 3 is used as limit, // because it catches same amount of cases as 4. -func ZeroUpper32Bits(x *Value, depth int) bool { - if x.Type.IsSigned() && x.Type.Size() < 8 { - // If the value is signed, it might get re-sign-extended - // during spill and restore. See issue 68227. - return false - } - switch x.Op { - // Every amd64 op below writes a 32-bit GPR result, which the - // hardware zero-extends into the full 64-bit register, so at the - // point of the write the upper 32 bits are zero. Ops whose result - // is memory, a flags value, or a narrower register do not qualify. - // - // 32-bit constants, zero-extensions and loads. The MOVW/MOVB - // loads assemble to zero-extending MOVWLZX/MOVBLZX. - case OpAMD64MOVLconst, OpAMD64MOVLQZX, - OpAMD64MOVLload, OpAMD64MOVLloadidx1, OpAMD64MOVLloadidx4, OpAMD64MOVLloadidx8, - OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2, - OpAMD64MOVBload, OpAMD64MOVBloadidx1, - // Byte-swapping 32-bit loads (MOVBE), zero-extending like MOVL. - OpAMD64MOVBELload, OpAMD64MOVBELloadidx1, OpAMD64MOVBELloadidx4, OpAMD64MOVBELloadidx8, - // 32-bit arithmetic and logic, register and folded-load forms. - OpAMD64ADDL, OpAMD64ADDLconst, OpAMD64SUBL, OpAMD64SUBLconst, - OpAMD64ANDL, OpAMD64ANDLconst, OpAMD64ORL, OpAMD64ORLconst, - OpAMD64XORL, OpAMD64XORLconst, OpAMD64NEGL, OpAMD64NOTL, - OpAMD64ADDLload, OpAMD64SUBLload, OpAMD64ANDLload, - OpAMD64ORLload, OpAMD64XORLload, - OpAMD64ADDLloadidx1, OpAMD64ADDLloadidx4, OpAMD64ADDLloadidx8, - OpAMD64SUBLloadidx1, OpAMD64SUBLloadidx4, OpAMD64SUBLloadidx8, - OpAMD64ANDLloadidx1, OpAMD64ANDLloadidx4, OpAMD64ANDLloadidx8, - OpAMD64ORLloadidx1, OpAMD64ORLloadidx4, OpAMD64ORLloadidx8, - OpAMD64XORLloadidx1, OpAMD64XORLloadidx4, OpAMD64XORLloadidx8, - // 32-bit shifts and rotates. RORLconst is absent because - // const-amount right rotates are canonicalized to ROLLconst. - OpAMD64SHRL, OpAMD64SHRLconst, OpAMD64SARL, OpAMD64SARLconst, - OpAMD64SHLL, OpAMD64SHLLconst, - OpAMD64ROLL, OpAMD64ROLLconst, OpAMD64RORL, - // BMI2 shifts, which AMD64latelower.rules promotes SHRL/SARL/SHLL - // into at GOAMD64>=3 in the same pass that applies this fold, - // plus their folded-load forms. - OpAMD64SHRXL, OpAMD64SARXL, OpAMD64SHLXL, - OpAMD64SHRXLload, OpAMD64SARXLload, OpAMD64SHLXLload, - OpAMD64SHRXLloadidx1, OpAMD64SHRXLloadidx4, OpAMD64SHRXLloadidx8, - OpAMD64SARXLloadidx1, OpAMD64SARXLloadidx4, OpAMD64SARXLloadidx8, - OpAMD64SHLXLloadidx1, OpAMD64SHLXLloadidx4, OpAMD64SHLXLloadidx8, - // 32-bit address computations and products. - OpAMD64LEAL, OpAMD64LEAL1, OpAMD64LEAL2, OpAMD64LEAL4, OpAMD64LEAL8, - OpAMD64MULL, OpAMD64MULLconst, - // In 64-bit mode a 32-bit CMOV zero-extends its destination - // even when the condition is false. - OpAMD64CMOVLCC, OpAMD64CMOVLCS, OpAMD64CMOVLEQ, OpAMD64CMOVLGE, - OpAMD64CMOVLGT, OpAMD64CMOVLHI, OpAMD64CMOVLLE, OpAMD64CMOVLLS, - OpAMD64CMOVLLT, OpAMD64CMOVLNE, - OpAMD64CMOVLEQF, OpAMD64CMOVLGEF, OpAMD64CMOVLGTF, OpAMD64CMOVLNEF, - // Byte swap, bit counts and BMI1 bit manipulation. - OpAMD64BSWAPL, OpAMD64POPCNTL, - OpAMD64ANDNL, OpAMD64BLSIL, OpAMD64BLSMSKL, - // Register-destination bit set/reset/complement. - OpAMD64BTSL, OpAMD64BTRL, OpAMD64BTCL, - // SBBL x, x: 32-bit result, 0 or -1 depending on the carry flag. - OpAMD64SBBLcarrymask, - // float -> int32 conversions. - OpAMD64CVTTSD2SL, OpAMD64CVTTSS2SL, - // 32-bit move out of an X register (MOVD xmm, r32). - OpAMD64MOVLf2i: - return true - case OpAMD64MOVQconst: - return uint64(uint32(x.AuxInt)) == uint64(x.AuxInt) - // arm64 likewise zero-extends every write to a W register into - // the full X register. - // - // 32-bit bit-twiddling, multiplies, divides and rotates. - case OpARM64REV16W, OpARM64REVW, OpARM64RBITW, OpARM64CLZW, OpARM64EXTRWconst, - OpARM64MULW, OpARM64MNEGW, OpARM64MADDW, OpARM64MSUBW, - OpARM64DIVW, OpARM64UDIVW, OpARM64MODW, OpARM64UMODW, - OpARM64RORW, OpARM64RORWconst, - // The zero-extensions themselves and the zero-extending loads. - // The MOVWload forms sign-extend and are deliberately not here. - OpARM64MOVWUreg, OpARM64MOVWUload, OpARM64MOVWUloadidx, OpARM64MOVWUloadidx4, - OpARM64MOVHUreg, OpARM64MOVHUload, OpARM64MOVHUloadidx, OpARM64MOVHUloadidx2, - OpARM64MOVBUreg, OpARM64MOVBUload, OpARM64MOVBUloadidx, - // float -> 32-bit int conversions. - OpARM64FCVTZSSW, OpARM64FCVTZSDW, OpARM64FCVTZUSW, OpARM64FCVTZUDW: - return true - case OpArg: // note: but not ArgIntReg - // amd64 always loads args from the stack unsigned. - // most other architectures load them sign/zero extended based on the type. - return x.Type.Size() == 4 && x.Block.Func.Config.arch == "amd64" - case OpSelect0, OpSelect1: - // A Select names one register result of a tuple-producing op, so - // the question is what that op's write does; recursing into the - // argument the way the Phi case below does would instead ask - // about the tuple itself, which no case above can answer. - s := x.Args[0].Op - if x.Op == OpSelect0 { - switch s { - case OpAMD64DIVL, OpAMD64DIVLU, // quotient, in a 32-bit GPR - OpAMD64MULLU, // low half of the 32x32 product - OpAMD64NEGLflags, // 32-bit negation - OpAMD64ADDLconstflags, // 32-bit add of a constant - OpAMD64BLSRL, // BMI1 reset-lowest-set-bit - OpAMD64MOVLatomicload, // atomic 32-bit load - OpAMD64XCHGL, // the old memory value, in a 32-bit GPR - OpAMD64XADDLlock, // the pre-add memory value, in a 32-bit GPR - OpARM64LDARW, // 32-bit load-acquire - OpARM64LDPW: // first word of a zero-extending pair load - return true - } - } else { - switch s { - case OpAMD64DIVL, OpAMD64DIVLU, // remainder, in a 32-bit GPR - OpARM64LDPW: // second word of a zero-extending pair load - return true - } - } - return false - case OpPhi: - // Phis can use each-other as an arguments, instead of tracking visited values, - // just limit recursion depth. - if depth <= 0 { - return false - } - for i := range x.Args { - if !ZeroUpper32Bits(x.Args[i], depth-1) { - return false - } - } - return true - - } - return false -} +func ZeroUpper32Bits(x *Value) bool { return zeroUpperBits(x, 32, 3) } // ZeroUpper48Bits is similar to ZeroUpper32Bits, but for upper 48 bits. -func ZeroUpper48Bits(x *Value, depth int) bool { - if x.Type.IsSigned() && x.Type.Size() <= 2 { +func ZeroUpper48Bits(x *Value) bool { return zeroUpperBits(x, 48, 3) } + +// ZeroUpper56Bits is similar to ZeroUpper32Bits, but for upper 56 bits. +func ZeroUpper56Bits(x *Value) bool { return zeroUpperBits(x, 56, 3) } + +// zeroUpperBits reports whether the 64-bit register holding x provably has +// its upper `bits` bits zero, i.e. the value is below 2^(64-bits). +// +// Which ops guarantee this is declared per op in the _gen op definitions +// (the zeroUpperBits attribute); only the value-dependent cases live here. +func zeroUpperBits(x *Value, bits int64, depth int) bool { + if x.Type.IsSigned() && 8*x.Type.Size() <= 64-bits { // A spill/restore sign-extends from the type's width (issue 68227). - // An int8/int16 may have its sign bit set, so a restore can write - // ones into the upper 48 bits. Wider signed types are safe: their - // value is below 2^16, so their sign bit is zero and a restore - // zero-extends. + // A signed type no wider than the claimed value width may have its + // sign bit set, so a restore can write ones into the upper bits. + // Wider signed types are safe: their value is below the type's + // sign bit, so a restore zero-extends. return false } - switch x.Op { - case OpAMD64MOVWQZX, OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2, - OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1: + if int64(opcodeTable[x.Op].zeroUpperBits) >= bits { return true - case OpAMD64MOVQconst, OpAMD64MOVLconst: - return uint64(uint16(x.AuxInt)) == uint64(x.AuxInt) - case OpARM64MOVHUreg, OpARM64MOVHUload, OpARM64MOVHUloadidx, OpARM64MOVHUloadidx2, - OpARM64MOVBUreg, OpARM64MOVBUload, OpARM64MOVBUloadidx: - return true - case OpArg: // note: but not ArgIntReg - return x.Type.Size() == 2 && x.Block.Func.Config.arch == "amd64" - case OpPhi, OpSelect0, OpSelect1: - // Phis can use each-other as an arguments, instead of tracking visited values, - // just limit recursion depth. - if depth <= 0 { - return false - } - for i := range x.Args { - if !ZeroUpper48Bits(x.Args[i], depth-1) { - return false - } - } - return true - - } - return false -} - -// ZeroUpper56Bits is similar to ZeroUpper32Bits, but for upper 56 bits. -func ZeroUpper56Bits(x *Value, depth int) bool { - if x.Type.IsSigned() && x.Type.Size() == 1 { - // As in ZeroUpper48Bits: an int8 may have its sign bit set, so a - // spill/restore can write ones into the upper 56 bits. Wider - // signed types are safe: their value is below 2^8, so their sign - // bit is zero and a restore zero-extends. - return false } switch x.Op { - case OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1: - return true case OpAMD64MOVQconst, OpAMD64MOVLconst: - return uint64(uint8(x.AuxInt)) == uint64(x.AuxInt) - case OpARM64MOVBUreg, OpARM64MOVBUload, OpARM64MOVBUloadidx: - return true + // A constant qualifies whenever its value fits the claimed width. + // (MOVLconst always zeroes the upper 32 bits, so for bits==32 it + // is already handled by its zeroUpperBits attribute.) + return uint64(x.AuxInt)>>(64-bits) == 0 case OpArg: // note: but not ArgIntReg - return x.Type.Size() == 1 && x.Block.Func.Config.arch == "amd64" - case OpPhi, OpSelect0, OpSelect1: + // amd64 always loads args from the stack unsigned. + // most other architectures load them sign/zero extended based on the type. + return 8*x.Type.Size() == 64-bits && x.Block.Func.Config.arch == "amd64" + case OpSelect0, OpSelect1: + // A Select names one register result of a tuple-producing op, so + // the question is what that op's write does. The op's attribute + // covers every integer result; a Select of a non-covered result + // (flags, memory) never appears as an operand of the rules that + // ask about upper bits. + return int64(opcodeTable[x.Args[0].Op].zeroUpperBits) >= bits + case OpPhi: // Phis can use each-other as an arguments, instead of tracking visited values, // just limit recursion depth. if depth <= 0 { return false } for i := range x.Args { - if !ZeroUpper56Bits(x.Args[i], depth-1) { + if !zeroUpperBits(x.Args[i], bits, depth-1) { return false } } return true - } return false } diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go b/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go index 531fbe1dd0117f..7ad27924f81236 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go @@ -30,11 +30,11 @@ func rewriteValueAMD64latelower(v *Value) bool { func rewriteValueAMD64latelower_OpAMD64MOVBQZX(v *Value) bool { v_0 := v.Args[0] // match: (MOVBQZX x) - // cond: ZeroUpper56Bits(x,3) + // cond: ZeroUpper56Bits(x) // result: x for { x := v_0 - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } v.copyOf(x) @@ -45,11 +45,11 @@ func rewriteValueAMD64latelower_OpAMD64MOVBQZX(v *Value) bool { func rewriteValueAMD64latelower_OpAMD64MOVLQZX(v *Value) bool { v_0 := v.Args[0] // match: (MOVLQZX x) - // cond: ZeroUpper32Bits(x,3) + // cond: ZeroUpper32Bits(x) // result: x for { x := v_0 - if !(ZeroUpper32Bits(x, 3)) { + if !(ZeroUpper32Bits(x)) { break } v.copyOf(x) @@ -60,11 +60,11 @@ func rewriteValueAMD64latelower_OpAMD64MOVLQZX(v *Value) bool { func rewriteValueAMD64latelower_OpAMD64MOVWQZX(v *Value) bool { v_0 := v.Args[0] // match: (MOVWQZX x) - // cond: ZeroUpper48Bits(x,3) + // cond: ZeroUpper48Bits(x) // result: x for { x := v_0 - if !(ZeroUpper48Bits(x, 3)) { + if !(ZeroUpper48Bits(x)) { break } v.copyOf(x) diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index a9fea2a0597b26..622ca5c30ecb52 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -25158,7 +25158,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (GE (CMPWconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBNZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPWconst { v_0 := b.Controls[0] @@ -25166,7 +25166,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBNZ, x) @@ -25174,7 +25174,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (GE (CMPconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBNZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPconst { v_0 := b.Controls[0] @@ -25182,7 +25182,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBNZ, x) @@ -26290,7 +26290,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (LT (CMPWconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPWconst { v_0 := b.Controls[0] @@ -26298,7 +26298,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBZ, x) @@ -26306,7 +26306,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (LT (CMPconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPconst { v_0 := b.Controls[0] @@ -26314,7 +26314,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBZ, x) @@ -27484,7 +27484,7 @@ func rewriteBlockARM64(b *Block) bool { } case block.BlockARM64UGE: // match: (UGE (CMPWconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBNZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPWconst { v_0 := b.Controls[0] @@ -27492,7 +27492,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBNZ, x) @@ -27500,7 +27500,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (UGE (CMPconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBNZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPconst { v_0 := b.Controls[0] @@ -27508,7 +27508,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBNZ, x) @@ -27674,7 +27674,7 @@ func rewriteBlockARM64(b *Block) bool { } case block.BlockARM64ULT: // match: (ULT (CMPWconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPWconst { v_0 := b.Controls[0] @@ -27682,7 +27682,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBZ, x) @@ -27690,7 +27690,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (ULT (CMPconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPconst { v_0 := b.Controls[0] @@ -27698,7 +27698,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBZ, x) diff --git a/src/cmd/compile/internal/ssa/rewriteARM64latelower.go b/src/cmd/compile/internal/ssa/rewriteARM64latelower.go index 671a7120a2a67c..9c2688785599b9 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64latelower.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64latelower.go @@ -341,11 +341,11 @@ func rewriteValueARM64latelower_OpARM64MOVBUreg(v *Value) bool { return true } // match: (MOVBUreg x) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: x for { x := v_0 - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } v.copyOf(x) @@ -469,11 +469,11 @@ func rewriteValueARM64latelower_OpARM64MOVDreg(v *Value) bool { func rewriteValueARM64latelower_OpARM64MOVHUreg(v *Value) bool { v_0 := v.Args[0] // match: (MOVHUreg x) - // cond: ZeroUpper48Bits(x, 3) + // cond: ZeroUpper48Bits(x) // result: x for { x := v_0 - if !(ZeroUpper48Bits(x, 3)) { + if !(ZeroUpper48Bits(x)) { break } v.copyOf(x) @@ -675,11 +675,11 @@ func rewriteValueARM64latelower_OpARM64MOVHreg(v *Value) bool { func rewriteValueARM64latelower_OpARM64MOVWUreg(v *Value) bool { v_0 := v.Args[0] // match: (MOVWUreg x) - // cond: ZeroUpper32Bits(x, 3) + // cond: ZeroUpper32Bits(x) // result: x for { x := v_0 - if !(ZeroUpper32Bits(x, 3)) { + if !(ZeroUpper32Bits(x)) { break } v.copyOf(x) diff --git a/test/codegen/noextend.go b/test/codegen/noextend.go index 68bf5472afb455..c014e38e39962f 100644 --- a/test/codegen/noextend.go +++ b/test/codegen/noextend.go @@ -857,3 +857,43 @@ func noZeroExtLDPW(p *[2]uint32) (uint64, uint64) { // arm64:"LDPW" -"MOVWU R[0-9]+, R[0-9]+" -"MOVD R[0-9]+, R[0-9]+" return uint64(p[0]), uint64(p[1]) } + +// Ops whose result is bounded below 2^8 regardless of input, declared +// via zeroUpperBits: 56 — even byte-sized zero-extensions fold away. + +func noZeroExt56CLZ(a uint64) uint8 { + // arm64:"CLZ " -"MOVBU R[0-9]+, R[0-9]+" -"MOVD R[0-9]+, R[0-9]+" + return uint8(bits.LeadingZeros64(a)) +} + +func noZeroExt56CLZW(a uint32) uint8 { + // arm64:"CLZW" -"MOVBU R[0-9]+, R[0-9]+" -"MOVD R[0-9]+, R[0-9]+" + return uint8(bits.LeadingZeros32(a)) +} + +func noZeroExt56POPCNTL(a uint32) uint8 { + // amd64/v2:"POPCNTL" -`MOVBLZX [A-Z][A-Z0-9]*, [A-Z][A-Z0-9]*` + return uint8(bits.OnesCount32(a)) +} + +// The flags-to-bool pseudo-ops produce 0/1 via a single CSET, so a +// bool-to-bool compare reads the CSET results directly. +func noZeroExtCSET(a, b, c, d uint64) bool { + // arm64:"CSET" -"MOVBU R[0-9]+, R[0-9]+" + return (a == b) == (c == d) +} + +// The 32-bit atomic exchange/and/or ops return their old value already +// zero-extended (LDAXRW on v8.0; SWPALW/LDCLRALW/LDORALW on v8.1). + +func noZeroExtAtomicAnd32(p *atomic.Uint32, m uint32) uint64 { + // arm64/v8.0:"LDAXRW" -"MOVWU R[0-9]+, R[0-9]+" + // arm64/v8.1:"LDCLRALW" -"MOVWU R[0-9]+, R[0-9]+" + return uint64(p.And(m)) +} + +func noZeroExtAtomicSwap32(p *atomic.Uint32, n uint32) uint64 { + // arm64/v8.0:"LDAXRW" -"MOVWU R[0-9]+, R[0-9]+" + // arm64/v8.1:"SWPALW" -"MOVWU R[0-9]+, R[0-9]+" + return uint64(p.Swap(n)) +} From ee74f9927647e1d020093dd847fe038fac46c95c Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Mon, 27 Jul 2026 12:26:27 +0300 Subject: [PATCH 18/21] cmd/compile/internal/ssa: fold sub-word read-modify-write into one memory op on amd64 The amd64 backend rewrites a load, a constant modify and a store of the same memory location into a single read-modify-write instruction, but only for 32- and 64-bit values: ADDLconstmodify and friends have no 8- or 16-bit counterpart. So var tab [256]byte tab[i&255]++ compiles to a MOVBLZX/INCL/MOVB triple, while the same code over a [256]uint32 compiles to a single INCL. Add {ADD,AND,OR,XOR}{B,W}constmodify, their indexed forms, and the lowering rules that build them. Byte and word arithmetic is done in 32-bit registers, so the rule matches an ADDLconst (etc.) consumed by a narrow store; the store keeps only the low 8 or 16 bits, which is what ADDB/ADDW compute. The constant is restricted to values representable as an 8-bit immediate, so every emitted form encodes as imm8 or as INC/DEC; that also keeps out the 16-bit immediates that cause length-changing-prefix stalls. The store width is unchanged, so the fold never writes bytes the original store did not. For the example above: MOVBLZX AL, AX MOVBLZX AL, AX LEAQ tab(SB), CX LEAQ tab(SB), CX MOVBLZX (CX)(AX*1), DX -> INCB (CX)(AX*1) INCL DX MOVB DL, (CX)(AX*1) 20 bytes of text become 14. That is -52 B in runtime.mapassign_fast64, -38 B in mapassign_fast32, -37 B in mapassign_faststr, -34 B in mapassign_fast64ptr, -32 B in mapassign and -26 B in internal/runtime/maps.(*Map).Clear. The other notable cluster is compress/flate, whose [...]uint8 code-length histogram accounts for 11 of the 12 largest std deltas. No significant performance difference observed. 386 has the same *Lconstmodify family and the same gap; this change does not add it. Updates #10432 Change-Id: I56a0e7cbffac975b253c52326b33fc0eba450e6c Reviewed-on: https://go-review.googlesource.com/c/go/+/806300 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Auto-Submit: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Mark Freeman --- src/cmd/compile/internal/amd64/ssa.go | 48 +- src/cmd/compile/internal/ssa/_gen/AMD64.rules | 21 + src/cmd/compile/internal/ssa/_gen/AMD64Ops.go | 20 + .../compile/internal/ssa/addressingmodes.go | 20 + src/cmd/compile/internal/ssa/opGen.go | 332 ++++++++++ src/cmd/compile/internal/ssa/rewriteAMD64.go | 616 ++++++++++++++++++ test/codegen/memops.go | 104 +++ 7 files changed, 1151 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 29301ac83334c3..c312cafebe7217 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -892,24 +892,34 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Reg = v.Args[2].Reg() memIdx(&p.To, v) ssagen.AddAux(&p.To, v) - case ssa.OpAMD64ADDQconstmodify, ssa.OpAMD64ADDLconstmodify: + case ssa.OpAMD64ADDQconstmodify, ssa.OpAMD64ADDLconstmodify, + ssa.OpAMD64ADDWconstmodify, ssa.OpAMD64ADDBconstmodify: sc := v.AuxValAndOff() off := sc.Off64() val := sc.Val() if val == 1 || val == -1 { var asm obj.As - if v.Op == ssa.OpAMD64ADDQconstmodify { - if val == 1 { - asm = x86.AINCQ - } else { + switch v.Op { + case ssa.OpAMD64ADDQconstmodify: + asm = x86.AINCQ + if val == -1 { asm = x86.ADECQ } - } else { - if val == 1 { - asm = x86.AINCL - } else { + case ssa.OpAMD64ADDLconstmodify: + asm = x86.AINCL + if val == -1 { asm = x86.ADECL } + case ssa.OpAMD64ADDWconstmodify: + asm = x86.AINCW + if val == -1 { + asm = x86.ADECW + } + default: + asm = x86.AINCB + if val == -1 { + asm = x86.ADECB + } } p := s.Prog(asm) p.To.Type = obj.TYPE_MEM @@ -920,6 +930,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { fallthrough case ssa.OpAMD64ANDQconstmodify, ssa.OpAMD64ANDLconstmodify, ssa.OpAMD64ORQconstmodify, ssa.OpAMD64ORLconstmodify, ssa.OpAMD64XORQconstmodify, ssa.OpAMD64XORLconstmodify, + ssa.OpAMD64ANDWconstmodify, ssa.OpAMD64ANDBconstmodify, ssa.OpAMD64ORWconstmodify, ssa.OpAMD64ORBconstmodify, + ssa.OpAMD64XORWconstmodify, ssa.OpAMD64XORBconstmodify, ssa.OpAMD64BTSQconstmodify, ssa.OpAMD64BTRQconstmodify, ssa.OpAMD64BTCQconstmodify: sc := v.AuxValAndOff() off := sc.Off64() @@ -960,7 +972,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpAMD64ADDLconstmodifyidx1, ssa.OpAMD64ADDLconstmodifyidx4, ssa.OpAMD64ADDLconstmodifyidx8, ssa.OpAMD64ADDQconstmodifyidx1, ssa.OpAMD64ADDQconstmodifyidx8, ssa.OpAMD64ANDLconstmodifyidx1, ssa.OpAMD64ANDLconstmodifyidx4, ssa.OpAMD64ANDLconstmodifyidx8, ssa.OpAMD64ANDQconstmodifyidx1, ssa.OpAMD64ANDQconstmodifyidx8, ssa.OpAMD64ORLconstmodifyidx1, ssa.OpAMD64ORLconstmodifyidx4, ssa.OpAMD64ORLconstmodifyidx8, ssa.OpAMD64ORQconstmodifyidx1, ssa.OpAMD64ORQconstmodifyidx8, - ssa.OpAMD64XORLconstmodifyidx1, ssa.OpAMD64XORLconstmodifyidx4, ssa.OpAMD64XORLconstmodifyidx8, ssa.OpAMD64XORQconstmodifyidx1, ssa.OpAMD64XORQconstmodifyidx8: + ssa.OpAMD64XORLconstmodifyidx1, ssa.OpAMD64XORLconstmodifyidx4, ssa.OpAMD64XORLconstmodifyidx8, ssa.OpAMD64XORQconstmodifyidx1, ssa.OpAMD64XORQconstmodifyidx8, + ssa.OpAMD64ADDWconstmodifyidx1, ssa.OpAMD64ADDWconstmodifyidx2, ssa.OpAMD64ADDBconstmodifyidx1, + ssa.OpAMD64ANDWconstmodifyidx1, ssa.OpAMD64ANDWconstmodifyidx2, ssa.OpAMD64ANDBconstmodifyidx1, + ssa.OpAMD64ORWconstmodifyidx1, ssa.OpAMD64ORWconstmodifyidx2, ssa.OpAMD64ORBconstmodifyidx1, + ssa.OpAMD64XORWconstmodifyidx1, ssa.OpAMD64XORWconstmodifyidx2, ssa.OpAMD64XORBconstmodifyidx1: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST sc := v.AuxValAndOff() @@ -978,6 +994,18 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case p.As == x86.AADDL && p.From.Offset == -1: p.As = x86.ADECL p.From.Type = obj.TYPE_NONE + case p.As == x86.AADDW && p.From.Offset == 1: + p.As = x86.AINCW + p.From.Type = obj.TYPE_NONE + case p.As == x86.AADDW && p.From.Offset == -1: + p.As = x86.ADECW + p.From.Type = obj.TYPE_NONE + case p.As == x86.AADDB && p.From.Offset == 1: + p.As = x86.AINCB + p.From.Type = obj.TYPE_NONE + case p.As == x86.AADDB && p.From.Offset == -1: + p.As = x86.ADECB + p.From.Type = obj.TYPE_NONE } memIdx(&p.To, v) ssagen.AddAux2(&p.To, v, sc.Off64()) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index 4988af6626d85f..0026b5d5f5ad08 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -1019,6 +1019,10 @@ ((ADD|AND|OR|XOR)Qconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) ((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) && ValAndOff(valoff1).canAdd32(off2) => ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) +((ADD|AND|OR|XOR)Wconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) && ValAndOff(valoff1).canAdd32(off2) => + ((ADD|AND|OR|XOR)Wconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) +((ADD|AND|OR|XOR)Bconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) && ValAndOff(valoff1).canAdd32(off2) => + ((ADD|AND|OR|XOR)Bconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) ((ADD|SUB|AND|OR|XOR)Qmodify [off1] {sym} (ADDQconst [off2] base) val mem) && is32Bit(int64(off1)+int64(off2)) => ((ADD|SUB|AND|OR|XOR)Qmodify [off1+off2] {sym} base val mem) ((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym} (ADDQconst [off2] base) val mem) && is32Bit(int64(off1)+int64(off2)) => @@ -1076,6 +1080,12 @@ ((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) && ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) => ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) +((ADD|AND|OR|XOR)Wconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + && ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) => + ((ADD|AND|OR|XOR)Wconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) +((ADD|AND|OR|XOR)Bconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + && ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) => + ((ADD|AND|OR|XOR)Bconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) ((ADD|SUB|AND|OR|XOR)Qmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => ((ADD|SUB|AND|OR|XOR)Qmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) @@ -1474,6 +1484,17 @@ (MOVLstore [off] {sym} ptr a:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) => ((ADD|AND|OR|XOR)Lconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) +// Sub-word read-modify-write. The narrow store keeps only the low 8/16 bits of +// the 32-bit result, so ADDB/ADDW etc. with the same constant is equivalent. +// The constant is restricted to an 8-bit immediate: it keeps every form we emit +// encodable as imm8 (or INC/DEC), which also avoids the 16-bit immediates that +// cause length-changing-prefix stalls. +(MOVWstore [off] {sym} ptr a:((ADD|AND|OR|XOR)Lconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) => + ((ADD|AND|OR|XOR)Wconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) +(MOVBstore [off] {sym} ptr a:((ADD|AND|OR|XOR)Lconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) => + ((ADD|AND|OR|XOR)Bconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) // float <-> int register moves, with no conversion. // These come up when compiling math.{Float{32,64}bits,Float{32,64}frombits}. diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go index 0615866c273671..bf0818f2df2d96 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go @@ -367,6 +367,8 @@ func init() { {name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32", clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "ADDQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ADDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDWconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDW", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDBconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDB", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "SUBQ", argLength: 2, reg: gp21sp2, asm: "SUBQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, @@ -444,6 +446,8 @@ func init() { {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 & auxint {name: "ANDQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "ANDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ANDWconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDW", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ANDBconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDB", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 | arg1 {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 | arg1 @@ -451,6 +455,8 @@ func init() { {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 | auxint {name: "ORQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "ORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ORWconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORW", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ORBconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORB", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 ^ arg1 {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 ^ arg1 @@ -458,6 +464,8 @@ func init() { {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 ^ auxint {name: "XORQconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "XORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "XORWconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORW", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "XORBconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORB", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem // CMPx: compare arg0 to arg1. {name: "CMPQ", argLength: 2, reg: gp2flags, asm: "CMPQ", typ: "Flags"}, @@ -701,15 +709,27 @@ func init() { {name: "ADDLconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ADDL", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ADDLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "ADDL", scale: 4, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ADDLconstmodifyidx8", argLength: 3, reg: gpstoreconstidx, asm: "ADDL", scale: 8, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDWconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ADDW", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDWconstmodifyidx2", argLength: 3, reg: gpstoreconstidx, asm: "ADDW", scale: 2, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDBconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ADDB", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ANDLconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ANDL", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ANDLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "ANDL", scale: 4, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ANDLconstmodifyidx8", argLength: 3, reg: gpstoreconstidx, asm: "ANDL", scale: 8, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ANDWconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ANDW", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ANDWconstmodifyidx2", argLength: 3, reg: gpstoreconstidx, asm: "ANDW", scale: 2, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ANDBconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ANDB", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ORLconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ORL", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ORLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "ORL", scale: 4, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ORLconstmodifyidx8", argLength: 3, reg: gpstoreconstidx, asm: "ORL", scale: 8, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ORWconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ORW", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ORWconstmodifyidx2", argLength: 3, reg: gpstoreconstidx, asm: "ORW", scale: 2, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ORBconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ORB", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "XORLconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "XORL", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "XORLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "XORL", scale: 4, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "XORLconstmodifyidx8", argLength: 3, reg: gpstoreconstidx, asm: "XORL", scale: 8, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "XORWconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "XORW", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "XORWconstmodifyidx2", argLength: 3, reg: gpstoreconstidx, asm: "XORW", scale: 2, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "XORBconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "XORB", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, // {NEG,NOT}x: unary ops // computes [NEG:-,NOT:^]arg0 diff --git a/src/cmd/compile/internal/ssa/addressingmodes.go b/src/cmd/compile/internal/ssa/addressingmodes.go index 4e3209e396b5af..a221c9f45a5612 100644 --- a/src/cmd/compile/internal/ssa/addressingmodes.go +++ b/src/cmd/compile/internal/ssa/addressingmodes.go @@ -316,6 +316,14 @@ var combine = map[[2]Op]Op{ [2]Op{OpAMD64ORQconstmodify, OpAMD64ADDQ}: OpAMD64ORQconstmodifyidx1, [2]Op{OpAMD64XORLconstmodify, OpAMD64ADDQ}: OpAMD64XORLconstmodifyidx1, [2]Op{OpAMD64XORQconstmodify, OpAMD64ADDQ}: OpAMD64XORQconstmodifyidx1, + [2]Op{OpAMD64ADDWconstmodify, OpAMD64ADDQ}: OpAMD64ADDWconstmodifyidx1, + [2]Op{OpAMD64ADDBconstmodify, OpAMD64ADDQ}: OpAMD64ADDBconstmodifyidx1, + [2]Op{OpAMD64ANDWconstmodify, OpAMD64ADDQ}: OpAMD64ANDWconstmodifyidx1, + [2]Op{OpAMD64ANDBconstmodify, OpAMD64ADDQ}: OpAMD64ANDBconstmodifyidx1, + [2]Op{OpAMD64ORWconstmodify, OpAMD64ADDQ}: OpAMD64ORWconstmodifyidx1, + [2]Op{OpAMD64ORBconstmodify, OpAMD64ADDQ}: OpAMD64ORBconstmodifyidx1, + [2]Op{OpAMD64XORWconstmodify, OpAMD64ADDQ}: OpAMD64XORWconstmodifyidx1, + [2]Op{OpAMD64XORBconstmodify, OpAMD64ADDQ}: OpAMD64XORBconstmodifyidx1, [2]Op{OpAMD64ADDLconstmodify, OpAMD64LEAQ1}: OpAMD64ADDLconstmodifyidx1, [2]Op{OpAMD64ADDLconstmodify, OpAMD64LEAQ4}: OpAMD64ADDLconstmodifyidx4, @@ -337,6 +345,18 @@ var combine = map[[2]Op]Op{ [2]Op{OpAMD64XORLconstmodify, OpAMD64LEAQ8}: OpAMD64XORLconstmodifyidx8, [2]Op{OpAMD64XORQconstmodify, OpAMD64LEAQ1}: OpAMD64XORQconstmodifyidx1, [2]Op{OpAMD64XORQconstmodify, OpAMD64LEAQ8}: OpAMD64XORQconstmodifyidx8, + [2]Op{OpAMD64ADDWconstmodify, OpAMD64LEAQ1}: OpAMD64ADDWconstmodifyidx1, + [2]Op{OpAMD64ADDWconstmodify, OpAMD64LEAQ2}: OpAMD64ADDWconstmodifyidx2, + [2]Op{OpAMD64ADDBconstmodify, OpAMD64LEAQ1}: OpAMD64ADDBconstmodifyidx1, + [2]Op{OpAMD64ANDWconstmodify, OpAMD64LEAQ1}: OpAMD64ANDWconstmodifyidx1, + [2]Op{OpAMD64ANDWconstmodify, OpAMD64LEAQ2}: OpAMD64ANDWconstmodifyidx2, + [2]Op{OpAMD64ANDBconstmodify, OpAMD64LEAQ1}: OpAMD64ANDBconstmodifyidx1, + [2]Op{OpAMD64ORWconstmodify, OpAMD64LEAQ1}: OpAMD64ORWconstmodifyidx1, + [2]Op{OpAMD64ORWconstmodify, OpAMD64LEAQ2}: OpAMD64ORWconstmodifyidx2, + [2]Op{OpAMD64ORBconstmodify, OpAMD64LEAQ1}: OpAMD64ORBconstmodifyidx1, + [2]Op{OpAMD64XORWconstmodify, OpAMD64LEAQ1}: OpAMD64XORWconstmodifyidx1, + [2]Op{OpAMD64XORWconstmodify, OpAMD64LEAQ2}: OpAMD64XORWconstmodifyidx2, + [2]Op{OpAMD64XORBconstmodify, OpAMD64LEAQ1}: OpAMD64XORBconstmodifyidx1, [2]Op{OpAMD64ADDSSload, OpAMD64LEAQ1}: OpAMD64ADDSSloadidx1, [2]Op{OpAMD64ADDSSload, OpAMD64LEAQ4}: OpAMD64ADDSSloadidx4, diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 5c9748d3828c03..17c2a661501503 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -309,6 +309,8 @@ const ( OpAMD64ADDLconst OpAMD64ADDQconstmodify OpAMD64ADDLconstmodify + OpAMD64ADDWconstmodify + OpAMD64ADDBconstmodify OpAMD64SUBQ OpAMD64SUBL OpAMD64SUBQconst @@ -350,18 +352,24 @@ const ( OpAMD64ANDLconst OpAMD64ANDQconstmodify OpAMD64ANDLconstmodify + OpAMD64ANDWconstmodify + OpAMD64ANDBconstmodify OpAMD64ORQ OpAMD64ORL OpAMD64ORQconst OpAMD64ORLconst OpAMD64ORQconstmodify OpAMD64ORLconstmodify + OpAMD64ORWconstmodify + OpAMD64ORBconstmodify OpAMD64XORQ OpAMD64XORL OpAMD64XORQconst OpAMD64XORLconst OpAMD64XORQconstmodify OpAMD64XORLconstmodify + OpAMD64XORWconstmodify + OpAMD64XORBconstmodify OpAMD64CMPQ OpAMD64CMPL OpAMD64CMPW @@ -531,15 +539,27 @@ const ( OpAMD64ADDLconstmodifyidx1 OpAMD64ADDLconstmodifyidx4 OpAMD64ADDLconstmodifyidx8 + OpAMD64ADDWconstmodifyidx1 + OpAMD64ADDWconstmodifyidx2 + OpAMD64ADDBconstmodifyidx1 OpAMD64ANDLconstmodifyidx1 OpAMD64ANDLconstmodifyidx4 OpAMD64ANDLconstmodifyidx8 + OpAMD64ANDWconstmodifyidx1 + OpAMD64ANDWconstmodifyidx2 + OpAMD64ANDBconstmodifyidx1 OpAMD64ORLconstmodifyidx1 OpAMD64ORLconstmodifyidx4 OpAMD64ORLconstmodifyidx8 + OpAMD64ORWconstmodifyidx1 + OpAMD64ORWconstmodifyidx2 + OpAMD64ORBconstmodifyidx1 OpAMD64XORLconstmodifyidx1 OpAMD64XORLconstmodifyidx4 OpAMD64XORLconstmodifyidx8 + OpAMD64XORWconstmodifyidx1 + OpAMD64XORWconstmodifyidx2 + OpAMD64XORBconstmodifyidx1 OpAMD64NEGQ OpAMD64NEGL OpAMD64NOTQ @@ -12925,6 +12945,36 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ADDWconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDW, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ADDBconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDB, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "SUBQ", argLen: 2, @@ -13622,6 +13672,36 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ANDWconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDW, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ANDBconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDB, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "ORQ", argLen: 2, @@ -13724,6 +13804,36 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ORWconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORW, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ORBconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORB, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "XORQ", argLen: 2, @@ -13826,6 +13936,36 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "XORWconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORW, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "XORBconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORB, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "CMPQ", argLen: 2, @@ -16683,6 +16823,54 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ADDWconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDW, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ADDWconstmodifyidx2", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDW, + scale: 2, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ADDBconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDB, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "ANDLconstmodifyidx1", auxType: auxSymValAndOff, @@ -16731,6 +16919,54 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ANDWconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDW, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ANDWconstmodifyidx2", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDW, + scale: 2, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ANDBconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDB, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "ORLconstmodifyidx1", auxType: auxSymValAndOff, @@ -16779,6 +17015,54 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ORWconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORW, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ORWconstmodifyidx2", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORW, + scale: 2, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ORBconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORB, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "XORLconstmodifyidx1", auxType: auxSymValAndOff, @@ -16827,6 +17111,54 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "XORWconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORW, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "XORWconstmodifyidx2", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORW, + scale: 2, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "XORBconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORB, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "NEGQ", argLen: 1, diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 8f501c19d28506..da19508fc959f7 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -57,6 +57,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ADCQ(v) case OpAMD64ADCQconst: return rewriteValueAMD64_OpAMD64ADCQconst(v) + case OpAMD64ADDBconstmodify: + return rewriteValueAMD64_OpAMD64ADDBconstmodify(v) case OpAMD64ADDL: return rewriteValueAMD64_OpAMD64ADDL(v) case OpAMD64ADDLconst: @@ -87,6 +89,10 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ADDSS(v) case OpAMD64ADDSSload: return rewriteValueAMD64_OpAMD64ADDSSload(v) + case OpAMD64ADDWconstmodify: + return rewriteValueAMD64_OpAMD64ADDWconstmodify(v) + case OpAMD64ANDBconstmodify: + return rewriteValueAMD64_OpAMD64ANDBconstmodify(v) case OpAMD64ANDL: return rewriteValueAMD64_OpAMD64ANDL(v) case OpAMD64ANDLconst: @@ -111,6 +117,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ANDQload(v) case OpAMD64ANDQmodify: return rewriteValueAMD64_OpAMD64ANDQmodify(v) + case OpAMD64ANDWconstmodify: + return rewriteValueAMD64_OpAMD64ANDWconstmodify(v) case OpAMD64BSFQ: return rewriteValueAMD64_OpAMD64BSFQ(v) case OpAMD64BSWAPL: @@ -379,6 +387,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64NOTL(v) case OpAMD64NOTQ: return rewriteValueAMD64_OpAMD64NOTQ(v) + case OpAMD64ORBconstmodify: + return rewriteValueAMD64_OpAMD64ORBconstmodify(v) case OpAMD64ORL: return rewriteValueAMD64_OpAMD64ORL(v) case OpAMD64ORLconst: @@ -399,6 +409,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ORQload(v) case OpAMD64ORQmodify: return rewriteValueAMD64_OpAMD64ORQmodify(v) + case OpAMD64ORWconstmodify: + return rewriteValueAMD64_OpAMD64ORWconstmodify(v) case OpAMD64ROLB: return rewriteValueAMD64_OpAMD64ROLB(v) case OpAMD64ROLBconst: @@ -3051,6 +3063,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64XCHGL(v) case OpAMD64XCHGQ: return rewriteValueAMD64_OpAMD64XCHGQ(v) + case OpAMD64XORBconstmodify: + return rewriteValueAMD64_OpAMD64XORBconstmodify(v) case OpAMD64XORL: return rewriteValueAMD64_OpAMD64XORL(v) case OpAMD64XORLconst: @@ -3071,6 +3085,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64XORQload(v) case OpAMD64XORQmodify: return rewriteValueAMD64_OpAMD64XORQmodify(v) + case OpAMD64XORWconstmodify: + return rewriteValueAMD64_OpAMD64XORWconstmodify(v) case OpAbsInt16x16: v.Op = OpAMD64VPABSW256 return true @@ -7594,6 +7610,54 @@ func rewriteValueAMD64_OpAMD64ADCQconst(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ADDBconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ADDBconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ADDBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ADDBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ADDBconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ADDBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ADDBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ADDL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -9006,6 +9070,102 @@ func rewriteValueAMD64_OpAMD64ADDSSload(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ADDWconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ADDWconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ADDWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ADDWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ADDWconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ADDWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ADDWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64ANDBconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ANDBconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ANDBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ANDBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ANDBconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ANDBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ANDBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ANDL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -9828,6 +9988,54 @@ func rewriteValueAMD64_OpAMD64ANDQmodify(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ANDWconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ANDWconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ANDWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ANDWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ANDWconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ANDWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ANDWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64BSFQ(v *Value) bool { v_0 := v.Args[0] b := v.Block @@ -26026,6 +26234,114 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.AddArg3(base, val, mem) return true } + // match: (MOVBstore [off] {sym} ptr a:(ADDLconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ADDBconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ADDLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVBload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ADDBconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVBstore [off] {sym} ptr a:(ANDLconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ANDBconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ANDLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVBload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ANDBconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVBstore [off] {sym} ptr a:(ORLconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ORBconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ORLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVBload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ORBconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVBstore [off] {sym} ptr a:(XORLconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (XORBconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64XORLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVBload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64XORBconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } // match: (MOVBstore [off] {sym} ptr (KMOVBi mask) mem) // result: (KMOVBstore [off] {sym} ptr mask mem) for { @@ -29009,6 +29325,114 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { v.AddArg3(base, val, mem) return true } + // match: (MOVWstore [off] {sym} ptr a:(ADDLconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ADDWconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ADDLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVWload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ADDWconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVWstore [off] {sym} ptr a:(ANDLconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ANDWconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ANDLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVWload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ANDWconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVWstore [off] {sym} ptr a:(ORLconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ORWconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ORLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVWload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ORWconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVWstore [off] {sym} ptr a:(XORLconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (XORWconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64XORLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVWload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64XORWconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } // match: (MOVWstore [i] {s} p x:(ROLWconst [8] w) mem) // cond: x.Uses == 1 && buildcfg.GOAMD64 >= 3 // result: (MOVBEWstore [i] {s} p w mem) @@ -29634,6 +30058,54 @@ func rewriteValueAMD64_OpAMD64NOTQ(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ORBconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ORBconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ORBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ORBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ORBconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ORBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ORBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -30286,6 +30758,54 @@ func rewriteValueAMD64_OpAMD64ORQmodify(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ORWconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ORWconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ORWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ORWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ORWconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ORWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ORWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ROLB(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -93107,6 +93627,54 @@ func rewriteValueAMD64_OpAMD64XCHGQ(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64XORBconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (XORBconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (XORBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64XORBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (XORBconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (XORBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64XORBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64XORL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -93847,6 +94415,54 @@ func rewriteValueAMD64_OpAMD64XORQmodify(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64XORWconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (XORWconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (XORWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64XORWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (XORWconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (XORWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64XORWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAddr(v *Value) bool { v_0 := v.Args[0] // match: (Addr {sym} base) diff --git a/test/codegen/memops.go b/test/codegen/memops.go index 378521c5f76e72..c7f7d63c0ec16b 100644 --- a/test/codegen/memops.go +++ b/test/codegen/memops.go @@ -401,3 +401,107 @@ func bitOps(p *[12]uint64) { // amd64: `BTCQ \$63, 88\(AX\)` p[11] ^= 1 << 63 } + +func constModify8(p *[8]uint8) { + // amd64: `INCB \([A-Z]+[0-9]*\)` -`MOVB` + p[0]++ + // amd64: `DECB 1\([A-Z]+[0-9]*\)` -`MOVB` + p[1]-- + // amd64: `ADDB [$]77, 2\([A-Z]+[0-9]*\)` -`MOVB` + p[2] += 77 + // amd64: `ANDB [$]77, 3\([A-Z]+[0-9]*\)` -`MOVB` + p[3] &= 77 + // amd64: `ORB [$]12, 4\([A-Z]+[0-9]*\)` -`MOVB` + p[4] |= 12 + // amd64: `ANDB [$]-13, 5\([A-Z]+[0-9]*\)` -`MOVB` + p[5] &^= 12 + // amd64: `XORB [$]12, 6\([A-Z]+[0-9]*\)` -`MOVB` + p[6] ^= 12 +} + +func constModify16(p *[8]uint16) { + // amd64: `INCW \([A-Z]+[0-9]*\)` -`MOVW` + p[0]++ + // amd64: `DECW 2\([A-Z]+[0-9]*\)` -`MOVW` + p[1]-- + // amd64: `ADDW [$]77, 4\([A-Z]+[0-9]*\)` -`MOVW` + p[2] += 77 + // amd64: `ANDW [$]77, 6\([A-Z]+[0-9]*\)` -`MOVW` + p[3] &= 77 + // amd64: `ORW [$]12, 8\([A-Z]+[0-9]*\)` -`MOVW` + p[4] |= 12 + // amd64: `ANDW [$]-13, 10\([A-Z]+[0-9]*\)` -`MOVW` + p[5] &^= 12 + // amd64: `XORW [$]12, 12\([A-Z]+[0-9]*\)` -`MOVW` + p[6] ^= 12 +} + +// Constants that do not fit in an 8-bit immediate keep the +// load/modify/store form rather than growing a 16-bit immediate. +func constModify16Wide(p *uint16) { + // amd64: -`ORW [$]` + *p |= 0x1234 +} + +func constModifyGlobal() { + // amd64: `ORB [$]12, command-line-arguments\.x8\+1\(SB\)` -`MOVB` + x8[1] |= 12 + // amd64: `XORW [$]12, command-line-arguments\.x16\+2\(SB\)` -`MOVW` + x16[1] ^= 12 +} + +func idxStorePlusOpConst8(x []uint8, i int) { + // amd64: `INCB 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVB` + x[i+1]++ + // amd64: `DECB 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+2]-- + // amd64: `ADDB [$]77, 3\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+3] += 77 + // amd64: `ANDB [$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+4] &= 77 + // amd64: `ORB [$]77, 5\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+5] |= 77 + // amd64: `XORB [$]77, 6\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+6] ^= 77 +} + +func idxStorePlusOpConst16(x []uint16, i int) { + // amd64: `INCW 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` -`MOVW` + x[i+1]++ + // amd64: `DECW 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+2]-- + // amd64: `ADDW [$]77, 6\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+3] += 77 + // amd64: `ANDW [$]77, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+4] &= 77 + // amd64: `ORW [$]77, 10\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+5] |= 77 + // amd64: `XORW [$]77, 12\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+6] ^= 77 +} + +func idxStorePlusOpConst16Idx1(b []byte, i int) { + v := uint16(b[i]) | uint16(b[i+1])<<8 + v += 77 + // amd64: `ADDW [$]77, \([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVW` + b[i] = byte(v) + b[i+1] = byte(v >> 8) + + v = uint16(b[i+2]) | uint16(b[i+3])<<8 + v &^= 12 + // amd64: `ANDW [$]-13, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVW` + b[i+2] = byte(v) + b[i+3] = byte(v >> 8) + + v = uint16(b[i+4]) | uint16(b[i+5])<<8 + v |= 77 + // amd64: `ORW [$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVW` + b[i+4] = byte(v) + b[i+5] = byte(v >> 8) + + v = uint16(b[i+6]) | uint16(b[i+7])<<8 + v ^= 77 + // amd64: `XORW [$]77, 6\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVW` + b[i+6] = byte(v) + b[i+7] = byte(v >> 8) +} From 54bae9bf84e4e045f46a523ecee0cae0747c6edb Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 30 Jul 2026 13:30:18 -0700 Subject: [PATCH 19/21] cmd/compile: reorder operations in multiply strength reduction Put regular shifts last, so that they can be folded into address calculations. Update #80639 Change-Id: I0a07abbc7a29e1c0c5d6b5c7ed2ae2cffe43957c Reviewed-on: https://go-review.googlesource.com/c/go/+/808200 Reviewed-by: Mark Freeman Reviewed-by: Keith Randall Reviewed-by: Jorropo LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/cmd/compile/internal/ssa/config.go | 46 +++++++++++++------------- test/codegen/multiply.go | 12 +++---- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 10304e79009403..f963986cb035e5 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -538,20 +538,6 @@ func (c *Config) buildRecipes(arch string) { func(m, x, y *Value) *Value { return m.Block.NewValue2(m.Pos, OpARM64SUB, m.Type, x, y) }) - // regular shifts - for i := 1; i < 64; i++ { - c := 10 - if i == 1 { - // Prefer x<<1 over x+x. - // Note that we eventually reverse this decision in ARM64latelower.rules, - // but this makes shift combining rules in ARM64.rules simpler. - c-- - } - r(1< Date: Thu, 9 Jul 2026 03:01:41 +0000 Subject: [PATCH 20/21] cmd/go: use the resolved buildmode in build IDs and build info When -buildmode=default is used, the link action ID hashed the literal string "default", so building with -buildmode=default and building with the buildmode it resolves to produced binaries that were identical except for their build IDs. Hash the resolved buildmode (ldBuildmode) instead, so that equivalent builds share a build ID and cached link outputs. Additionally, the build info stamped into binaries normalized -buildmode=default to "exe" without accounting for platforms where the default is PIE (android, ios, darwin, and windows without -race), misreporting the buildmode actually given to the linker. Record "pie" on those platforms instead. Together these make it possible to reproduce a binary built with -buildmode=default from its stamped build info alone. Fixes #63559 Change-Id: If3ac6a6a84fbf20097ff3009e228ce07705d6835 GitHub-Last-Rev: 1ddf5bfef00c64cc589d90e4e8bf4257f8d05b88 GitHub-Pull-Request: golang/go#80312 Reviewed-on: https://go-review.googlesource.com/c/go/+/798680 Reviewed-by: Mark Freeman LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Sean Liao Reviewed-by: Michael Pratt --- src/cmd/go/internal/load/pkg.go | 3 ++ src/cmd/go/internal/work/exec.go | 5 ++- src/cmd/go/scriptconds_test.go | 13 +++++++ src/cmd/go/testdata/script/README | 2 + .../build_buildmode_default_reproducible.txt | 37 +++++++++++++++++++ src/cmd/go/testdata/script/version.txt | 6 ++- 6 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/cmd/go/testdata/script/build_buildmode_default_reproducible.txt diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 6c1e51e1a3e0a8..70616305f0defa 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -2443,6 +2443,9 @@ func (p *Package) setBuildInfo(ctx context.Context, f *modfetch.Fetcher, autoVCS if buildmode == "default" { if p.Name == "main" { buildmode = "exe" + if platform.DefaultPIE(cfg.Goos, cfg.Goarch, cfg.BuildRace) { + buildmode = "pie" + } } else { buildmode = "archive" } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index db3b7bfc87efb3..41d1673dec9372 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -1669,7 +1669,10 @@ func (b *Builder) linkActionID(a *Action) cache.ActionID { // Toolchain-independent configuration. fmt.Fprintf(h, "link\n") - fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) + // Hash the resolved buildmode (ldBuildmode), not cfg.BuildBuildmode, + // so that -buildmode=default produces the same build ID as the + // buildmode it resolves to. See go.dev/issue/63559. + fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", ldBuildmode, cfg.Goos, cfg.Goarch) fmt.Fprintf(h, "import %q\n", p.ImportPath) fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix) fmt.Fprintf(h, "defaultgodebug %q\n", p.DefaultGODEBUG) diff --git a/src/cmd/go/scriptconds_test.go b/src/cmd/go/scriptconds_test.go index 25053dd1da562b..277352ddaf921f 100644 --- a/src/cmd/go/scriptconds_test.go +++ b/src/cmd/go/scriptconds_test.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "internal/buildcfg" + "internal/platform" "os" "os/exec" "path/filepath" @@ -45,6 +46,7 @@ func scriptConditions(t *testing.T) map[string]script.Cond { add("git-sha256", script.OnceCondition("the local 'git' version is recent enough to support sha256 object/commit hashes", gitSupportsSHA256)) add("trimpath", script.OnceCondition("test binary was built with -trimpath", isTrimpath)) add("default-cgo", lazyBool("when CGO_ENABLED=1|0 was set in make.bash", defaultCgo)) + add("default-pie", script.Condition("-buildmode=default resolves to -buildmode=pie", defaultPIE)) return conds } @@ -149,3 +151,14 @@ func gitSupportsSHA256() (bool, error) { func defaultCgo() bool { return buildcfg.DefaultCGO_ENABLED == "1" || buildcfg.DefaultCGO_ENABLED == "0" } + +// defaultPIE reports whether -buildmode=default resolves to -buildmode=pie for +// the script's GOOS/GOARCH. It assumes -race is not in effect, which is the only +// case where the resolved default buildmode depends on the race flag (PIE is not +// the default with -race on windows). Scripts that build with -race must not rely +// on this condition. +func defaultPIE(s *script.State) (bool, error) { + GOOS, _ := s.LookupEnv("GOOS") + GOARCH, _ := s.LookupEnv("GOARCH") + return platform.DefaultPIE(GOOS, GOARCH, false), nil +} diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README index 71052159b6e4f5..cd0484243fdeed 100644 --- a/src/cmd/go/testdata/script/README +++ b/src/cmd/go/testdata/script/README @@ -391,6 +391,8 @@ The available conditions are: cmd/go GOOS/GOARCH != GOHOSTOS/GOHOSTARCH [default-cgo] when CGO_ENABLED=1|0 was set in make.bash +[default-pie] + -buildmode=default resolves to -buildmode=pie [exec:*] names an executable in the test binary's PATH [fuzz] diff --git a/src/cmd/go/testdata/script/build_buildmode_default_reproducible.txt b/src/cmd/go/testdata/script/build_buildmode_default_reproducible.txt new file mode 100644 index 00000000000000..a841e5c45b47e4 --- /dev/null +++ b/src/cmd/go/testdata/script/build_buildmode_default_reproducible.txt @@ -0,0 +1,37 @@ +# Issue 63559: building with -buildmode=default should produce +# a binary identical to one built with the buildmode that default +# resolves to, and the build info stamped into the binary should +# record the resolved buildmode. + +[short] skip 'links binaries' +# gccgo does not set -fPIE for the default->pie case (unlike explicit +# -buildmode=pie), so the two binaries would not be identical there. +[compiler:gccgo] skip + +# Build with -buildmode=default and, separately, with the buildmode that +# default resolves to. Use distinct build caches so that the second build +# cannot be served from the first build's link cache: the binaries must be +# byte-identical because they are truly reproducible, not because one was +# copied from the other. +env GOCACHE=$WORK/cache-default +go build -buildmode=default -o default$GOEXE . + +env GOCACHE=$WORK/cache-explicit +[!default-pie] go build -buildmode=exe -o explicit$GOEXE . +[default-pie] go build -buildmode=pie -o explicit$GOEXE . + +cmp -q default$GOEXE explicit$GOEXE + +# The build info must record the resolved buildmode, not the literal "default". +go version -m default$GOEXE +[!default-pie] stdout -buildmode=exe +[default-pie] stdout -buildmode=pie + +-- go.mod -- +module m + +go 1.26 +-- main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/version.txt b/src/cmd/go/testdata/script/version.txt index 722859f25867e7..5958dca930de83 100644 --- a/src/cmd/go/testdata/script/version.txt +++ b/src/cmd/go/testdata/script/version.txt @@ -47,14 +47,16 @@ go build -o fortune.exe rsc.io/fortune go version fortune.exe stdout '^fortune.exe: .+' go version -m fortune.exe -stdout -buildmode=exe +[!default-pie] stdout -buildmode=exe +[default-pie] stdout -buildmode=pie stdout '^\tpath\trsc.io/fortune' stdout '^\tmod\trsc.io/fortune\tv1.0.0' # Check the build info of a binary built from $GOROOT/src/cmd go build -o test2json.exe cmd/test2json go version -m test2json.exe -stdout -buildmode=exe +[!default-pie] stdout -buildmode=exe +[default-pie] stdout -buildmode=pie stdout '^test2json.exe: .+' stdout '^\tpath\tcmd/test2json$' ! stdout 'mod[^e]' From bbf9f41689414a0c608f4f72739381b78118cfb2 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Tue, 28 Jul 2026 15:50:03 +0800 Subject: [PATCH 21/21] go/build/constraint: simplify double negations in Expr.String NotExpr.String currently concatenates its leading "!" with the string form of an inner NotExpr. This produces expressions such as "!!linux", which Parse rejects as a double negation. Elide pairs of nested negations while formatting. Account for the effective operator when adding parentheses, so simplifying a negation nested inside an AND or OR expression does not change its meaning. Fixes golang/go#80593 Change-Id: Id15885c8b408f8cff143bd994b310523a5cb8452 Reviewed-on: https://go-review.googlesource.com/c/go/+/806682 Reviewed-by: Russ Cox Reviewed-by: Mark Freeman Reviewed-by: Sean Liao Auto-Submit: Sean Liao LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/go/build/constraint/expr.go | 20 ++++++++++++++++++++ src/go/build/constraint/expr_test.go | 12 ++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/go/build/constraint/expr.go b/src/go/build/constraint/expr.go index 943c8f3444b3f8..66d22439e897c3 100644 --- a/src/go/build/constraint/expr.go +++ b/src/go/build/constraint/expr.go @@ -66,6 +66,9 @@ func (x *NotExpr) Eval(ok func(tag string) bool) bool { } func (x *NotExpr) String() string { + if y := stripDoubleNot(x); y != x { + return y.String() + } s := x.X.String() switch x.X.(type) { case *AndExpr, *OrExpr: @@ -76,6 +79,21 @@ func (x *NotExpr) String() string { func not(x Expr) Expr { return &NotExpr{x} } +// stripDoubleNot removes pairs of leading negations from x. +func stripDoubleNot(x Expr) Expr { + for { + n, ok := x.(*NotExpr) + if !ok { + return x + } + nn, ok := n.X.(*NotExpr) + if !ok { + return x + } + x = nn.X + } +} + // An AndExpr represents the expression X && Y. type AndExpr struct { X, Y Expr @@ -95,6 +113,7 @@ func (x *AndExpr) String() string { } func andArg(x Expr) string { + x = stripDoubleNot(x) s := x.String() if _, ok := x.(*OrExpr); ok { s = "(" + s + ")" @@ -125,6 +144,7 @@ func (x *OrExpr) String() string { } func orArg(x Expr) string { + x = stripDoubleNot(x) s := x.String() if _, ok := x.(*AndExpr); ok { s = "(" + s + ")" diff --git a/src/go/build/constraint/expr_test.go b/src/go/build/constraint/expr_test.go index f0d08956aad82e..798f49007ac638 100644 --- a/src/go/build/constraint/expr_test.go +++ b/src/go/build/constraint/expr_test.go @@ -25,6 +25,10 @@ var exprStringTests = []struct { x: not(tag("abc")), out: "!abc", }, + { + x: not(not(tag("abc"))), + out: "abc", + }, { x: not(and(tag("abc"), tag("def"))), out: "!(abc && def)", @@ -33,10 +37,18 @@ var exprStringTests = []struct { x: and(tag("abc"), or(tag("def"), tag("ghi"))), out: "abc && (def || ghi)", }, + { + x: and(tag("abc"), not(not(or(tag("def"), tag("ghi"))))), + out: "abc && (def || ghi)", + }, { x: or(and(tag("abc"), tag("def")), tag("ghi")), out: "(abc && def) || ghi", }, + { + x: or(not(not(and(tag("abc"), tag("def")))), tag("ghi")), + out: "(abc && def) || ghi", + }, } func TestExprString(t *testing.T) {