Compare commits

...

28 Commits

Author SHA1 Message Date
Chris Broadfoot
cd6b6202dd [release-branch.go1.8] go1.8
Change-Id: If1e38f02db86449abd4c8a57988d9825b1cf2511
Reviewed-on: https://go-review.googlesource.com/37132
Run-TryBot: Chris Broadfoot <cbro@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-02-16 17:12:24 +00:00
Chris Broadfoot
606eb9b0c1 [release-branch.go1.8] doc: document go1.8
Change-Id: Ie2144d001c6b4b2293d07b2acf62d7e3cd0b46a7
Reviewed-on: https://go-review.googlesource.com/37130
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/37131
2017-02-16 16:41:41 +00:00
Russ Cox
bcda91c18d [release-branch.go1.8] runtime: do not call wakep from enlistWorker, to avoid possible deadlock
We have seen one instance of a production job suddenly spinning to
100% CPU and becoming unresponsive. In that one instance, a SIGQUIT
was sent after 328 minutes of spinning, and the stacks showed a single
goroutine in "IO wait (scan)" state.

Looking for things that might get stuck if a goroutine got stuck in
scanning a stack, we found that injectglist does:

	lock(&sched.lock)
	var n int
	for n = 0; glist != nil; n++ {
		gp := glist
		glist = gp.schedlink.ptr()
		casgstatus(gp, _Gwaiting, _Grunnable)
		globrunqput(gp)
	}
	unlock(&sched.lock)

and that casgstatus spins on gp.atomicstatus until the _Gscan bit goes
away. Essentially, this code locks sched.lock and then while holding
sched.lock, waits to lock gp.atomicstatus.

The code that is doing the scan is:

	if castogscanstatus(gp, s, s|_Gscan) {
		if !gp.gcscandone {
			scanstack(gp, gcw)
			gp.gcscandone = true
		}
		restartg(gp)
		break loop
	}

More analysis showed that scanstack can, in a rare case, end up
calling back into code that acquires sched.lock. For example:

	runtime.scanstack at proc.go:866
	calls runtime.gentraceback at mgcmark.go:842
	calls runtime.scanstack$1 at traceback.go:378
	calls runtime.scanframeworker at mgcmark.go:819
	calls runtime.scanblock at mgcmark.go:904
	calls runtime.greyobject at mgcmark.go:1221
	calls (*runtime.gcWork).put at mgcmark.go:1412
	calls (*runtime.gcControllerState).enlistWorker at mgcwork.go:127
	calls runtime.wakep at mgc.go:632
	calls runtime.startm at proc.go:1779
	acquires runtime.sched.lock at proc.go:1675

This path was found with an automated deadlock-detecting tool.
There are many such paths but they all go through enlistWorker -> wakep.

The evidence strongly suggests that one of these paths is what caused
the deadlock we observed. We're running those jobs with
GOTRACEBACK=crash now to try to get more information if it happens
again.

Further refinement and analysis shows that if we drop the wakep call
from enlistWorker, the remaining few deadlock cycles found by the tool
are all false positives caused by not understanding the effect of calls
to func variables.

The enlistWorker -> wakep call was intended only as a performance
optimization, it rarely executes, and if it does execute at just the
wrong time it can (and plausibly did) cause the deadlock we saw.

Comment it out, to avoid the potential deadlock.

Fixes #19112.
Unfixes #14179.

Change-Id: I6f7e10b890b991c11e79fab7aeefaf70b5d5a07b
Reviewed-on: https://go-review.googlesource.com/37093
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-on: https://go-review.googlesource.com/37022
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-02-16 15:25:04 +00:00
Sarah Adams
7d7a0a9d64 [release-branch.go1.8] doc: update Code of Conduct wording and scope
This change removes the punitive language and anonymous reporting mechanism
from the Code of Conduct document. Read on for the rationale.

More than a year has passed since the Go Code of Conduct was introduced.
In that time, there have been a small number (<30) of reports to the Working Group.
Some reports we handled well, with positive outcomes for all involved.
A few reports we handled badly, resulting in hurt feelings and a bad
experience for all involved.

On reflection, the reports that had positive outcomes were ones where the
Working Group took the role of advisor/facilitator, listening to complaints and
providing suggestions and advice to the parties involved.
The reports that had negative outcomes were ones where the subject of the
report felt threatened by the Working Group and Code of Conduct.

After some discussion among the Working Group, we saw that we are most
effective as facilitators, rather than disciplinarians. The various Go spaces
already have moderators; this change to the CoC acknowledges their authority
and places the group in a purely advisory role. If an incident is
reported to the group we may provide information to or make a
suggestion the moderators, but the Working Group need not (and should not) have
any authority to take disciplinary action.

In short, we want it to be clear that the Working Group are here to help
resolve conflict, period.

The second change made here is the removal of the anonymous reporting mechanism.
To date, the quality of anonymous reports has been low, and with no way to
reach out to the reporter for more information there is often very little we
can do in response. Removing this one-way reporting mechanism strengthens the
message that the Working Group are here to facilitate a constructive dialogue.

Change-Id: Iee52aff5446accd0dae0c937bb3aa89709ad5fb4
Reviewed-on: https://go-review.googlesource.com/37014
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/37040
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-02-15 21:51:35 +00:00
Russ Cox
cedc511a6e [release-branch.go1.8] encoding/xml: fix incorrect indirect code in chardata, comment, innerxml fields
The new tests in this CL have been checked against Go 1.7 as well
and all pass in Go 1.7, with the one exception noted in a comment
(an intentional change to omitempty already present before this CL).

CL 15684 made the intentional change to omitempty.
This CL fixes bugs introduced along the way.

Most of these are corner cases that are arguably not that important,
but they've always worked all the way back to Go 1, and someone
cared enough to file #19063. The most significant problem found
while adding tests is that in the case of a nil *string field with
`xml:",chardata"`, the existing code silently stops processing not just
that field but the entire remainder of the struct.
Even if #19063 were not worth fixing, this chardata bug would be.

Fixes #19063.

Change-Id: I318cf8f9945e1a4615982d9904e109fde577ebf9
Reviewed-on: https://go-review.googlesource.com/36954
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
(cherry picked from commit 72aa757ddd)
Reviewed-on: https://go-review.googlesource.com/37016
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-02-15 14:31:02 +00:00
Daniel Theophanes
ae13ccfd6d [release-branch.go1.8] database/sql: convert test timeouts to explicit waits with checks
When testing context cancelation behavior do not rely on context
timeouts. Use explicit checks in all such tests. In closeDB
convert the simple check for zero open conns with a wait loop
for zero open conns.

Fixes #19024
Fixes #19041

Change-Id: Iecfcc4467e91249fceb21ffd1f7c62c58140d8e9
Reviewed-on: https://go-review.googlesource.com/36902
Run-TryBot: Daniel Theophanes <kardianos@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/36917
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Daniel Theophanes <kardianos@gmail.com>
2017-02-13 19:22:34 +00:00
Michael Hudson-Doyle
7cec9a583d [release-branch.go1.8] reflect: clear ptrToThis in Ptr when allocating result on heap
Otherwise, calling PtrTo on the result will fail.

Fixes #19003

Change-Id: I8d7d1981a5d0417d5aee52740469d71e90734963
Reviewed-on: https://go-review.googlesource.com/36731
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/36718
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-02-10 17:53:40 +00:00
Daniel Theophanes
d84dee069a [release-branch.go1.8] database/sql: ensure driverConns are closed if not returned to pool
Previously if a connection was requested but timed out during the
request and when acquiring the db.Lock the connection request
is fulfilled and the request is unable to be returned to the
connection pool, then then driver connection would not be closed.

No tests were added or modified because I was unable to determine
how to trigger this situation without something invasive.

Change-Id: I9d4dc680e3fdcf63d79d212174a5b8b313f363f1
Reviewed-on: https://go-review.googlesource.com/36641
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/36714
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-02-10 17:53:36 +00:00
Daniel Theophanes
f1e44a4b74 [release-branch.go1.8] database/sql: do not exhaust connection pool on conn request timeout
Previously if a context was canceled while it was waiting for a
connection request, that connection request would leak.

To prevent this remove the pending connection request if the
context is canceled and ensure no connection has been sent on the channel.
This requires a change to how the connection requests are represented in the DB.

Fixes #18995

Change-Id: I9a274b48b8f4f7ca46cdee166faa38f56d030852
Reviewed-on: https://go-review.googlesource.com/36563
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/36613
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-02-10 17:53:29 +00:00
Daniel Theophanes
3ade54063e [release-branch.go1.8] database/sql: record the context error in Rows if canceled
Previously it was intended that Rows.Scan would return
an error and Rows.Err would return nil. This was problematic
because drivers could not differentiate between a normal
Rows.Close or a context cancel close.

The alternative is to require drivers to return a Scan to return
an error if the driver is closed while there are still rows to be read.
This is currently not how several drivers currently work and may be
difficult to detect when there are additional rows.

At the same time guard the the Rows.lasterr and prevent a close
while a Rows operation is active.

For the drivers that do not have Context methods, do not check for
context cancelation after the operation, but before for any operation
that may modify the database state.

Fixes #18961

Change-Id: I49a25318ecd9f97a35d5b50540ecd850c01cfa5e
Reviewed-on: https://go-review.googlesource.com/36485
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/36614
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-02-09 03:47:26 +00:00
Russ Cox
0545006bdb [release-branch.go1.8] crypto/x509: check for new tls-ca-bundle.pem last
We added CentOS 7's /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
to the list in response to #17549 - not being able to find any certs otherwise.

Now we have #18813, where CentOS 6 apparently has both that file
and /etc/pki/tls/certs/ca-bundle.crt, and the latter is complete while
the former is not.

Moving the new CentOS 7 file to the bottom of the list should fix both
problems: the CentOS 7 system that didn't have any of the other files
in the list will still find the new one, and existing systems will still
keep using what they were using instead of preferring the new path
that may or may not be complete on some systems.

Fixes #18813.

Change-Id: I5275ab67424b95e7210e14938d3e986c8caee0ba
Reviewed-on: https://go-review.googlesource.com/36429
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/36530
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-02-08 17:50:39 +00:00
Russ Cox
1363eeba65 [release-branch.go1.8] cmd/go, go/build: better defenses against GOPATH=GOROOT
Fixes #18863.

Change-Id: I0723563cd23728b0d43ebcc25979bf8d21e2a72c
Reviewed-on: https://go-review.googlesource.com/36427
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/36536
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-02-07 19:42:47 +00:00
Cherry Zhang
1edfd64761 [release-branch.go1.8] cmd/compile: do not use "oaslit" for global
The compiler did not emit write barrier for assigning global with
struct literal, like global = T{} where T contains pointer.

The relevant code path is:
walkexpr OAS var_ OSTRUCTLIT
    oaslit
        anylit OSTRUCTLIT
            walkexpr OAS var_ nil
            return without adding write barrier
    return true
break (without adding write barrier)

This CL makes oaslit not apply to globals. See also CL
https://go-review.googlesource.com/c/36355/ for an alternative
fix.

The downside of this is that it generates static data for zeroing
struct now. Also this only covers global. If there is any lurking
bug with implicit zeroing other than globals, this doesn't fix.

Fixes #18956.

Change-Id: Ibcd27e4fae3aa38390ffa94a32a9dd7a802e4b37
Reviewed-on: https://go-review.googlesource.com/36410
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
(cherry picked from commit 160914e33c)
Reviewed-on: https://go-review.googlesource.com/36531
2017-02-07 17:39:16 +00:00
Robert Griesemer
6eb0f5440e [release-branch.go1.8] cmd/compile/internal/syntax: avoid follow-up error for incorrect if statement
This is a follow-up on https://go-review.googlesource.com/36470
and leads to a more stable fix. The above CL relied on filtering
of multiple errors on the same line to avoid more than one error
for an `if` statement of the form `if a := 10 {}`. This CL avoids
the secondary error ("missing condition in if statement") in the
first place.

For #18915.

Change-Id: I8517f485cc2305965276c17d8f8797d61ef9e999
Reviewed-on: https://go-review.googlesource.com/36479
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-on: https://go-review.googlesource.com/36424
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
2017-02-07 16:52:00 +00:00
Robert Griesemer
c543cc353d [release-branch.go1.8] cmd/compile/internal/syntax: make a parser error "1.7 compliant"
For code such as

	if a := 10 { ...

the 1.7 compiler reported

	a := 10 used as value

while the 1.8 compiler reported

	invalid condition, tag, or type switch guard

Changed the error message to match the 1.7 compiler.

Fixes #18915.

Change-Id: I01308862e461922e717f9f8295a9db53d5a914eb
Reviewed-on: https://go-review.googlesource.com/36470
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/36422
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
2017-02-07 16:51:22 +00:00
David Crawshaw
f0749fe163 [release-branch.go1.8] cmd/link: use external linking for PIE by default
Now `go test -buildmode=pie std -short` passes on linux/amd64.

Updates #18968

Change-Id: Ide21877713e00edc64c1700c950016d6bff8de0e
Reviewed-on: https://go-review.googlesource.com/36417
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/36421
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
Reviewed-by: Minux Ma <minux@golang.org>
2017-02-07 01:40:49 +00:00
Andrew Gerrand
ba878ac0c8 [release-branch.go1.8] doc: remove inactive members of the CoC working group
Dave and Jason have moved on to other things.

Change-Id: I702d11bedfab1f47a33679a48c2309f49021229e
Reviewed-on: https://go-review.googlesource.com/36450
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-on: https://go-review.googlesource.com/36474
Reviewed-by: Andrew Gerrand <adg@golang.org>
2017-02-07 01:17:07 +00:00
Russ Cox
6177f6d448 [release-branch.go1.8] vendor/golang.org/x/crypto/curve25519: avoid loss of R15 in -dynlink mode
Original code fixed in https://go-review.googlesource.com/#/c/36359/.

Fixes #18820.

Change-Id: I060e6c9d0e312b4fd5d0674aff131055bf5cf61d
Reviewed-on: https://go-review.googlesource.com/36412
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/36414
Reviewed-by: Austin Clements <austin@google.com>
2017-02-06 21:57:50 +00:00
Cherry Zhang
67cd1fa780 [release-branch.go1.8] cmd/compile: do not fold large offset on ARM64
Fixes #18933.

Change-Id: I1ab524fdca006100ec6af572065b496f68d6a5c3
Reviewed-on: https://go-review.googlesource.com/36413
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-02-06 21:23:08 +00:00
Michael Munday
758a7281ab [release-branch.go1.8] cmd/compile: fix type propagation through s390x SSA rules
This CL fixes two issues:

1. Load ops were initially always lowered to unsigned loads, even
   for signed types. This was fine by itself however LoadReg ops
   (used to re-load spilled values) were lowered to signed loads
   for signed types. This meant that spills could invalidate
   optimizations that assumed the original unsigned load.

2. Types were not always being maintained correctly through rules
   designed to eliminate unnecessary zero and sign extensions.

Updates #18906 and fixes #18958 (backport of CL 36256 to 1.8).

Change-Id: Id44953b0f644cad047e8474edbd24e8a344ca9a7
Reviewed-on: https://go-review.googlesource.com/36350
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-02-06 16:41:29 +00:00
Alberto Donizetti
470704531d [release-branch.go1.8] testing: stop timeout-timer after running tests
Fixes #18845

Fixes #18870 (Go 1.8 backport)

Change-Id: Icdc3e2067807781e42f2ffc94d1824aed94d3713
Reviewed-on: https://go-review.googlesource.com/35956
Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
(cherry picked from commit 7d8bfdde45)
Reviewed-on: https://go-review.googlesource.com/36125
2017-02-02 06:51:54 +00:00
Filippo Valsorda
648bb34484 [release-branch.go1.8] doc: mention SHA-256 CBC suites are off by default
Change-Id: I82c41bd1d82adda457ddb5dd08caf0647905da22
Reviewed-on: https://go-review.googlesource.com/36091
Reviewed-by: Matt Layher <mdlayher@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
(cherry picked from commit de479267ef)
Reviewed-on: https://go-review.googlesource.com/36130
2017-02-01 21:37:57 +00:00
Russ Cox
d8d2f036a5 [release-branch.go1.8] all: final merge of master into Go 1.8 release branch
After this, we will merge some of the dev work like
type aliases and inlining into master, so any additional
changes for the Go 1.8 release will need to be cherry-picked,
not merged.

3e55059f cmd/dist: really skip the testsanitizers tests on Android
09496599 runtime: add explicit (void) in C to avoid GCC 7 problem
4cffe2b6 cmd/dist: use the target GOOS to skip the test for issue 18153
6bdb0c11 doc: update go1.8 release notes after TxOptions change
09096bd3 cmd/go: update alldocs after CL 35150
96ea0918 cmd/compile: use CMPWU for 32-bit or smaller unsigned Geq on ppc64{,le}
21a8db1c doc: document go1.7.5

Change-Id: I9e6a30c3fac43d4d4d15e93054ac00964c3ee958
2017-01-31 09:53:37 -05:00
Chris Broadfoot
2a5f65a98c [release-branch.go1.8] go1.8rc3
Change-Id: Ie306bb5355f56113356fc141f3c1a56872b39f9e
Reviewed-on: https://go-review.googlesource.com/35836
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-01-26 17:42:08 +00:00
Chris Broadfoot
2f6c20b46c [release-branch.go1.8] all: merge master into release-branch.go1.8
78860b2ad2 cmd/go: don't reject ./... matching top-level file outside GOPATH
2b283cedef database/sql: fix race when canceling queries immediately
1cf08182f9 go/printer: fix format with leading comments in composite literal
b531eb3062 runtime: reorder modules so main.main comes first
165cfbc409 database/sql: let tests wait for db pool to come to expected state
ea73649343 doc: update gccgo docs
1db16711f5 doc: clarify what to do with Go 1.4 when installing from source
3717b429f2 doc: note that plugins are not fully baked
98842cabb6 net/http: don't send body on redirects for 301, 302, 303 when GetBody is set
314180e7f6 net/http: fix a nit
aad06da2b9 cmd/link: mark DWARF function symbols as reachable
be9dcfec29 doc: mention testing.MainStart signature change
a96e117a58 runtime: amd64, use 4-byte ops for memmove of 4 bytes
4cce27a3fa cmd/compile: fix constant propagation through s390x MOVDNE instructions
1be957d703 misc/cgo/test: pass current environment to syscall.Exec
ec654e2251 misc/cgo/test: fix test when using GCC 7
256a605faa cmd/compile: don't use nilcheck information until the next block
e8d5989ed1 cmd/compile: fix compilebench -alloc
ea7d9e6a52 runtime: check for nil g and m in msanread

Change-Id: I61d508d4f0efe4b72e7396645c8ad6088d2bfa6e
2017-01-26 09:24:31 -08:00
Chris Broadfoot
59f181b6fd [release-branch.go1.8] go1.8rc2
Change-Id: Ifcf2e13b962aa10280df8ca76cb21b37e3533f8f
Reviewed-on: https://go-review.googlesource.com/35475
Run-TryBot: Chris Broadfoot <cbro@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-01-19 20:58:37 +00:00
Chris Broadfoot
d18087cb25 [release-branch.go1.8] all: merge master into release-branch.go1.8
6593d8650d go/ast: fix Object's doc comment about Data
c1730ae424 runtime: force workers out before checking mark roots
d10eddcba3 testing: make parallel t.Run safe again
2c8b70eacf crypto/x509: revert SystemCertPool implementation for Windows
fcfd91858b doc/go1.8: document Plan 9 requirements
81a61a96c9 runtime: for plugins, don't add duplicate itabs
f674537cc9 README.md: update and simplify
d8711919db cmd/go: fix bug help message
48d8edb5b2 crypto/tls: disable CBC cipher suites with SHA-256 by default
92ecd78933 cmd/compile: add ZeroWB case in writebarrier
787125abab doc: 2017 is the Year of the Gopher
5b708a6b6a cmd/compile: lvalues are only required for == when calling runtime fns
e83d506714 vendor/golang_org/x/crypto/poly1305: revendor to pick up fix for #18673
76f981c8d8 net/http: skip TestServerHijackGetsBackgroundByte on Plan 9
e395e3246a net/http: skip TestServerHijackGetsBackgroundByte_big on Plan 9
6a3c6c0de8 net/http: add another hijack-after-background-read test
467109bf56 all: test adjustments for the iOS builder
b2a3b54b95 net/http: make sure Hijack's bufio.Reader includes pre-read background byte
593ea3b360 cmd/go, misc: rework cwd handling for iOS tests
0642b8a2f1 syscall: export Fsid.X__val on s390x
4601eae6ba doc/gdb: mention GOTRACEBACK=crash
4c4c5fc7a3 misc/cgo/testplugin: test that types and itabs are unique
22689c4450 reflect: keep makeFuncImpl live across makeFuncStub
9cf06ed6cd cmd/link: only exclude C-only symbols on darwin
9c3630f578 compress/flate: avoid large stack growth in fillDeflate
4f0aac52d9 cmd/go: add comment about SIGUSR2 on iOS
333f764df3 cmd/go, misc: switch from breakpoint to SIGUSR2
39e31d5ec0 doc/go1.8: update timezone database version
08da8201ca misc/cgo/testshared: test that types and itabs are unique
fdde7ba2a2 runtime: avoid clobbering C callee-save register in cgoSigtramp
f65abf6ddc cmd/compile: hide testdclstack behind debug flag
641ef2a733 compress/gzip: skip TestGZIPFilesHaveZeroMTimes on non-builders
0724aa813f crypto/dsa: gofmt
ac05542985 net/http: deflake TestRetryIdempotentRequestsOnError
b842c9aac7 doc: remove inline styles

Change-Id: I642c056732fe1e8081e9d73e086e38ea0b2568cc
2017-01-19 12:36:53 -08:00
Chris Broadfoot
3de6e96e4b [release-branch.go1.8] go1.8rc1
Change-Id: I68a99a4d750357dd59eb48f7c05b4dc08c64c92d
Reviewed-on: https://go-review.googlesource.com/35097
Run-TryBot: Chris Broadfoot <cbro@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-01-10 19:35:03 +00:00
40 changed files with 1435 additions and 605 deletions

1
VERSION Normal file
View File

@@ -0,0 +1 @@
go1.8

View File

@@ -148,29 +148,26 @@ These actions are explicitly forbidden in Go spaces:
<p>
The Go spaces are not free speech venues; they are for discussion about Go.
These spaces have moderators.
The goal of the moderators is to facilitate civil discussion about Go.
Each of these spaces have their own moderators.
</p>
<p>
When using the official Go spaces you should act in the spirit of the “Gopher
values”.
If you conduct yourself in a way that is explicitly forbidden by the CoC,
you will be warned and asked to stop.
If you do not stop, you will be removed from our community spaces temporarily.
Repeated, willful breaches of the CoC will result in a permanent ban.
If a reported conflict cannot be resolved amicably, the CoC Working Group
may make a recommendation to the relevant forum moderators.
</p>
<p>
Moderators are held to a higher standard than other community members.
If a moderator creates an inappropriate situation, they should expect less
leeway than others, and should expect to be removed from their position if they
cannot adhere to the CoC.
CoC Working Group members and forum moderators are held to a higher standard than other community members.
If a working group member or moderator creates an inappropriate situation, they
should expect less leeway than others, and should expect to be removed from
their position if they cannot adhere to the CoC.
</p>
<p>
Complaints about moderator actions must be handled using the reporting process
below.
Complaints about working group member or moderator actions must be handled
using the reporting process below.
</p>
<h2 id="reporting">Reporting issues</h2>
@@ -185,8 +182,6 @@ satisfaction of all parties. They are:
<ul>
<li>Aditya Mukerjee &lt;dev@chimeracoder.net&gt;
<li>Andrew Gerrand &lt;adg@golang.org&gt;
<li>Dave Cheney &lt;dave@cheney.net&gt;
<li>Jason Buberel &lt;jbuberel@google.com&gt;
<li>Peggy Li &lt;peggyli.224@gmail.com&gt;
<li>Sarah Adams &lt;sadams.codes@gmail.com&gt;
<li>Steve Francia &lt;steve.francia@gmail.com&gt;
@@ -201,13 +196,10 @@ particular individual or group.
</p>
<ul>
<li>Mail <a href="mailto:conduct@golang.org">conduct@golang.org</a> or
<a href="https://golang.org/s/conduct-report">submit an anonymous report</a>.
<li>Mail <a href="mailto:conduct@golang.org">conduct@golang.org</a>.
<ul>
<li>Your message will reach the Working Group.
<li>Reports are confidential within the Working Group.
<li>Should you choose to remain anonymous then the Working Group cannot
notify you of the outcome of your report.
<li>You may contact a member of the group directly if you do not feel
comfortable contacting the group as a whole. That member will then raise
the issue with the Working Group as a whole, preserving the privacy of the
@@ -229,11 +221,8 @@ particular individual or group.
<li>The Working Group will reach a decision as to how to act. These may include:
<ul>
<li>Nothing.
<li>A request for a private or public apology.
<li>A private or public warning.
<li>An imposed vacation (for instance, asking someone to abstain for a week
from a mailing list or IRC).
<li>A permanent or temporary ban from some or all Go spaces.
<li>Passing the report along to the offender.
<li>A recommendation of action to the relevant forum moderators.
</ul>
<li>The Working Group will reach out to the original reporter to let them know
the decision.
@@ -246,7 +235,6 @@ particular individual or group.
conflicts in the most harmonious way possible.</b>
We hope that in most cases issues may be resolved through polite discussion and
mutual agreement.
Bannings and other forceful measures are to be employed only as a last resort.
</p>
<p>

View File

@@ -30,6 +30,13 @@ to fix critical security problems in both Go 1.4 and Go 1.5 as they arise.
See the <a href="/security">security policy</a> for more details.
</p>
<h2 id="go1.8">go1.8 (released 2017/02/16)</h2>
<p>
Go 1.8 is a major release of Go.
Read the <a href="/doc/go1.8">Go 1.8 Release Notes</a> for more information.
</p>
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
<p>

View File

@@ -15,12 +15,7 @@ Do not send CLs removing the interior tags from such phrases.
ul li { margin: 0.5em 0; }
</style>
<h2 id="introduction">DRAFT RELEASE NOTES - Introduction to Go 1.8</h2>
<p><strong>
Go 1.8 is not yet released. These are work-in-progress
release notes. Go 1.8 is expected to be released in February 2017.
</strong></p>
<h2 id="introduction">Introduction to Go 1.8</h2>
<p>
The latest Go release, version 1.8, arrives six months after <a href="go1.7">Go 1.7</a>.
@@ -799,9 +794,9 @@ Optimizations and minor bug fixes are not listed.
hardware support for AES-GCM is present.
</p>
<p> <!-- CL 27315 -->
<p> <!-- CL 27315, CL 35290 -->
AES-128-CBC cipher suites with SHA-256 are also
now supported.
now supported, but disabled by default.
</p>
</dd>

View File

@@ -221,7 +221,7 @@ To build without <code>cgo</code>, set the environment variable
Change to the directory that will be its parent
and make sure the <code>go</code> directory does not exist.
Then clone the repository and check out the latest release tag
(<code class="versionTag">go1.7.4</code>, for example):</p>
(<code class="versionTag">go1.8</code>, for example):</p>
<pre>
$ git clone https://go.googlesource.com/go
@@ -409,7 +409,7 @@ New releases are announced on the
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
mailing list.
Each announcement mentions the latest release tag, for instance,
<code class="versionTag">go1.7.4</code>.
<code class="versionTag">go1.8</code>.
</p>
<p>

View File

@@ -585,7 +585,7 @@ func isliteral(n *Node) bool {
}
func (n *Node) isSimpleName() bool {
return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP
return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP && n.Class != PEXTERN
}
func litas(l *Node, r *Node, init *Nodes) {

View File

@@ -424,7 +424,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg()
gc.AddAux2(&p.To, v, sc.Off())
case ssa.OpCopy, ssa.OpS390XMOVDconvert:
case ssa.OpCopy, ssa.OpS390XMOVDconvert, ssa.OpS390XMOVDreg:
if v.Type.IsMemory() {
return
}
@@ -433,6 +433,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
if x != y {
opregreg(moveByType(v.Type), y, x)
}
case ssa.OpS390XMOVDnop:
if v.Reg() != v.Args[0].Reg() {
v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
// nothing to do
case ssa.OpLoadReg:
if v.Type.IsFlags() {
v.Fatalf("load flags not implemented: %v", v.LongString())

View File

@@ -529,109 +529,147 @@
// can be encoded in the instructions
// since this rewriting takes place before stack allocation, the offset to SP is unknown,
// so don't do it for args and locals with unaligned offset
(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBload [off1+off2] {sym} ptr mem)
(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBUload [off1+off2] {sym} ptr mem)
(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2) ->
(MOVBload [off1+off2] {sym} ptr mem)
(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2) ->
(MOVBUload [off1+off2] {sym} ptr mem)
(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVHload [off1+off2] {sym} ptr mem)
(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVHUload [off1+off2] {sym} ptr mem)
(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVWload [off1+off2] {sym} ptr mem)
(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVWUload [off1+off2] {sym} ptr mem)
(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVDload [off1+off2] {sym} ptr mem)
(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(FMOVSload [off1+off2] {sym} ptr mem)
(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(FMOVDload [off1+off2] {sym} ptr mem)
(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVBstore [off1+off2] {sym} ptr val mem)
(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(off1+off2) ->
(MOVBstore [off1+off2] {sym} ptr val mem)
(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
&& (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVHstore [off1+off2] {sym} ptr val mem)
(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVWstore [off1+off2] {sym} ptr val mem)
(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
&& (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVDstore [off1+off2] {sym} ptr val mem)
(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(FMOVSstore [off1+off2] {sym} ptr val mem)
(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
&& (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(FMOVDstore [off1+off2] {sym} ptr val mem)
(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBstorezero [off1+off2] {sym} ptr mem)
(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2) ->
(MOVBstorezero [off1+off2] {sym} ptr mem)
(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVHstorezero [off1+off2] {sym} ptr mem)
(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVWstorezero [off1+off2] {sym} ptr mem)
(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
&& (off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
&& is32Bit(off1+off2)
&& ((off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)) ->
(MOVDstorezero [off1+off2] {sym} ptr mem)
(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2) ->
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2) ->
(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2) ->
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2) ->
(MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(off1+off2)
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
(MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)

View File

@@ -312,9 +312,12 @@
// Lowering loads
(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem)
(Load <t> ptr mem) && is32BitInt(t) -> (MOVWZload ptr mem)
(Load <t> ptr mem) && is16BitInt(t) -> (MOVHZload ptr mem)
(Load <t> ptr mem) && (t.IsBoolean() || is8BitInt(t)) -> (MOVBZload ptr mem)
(Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem)
(Load <t> ptr mem) && is32BitInt(t) && !isSigned(t) -> (MOVWZload ptr mem)
(Load <t> ptr mem) && is16BitInt(t) && isSigned(t) -> (MOVHload ptr mem)
(Load <t> ptr mem) && is16BitInt(t) && !isSigned(t) -> (MOVHZload ptr mem)
(Load <t> ptr mem) && is8BitInt(t) && isSigned(t) -> (MOVBload ptr mem)
(Load <t> ptr mem) && (t.IsBoolean() || (is8BitInt(t) && !isSigned(t))) -> (MOVBZload ptr mem)
(Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem)
(Load <t> ptr mem) && is64BitFloat(t) -> (FMOVDload ptr mem)
@@ -445,16 +448,20 @@
// ***************************
// TODO: Should the optimizations be a separate pass?
// if a register move has only 1 use, just use the same register without emitting instruction
// MOVDnop doesn't emit instruction, only for ensuring the type.
(MOVDreg x) && x.Uses == 1 -> (MOVDnop x)
// Fold sign extensions into conditional moves of constants.
// Designed to remove the MOVBZreg inserted by the If lowering.
(MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
(MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
(MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
(MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
(MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
(MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
(MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
(MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
(MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
(MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
(MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
(MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
(MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
(MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
(MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
(MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
// Fold boolean tests into blocks.
(NE (CMPWconst [0] (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (LT cmp yes no)
@@ -572,46 +579,46 @@
(MOVDNE x y (InvertFlags cmp)) -> (MOVDNE x y cmp)
// don't extend after proper load
(MOVBreg x:(MOVBload _ _)) -> x
(MOVBZreg x:(MOVBZload _ _)) -> x
(MOVHreg x:(MOVBload _ _)) -> x
(MOVHreg x:(MOVBZload _ _)) -> x
(MOVHreg x:(MOVHload _ _)) -> x
(MOVHZreg x:(MOVBZload _ _)) -> x
(MOVHZreg x:(MOVHZload _ _)) -> x
(MOVWreg x:(MOVBload _ _)) -> x
(MOVWreg x:(MOVBZload _ _)) -> x
(MOVWreg x:(MOVHload _ _)) -> x
(MOVWreg x:(MOVHZload _ _)) -> x
(MOVWreg x:(MOVWload _ _)) -> x
(MOVWZreg x:(MOVBZload _ _)) -> x
(MOVWZreg x:(MOVHZload _ _)) -> x
(MOVWZreg x:(MOVWZload _ _)) -> x
(MOVBreg x:(MOVBload _ _)) -> (MOVDreg x)
(MOVBZreg x:(MOVBZload _ _)) -> (MOVDreg x)
(MOVHreg x:(MOVBload _ _)) -> (MOVDreg x)
(MOVHreg x:(MOVBZload _ _)) -> (MOVDreg x)
(MOVHreg x:(MOVHload _ _)) -> (MOVDreg x)
(MOVHZreg x:(MOVBZload _ _)) -> (MOVDreg x)
(MOVHZreg x:(MOVHZload _ _)) -> (MOVDreg x)
(MOVWreg x:(MOVBload _ _)) -> (MOVDreg x)
(MOVWreg x:(MOVBZload _ _)) -> (MOVDreg x)
(MOVWreg x:(MOVHload _ _)) -> (MOVDreg x)
(MOVWreg x:(MOVHZload _ _)) -> (MOVDreg x)
(MOVWreg x:(MOVWload _ _)) -> (MOVDreg x)
(MOVWZreg x:(MOVBZload _ _)) -> (MOVDreg x)
(MOVWZreg x:(MOVHZload _ _)) -> (MOVDreg x)
(MOVWZreg x:(MOVWZload _ _)) -> (MOVDreg x)
// don't extend if argument is already extended
(MOVBreg x:(Arg <t>)) && is8BitInt(t) && isSigned(t) -> x
(MOVBZreg x:(Arg <t>)) && is8BitInt(t) && !isSigned(t) -> x
(MOVHreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && isSigned(t) -> x
(MOVHZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && !isSigned(t) -> x
(MOVWreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t) -> x
(MOVWZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t) -> x
(MOVBreg x:(Arg <t>)) && is8BitInt(t) && isSigned(t) -> (MOVDreg x)
(MOVBZreg x:(Arg <t>)) && is8BitInt(t) && !isSigned(t) -> (MOVDreg x)
(MOVHreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && isSigned(t) -> (MOVDreg x)
(MOVHZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && !isSigned(t) -> (MOVDreg x)
(MOVWreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t) -> (MOVDreg x)
(MOVWZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t) -> (MOVDreg x)
// fold double extensions
(MOVBreg x:(MOVBreg _)) -> x
(MOVBZreg x:(MOVBZreg _)) -> x
(MOVHreg x:(MOVBreg _)) -> x
(MOVHreg x:(MOVBZreg _)) -> x
(MOVHreg x:(MOVHreg _)) -> x
(MOVHZreg x:(MOVBZreg _)) -> x
(MOVHZreg x:(MOVHZreg _)) -> x
(MOVWreg x:(MOVBreg _)) -> x
(MOVWreg x:(MOVBZreg _)) -> x
(MOVWreg x:(MOVHreg _)) -> x
(MOVWreg x:(MOVHreg _)) -> x
(MOVWreg x:(MOVWreg _)) -> x
(MOVWZreg x:(MOVBZreg _)) -> x
(MOVWZreg x:(MOVHZreg _)) -> x
(MOVWZreg x:(MOVWZreg _)) -> x
(MOVBreg x:(MOVBreg _)) -> (MOVDreg x)
(MOVBZreg x:(MOVBZreg _)) -> (MOVDreg x)
(MOVHreg x:(MOVBreg _)) -> (MOVDreg x)
(MOVHreg x:(MOVBZreg _)) -> (MOVDreg x)
(MOVHreg x:(MOVHreg _)) -> (MOVDreg x)
(MOVHZreg x:(MOVBZreg _)) -> (MOVDreg x)
(MOVHZreg x:(MOVHZreg _)) -> (MOVDreg x)
(MOVWreg x:(MOVBreg _)) -> (MOVDreg x)
(MOVWreg x:(MOVBZreg _)) -> (MOVDreg x)
(MOVWreg x:(MOVHreg _)) -> (MOVDreg x)
(MOVWreg x:(MOVHreg _)) -> (MOVDreg x)
(MOVWreg x:(MOVWreg _)) -> (MOVDreg x)
(MOVWZreg x:(MOVBZreg _)) -> (MOVDreg x)
(MOVWZreg x:(MOVHZreg _)) -> (MOVDreg x)
(MOVWZreg x:(MOVWZreg _)) -> (MOVDreg x)
// fold extensions into constants
(MOVBreg (MOVDconst [c])) -> (MOVDconst [int64(int8(c))])
@@ -641,10 +648,10 @@
(MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem)
// replace load from same location as preceding store with copy
(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
// Don't extend before storing
(MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)

View File

@@ -311,6 +311,9 @@ func init() {
{name: "MOVHZreg", argLength: 1, reg: gp11sp, asm: "MOVHZ", typ: "UInt64"}, // zero extend arg0 from int16 to int64
{name: "MOVWreg", argLength: 1, reg: gp11sp, asm: "MOVW", typ: "Int64"}, // sign extend arg0 from int32 to int64
{name: "MOVWZreg", argLength: 1, reg: gp11sp, asm: "MOVWZ", typ: "UInt64"}, // zero extend arg0 from int32 to int64
{name: "MOVDreg", argLength: 1, reg: gp11sp, asm: "MOVD"}, // move from arg0
{name: "MOVDnop", argLength: 1, reg: gp11, resultInArg0: true}, // nop, return arg0 in same register
{name: "MOVDconst", reg: gp01, asm: "MOVD", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint

View File

@@ -1473,6 +1473,8 @@ const (
OpS390XMOVHZreg
OpS390XMOVWreg
OpS390XMOVWZreg
OpS390XMOVDreg
OpS390XMOVDnop
OpS390XMOVDconst
OpS390XCFDBRA
OpS390XCGDBRA
@@ -18570,6 +18572,32 @@ var opcodeTable = [...]opInfo{
},
},
},
{
name: "MOVDreg",
argLen: 1,
asm: s390x.AMOVD,
reg: regInfo{
inputs: []inputInfo{
{0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
outputs: []outputInfo{
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
name: "MOVDnop",
argLen: 1,
resultInArg0: true,
reg: regInfo{
inputs: []inputInfo{
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
outputs: []outputInfo{
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
name: "MOVDconst",
auxType: auxInt64,

View File

@@ -2625,7 +2625,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (FMOVDload [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -2637,7 +2637,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64FMOVDload)
@@ -2648,7 +2648,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
return true
}
// match: (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -2661,7 +2661,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64FMOVDload)
@@ -2677,7 +2677,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
// cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (FMOVDstore [off1+off2] {sym} ptr val mem)
for {
off1 := v.AuxInt
@@ -2690,7 +2690,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64FMOVDstore)
@@ -2702,7 +2702,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
return true
}
// match: (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
for {
off1 := v.AuxInt
@@ -2716,7 +2716,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64FMOVDstore)
@@ -2733,7 +2733,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (FMOVSload [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -2745,7 +2745,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64FMOVSload)
@@ -2756,7 +2756,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
return true
}
// match: (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -2769,7 +2769,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64FMOVSload)
@@ -2785,7 +2785,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (FMOVSstore [off1+off2] {sym} ptr val mem)
for {
off1 := v.AuxInt
@@ -2798,7 +2798,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64FMOVSstore)
@@ -2810,7 +2810,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
return true
}
// match: (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
for {
off1 := v.AuxInt
@@ -2824,7 +2824,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64FMOVSstore)
@@ -3511,7 +3511,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem)
// cond:
// cond: is32Bit(off1+off2)
// result: (MOVBUload [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -3523,6 +3523,9 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !(is32Bit(off1 + off2)) {
break
}
v.reset(OpARM64MOVBUload)
v.AuxInt = off1 + off2
v.Aux = sym
@@ -3531,7 +3534,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
return true
}
// match: (MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2)
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
// result: (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -3544,7 +3547,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2)) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
break
}
v.reset(OpARM64MOVBUload)
@@ -3623,7 +3626,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem)
// cond:
// cond: is32Bit(off1+off2)
// result: (MOVBload [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -3635,6 +3638,9 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !(is32Bit(off1 + off2)) {
break
}
v.reset(OpARM64MOVBload)
v.AuxInt = off1 + off2
v.Aux = sym
@@ -3643,7 +3649,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
return true
}
// match: (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2)
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
// result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -3656,7 +3662,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2)) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
break
}
v.reset(OpARM64MOVBload)
@@ -3735,7 +3741,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem)
// cond:
// cond: is32Bit(off1+off2)
// result: (MOVBstore [off1+off2] {sym} ptr val mem)
for {
off1 := v.AuxInt
@@ -3748,6 +3754,9 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !(is32Bit(off1 + off2)) {
break
}
v.reset(OpARM64MOVBstore)
v.AuxInt = off1 + off2
v.Aux = sym
@@ -3757,7 +3766,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
return true
}
// match: (MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
// cond: canMergeSym(sym1,sym2)
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
// result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
for {
off1 := v.AuxInt
@@ -3771,7 +3780,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !(canMergeSym(sym1, sym2)) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
break
}
v.reset(OpARM64MOVBstore)
@@ -3936,7 +3945,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
// cond:
// cond: is32Bit(off1+off2)
// result: (MOVBstorezero [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -3948,6 +3957,9 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !(is32Bit(off1 + off2)) {
break
}
v.reset(OpARM64MOVBstorezero)
v.AuxInt = off1 + off2
v.Aux = sym
@@ -3956,7 +3968,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
return true
}
// match: (MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2)
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
// result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -3969,7 +3981,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2)) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
break
}
v.reset(OpARM64MOVBstorezero)
@@ -3985,7 +3997,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVDload [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -3997,7 +4009,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVDload)
@@ -4008,7 +4020,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
return true
}
// match: (MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -4021,7 +4033,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVDload)
@@ -4088,7 +4100,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
// cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVDstore [off1+off2] {sym} ptr val mem)
for {
off1 := v.AuxInt
@@ -4101,7 +4113,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVDstore)
@@ -4113,7 +4125,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
return true
}
// match: (MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
for {
off1 := v.AuxInt
@@ -4127,7 +4139,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVDstore)
@@ -4166,7 +4178,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVDstorezero [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -4178,7 +4190,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%2 == 8 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%2 == 8 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVDstorezero)
@@ -4189,7 +4201,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
return true
}
// match: (MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -4202,7 +4214,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVDstorezero)
@@ -4218,7 +4230,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVHUload [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -4230,7 +4242,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVHUload)
@@ -4241,7 +4253,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
return true
}
// match: (MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -4254,7 +4266,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVHUload)
@@ -4357,7 +4369,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVHload [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -4369,7 +4381,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVHload)
@@ -4380,7 +4392,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
return true
}
// match: (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -4393,7 +4405,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVHload)
@@ -4520,7 +4532,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
// cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVHstore [off1+off2] {sym} ptr val mem)
for {
off1 := v.AuxInt
@@ -4533,7 +4545,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVHstore)
@@ -4545,7 +4557,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
return true
}
// match: (MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
for {
off1 := v.AuxInt
@@ -4559,7 +4571,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVHstore)
@@ -4682,7 +4694,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVHstorezero [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -4694,7 +4706,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVHstorezero)
@@ -4705,7 +4717,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
return true
}
// match: (MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -4718,7 +4730,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVHstorezero)
@@ -4734,7 +4746,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVWUload [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -4746,7 +4758,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVWUload)
@@ -4757,7 +4769,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
return true
}
// match: (MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -4770,7 +4782,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVWUload)
@@ -4897,7 +4909,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVWload [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -4909,7 +4921,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVWload)
@@ -4920,7 +4932,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
return true
}
// match: (MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -4933,7 +4945,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVWload)
@@ -5108,7 +5120,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVWstore [off1+off2] {sym} ptr val mem)
for {
off1 := v.AuxInt
@@ -5121,7 +5133,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVWstore)
@@ -5133,7 +5145,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
return true
}
// match: (MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
for {
off1 := v.AuxInt
@@ -5147,7 +5159,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
ptr := v_0.Args[0]
val := v.Args[1]
mem := v.Args[2]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVWstore)
@@ -5228,7 +5240,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
// cond: is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym))
// result: (MOVWstorezero [off1+off2] {sym} ptr mem)
for {
off1 := v.AuxInt
@@ -5240,7 +5252,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
off2 := v_0.AuxInt
ptr := v_0.Args[0]
mem := v.Args[1]
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
if !(is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym))) {
break
}
v.reset(OpARM64MOVWstorezero)
@@ -5251,7 +5263,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
return true
}
// match: (MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
// result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for {
off1 := v.AuxInt
@@ -5264,7 +5276,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
sym2 := v_0.Aux
ptr := v_0.Args[0]
mem := v.Args[1]
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
break
}
v.reset(OpARM64MOVWstorezero)

View File

@@ -524,6 +524,8 @@ func rewriteValueS390X(v *Value, config *Config) bool {
return rewriteValueS390X_OpS390XMOVDload(v, config)
case OpS390XMOVDloadidx:
return rewriteValueS390X_OpS390XMOVDloadidx(v, config)
case OpS390XMOVDreg:
return rewriteValueS390X_OpS390XMOVDreg(v, config)
case OpS390XMOVDstore:
return rewriteValueS390X_OpS390XMOVDstore(v, config)
case OpS390XMOVDstoreconst:
@@ -3236,13 +3238,28 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
return true
}
// match: (Load <t> ptr mem)
// cond: is32BitInt(t)
// cond: is32BitInt(t) && isSigned(t)
// result: (MOVWload ptr mem)
for {
t := v.Type
ptr := v.Args[0]
mem := v.Args[1]
if !(is32BitInt(t) && isSigned(t)) {
break
}
v.reset(OpS390XMOVWload)
v.AddArg(ptr)
v.AddArg(mem)
return true
}
// match: (Load <t> ptr mem)
// cond: is32BitInt(t) && !isSigned(t)
// result: (MOVWZload ptr mem)
for {
t := v.Type
ptr := v.Args[0]
mem := v.Args[1]
if !(is32BitInt(t)) {
if !(is32BitInt(t) && !isSigned(t)) {
break
}
v.reset(OpS390XMOVWZload)
@@ -3251,13 +3268,28 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
return true
}
// match: (Load <t> ptr mem)
// cond: is16BitInt(t)
// cond: is16BitInt(t) && isSigned(t)
// result: (MOVHload ptr mem)
for {
t := v.Type
ptr := v.Args[0]
mem := v.Args[1]
if !(is16BitInt(t) && isSigned(t)) {
break
}
v.reset(OpS390XMOVHload)
v.AddArg(ptr)
v.AddArg(mem)
return true
}
// match: (Load <t> ptr mem)
// cond: is16BitInt(t) && !isSigned(t)
// result: (MOVHZload ptr mem)
for {
t := v.Type
ptr := v.Args[0]
mem := v.Args[1]
if !(is16BitInt(t)) {
if !(is16BitInt(t) && !isSigned(t)) {
break
}
v.reset(OpS390XMOVHZload)
@@ -3266,13 +3298,28 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
return true
}
// match: (Load <t> ptr mem)
// cond: (t.IsBoolean() || is8BitInt(t))
// cond: is8BitInt(t) && isSigned(t)
// result: (MOVBload ptr mem)
for {
t := v.Type
ptr := v.Args[0]
mem := v.Args[1]
if !(is8BitInt(t) && isSigned(t)) {
break
}
v.reset(OpS390XMOVBload)
v.AddArg(ptr)
v.AddArg(mem)
return true
}
// match: (Load <t> ptr mem)
// cond: (t.IsBoolean() || (is8BitInt(t) && !isSigned(t)))
// result: (MOVBZload ptr mem)
for {
t := v.Type
ptr := v.Args[0]
mem := v.Args[1]
if !(t.IsBoolean() || is8BitInt(t)) {
if !(t.IsBoolean() || (is8BitInt(t) && !isSigned(t))) {
break
}
v.reset(OpS390XMOVBZload)
@@ -7802,7 +7849,7 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
_ = b
// match: (MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
// result: (MOVDreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -7818,8 +7865,7 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
@@ -7976,7 +8022,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
_ = b
// match: (MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _))
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVDLT {
@@ -7995,14 +8041,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _))
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVDLE {
@@ -8021,14 +8066,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _))
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVDGT {
@@ -8047,14 +8091,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _))
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVDGE {
@@ -8073,14 +8116,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _))
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVDEQ {
@@ -8099,14 +8141,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _))
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVDNE {
@@ -8125,14 +8166,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _))
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVDGTnoinv {
@@ -8151,14 +8191,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _))
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVDGEnoinv {
@@ -8177,27 +8216,25 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(MOVBZload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(Arg <t>))
// cond: is8BitInt(t) && !isSigned(t)
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpArg {
@@ -8207,21 +8244,19 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
if !(is8BitInt(t) && !isSigned(t)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBZreg x:(MOVBZreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
@@ -8349,20 +8384,19 @@ func rewriteValueS390X_OpS390XMOVBreg(v *Value, config *Config) bool {
_ = b
// match: (MOVBreg x:(MOVBload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBreg x:(Arg <t>))
// cond: is8BitInt(t) && isSigned(t)
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpArg {
@@ -8372,21 +8406,19 @@ func rewriteValueS390X_OpS390XMOVBreg(v *Value, config *Config) bool {
if !(is8BitInt(t) && isSigned(t)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVBreg x:(MOVBreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
@@ -9995,7 +10027,7 @@ func rewriteValueS390X_OpS390XMOVDload(v *Value, config *Config) bool {
_ = b
// match: (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
// result: (MOVDreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -10011,8 +10043,7 @@ func rewriteValueS390X_OpS390XMOVDload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
@@ -10164,6 +10195,23 @@ func rewriteValueS390X_OpS390XMOVDloadidx(v *Value, config *Config) bool {
}
return false
}
func rewriteValueS390X_OpS390XMOVDreg(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (MOVDreg x)
// cond: x.Uses == 1
// result: (MOVDnop x)
for {
x := v.Args[0]
if !(x.Uses == 1) {
break
}
v.reset(OpS390XMOVDnop)
v.AddArg(x)
return true
}
return false
}
func rewriteValueS390X_OpS390XMOVDstore(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -10912,7 +10960,7 @@ func rewriteValueS390X_OpS390XMOVHZload(v *Value, config *Config) bool {
_ = b
// match: (MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
// result: (MOVDreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -10928,8 +10976,7 @@ func rewriteValueS390X_OpS390XMOVHZload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
@@ -11086,33 +11133,31 @@ func rewriteValueS390X_OpS390XMOVHZreg(v *Value, config *Config) bool {
_ = b
// match: (MOVHZreg x:(MOVBZload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHZreg x:(MOVHZload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHZload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHZreg x:(Arg <t>))
// cond: (is8BitInt(t) || is16BitInt(t)) && !isSigned(t)
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpArg {
@@ -11122,34 +11167,31 @@ func rewriteValueS390X_OpS390XMOVHZreg(v *Value, config *Config) bool {
if !((is8BitInt(t) || is16BitInt(t)) && !isSigned(t)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHZreg x:(MOVBZreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHZreg x:(MOVHZreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHZreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
@@ -11277,46 +11319,43 @@ func rewriteValueS390X_OpS390XMOVHreg(v *Value, config *Config) bool {
_ = b
// match: (MOVHreg x:(MOVBload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHreg x:(MOVBZload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHreg x:(MOVHload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHreg x:(Arg <t>))
// cond: (is8BitInt(t) || is16BitInt(t)) && isSigned(t)
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpArg {
@@ -11326,47 +11365,43 @@ func rewriteValueS390X_OpS390XMOVHreg(v *Value, config *Config) bool {
if !((is8BitInt(t) || is16BitInt(t)) && isSigned(t)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHreg x:(MOVBreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHreg x:(MOVBZreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVHreg x:(MOVHreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
@@ -12310,7 +12345,7 @@ func rewriteValueS390X_OpS390XMOVWZload(v *Value, config *Config) bool {
_ = b
// match: (MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
// result: (MOVDreg x)
for {
off := v.AuxInt
sym := v.Aux
@@ -12326,8 +12361,7 @@ func rewriteValueS390X_OpS390XMOVWZload(v *Value, config *Config) bool {
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
@@ -12484,46 +12518,43 @@ func rewriteValueS390X_OpS390XMOVWZreg(v *Value, config *Config) bool {
_ = b
// match: (MOVWZreg x:(MOVBZload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWZreg x:(MOVHZload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHZload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWZreg x:(MOVWZload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVWZload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWZreg x:(Arg <t>))
// cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpArg {
@@ -12533,47 +12564,43 @@ func rewriteValueS390X_OpS390XMOVWZreg(v *Value, config *Config) bool {
if !((is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWZreg x:(MOVBZreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWZreg x:(MOVHZreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHZreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWZreg x:(MOVWZreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVWZreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
@@ -12701,72 +12728,67 @@ func rewriteValueS390X_OpS390XMOVWreg(v *Value, config *Config) bool {
_ = b
// match: (MOVWreg x:(MOVBload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(MOVBZload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(MOVHload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(MOVHZload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHZload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(MOVWload _ _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVWload {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(Arg <t>))
// cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t)
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpArg {
@@ -12776,73 +12798,67 @@ func rewriteValueS390X_OpS390XMOVWreg(v *Value, config *Config) bool {
if !((is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t)) {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(MOVBreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(MOVBZreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVBZreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(MOVHreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(MOVHreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVHreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}
// match: (MOVWreg x:(MOVWreg _))
// cond:
// result: x
// result: (MOVDreg x)
for {
x := v.Args[0]
if x.Op != OpS390XMOVWreg {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.reset(OpS390XMOVDreg)
v.AddArg(x)
return true
}

View File

@@ -1634,6 +1634,8 @@ func (p *parser) stmtBody(context string) []Stmt {
return body
}
var dummyCond = &Name{Value: "false"}
func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleStmt) {
if p.tok == _Lbrace {
return
@@ -1680,7 +1682,8 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
case *ExprStmt:
cond = s.X
default:
p.error("invalid condition, tag, or type switch guard")
p.syntax_error(fmt.Sprintf("%s used as value", String(s)))
cond = dummyCond // avoid follow-up error for if statements
}
p.xnest = outer

View File

@@ -428,7 +428,7 @@ func downloadPackage(p *Package) error {
return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
}
// Guard against people setting GOPATH=$GOROOT.
if list[0] == goroot {
if filepath.Clean(list[0]) == filepath.Clean(goroot) {
return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
}
if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {

View File

@@ -1683,173 +1683,111 @@ func homeEnvName() string {
}
}
// Test go env missing GOPATH shows default.
func TestMissingGOPATHEnvShowsDefault(t *testing.T) {
func TestDefaultGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.setenv("GOPATH", "")
tg.tempDir("home/go")
tg.setenv(homeEnvName(), tg.path("home"))
tg.run("env", "GOPATH")
tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go")
want := filepath.Join(os.Getenv(homeEnvName()), "go")
got := strings.TrimSpace(tg.getStdout())
if got != want {
t.Errorf("got %q; want %q", got, want)
}
tg.setenv("GOROOT", tg.path("home/go"))
tg.run("env", "GOPATH")
tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go")
tg.setenv("GOROOT", tg.path("home/go")+"/")
tg.run("env", "GOPATH")
tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/")
}
// Test go get missing GOPATH causes go get to warn if directory doesn't exist.
func TestMissingGOPATHGetWarnsIfNotExists(t *testing.T) {
func TestDefaultGOPATHGet(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
if _, err := exec.LookPath("git"); err != nil {
t.Skip("skipping because git binary not found")
}
tg := testgo(t)
defer tg.cleanup()
// setenv variables for test and defer deleting temporary home directory.
tg.setenv("GOPATH", "")
tmp, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("could not create tmp home: %v", err)
}
defer os.RemoveAll(tmp)
tg.setenv(homeEnvName(), tmp)
tg.tempDir("home")
tg.setenv(homeEnvName(), tg.path("home"))
// warn for creating directory
tg.run("get", "-v", "github.com/golang/example/hello")
tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH")
want := fmt.Sprintf("created GOPATH=%s; see 'go help gopath'", filepath.Join(tmp, "go"))
got := strings.TrimSpace(tg.getStderr())
if !strings.Contains(got, want) {
t.Errorf("got %q; want %q", got, want)
}
}
// Test go get missing GOPATH causes no warning if directory exists.
func TestMissingGOPATHGetDoesntWarnIfExists(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
if _, err := exec.LookPath("git"); err != nil {
t.Skip("skipping because git binary not found")
}
tg := testgo(t)
defer tg.cleanup()
// setenv variables for test and defer resetting them.
tg.setenv("GOPATH", "")
tmp, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("could not create tmp home: %v", err)
}
defer os.RemoveAll(tmp)
if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
t.Fatalf("could not create $HOME/go: %v", err)
}
tg.setenv(homeEnvName(), tmp)
// no warning if directory already exists
tg.must(os.RemoveAll(tg.path("home/go")))
tg.tempDir("home/go")
tg.run("get", "github.com/golang/example/hello")
tg.grepStderrNot(".", "expected no output on standard error")
got := strings.TrimSpace(tg.getStderr())
if got != "" {
t.Errorf("got %q; wants empty", got)
}
// error if $HOME/go is a file
tg.must(os.RemoveAll(tg.path("home/go")))
tg.tempFile("home/go", "")
tg.runFail("get", "github.com/golang/example/hello")
tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file")
}
// Test go get missing GOPATH fails if pointed file is not a directory.
func TestMissingGOPATHGetFailsIfItsNotDirectory(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
// setenv variables for test and defer resetting them.
tg.setenv("GOPATH", "")
tmp, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("could not create tmp home: %v", err)
}
defer os.RemoveAll(tmp)
tg.tempDir("home")
tg.setenv(homeEnvName(), tg.path("home"))
path := filepath.Join(tmp, "go")
if err := ioutil.WriteFile(path, nil, 0777); err != nil {
t.Fatalf("could not create GOPATH at %s: %v", path, err)
}
tg.setenv(homeEnvName(), tmp)
const pkg = "github.com/golang/example/hello"
tg.runFail("get", pkg)
msg := "not a directory"
if runtime.GOOS == "windows" {
msg = "The system cannot find the path specified."
}
want := fmt.Sprintf("package %s: mkdir %s: %s", pkg, filepath.Join(tmp, "go"), msg)
got := strings.TrimSpace(tg.getStderr())
if got != want {
t.Errorf("got %q; wants %q", got, want)
}
}
// Test go install of missing package when missing GOPATH fails and shows default GOPATH.
func TestMissingGOPATHInstallMissingPackageFailsAndShowsDefault(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
// setenv variables for test and defer resetting them.
tg.setenv("GOPATH", "")
tmp, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("could not create tmp home: %v", err)
}
defer os.RemoveAll(tmp)
if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
t.Fatalf("could not create $HOME/go: %v", err)
}
tg.setenv(homeEnvName(), tmp)
const pkg = "github.com/golang/example/hello"
tg.runFail("install", pkg)
pkgPath := filepath.Join(strings.Split(pkg, "/")...)
want := fmt.Sprintf("can't load package: package %s: cannot find package \"%s\" in any of:", pkg, pkg) +
fmt.Sprintf("\n\t%s (from $GOROOT)", filepath.Join(runtime.GOROOT(), "src", pkgPath)) +
fmt.Sprintf("\n\t%s (from $GOPATH)", filepath.Join(tmp, "go", "src", pkgPath))
got := strings.TrimSpace(tg.getStderr())
if got != want {
t.Errorf("got %q; wants %q", got, want)
}
tg.runFail("install", "github.com/golang/example/hello")
tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")
}
// Issue 4186. go get cannot be used to download packages to $GOROOT.
// Test that without GOPATH set, go get should fail.
func TestWithoutGOPATHGoGetFails(t *testing.T) {
func TestGoGetIntoGOROOT(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempDir("src")
tg.setenv("GOPATH", "")
tg.setenv("GOROOT", tg.path("."))
tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
}
// Test that with GOPATH=$GOROOT, go get should fail.
func TestWithGOPATHEqualsGOROOTGoGetFails(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempDir("src")
// Fails because GOROOT=GOPATH
tg.setenv("GOPATH", tg.path("."))
tg.setenv("GOROOT", tg.path("."))
tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
tg.runFail("get", "-d", "github.com/golang/example/hello")
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
// Fails because GOROOT=GOPATH after cleaning.
tg.setenv("GOPATH", tg.path(".")+"/")
tg.setenv("GOROOT", tg.path("."))
tg.runFail("get", "-d", "github.com/golang/example/hello")
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
tg.setenv("GOPATH", tg.path("."))
tg.setenv("GOROOT", tg.path(".")+"/")
tg.runFail("get", "-d", "github.com/golang/example/hello")
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
// Fails because GOROOT=$HOME/go so default GOPATH unset.
tg.tempDir("home/go")
tg.setenv(homeEnvName(), tg.path("home"))
tg.setenv("GOPATH", "")
tg.setenv("GOROOT", tg.path("home/go"))
tg.runFail("get", "-d", "github.com/golang/example/hello")
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
tg.setenv(homeEnvName(), tg.path("home")+"/")
tg.setenv("GOPATH", "")
tg.setenv("GOROOT", tg.path("home/go"))
tg.runFail("get", "-d", "github.com/golang/example/hello")
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
tg.setenv(homeEnvName(), tg.path("home"))
tg.setenv("GOPATH", "")
tg.setenv("GOROOT", tg.path("home/go")+"/")
tg.runFail("get", "-d", "github.com/golang/example/hello")
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
}
func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
@@ -3744,6 +3682,13 @@ func TestMatchesOnlySubtestParallelIsOK(t *testing.T) {
tg.grepBoth(okPattern, "go test did not say ok")
}
// Issue 18845
func TestBenchTimeout(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go")
}
func TestLinkXImportPathEscape(t *testing.T) {
// golang.org/issue/16710
tg := testgo(t)

View File

@@ -136,7 +136,7 @@ func main() {
// Diagnose common mistake: GOPATH==GOROOT.
// This setting is equivalent to not setting GOPATH at all,
// which is not what most people want when they do it.
if gopath := buildContext.GOPATH; gopath == runtime.GOROOT() {
if gopath := buildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
} else {
for _, p := range filepath.SplitList(gopath) {

View File

@@ -0,0 +1,10 @@
package timeoutbench_test
import (
"testing"
"time"
)
func BenchmarkSleep1s(b *testing.B) {
time.Sleep(1 * time.Second)
}

View File

@@ -238,6 +238,8 @@ func determineLinkMode(ctxt *Link) {
Linkmode = LinkExternal
} else if iscgo && externalobj {
Linkmode = LinkExternal
} else if Buildmode == BuildmodePIE {
Linkmode = LinkExternal // https://golang.org/issue/18968
} else {
Linkmode = LinkInternal
}

View File

@@ -7,8 +7,8 @@ package x509
// Possible certificate files; stop after finding one.
var certFiles = []string{
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
"/etc/ssl/ca-bundle.pem", // OpenSUSE
"/etc/pki/tls/cacert.pem", // OpenELEC
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
}

View File

@@ -35,15 +35,12 @@ func ctxDriverExec(ctx context.Context, execer driver.Execer, query string, nvda
return nil, err
}
resi, err := execer.Exec(query, dargs)
if err == nil {
select {
default:
case <-ctx.Done():
return resi, ctx.Err()
}
select {
default:
case <-ctx.Done():
return nil, ctx.Err()
}
return resi, err
return execer.Exec(query, dargs)
}
func ctxDriverQuery(ctx context.Context, queryer driver.Queryer, query string, nvdargs []driver.NamedValue) (driver.Rows, error) {
@@ -56,16 +53,12 @@ func ctxDriverQuery(ctx context.Context, queryer driver.Queryer, query string, n
return nil, err
}
rowsi, err := queryer.Query(query, dargs)
if err == nil {
select {
default:
case <-ctx.Done():
rowsi.Close()
return nil, ctx.Err()
}
select {
default:
case <-ctx.Done():
return nil, ctx.Err()
}
return rowsi, err
return queryer.Query(query, dargs)
}
func ctxDriverStmtExec(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Result, error) {
@@ -77,15 +70,12 @@ func ctxDriverStmtExec(ctx context.Context, si driver.Stmt, nvdargs []driver.Nam
return nil, err
}
resi, err := si.Exec(dargs)
if err == nil {
select {
default:
case <-ctx.Done():
return resi, ctx.Err()
}
select {
default:
case <-ctx.Done():
return nil, ctx.Err()
}
return resi, err
return si.Exec(dargs)
}
func ctxDriverStmtQuery(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Rows, error) {
@@ -97,16 +87,12 @@ func ctxDriverStmtQuery(ctx context.Context, si driver.Stmt, nvdargs []driver.Na
return nil, err
}
rowsi, err := si.Query(dargs)
if err == nil {
select {
default:
case <-ctx.Done():
rowsi.Close()
return nil, ctx.Err()
}
select {
default:
case <-ctx.Done():
return nil, ctx.Err()
}
return rowsi, err
return si.Query(dargs)
}
var errLevelNotSupported = errors.New("sql: selected isolation level is not supported")

View File

@@ -305,8 +305,9 @@ type DB struct {
mu sync.Mutex // protects following fields
freeConn []*driverConn
connRequests []chan connRequest
numOpen int // number of opened and pending open connections
connRequests map[uint64]chan connRequest
nextRequest uint64 // Next key to use in connRequests.
numOpen int // number of opened and pending open connections
// Used to signal the need for new connections
// a goroutine running connectionOpener() reads on this chan and
// maybeOpenNewConnections sends on the chan (one send per needed connection)
@@ -572,10 +573,11 @@ func Open(driverName, dataSourceName string) (*DB, error) {
return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
}
db := &DB{
driver: driveri,
dsn: dataSourceName,
openerCh: make(chan struct{}, connectionRequestQueueSize),
lastPut: make(map[*driverConn]string),
driver: driveri,
dsn: dataSourceName,
openerCh: make(chan struct{}, connectionRequestQueueSize),
lastPut: make(map[*driverConn]string),
connRequests: make(map[uint64]chan connRequest),
}
go db.connectionOpener()
return db, nil
@@ -881,6 +883,14 @@ type connRequest struct {
var errDBClosed = errors.New("sql: database is closed")
// nextRequestKeyLocked returns the next connection request key.
// It is assumed that nextRequest will not overflow.
func (db *DB) nextRequestKeyLocked() uint64 {
next := db.nextRequest
db.nextRequest++
return next
}
// conn returns a newly-opened or cached *driverConn.
func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error) {
db.mu.Lock()
@@ -918,12 +928,25 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn
// Make the connRequest channel. It's buffered so that the
// connectionOpener doesn't block while waiting for the req to be read.
req := make(chan connRequest, 1)
db.connRequests = append(db.connRequests, req)
reqKey := db.nextRequestKeyLocked()
db.connRequests[reqKey] = req
db.mu.Unlock()
// Timeout the connection request with the context.
select {
case <-ctx.Done():
// Remove the connection request and ensure no value has been sent
// on it after removing.
db.mu.Lock()
delete(db.connRequests, reqKey)
db.mu.Unlock()
select {
default:
case ret, ok := <-req:
if ok {
db.putConn(ret.conn, ret.err)
}
}
return nil, ctx.Err()
case ret, ok := <-req:
if !ok {
@@ -1044,12 +1067,12 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
return false
}
if c := len(db.connRequests); c > 0 {
req := db.connRequests[0]
// This copy is O(n) but in practice faster than a linked list.
// TODO: consider compacting it down less often and
// moving the base instead?
copy(db.connRequests, db.connRequests[1:])
db.connRequests = db.connRequests[:c-1]
var req chan connRequest
var reqKey uint64
for reqKey, req = range db.connRequests {
break
}
delete(db.connRequests, reqKey) // Remove from pending requests.
if err == nil {
dc.inUse = true
}
@@ -2071,14 +2094,21 @@ type Rows struct {
dc *driverConn // owned; must call releaseConn when closed to release
releaseConn func(error)
rowsi driver.Rows
cancel func() // called when Rows is closed, may be nil.
closeStmt *driverStmt // if non-nil, statement to Close on close
// closed value is 1 when the Rows is closed.
// Use atomic operations on value when checking value.
closed int32
cancel func() // called when Rows is closed, may be nil.
lastcols []driver.Value
lasterr error // non-nil only if closed is true
closeStmt *driverStmt // if non-nil, statement to Close on close
// closemu prevents Rows from closing while there
// is an active streaming result. It is held for read during non-close operations
// and exclusively during close.
//
// closemu guards lasterr and closed.
closemu sync.RWMutex
closed bool
lasterr error // non-nil only if closed is true
// lastcols is only used in Scan, Next, and NextResultSet which are expected
// not not be called concurrently.
lastcols []driver.Value
}
func (rs *Rows) initContextClose(ctx context.Context) {
@@ -2089,7 +2119,7 @@ func (rs *Rows) initContextClose(ctx context.Context) {
// awaitDone blocks until the rows are closed or the context canceled.
func (rs *Rows) awaitDone(ctx context.Context) {
<-ctx.Done()
rs.Close()
rs.close(ctx.Err())
}
// Next prepares the next result row for reading with the Scan method. It
@@ -2099,8 +2129,19 @@ func (rs *Rows) awaitDone(ctx context.Context) {
//
// Every call to Scan, even the first one, must be preceded by a call to Next.
func (rs *Rows) Next() bool {
if rs.isClosed() {
return false
var doClose, ok bool
withLock(rs.closemu.RLocker(), func() {
doClose, ok = rs.nextLocked()
})
if doClose {
rs.Close()
}
return ok
}
func (rs *Rows) nextLocked() (doClose, ok bool) {
if rs.closed {
return false, false
}
if rs.lastcols == nil {
rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns()))
@@ -2109,23 +2150,21 @@ func (rs *Rows) Next() bool {
if rs.lasterr != nil {
// Close the connection if there is a driver error.
if rs.lasterr != io.EOF {
rs.Close()
return false
return true, false
}
nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
if !ok {
rs.Close()
return false
return true, false
}
// The driver is at the end of the current result set.
// Test to see if there is another result set after the current one.
// Only close Rows if there is no further result sets to read.
if !nextResultSet.HasNextResultSet() {
rs.Close()
doClose = true
}
return false
return doClose, false
}
return true
return false, true
}
// NextResultSet prepares the next result set for reading. It returns true if
@@ -2137,18 +2176,28 @@ func (rs *Rows) Next() bool {
// scanning. If there are further result sets they may not have rows in the result
// set.
func (rs *Rows) NextResultSet() bool {
if rs.isClosed() {
var doClose bool
defer func() {
if doClose {
rs.Close()
}
}()
rs.closemu.RLock()
defer rs.closemu.RUnlock()
if rs.closed {
return false
}
rs.lastcols = nil
nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
if !ok {
rs.Close()
doClose = true
return false
}
rs.lasterr = nextResultSet.NextResultSet()
if rs.lasterr != nil {
rs.Close()
doClose = true
return false
}
return true
@@ -2157,6 +2206,8 @@ func (rs *Rows) NextResultSet() bool {
// Err returns the error, if any, that was encountered during iteration.
// Err may be called after an explicit or implicit Close.
func (rs *Rows) Err() error {
rs.closemu.RLock()
defer rs.closemu.RUnlock()
if rs.lasterr == io.EOF {
return nil
}
@@ -2167,7 +2218,9 @@ func (rs *Rows) Err() error {
// Columns returns an error if the rows are closed, or if the rows
// are from QueryRow and there was a deferred error.
func (rs *Rows) Columns() ([]string, error) {
if rs.isClosed() {
rs.closemu.RLock()
defer rs.closemu.RUnlock()
if rs.closed {
return nil, errors.New("sql: Rows are closed")
}
if rs.rowsi == nil {
@@ -2179,7 +2232,9 @@ func (rs *Rows) Columns() ([]string, error) {
// ColumnTypes returns column information such as column type, length,
// and nullable. Some information may not be available from some drivers.
func (rs *Rows) ColumnTypes() ([]*ColumnType, error) {
if rs.isClosed() {
rs.closemu.RLock()
defer rs.closemu.RUnlock()
if rs.closed {
return nil, errors.New("sql: Rows are closed")
}
if rs.rowsi == nil {
@@ -2329,9 +2384,13 @@ func rowsColumnInfoSetup(rowsi driver.Rows) []*ColumnType {
// For scanning into *bool, the source may be true, false, 1, 0, or
// string inputs parseable by strconv.ParseBool.
func (rs *Rows) Scan(dest ...interface{}) error {
if rs.isClosed() {
rs.closemu.RLock()
if rs.closed {
rs.closemu.RUnlock()
return errors.New("sql: Rows are closed")
}
rs.closemu.RUnlock()
if rs.lastcols == nil {
return errors.New("sql: Scan called without calling Next")
}
@@ -2351,20 +2410,28 @@ func (rs *Rows) Scan(dest ...interface{}) error {
// hook throug a test only mutex.
var rowsCloseHook = func() func(*Rows, *error) { return nil }
func (rs *Rows) isClosed() bool {
return atomic.LoadInt32(&rs.closed) != 0
}
// Close closes the Rows, preventing further enumeration. If Next is called
// and returns false and there are no further result sets,
// the Rows are closed automatically and it will suffice to check the
// result of Err. Close is idempotent and does not affect the result of Err.
func (rs *Rows) Close() error {
if !atomic.CompareAndSwapInt32(&rs.closed, 0, 1) {
return rs.close(nil)
}
func (rs *Rows) close(err error) error {
rs.closemu.Lock()
defer rs.closemu.Unlock()
if rs.closed {
return nil
}
rs.closed = true
err := rs.rowsi.Close()
if rs.lasterr == nil {
rs.lasterr = err
}
err = rs.rowsi.Close()
if fn := rowsCloseHook(); fn != nil {
fn(rs, &err)
}

View File

@@ -153,8 +153,13 @@ func closeDB(t testing.TB, db *DB) {
if err != nil {
t.Fatalf("error closing DB: %v", err)
}
if count := db.numOpenConns(); count != 0 {
t.Fatalf("%d connections still open after closing DB", count)
var numOpen int
if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
numOpen = db.numOpenConns()
return numOpen == 0
}) {
t.Fatalf("%d connections still open after closing DB", numOpen)
}
}
@@ -276,6 +281,7 @@ func TestQuery(t *testing.T) {
}
}
// TestQueryContext tests canceling the context while scanning the rows.
func TestQueryContext(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -297,7 +303,7 @@ func TestQueryContext(t *testing.T) {
for rows.Next() {
if index == 2 {
cancel()
time.Sleep(10 * time.Millisecond)
waitForRowsClose(t, rows, 5*time.Second)
}
var r row
err = rows.Scan(&r.age, &r.name)
@@ -313,9 +319,13 @@ func TestQueryContext(t *testing.T) {
got = append(got, r)
index++
}
err = rows.Err()
if err != nil {
t.Fatalf("Err: %v", err)
select {
case <-ctx.Done():
if err := ctx.Err(); err != context.Canceled {
t.Fatalf("context err = %v; want context.Canceled")
}
default:
t.Fatalf("context err = nil; want context.Canceled")
}
want := []row{
{age: 1, name: "Alice"},
@@ -327,6 +337,7 @@ func TestQueryContext(t *testing.T) {
// And verify that the final rows.Next() call, which hit EOF,
// also closed the rows connection.
waitForRowsClose(t, rows, 5*time.Second)
waitForFree(t, db, 5*time.Second, 1)
if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
t.Errorf("executed %d Prepare statements; want 1", prepares)
@@ -356,12 +367,27 @@ func waitForFree(t *testing.T, db *DB, maxWait time.Duration, want int) {
}
}
func waitForRowsClose(t *testing.T, rows *Rows, maxWait time.Duration) {
if !waitCondition(maxWait, 5*time.Millisecond, func() bool {
rows.closemu.RLock()
defer rows.closemu.RUnlock()
return rows.closed
}) {
t.Fatal("failed to close rows")
}
}
// TestQueryContextWait ensures that rows and all internal statements are closed when
// a query context is closed during execution.
func TestQueryContextWait(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
prepares0 := numPrepares(t, db)
ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*15)
// TODO(kardianos): convert this from using a timeout to using an explicit
// cancel when the query signals that is is "executing" the query.
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
defer cancel()
// This will trigger the *fakeConn.Prepare method which will take time
// performing the query. The ctxDriverPrepare func will check the context
@@ -374,10 +400,15 @@ func TestQueryContextWait(t *testing.T) {
// Verify closed rows connection after error condition.
waitForFree(t, db, 5*time.Second, 1)
if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
t.Errorf("executed %d Prepare statements; want 1", prepares)
// TODO(kardianos): if the context timeouts before the db.QueryContext
// executes this check may fail. After adjusting how the context
// is canceled above revert this back to a Fatal error.
t.Logf("executed %d Prepare statements; want 1", prepares)
}
}
// TestTxContextWait tests the transaction behavior when the tx context is canceled
// during execution of the query.
func TestTxContextWait(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -386,6 +417,10 @@ func TestTxContextWait(t *testing.T) {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
// Guard against the context being canceled before BeginTx completes.
if err == context.DeadlineExceeded {
t.Skip("tx context canceled prior to first use")
}
t.Fatal(err)
}
@@ -398,12 +433,6 @@ func TestTxContextWait(t *testing.T) {
}
waitForFree(t, db, 5*time.Second, 0)
// Ensure the dropped connection allows more connections to be made.
// Checked on DB Close.
waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
return db.numOpenConns() == 0
})
}
func TestMultiResultSetQuery(t *testing.T) {
@@ -527,6 +556,63 @@ func TestQueryNamedArg(t *testing.T) {
}
}
func TestPoolExhaustOnCancel(t *testing.T) {
if testing.Short() {
t.Skip("long test")
}
db := newTestDB(t, "people")
defer closeDB(t, db)
max := 3
db.SetMaxOpenConns(max)
// First saturate the connection pool.
// Then start new requests for a connection that is cancelled after it is requested.
var saturate, saturateDone sync.WaitGroup
saturate.Add(max)
saturateDone.Add(max)
for i := 0; i < max; i++ {
go func() {
saturate.Done()
rows, err := db.Query("WAIT|500ms|SELECT|people|name,photo|")
if err != nil {
t.Fatalf("Query: %v", err)
}
rows.Close()
saturateDone.Done()
}()
}
saturate.Wait()
// Now cancel the request while it is waiting.
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
for i := 0; i < max; i++ {
ctxReq, cancelReq := context.WithCancel(ctx)
go func() {
time.Sleep(time.Millisecond * 100)
cancelReq()
}()
err := db.PingContext(ctxReq)
if err != context.Canceled {
t.Fatalf("PingContext (Exhaust): %v", err)
}
}
saturateDone.Wait()
// Now try to open a normal connection.
err := db.PingContext(ctx)
if err != nil {
t.Fatalf("PingContext (Normal): %v", err)
}
}
func TestByteOwnership(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -2677,7 +2763,6 @@ func TestIssue18429(t *testing.T) {
}()
}
wg.Wait()
time.Sleep(milliWait * 3 * time.Millisecond)
}
// TestIssue18719 closes the context right before use. The sql.driverConn
@@ -2720,14 +2805,8 @@ func TestIssue18719(t *testing.T) {
// Do not explicitly rollback. The rollback will happen from the
// canceled context.
// Wait for connections to return to pool.
var numOpen int
if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
numOpen = db.numOpenConns()
return numOpen == 0
}) {
t.Fatalf("open conns after hitting EOF = %d; want 0", numOpen)
}
cancel()
waitForRowsClose(t, rows, 5*time.Second)
}
func TestConcurrency(t *testing.T) {

View File

@@ -775,6 +775,20 @@ func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []
var ddBytes = []byte("--")
// indirect drills into interfaces and pointers, returning the pointed-at value.
// If it encounters a nil interface or pointer, indirect returns that nil value.
// This can turn into an infinite loop given a cyclic chain,
// but it matches the Go 1 behavior.
func indirect(vf reflect.Value) reflect.Value {
for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
if vf.IsNil() {
return vf
}
vf = vf.Elem()
}
return vf
}
func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
s := parentStack{p: p}
for i := range tinfo.fields {
@@ -816,17 +830,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
continue
}
}
// Drill into interfaces and pointers.
// This can turn into an infinite loop given a cyclic chain,
// but it matches the Go 1 behavior.
for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
if vf.IsNil() {
return nil
}
vf = vf.Elem()
}
var scratch [64]byte
vf = indirect(vf)
switch vf.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil {
@@ -861,6 +867,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
if err := s.trim(finfo.parents); err != nil {
return err
}
vf = indirect(vf)
k := vf.Kind()
if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
@@ -901,6 +908,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
continue
case fInnerXml:
vf = indirect(vf)
iface := vf.Interface()
switch raw := iface.(type) {
case []byte:

View File

@@ -386,6 +386,140 @@ func ifaceptr(x interface{}) interface{} {
return &x
}
func stringptr(x string) *string {
return &x
}
type T1 struct{}
type T2 struct{}
type T3 struct{}
type IndirComment struct {
T1 T1
Comment *string `xml:",comment"`
T2 T2
}
type DirectComment struct {
T1 T1
Comment string `xml:",comment"`
T2 T2
}
type IfaceComment struct {
T1 T1
Comment interface{} `xml:",comment"`
T2 T2
}
type IndirChardata struct {
T1 T1
Chardata *string `xml:",chardata"`
T2 T2
}
type DirectChardata struct {
T1 T1
Chardata string `xml:",chardata"`
T2 T2
}
type IfaceChardata struct {
T1 T1
Chardata interface{} `xml:",chardata"`
T2 T2
}
type IndirCDATA struct {
T1 T1
CDATA *string `xml:",cdata"`
T2 T2
}
type DirectCDATA struct {
T1 T1
CDATA string `xml:",cdata"`
T2 T2
}
type IfaceCDATA struct {
T1 T1
CDATA interface{} `xml:",cdata"`
T2 T2
}
type IndirInnerXML struct {
T1 T1
InnerXML *string `xml:",innerxml"`
T2 T2
}
type DirectInnerXML struct {
T1 T1
InnerXML string `xml:",innerxml"`
T2 T2
}
type IfaceInnerXML struct {
T1 T1
InnerXML interface{} `xml:",innerxml"`
T2 T2
}
type IndirElement struct {
T1 T1
Element *string
T2 T2
}
type DirectElement struct {
T1 T1
Element string
T2 T2
}
type IfaceElement struct {
T1 T1
Element interface{}
T2 T2
}
type IndirOmitEmpty struct {
T1 T1
OmitEmpty *string `xml:",omitempty"`
T2 T2
}
type DirectOmitEmpty struct {
T1 T1
OmitEmpty string `xml:",omitempty"`
T2 T2
}
type IfaceOmitEmpty struct {
T1 T1
OmitEmpty interface{} `xml:",omitempty"`
T2 T2
}
type IndirAny struct {
T1 T1
Any *string `xml:",any"`
T2 T2
}
type DirectAny struct {
T1 T1
Any string `xml:",any"`
T2 T2
}
type IfaceAny struct {
T1 T1
Any interface{} `xml:",any"`
T2 T2
}
var (
nameAttr = "Sarah"
ageAttr = uint(12)
@@ -398,10 +532,12 @@ var (
// please try to make them two-way as well to ensure that
// marshaling and unmarshaling are as symmetrical as feasible.
var marshalTests = []struct {
Value interface{}
ExpectXML string
MarshalOnly bool
UnmarshalOnly bool
Value interface{}
ExpectXML string
MarshalOnly bool
MarshalError string
UnmarshalOnly bool
UnmarshalError string
}{
// Test nil marshals to nothing
{Value: nil, ExpectXML: ``, MarshalOnly: true},
@@ -1133,6 +1269,382 @@ var marshalTests = []struct {
ExpectXML: `<NestedAndCData><A><B></B><B></B></A><![CDATA[test]]></NestedAndCData>`,
Value: &NestedAndCData{AB: make([]string, 2), CDATA: "test"},
},
// Test pointer indirection in various kinds of fields.
// https://golang.org/issue/19063
{
ExpectXML: `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
Value: &IndirComment{Comment: stringptr("hi")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirComment><T1></T1><T2></T2></IndirComment>`,
Value: &IndirComment{Comment: stringptr("")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirComment><T1></T1><T2></T2></IndirComment>`,
Value: &IndirComment{Comment: nil},
MarshalError: "xml: bad type for comment field of xml.IndirComment",
},
{
ExpectXML: `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
Value: &IndirComment{Comment: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
Value: &IfaceComment{Comment: "hi"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
Value: &IfaceComment{Comment: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
Value: &IfaceComment{Comment: nil},
MarshalError: "xml: bad type for comment field of xml.IfaceComment",
},
{
ExpectXML: `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
Value: &IfaceComment{Comment: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectComment><T1></T1><!--hi--><T2></T2></DirectComment>`,
Value: &DirectComment{Comment: string("hi")},
},
{
ExpectXML: `<DirectComment><T1></T1><T2></T2></DirectComment>`,
Value: &DirectComment{Comment: string("")},
},
{
ExpectXML: `<IndirChardata><T1></T1>hi<T2></T2></IndirChardata>`,
Value: &IndirChardata{Chardata: stringptr("hi")},
},
{
ExpectXML: `<IndirChardata><T1></T1><![CDATA[hi]]><T2></T2></IndirChardata>`,
Value: &IndirChardata{Chardata: stringptr("hi")},
UnmarshalOnly: true, // marshals without CDATA
},
{
ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
Value: &IndirChardata{Chardata: stringptr("")},
},
{
ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
Value: &IndirChardata{Chardata: nil},
MarshalOnly: true, // unmarshal leaves Chardata=stringptr("")
},
{
ExpectXML: `<IfaceChardata><T1></T1>hi<T2></T2></IfaceChardata>`,
Value: &IfaceChardata{Chardata: string("hi")},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceChardata><T1></T1><![CDATA[hi]]><T2></T2></IfaceChardata>`,
Value: &IfaceChardata{Chardata: string("hi")},
UnmarshalOnly: true, // marshals without CDATA
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
Value: &IfaceChardata{Chardata: string("")},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
Value: &IfaceChardata{Chardata: nil},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<DirectChardata><T1></T1>hi<T2></T2></DirectChardata>`,
Value: &DirectChardata{Chardata: string("hi")},
},
{
ExpectXML: `<DirectChardata><T1></T1><![CDATA[hi]]><T2></T2></DirectChardata>`,
Value: &DirectChardata{Chardata: string("hi")},
UnmarshalOnly: true, // marshals without CDATA
},
{
ExpectXML: `<DirectChardata><T1></T1><T2></T2></DirectChardata>`,
Value: &DirectChardata{Chardata: string("")},
},
{
ExpectXML: `<IndirCDATA><T1></T1><![CDATA[hi]]><T2></T2></IndirCDATA>`,
Value: &IndirCDATA{CDATA: stringptr("hi")},
},
{
ExpectXML: `<IndirCDATA><T1></T1>hi<T2></T2></IndirCDATA>`,
Value: &IndirCDATA{CDATA: stringptr("hi")},
UnmarshalOnly: true, // marshals with CDATA
},
{
ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
Value: &IndirCDATA{CDATA: stringptr("")},
},
{
ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
Value: &IndirCDATA{CDATA: nil},
MarshalOnly: true, // unmarshal leaves CDATA=stringptr("")
},
{
ExpectXML: `<IfaceCDATA><T1></T1><![CDATA[hi]]><T2></T2></IfaceCDATA>`,
Value: &IfaceCDATA{CDATA: string("hi")},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceCDATA><T1></T1>hi<T2></T2></IfaceCDATA>`,
Value: &IfaceCDATA{CDATA: string("hi")},
UnmarshalOnly: true, // marshals with CDATA
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
Value: &IfaceCDATA{CDATA: string("")},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
Value: &IfaceCDATA{CDATA: nil},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<DirectCDATA><T1></T1><![CDATA[hi]]><T2></T2></DirectCDATA>`,
Value: &DirectCDATA{CDATA: string("hi")},
},
{
ExpectXML: `<DirectCDATA><T1></T1>hi<T2></T2></DirectCDATA>`,
Value: &DirectCDATA{CDATA: string("hi")},
UnmarshalOnly: true, // marshals with CDATA
},
{
ExpectXML: `<DirectCDATA><T1></T1><T2></T2></DirectCDATA>`,
Value: &DirectCDATA{CDATA: string("")},
},
{
ExpectXML: `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
Value: &IndirInnerXML{InnerXML: stringptr("<hi/>")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
Value: &IndirInnerXML{InnerXML: stringptr("")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
Value: &IndirInnerXML{InnerXML: nil},
},
{
ExpectXML: `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
Value: &IndirInnerXML{InnerXML: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
Value: &IfaceInnerXML{InnerXML: "<hi/>"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
Value: &IfaceInnerXML{InnerXML: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
Value: &IfaceInnerXML{InnerXML: nil},
},
{
ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
Value: &IfaceInnerXML{InnerXML: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
Value: &DirectInnerXML{InnerXML: string("<hi/>")},
MarshalOnly: true,
},
{
ExpectXML: `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
Value: &DirectInnerXML{InnerXML: string("<T1></T1><hi/><T2></T2>")},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
Value: &DirectInnerXML{InnerXML: string("")},
MarshalOnly: true,
},
{
ExpectXML: `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
Value: &DirectInnerXML{InnerXML: string("<T1></T1><T2></T2>")},
UnmarshalOnly: true,
},
{
ExpectXML: `<IndirElement><T1></T1><Element>hi</Element><T2></T2></IndirElement>`,
Value: &IndirElement{Element: stringptr("hi")},
},
{
ExpectXML: `<IndirElement><T1></T1><Element></Element><T2></T2></IndirElement>`,
Value: &IndirElement{Element: stringptr("")},
},
{
ExpectXML: `<IndirElement><T1></T1><T2></T2></IndirElement>`,
Value: &IndirElement{Element: nil},
},
{
ExpectXML: `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
Value: &IfaceElement{Element: "hi"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
Value: &IfaceElement{Element: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
Value: &IfaceElement{Element: nil},
},
{
ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
Value: &IfaceElement{Element: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectElement><T1></T1><Element>hi</Element><T2></T2></DirectElement>`,
Value: &DirectElement{Element: string("hi")},
},
{
ExpectXML: `<DirectElement><T1></T1><Element></Element><T2></T2></DirectElement>`,
Value: &DirectElement{Element: string("")},
},
{
ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IndirOmitEmpty>`,
Value: &IndirOmitEmpty{OmitEmpty: stringptr("hi")},
},
{
// Note: Changed in Go 1.8 to include <OmitEmpty> element (because x.OmitEmpty != nil).
ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
Value: &IndirOmitEmpty{OmitEmpty: stringptr("")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
Value: &IndirOmitEmpty{OmitEmpty: stringptr("")},
UnmarshalOnly: true,
},
{
ExpectXML: `<IndirOmitEmpty><T1></T1><T2></T2></IndirOmitEmpty>`,
Value: &IndirOmitEmpty{OmitEmpty: nil},
},
{
ExpectXML: `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
Value: &IfaceOmitEmpty{OmitEmpty: "hi"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
Value: &IfaceOmitEmpty{OmitEmpty: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
Value: &IfaceOmitEmpty{OmitEmpty: nil},
},
{
ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
Value: &IfaceOmitEmpty{OmitEmpty: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></DirectOmitEmpty>`,
Value: &DirectOmitEmpty{OmitEmpty: string("hi")},
},
{
ExpectXML: `<DirectOmitEmpty><T1></T1><T2></T2></DirectOmitEmpty>`,
Value: &DirectOmitEmpty{OmitEmpty: string("")},
},
{
ExpectXML: `<IndirAny><T1></T1><Any>hi</Any><T2></T2></IndirAny>`,
Value: &IndirAny{Any: stringptr("hi")},
},
{
ExpectXML: `<IndirAny><T1></T1><Any></Any><T2></T2></IndirAny>`,
Value: &IndirAny{Any: stringptr("")},
},
{
ExpectXML: `<IndirAny><T1></T1><T2></T2></IndirAny>`,
Value: &IndirAny{Any: nil},
},
{
ExpectXML: `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
Value: &IfaceAny{Any: "hi"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
Value: &IfaceAny{Any: nil},
},
{
ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectAny><T1></T1><Any>hi</Any><T2></T2></DirectAny>`,
Value: &DirectAny{Any: string("hi")},
},
{
ExpectXML: `<DirectAny><T1></T1><Any></Any><T2></T2></DirectAny>`,
Value: &DirectAny{Any: string("")},
},
{
ExpectXML: `<IndirFoo><T1></T1><Foo>hi</Foo><T2></T2></IndirFoo>`,
Value: &IndirAny{Any: stringptr("hi")},
UnmarshalOnly: true,
},
{
ExpectXML: `<IndirFoo><T1></T1><Foo></Foo><T2></T2></IndirFoo>`,
Value: &IndirAny{Any: stringptr("")},
UnmarshalOnly: true,
},
{
ExpectXML: `<IndirFoo><T1></T1><T2></T2></IndirFoo>`,
Value: &IndirAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceFoo><T1></T1><Foo>hi</Foo><T2></T2></IfaceFoo>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectFoo><T1></T1><Foo>hi</Foo><T2></T2></DirectFoo>`,
Value: &DirectAny{Any: string("hi")},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectFoo><T1></T1><Foo></Foo><T2></T2></DirectFoo>`,
Value: &DirectAny{Any: string("")},
UnmarshalOnly: true,
},
}
func TestMarshal(t *testing.T) {
@@ -1142,7 +1654,17 @@ func TestMarshal(t *testing.T) {
}
data, err := Marshal(test.Value)
if err != nil {
t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
if test.MarshalError == "" {
t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
continue
}
if !strings.Contains(err.Error(), test.MarshalError) {
t.Errorf("#%d: marshal(%#v): %s, want %q", idx, test.Value, err, test.MarshalError)
}
continue
}
if test.MarshalError != "" {
t.Errorf("#%d: Marshal succeeded, want error %q", idx, test.MarshalError)
continue
}
if got, want := string(data), test.ExpectXML; got != want {
@@ -1268,8 +1790,16 @@ func TestUnmarshal(t *testing.T) {
}
if err != nil {
t.Errorf("#%d: unexpected error: %#v", i, err)
} else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
if test.UnmarshalError == "" {
t.Errorf("#%d: unmarshal(%#v): %s", i, test.ExpectXML, err)
continue
}
if !strings.Contains(err.Error(), test.UnmarshalError) {
t.Errorf("#%d: unmarshal(%#v): %s, want %q", i, test.ExpectXML, err, test.UnmarshalError)
}
continue
}
if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
}
}

View File

@@ -266,7 +266,7 @@ func defaultGOPATH() string {
}
if home := os.Getenv(env); home != "" {
def := filepath.Join(home, "go")
if def == runtime.GOROOT() {
if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
// Don't set the default GOPATH to GOROOT,
// as that will trigger warnings from the go tool.
return ""

View File

@@ -2478,17 +2478,24 @@ func TestNumMethodOnDDD(t *testing.T) {
}
func TestPtrTo(t *testing.T) {
// This block of code means that the ptrToThis field of the
// reflect data for *unsafe.Pointer is non zero, see
// https://golang.org/issue/19003
var x unsafe.Pointer
var y = &x
var z = &y
var i int
typ := TypeOf(i)
typ := TypeOf(z)
for i = 0; i < 100; i++ {
typ = PtrTo(typ)
}
for i = 0; i < 100; i++ {
typ = typ.Elem()
}
if typ != TypeOf(i) {
t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(i))
if typ != TypeOf(z) {
t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(z))
}
}

View File

@@ -1469,6 +1469,7 @@ func (t *rtype) ptrTo() *rtype {
pp := *prototype
pp.str = resolveReflectName(newName(s, "", "", false))
pp.ptrToThis = 0
// For the type structures linked into the binary, the
// compiler provides a good hash of the string.

View File

@@ -628,10 +628,12 @@ func (c *gcControllerState) endCycle() {
//go:nowritebarrier
func (c *gcControllerState) enlistWorker() {
// If there are idle Ps, wake one so it will run an idle worker.
if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 {
wakep()
return
}
// NOTE: This is suspected of causing deadlocks. See golang.org/issue/19112.
//
// if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 {
// wakep()
// return
// }
// There are no idle Ps. If we need more dedicated workers,
// try to preempt a running P so it will switch to a worker.

View File

@@ -821,6 +821,7 @@ func (m *M) Run() int {
haveExamples = len(m.examples) > 0
testRan, testOk := runTests(m.deps.MatchString, m.tests)
exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
stopAlarm()
if !testRan && !exampleRan && *matchBenchmarks == "" {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
}

View File

@@ -0,0 +1,8 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
#define REDMASK51 0x0007FFFFFFFFFFFF

View File

@@ -7,8 +7,8 @@
// +build amd64,!gccgo,!appengine
DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF
GLOBL ·REDMASK51(SB), 8, $8
// These constants cannot be encoded in non-MOVQ immediates.
// We access them directly from memory instead.
DATA ·_121666_213(SB)/8, $996687872
GLOBL ·_121666_213(SB), 8, $8

View File

@@ -7,6 +7,8 @@
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// func freeze(inout *[5]uint64)
TEXT ·freeze(SB),7,$0-8
MOVQ inout+0(FP), DI
@@ -16,7 +18,7 @@ TEXT ·freeze(SB),7,$0-8
MOVQ 16(DI),CX
MOVQ 24(DI),R8
MOVQ 32(DI),R9
MOVQ ·REDMASK51(SB),AX
MOVQ $REDMASK51,AX
MOVQ AX,R10
SUBQ $18,R10
MOVQ $3,R11

View File

@@ -7,6 +7,8 @@
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// func ladderstep(inout *[5][5]uint64)
TEXT ·ladderstep(SB),0,$296-8
MOVQ inout+0(FP),DI
@@ -118,7 +120,7 @@ TEXT ·ladderstep(SB),0,$296-8
MULQ 72(SP)
ADDQ AX,R12
ADCQ DX,R13
MOVQ ·REDMASK51(SB),DX
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
ANDQ DX,SI
SHLQ $13,R9:R8
@@ -233,7 +235,7 @@ TEXT ·ladderstep(SB),0,$296-8
MULQ 32(SP)
ADDQ AX,R12
ADCQ DX,R13
MOVQ ·REDMASK51(SB),DX
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
ANDQ DX,SI
SHLQ $13,R9:R8
@@ -438,7 +440,7 @@ TEXT ·ladderstep(SB),0,$296-8
MULQ 72(SP)
ADDQ AX,R12
ADCQ DX,R13
MOVQ ·REDMASK51(SB),DX
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
ANDQ DX,SI
SHLQ $13,R9:R8
@@ -588,7 +590,7 @@ TEXT ·ladderstep(SB),0,$296-8
MULQ 32(SP)
ADDQ AX,R12
ADCQ DX,R13
MOVQ ·REDMASK51(SB),DX
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
ANDQ DX,SI
SHLQ $13,R9:R8
@@ -728,7 +730,7 @@ TEXT ·ladderstep(SB),0,$296-8
MULQ 152(DI)
ADDQ AX,R12
ADCQ DX,R13
MOVQ ·REDMASK51(SB),DX
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
ANDQ DX,SI
SHLQ $13,R9:R8
@@ -843,7 +845,7 @@ TEXT ·ladderstep(SB),0,$296-8
MULQ 192(DI)
ADDQ AX,R12
ADCQ DX,R13
MOVQ ·REDMASK51(SB),DX
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
ANDQ DX,SI
SHLQ $13,R9:R8
@@ -993,7 +995,7 @@ TEXT ·ladderstep(SB),0,$296-8
MULQ 32(DI)
ADDQ AX,R12
ADCQ DX,R13
MOVQ ·REDMASK51(SB),DX
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
ANDQ DX,SI
SHLQ $13,R9:R8
@@ -1143,7 +1145,7 @@ TEXT ·ladderstep(SB),0,$296-8
MULQ 112(SP)
ADDQ AX,R12
ADCQ DX,R13
MOVQ ·REDMASK51(SB),DX
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
ANDQ DX,SI
SHLQ $13,R9:R8
@@ -1329,7 +1331,7 @@ TEXT ·ladderstep(SB),0,$296-8
MULQ 192(SP)
ADDQ AX,R12
ADCQ DX,R13
MOVQ ·REDMASK51(SB),DX
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
ANDQ DX,SI
SHLQ $13,R9:R8

View File

@@ -7,6 +7,8 @@
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// func mul(dest, a, b *[5]uint64)
TEXT ·mul(SB),0,$16-24
MOVQ dest+0(FP), DI
@@ -121,7 +123,7 @@ TEXT ·mul(SB),0,$16-24
MULQ 32(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ ·REDMASK51(SB),SI
MOVQ $REDMASK51,SI
SHLQ $13,R9:R8
ANDQ SI,R8
SHLQ $13,R11:R10

View File

@@ -7,6 +7,8 @@
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// func square(out, in *[5]uint64)
TEXT ·square(SB),7,$0-16
MOVQ out+0(FP), DI
@@ -84,7 +86,7 @@ TEXT ·square(SB),7,$0-16
MULQ 32(SI)
ADDQ AX,R13
ADCQ DX,R14
MOVQ ·REDMASK51(SB),SI
MOVQ $REDMASK51,SI
SHLQ $13,R8:CX
ANDQ SI,CX
SHLQ $13,R10:R9

View File

@@ -0,0 +1,36 @@
// run
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
//go:noinline
func f(x int) {
}
//go:noinline
func val() int8 {
return -1
}
var (
array = [257]int{}
slice = array[1:]
)
func init() {
for i := range array {
array[i] = i - 1
}
}
func main() {
x := val()
y := int(uint8(x))
f(y) // try and force y to be calculated and spilled
if slice[y] != 255 {
panic("incorrect value")
}
}

View File

@@ -0,0 +1,21 @@
// errorcheck
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Make sure error message for invalid conditions
// or tags are consistent with earlier Go versions.
package p
func _() {
if a := 10 { // ERROR "a := 10 used as value"
}
for b := 10 { // ERROR "b := 10 used as value"
}
switch c := 10 { // ERROR "c := 10 used as value"
}
}

View File

@@ -1,4 +1,4 @@
// +build amd64
// +build !386,!arm,!mips,!mipsle,!amd64p32
// compile
// Copyright 2013 The Go Authors. All rights reserved.

View File

@@ -220,3 +220,19 @@ func f22(x *int) (y *int) {
*p = x // no barrier
return
}
type T23 struct {
p *int
a int
}
var t23 T23
var i23 int
func f23() {
// zeroing global needs write barrier for the hybrid barrier.
t23 = T23{} // ERROR "write barrier"
// also test partial assignments
t23 = T23{a: 1} // ERROR "write barrier"
t23 = T23{p: &i23} // ERROR "write barrier"
}